From 2a2ad8931e719ed8066db368f80db74d94d16169 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Sun, 11 Jan 2015 14:55:01 -0600 Subject: [PATCH 001/651] Updating sample configuration - adding warning about using gzip with ssl. --- debian/changelog | 7 +++++++ debian/conf/sites-available/default | 3 +++ 2 files changed, 10 insertions(+) diff --git a/debian/changelog b/debian/changelog index be7399f..9f91900 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.6.2-6) UNRELEASED; urgency=medium + + * debian/conf/sites-available/default: + + Add comment about disabling gzip in HTTPS. (Closes: #773332) + + -- Michael Lustfield Sun, 11 Jan 2015 14:49:36 -0600 + nginx (1.6.2-5) unstable; urgency=medium [ Christos Trochalakis ] diff --git a/debian/conf/sites-available/default b/debian/conf/sites-available/default index b4c49af..d63660c 100644 --- a/debian/conf/sites-available/default +++ b/debian/conf/sites-available/default @@ -22,6 +22,9 @@ server { # listen 443 ssl default_server; # listen [::]:443 ssl default_server; # + # Note: You should disable gzip for SSL traffic. + # See: https://bugs.debian.org/773332 + # # Self signed certs generated by the ssl-cert package # Don't use them in a production server! # From 635d51ca6d52b8ff57d4312de23f6c0913572d8f Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Sun, 11 Jan 2015 16:00:56 -0600 Subject: [PATCH 002/651] Added vim syntax highlighting. --- debian/changelog | 2 ++ debian/nginx-common.dirs | 2 ++ debian/nginx-common.install | 2 ++ 3 files changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 9f91900..d44a80b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,8 @@ nginx (1.6.2-6) UNRELEASED; urgency=medium * debian/conf/sites-available/default: + Add comment about disabling gzip in HTTPS. (Closes: #773332) + * debian/nginx-common.{dirs,install}, debian/vim/*: + + Installing vim syntax highlighting from package. (Closes: #771609) -- Michael Lustfield Sun, 11 Jan 2015 14:49:36 -0600 diff --git a/debian/nginx-common.dirs b/debian/nginx-common.dirs index c4ea108..d75dabf 100644 --- a/debian/nginx-common.dirs +++ b/debian/nginx-common.dirs @@ -4,6 +4,8 @@ etc/nginx/sites-enabled etc/nginx/conf.d etc/ufw/applications.d usr/share/nginx +usr/share/vim/addons +usr/share/vim/registry var/log/nginx var/lib/nginx var/www/html diff --git a/debian/nginx-common.install b/debian/nginx-common.install index 35114de..9148328 100644 --- a/debian/nginx-common.install +++ b/debian/nginx-common.install @@ -1,3 +1,5 @@ debian/conf/* etc/nginx debian/ufw/nginx etc/ufw/applications.d debian/index.html usr/share/nginx/html/ +debian/vim/nginx.yaml usr/share/vim/registry +contrib/vim/* usr/share/vim/addons From 586aebd331900f87f850fef126bcc462033b5a12 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Sun, 11 Jan 2015 16:03:03 -0600 Subject: [PATCH 003/651] Adding note for contribution. --- debian/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/changelog b/debian/changelog index d44a80b..ede0c9d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,7 @@ nginx (1.6.2-6) UNRELEASED; urgency=medium + Add comment about disabling gzip in HTTPS. (Closes: #773332) * debian/nginx-common.{dirs,install}, debian/vim/*: + Installing vim syntax highlighting from package. (Closes: #771609) + Thanks Emmanuel Bouthenot for building this patch. -- Michael Lustfield Sun, 11 Jan 2015 14:49:36 -0600 From b7385768b68ec795bec7b5edb13b46cdcb6c2204 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Sun, 11 Jan 2015 16:05:59 -0600 Subject: [PATCH 004/651] Adding missing files. --- debian/vim/nginx.yaml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 debian/vim/nginx.yaml diff --git a/debian/vim/nginx.yaml b/debian/vim/nginx.yaml new file mode 100644 index 0000000..37cf6bf --- /dev/null +++ b/debian/vim/nginx.yaml @@ -0,0 +1,6 @@ +addon: nginx +description: "allow syntax highlighting for Nginx configuration files" +files: + - ftdetect/nginx.vim + - indent/nginx.vim + - syntax/nginx.vim From 8680ff9cd1c96170f6e79f9d71726e9b62013940 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Sun, 11 Jan 2015 16:20:46 -0600 Subject: [PATCH 005/651] Adding upstart script --- debian/changelog | 3 +++ debian/nginx-common.nginx.upstart | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 debian/nginx-common.nginx.upstart diff --git a/debian/changelog b/debian/changelog index ede0c9d..cfba02f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -5,6 +5,9 @@ nginx (1.6.2-6) UNRELEASED; urgency=medium * debian/nginx-common.{dirs,install}, debian/vim/*: + Installing vim syntax highlighting from package. (Closes: #771609) Thanks Emmanuel Bouthenot for building this patch. + * debian/nginx-common.nginx.upstart: + + Created file to support upstart jobs. (Closes: #745483) + Thanks Cameron Norman for building this file. -- Michael Lustfield Sun, 11 Jan 2015 14:49:36 -0600 diff --git a/debian/nginx-common.nginx.upstart b/debian/nginx-common.nginx.upstart new file mode 100644 index 0000000..317bcb0 --- /dev/null +++ b/debian/nginx-common.nginx.upstart @@ -0,0 +1,16 @@ +description "nginx - small, powerful, scalable web/proxy server" + +start on filesystem and static-network-up +stop on runlevel [016] + +expect fork +respawn + +pre-start script + [ -x /usr/sbin/nginx ] || { stop; exit 0; } + /usr/sbin/nginx -q -t -g 'daemon on; master_process on;' || { stop; exit 0; } +end script + +exec /usr/sbin/nginx -g 'daemon on; master_process on;' + +pre-stop exec /usr/sbin/nginx -s quit From 843750b958f40f2dcbf835ca931f01abe9d817a0 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Sun, 11 Jan 2015 16:27:24 -0600 Subject: [PATCH 006/651] Adding -fPIE -pie to build. --- debian/changelog | 2 ++ debian/rules | 1 + 2 files changed, 3 insertions(+) diff --git a/debian/changelog b/debian/changelog index cfba02f..6b2d9ef 100644 --- a/debian/changelog +++ b/debian/changelog @@ -8,6 +8,8 @@ nginx (1.6.2-6) UNRELEASED; urgency=medium * debian/nginx-common.nginx.upstart: + Created file to support upstart jobs. (Closes: #745483) Thanks Cameron Norman for building this file. + * debian/rules: + + Added -fPIE -pie to build. (Closes: #747025) -- Michael Lustfield Sun, 11 Jan 2015 14:49:36 -0600 diff --git a/debian/rules b/debian/rules index 9e3f259..16f6701 100755 --- a/debian/rules +++ b/debian/rules @@ -29,6 +29,7 @@ endif common_configure_flags := \ --with-cc-opt="$(debian_cflags)" \ --with-ld-opt="$(debian_ldflags)" \ + -fPIE -pie \ --prefix=/usr/share/nginx \ --conf-path=/etc/nginx/nginx.conf \ --http-log-path=/var/log/nginx/access.log \ From ef4e50d1552c5fd883e7cdf8fe0ded933af12f37 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Sun, 11 Jan 2015 16:33:05 -0600 Subject: [PATCH 007/651] Updated nginx-lua version. --- debian/changelog | 2 + debian/modules/README.Modules-versions | 6 +- debian/modules/nginx-lua/.gitmodules | 3 + debian/modules/nginx-lua/README.markdown | 161 ++++++++++-------- .../modules/nginx-lua/doc/HttpLuaModule.wiki | 147 +++++++++------- .../nginx-lua/src/api/ngx_http_lua_api.h | 2 +- .../nginx-lua/src/ngx_http_lua_accessby.c | 2 +- .../nginx-lua/src/ngx_http_lua_common.h | 5 +- .../nginx-lua/src/ngx_http_lua_contentby.c | 7 +- .../nginx-lua/src/ngx_http_lua_directive.c | 89 +++++++++- .../nginx-lua/src/ngx_http_lua_headers.c | 50 ++---- .../nginx-lua/src/ngx_http_lua_initworkerby.c | 17 +- .../nginx-lua/src/ngx_http_lua_logby.c | 3 +- .../nginx-lua/src/ngx_http_lua_module.c | 4 + .../nginx-lua/src/ngx_http_lua_output.c | 83 ++++----- .../nginx-lua/src/ngx_http_lua_phase.c | 4 + .../nginx-lua/src/ngx_http_lua_rewriteby.c | 3 +- .../nginx-lua/src/ngx_http_lua_sleep.c | 6 +- .../nginx-lua/src/ngx_http_lua_socket_tcp.c | 60 ++++++- .../nginx-lua/src/ngx_http_lua_socket_udp.c | 6 +- .../nginx-lua/src/ngx_http_lua_timer.c | 115 +++++++++++-- .../modules/nginx-lua/src/ngx_http_lua_util.c | 135 +++++++-------- .../modules/nginx-lua/src/ngx_http_lua_util.h | 19 ++- debian/modules/nginx-lua/t/002-content.t | 4 +- debian/modules/nginx-lua/t/009-log.t | 30 ++-- debian/modules/nginx-lua/t/014-bugs.t | 3 +- debian/modules/nginx-lua/t/020-subrequest.t | 2 - .../nginx-lua/t/023-rewrite/on-abort.t | 12 +- .../nginx-lua/t/023-rewrite/tcp-socket.t | 30 ++-- .../nginx-lua/t/023-rewrite/unix-socket.t | 4 +- .../nginx-lua/t/023-rewrite/uthread-spawn.t | 4 +- .../modules/nginx-lua/t/024-access/on-abort.t | 12 +- .../nginx-lua/t/024-access/uthread-spawn.t | 4 +- debian/modules/nginx-lua/t/044-req-body.t | 14 +- debian/modules/nginx-lua/t/056-flush.t | 35 +++- .../modules/nginx-lua/t/057-flush-timeout.t | 108 +++++++++++- debian/modules/nginx-lua/t/058-tcp-socket.t | 116 +++++++++++-- debian/modules/nginx-lua/t/059-unix-socket.t | 4 +- debian/modules/nginx-lua/t/064-pcall.t | 13 +- debian/modules/nginx-lua/t/073-backtrace.t | 16 +- debian/modules/nginx-lua/t/075-logby.t | 9 +- debian/modules/nginx-lua/t/082-body-filter.t | 6 +- debian/modules/nginx-lua/t/087-udp-socket.t | 52 ++++-- debian/modules/nginx-lua/t/089-phase.t | 21 ++- debian/modules/nginx-lua/t/091-coroutine.t | 9 +- .../modules/nginx-lua/t/093-uthread-spawn.t | 4 +- debian/modules/nginx-lua/t/098-uthread-wait.t | 24 +-- debian/modules/nginx-lua/t/101-on-abort.t | 12 +- .../modules/nginx-lua/t/104-req-raw-header.t | 106 +++++++++++- debian/modules/nginx-lua/t/106-timer.t | 68 ++++++-- debian/modules/nginx-lua/t/107-timer-errors.t | 72 ++++---- debian/modules/nginx-lua/t/108-timer-safe.t | 8 +- debian/modules/nginx-lua/t/124-init-worker.t | 36 +++- debian/modules/nginx-lua/t/129-ssl-socket.t | 58 +++++-- debian/modules/nginx-lua/util/build2.sh | 1 + debian/modules/nginx-lua/valgrind.suppress | 10 ++ 56 files changed, 1300 insertions(+), 536 deletions(-) create mode 100644 debian/modules/nginx-lua/.gitmodules diff --git a/debian/changelog b/debian/changelog index 6b2d9ef..37922fa 100644 --- a/debian/changelog +++ b/debian/changelog @@ -10,6 +10,8 @@ nginx (1.6.2-6) UNRELEASED; urgency=medium Thanks Cameron Norman for building this file. * debian/rules: + Added -fPIE -pie to build. (Closes: #747025) + * debian/modules/nginx-lua/*: + + Updated module version. (Closes: #762494) -- Michael Lustfield Sun, 11 Jan 2015 14:49:36 -0600 diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index 542ecee..d4bd95c 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -21,9 +21,9 @@ README for Modules versions Version: v0.56 nginx-lua - Homepage: https://github.com/chaoslawful/lua-nginx-module - https://github.com/chaoslawful/lua-nginx-module.git - Version: v0.9.12 + Homepage: https://github.com/openresty/lua-nginx-module + https://github.com/openresty/lua-nginx-module.git + Version: v0.9.13 nginx-upstream-fair Homepage: https://github.com/gnosek/nginx-upstream-fair diff --git a/debian/modules/nginx-lua/.gitmodules b/debian/modules/nginx-lua/.gitmodules new file mode 100644 index 0000000..db339a7 --- /dev/null +++ b/debian/modules/nginx-lua/.gitmodules @@ -0,0 +1,3 @@ +[submodule "deps/ngx_devel_kit"] + path = deps/ngx_devel_kit + url = git://github.com/simpl/ngx_devel_kit.git diff --git a/debian/modules/nginx-lua/README.markdown b/debian/modules/nginx-lua/README.markdown index b344ff5..d620ec4 100644 --- a/debian/modules/nginx-lua/README.markdown +++ b/debian/modules/nginx-lua/README.markdown @@ -37,6 +37,7 @@ Table of Contents * [Lua Coroutine Yielding/Resuming](#lua-coroutine-yieldingresuming) * [Lua Variable Scope](#lua-variable-scope) * [Locations Configured by Subrequest Directives of Other Modules](#locations-configured-by-subrequest-directives-of-other-modules) + * [Cocockets Not Available Everywhere](#cocockets-not-available-everywhere) * [Special PCRE Sequences](#special-pcre-sequences) * [Mixing with SSI Not Supported](#mixing-with-ssi-not-supported) * [SPDY Mode Not Fully Supported](#spdy-mode-not-fully-supported) @@ -53,12 +54,12 @@ Table of Contents Status ====== -This module is under active development and is production ready. +Production ready. Version ======= -This document describes ngx_lua [v0.9.12](https://github.com/openresty/lua-nginx-module/tags) released on 2 September 2014. +This document describes ngx_lua [v0.9.13](https://github.com/openresty/lua-nginx-module/tags) released on 21 November 2014. Synopsis ======== @@ -291,7 +292,7 @@ Nginx Compatibility =================== The latest module is compatible with the following versions of Nginx: -* 1.7.x (last tested: 1.7.4) +* 1.7.x (last tested: 1.7.7) * 1.6.x * 1.5.x (last tested: 1.5.12) * 1.4.x (last tested: 1.4.4) @@ -312,17 +313,17 @@ The [ngx_openresty bundle](http://openresty.org) can be used to install Nginx, n Alternatively, ngx_lua can be manually compiled into Nginx: 1. Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuaJIT can be downloaded from the [the LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuajIT and/or Lua. -1. Download the latest version of the ngx_devel_kit (NDK) module [HERE](http://github.com/simpl/ngx_devel_kit/tags). -1. Download the latest version of ngx_lua [HERE](http://github.com/openresty/lua-nginx-module/tags). +1. Download the latest version of the ngx_devel_kit (NDK) module [HERE](https://github.com/simpl/ngx_devel_kit/tags). +1. Download the latest version of ngx_lua [HERE](https://github.com/openresty/lua-nginx-module/tags). 1. Download the latest version of Nginx [HERE](http://nginx.org/) (See [Nginx Compatibility](#nginx-compatibility)) Build the source with this module: ```bash -wget 'http://nginx.org/download/nginx-1.7.4.tar.gz' -tar -xzvf nginx-1.7.4.tar.gz -cd nginx-1.7.4/ +wget 'http://nginx.org/download/nginx-1.7.7.tar.gz' +tar -xzvf nginx-1.7.7.tar.gz +cd nginx-1.7.7/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib @@ -412,7 +413,7 @@ The [openresty](https://groups.google.com/group/openresty) mailing list is for C Code Repository =============== -The code repository of this project is hosted on github at [openresty/lua-nginx-module](http://github.com/openresty/lua-nginx-module). +The code repository of this project is hosted on github at [openresty/lua-nginx-module](https://github.com/openresty/lua-nginx-module). [Back to TOC](#table-of-contents) @@ -703,7 +704,7 @@ To find out all the uses of Lua global variables in your Lua code, you can run t The output says that the line 1489 of file `lib/foo/bar.lua` writes to a global variable named `contains`, the line 1506 reads from the global variable `setvar`, and line 1545 reads the global `varexpand`. -This tool will guarantee that local variables in the Lua module functions are all declared with the `local` keyword, otherwise a runtime exception will be thrown. It prevents undesirable race conditions while accessing such variables. See [Data Sharing within an Nginx Worker](#data_sharing_within_an_nginx_worker) for the reasons behind this. +This tool will guarantee that local variables in the Lua module functions are all declared with the `local` keyword, otherwise a runtime exception will be thrown. It prevents undesirable race conditions while accessing such variables. See [Data Sharing within an Nginx Worker](#data-sharing-within-an-nginx-worker) for the reasons behind this. [Back to TOC](#table-of-contents) @@ -735,6 +736,17 @@ will not work as expected. [Back to TOC](#table-of-contents) +Cocockets Not Available Everywhere +---------------------------------- + +Due the internal limitations in the nginx core, the cosocket API are disabled in the following contexts: [set_by_lua*](#set_by_lua), [log_by_lua*](#log_by_lua), [header_filter_by_lua*](#header_filter_by_lua), and [body_filter_by_lua](#body_filter_by_lua). + +The cosockets are currently also disabled in the [init_by_lua*](#init_by_lua) and [init_worker_by_lua*](#init_worker_by_lua) directive contexts but we may add support for these contexts in the future because there is no limitation in the nginx core (or the limitation might be worked around). + +There exists a work-around, however, when the original context does *not* need to wait for the cosocket results. That is, creating a 0-delay timer via the [ngx.timer.at](#ngxtimerat) API and do the cosocket results in the timer handler, which runs asynchronously as to the original context creating the timer. + +[Back to TOC](#table-of-contents) + Special PCRE Sequences ---------------------- PCRE sequences such as `\d`, `\s`, or `\w`, require special attention because in string literals, the backslash character, `\`, is stripped out by both the Lua language parser and by the Nginx config file parser before processing. So the following snippet will not work as expected: @@ -881,22 +893,22 @@ The following dependencies are required to run the test suite: * Nginx version >= 1.4.2 * Perl modules: - * Test::Nginx: + * Test::Nginx: * Nginx modules: * [ngx_devel_kit](https://github.com/simpl/ngx_devel_kit) - * [ngx_set_misc](http://github.com/openresty/set-misc-nginx-module) + * [ngx_set_misc](https://github.com/openresty/set-misc-nginx-module) * [ngx_auth_request](http://mdounin.ru/files/ngx_http_auth_request_module-0.2.tar.gz) (this is not needed if you're using Nginx 1.5.4+. - * [ngx_echo](http://github.com/openresty/echo-nginx-module) - * [ngx_memc](http://github.com/openresty/memc-nginx-module) - * [ngx_srcache](http://github.com/openresty/srcache-nginx-module) + * [ngx_echo](https://github.com/openresty/echo-nginx-module) + * [ngx_memc](https://github.com/openresty/memc-nginx-module) + * [ngx_srcache](https://github.com/openresty/srcache-nginx-module) * ngx_lua (i.e., this module) - * [ngx_lua_upstream](http://github.com/openresty/lua-upstream-nginx-module) - * [ngx_headers_more](http://github.com/openresty/headers-more-nginx-module) - * [ngx_drizzle](http://github.com/openresty/drizzle-nginx-module) - * [ngx_rds_json](http://github.com/openresty/rds-json-nginx-module) + * [ngx_lua_upstream](https://github.com/openresty/lua-upstream-nginx-module) + * [ngx_headers_more](https://github.com/openresty/headers-more-nginx-module) + * [ngx_drizzle](https://github.com/openresty/drizzle-nginx-module) + * [ngx_rds_json](https://github.com/openresty/rds-json-nginx-module) * [ngx_coolkit](https://github.com/FRiCKLE/ngx_coolkit) - * [ngx_redis2](http://github.com/openresty/redis2-nginx-module) + * [ngx_redis2](https://github.com/openresty/redis2-nginx-module) The order in which these modules are added during configuration is important because the position of any filter module in the filtering chain determines the final output, for example. The correct adding order is shown above. @@ -955,22 +967,23 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND See Also ======== -* [lua-resty-memcached](http://github.com/openresty/lua-resty-memcached) library based on ngx_lua cosocket. -* [lua-resty-redis](http://github.com/openresty/lua-resty-redis) library based on ngx_lua cosocket. -* [lua-resty-mysql](http://github.com/openresty/lua-resty-mysql) library based on ngx_lua cosocket. -* [lua-resty-upload](http://github.com/openresty/lua-resty-upload) library based on ngx_lua cosocket. -* [lua-resty-dns](http://github.com/openresty/lua-resty-dns) library based on ngx_lua cosocket. -* [lua-resty-websocket](http://github.com/openresty/lua-resty-websocket) library for both WebSocket server and client, based on ngx_lua cosocket. -* [lua-resty-string](http://github.com/openresty/lua-resty-string) library based on [LuaJIT FFI](http://luajit.org/ext_ffi.html). -* [lua-resty-lock](http://github.com/openresty/lua-resty-lock) library for a nonblocking simple lock API. +* [lua-resty-memcached](https://github.com/openresty/lua-resty-memcached) library based on ngx_lua cosocket. +* [lua-resty-redis](https://github.com/openresty/lua-resty-redis) library based on ngx_lua cosocket. +* [lua-resty-mysql](https://github.com/openresty/lua-resty-mysql) library based on ngx_lua cosocket. +* [lua-resty-upload](https://github.com/openresty/lua-resty-upload) library based on ngx_lua cosocket. +* [lua-resty-dns](https://github.com/openresty/lua-resty-dns) library based on ngx_lua cosocket. +* [lua-resty-websocket](https://github.com/openresty/lua-resty-websocket) library for both WebSocket server and client, based on ngx_lua cosocket. +* [lua-resty-string](https://github.com/openresty/lua-resty-string) library based on [LuaJIT FFI](http://luajit.org/ext_ffi.html). +* [lua-resty-lock](https://github.com/openresty/lua-resty-lock) library for a nonblocking simple lock API. +* [lua-resty-cookie](https://github.com/cloudflare/lua-resty-cookie) library for HTTP cookie manipulation. * [Routing requests to different MySQL queries based on URI arguments](http://openresty.org/#RoutingMySQLQueriesBasedOnURIArgs) * [Dynamic Routing Based on Redis and Lua](http://openresty.org/#DynamicRoutingBasedOnRedis) * [Using LuaRocks with ngx_lua](http://openresty.org/#UsingLuaRocks) * [Introduction to ngx_lua](https://github.com/openresty/lua-nginx-module/wiki/Introduction) -* [ngx_devel_kit](http://github.com/simpl/ngx_devel_kit) +* [ngx_devel_kit](https://github.com/simpl/ngx_devel_kit) * [echo-nginx-module](http://github.com/openresty/echo-nginx-module) * [drizzle-nginx-module](http://github.com/openresty/drizzle-nginx-module) -* [postgres-nginx-module](http://github.com/FRiCKLE/ngx_postgres) +* [postgres-nginx-module](https://github.com/FRiCKLE/ngx_postgres) * [memc-nginx-module](http://github.com/openresty/memc-nginx-module) * [The ngx_openresty bundle](http://openresty.org) * [Nginx Systemtap Toolkit](https://github.com/openresty/nginx-systemtap-toolkit) @@ -1208,7 +1221,7 @@ But note that, the [lua_shared_dict](#lua_shared_dict)'s shm storage will not be Because the Lua code in this context runs before Nginx forks its worker processes (if any), data or code loaded here will enjoy the [Copy-on-write (COW)](http://en.wikipedia.org/wiki/Copy-on-write) feature provided by many operating systems among all the worker processes, thus saving a lot of memory. -Do *not* initialize your own Lua global variables in this context because use of Lua global variables have performance penalties and can lead to global namespace pollution (see the [Lua Variable Scope](#lua_variable_scope) section for more details). The recommended way is to use proper [Lua module](http://www.lua.org/manual/5.1/manual.html#5.3) files (but do not use the standard Lua function [module()](http://www.lua.org/manual/5.1/manual.html#pdf-module) to define Lua modules because it pollutes the global namespace as well) and call [require()](http://www.lua.org/manual/5.1/manual.html#pdf-require) to load your own module files in `init_by_lua` or other contexts ([require()](http://www.lua.org/manual/5.1/manual.html#pdf-require) does cache the loaded Lua modules in the global `package.loaded` table in the Lua registry so your modules will only loaded once for the whole Lua VM instance). +Do *not* initialize your own Lua global variables in this context because use of Lua global variables have performance penalties and can lead to global namespace pollution (see the [Lua Variable Scope](#lua-variable-scope) section for more details). The recommended way is to use proper [Lua module](http://www.lua.org/manual/5.1/manual.html#5.3) files (but do not use the standard Lua function [module()](http://www.lua.org/manual/5.1/manual.html#pdf-module) to define Lua modules because it pollutes the global namespace as well) and call [require()](http://www.lua.org/manual/5.1/manual.html#pdf-require) to load your own module files in `init_by_lua` or other contexts ([require()](http://www.lua.org/manual/5.1/manual.html#pdf-require) does cache the loaded Lua modules in the global `package.loaded` table in the Lua registry so your modules will only loaded once for the whole Lua VM instance). Only a small set of the [Nginx API for Lua](#nginx-api-for-lua) is supported in this context: @@ -2490,7 +2503,7 @@ location /foo { set $a 32; set $b 56; - set_by_lua $res + set_by_lua $sum 'return tonumber(ngx.arg[1]) + tonumber(ngx.arg[2])' $a $b; @@ -3080,7 +3093,7 @@ There is a hard-coded upper limit on the number of concurrent subrequests possib The limit can be manually modified if required by editing the definition of the `NGX_HTTP_MAX_SUBREQUESTS` macro in the `nginx/src/http/ngx_http_request.h` file in the Nginx source tree. -Please also refer to restrictions on capturing locations configured by [subrequest directives of other modules](#locations_configured_by_subrequest_directives_of_other_modules). +Please also refer to restrictions on capturing locations configured by [subrequest directives of other modules](#locations-configured-by-subrequest-directives-of-other-modules). [Back to TOC](#nginx-api-for-lua) @@ -3145,7 +3158,7 @@ ngx.location.capture = end ``` -Please also refer to restrictions on capturing locations configured by [subrequest directives of other modules](#locations_configured_by_subrequest_directives_of_other_modules). +Please also refer to restrictions on capturing locations configured by [subrequest directives of other modules](#locations-configured-by-subrequest-directives-of-other-modules). [Back to TOC](#nginx-api-for-lua) @@ -4123,7 +4136,7 @@ ngx.exec **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** -Does an internal redirect to `uri` with `args`. +Does an internal redirect to `uri` with `args` and is similar to the [echo_exec](http://github.com/openresty/echo-nginx-module#echo_exec) directive of the [echo-nginx-module](http://github.com/openresty/echo-nginx-module). ```lua @@ -4132,21 +4145,6 @@ ngx.exec('/some-location', 'a=3&b=5&c=6'); ngx.exec('/some-location?a=3&b=5', 'c=6'); ``` -Named locations are also supported, but query strings are ignored. For example, - -```nginx - -location /foo { - content_by_lua ' - ngx.exec("@bar"); - '; -} - -location @bar { - ... -} -``` - The optional second `args` can be used to specify extra URI query arguments, for example: ```lua @@ -4161,19 +4159,41 @@ Alternatively, a Lua table can be passed for the `args` argument for ngx_lua to ngx.exec("/foo", { a = 3, b = "hello world" }) ``` -The result is exactly the same as the previous example. The format for the Lua table passed as the `args` argument is identical to the format used in the [ngx.encode_args](#ngxencode_args) method. +The result is exactly the same as the previous example. -Note that this is very different from [ngx.redirect](#ngxredirect) in that -it is just an internal redirect and no new HTTP traffic is involved. +The format for the Lua table passed as the `args` argument is identical to the format used in the [ngx.encode_args](#ngxencode_args) method. -This method never returns. +Named locations are also supported but the second `args` argument will be ignored if present and the querystring for the new target is inherited from the referring location (if any). -This method *must* be called before [ngx.send_headers](#ngxsend_headers) or explicit response body +`GET /foo/file.php?a=hello` will return "hello" and not "goodbye" in the example below + +```nginx + +location /foo { + content_by_lua ' + ngx.exec("@bar", "a=goodbye"); + '; +} + +location @bar { + content_by_lua ' + local args = ngx.req.get_uri_args() + for key, val in pairs(args) do + if key == "a" then + ngx.say(val) + end + end + '; +} +``` + +Note that the `ngx.exec` method is different from [ngx.redirect](#ngxredirect) in that +it is purely an internal redirect and that no new external HTTP traffic is involved. + +Also note that this method call terminates the processing of the current request and that it *must* be called before [ngx.send_headers](#ngxsend_headers) or explicit response body outputs by either [ngx.print](#ngxprint) or [ngx.say](#ngxsay). -It is strongly recommended to combine the `return` statement with this call, i.e., `return ngx.exec(...)`. - -This method is similar to the [echo_exec](http://github.com/openresty/echo-nginx-module#echo_exec) directive of the [echo-nginx-module](http://github.com/openresty/echo-nginx-module). +It is recommended that a coding style that combines this method call with the `return` statement, i.e., `return ngx.exec(...)` be adopted when this method call is used in contexts other than [header_filter_by_lua](#header_filter_by_lua) to reinforce the fact that the request processing is being terminated. [Back to TOC](#nginx-api-for-lua) @@ -4188,7 +4208,7 @@ Issue an `HTTP 301` or `302` redirection to `uri`. The optional `status` parameter specifies whether `301` or `302` to be used. It is `302` (`ngx.HTTP_MOVED_TEMPORARILY`) by default. -Here is an example assuming the current server name is `localhost` and that it is listening on Port 1984: +Here is an example assuming the current server name is `localhost` and that it is listening on port 1984: ```lua @@ -4216,9 +4236,7 @@ We can also use the numerical code directly as the second `status` argument: return ngx.redirect("/foo", 301) ``` -This method *must* be called before [ngx.send_headers](#ngxsend_headers) or explicit response body outputs by either [ngx.print](#ngxprint) or [ngx.say](#ngxsay). - -This method is very much like the [rewrite](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) directive with the `redirect` modifier in the standard +This method is similar to the [rewrite](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) directive with the `redirect` modifier in the standard [[HttpRewriteModule]], for example, this `nginx.conf` snippet ```nginx @@ -4254,7 +4272,10 @@ URI arguments can be specified as well, for example: return ngx.redirect('/foo?a=3&b=4') ``` -This method call terminates the current request's processing and never returns. It is recommended to combine the `return` statement with this call, i.e., `return ngx.redirect(...)`, so as to be more explicit. +Note that this method call terminates the processing of the current request and that it *must* be called before [ngx.send_headers](#ngxsend_headers) or explicit response body +outputs by either [ngx.print](#ngxprint) or [ngx.say](#ngxsay). + +It is recommended that a coding style that combines this method call with the `return` statement, i.e., `return ngx.redirect(...)` be adopted when this method call is used in contexts other than [header_filter_by_lua](#header_filter_by_lua) to reinforce the fact that the request processing is being terminated. [Back to TOC](#nginx-api-for-lua) @@ -4376,7 +4397,7 @@ ngx.exit -------- **syntax:** *ngx.exit(status)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, ngx.timer.** When `status >= 200` (i.e., `ngx.HTTP_OK` and above), it will interrupt the execution of the current request and return status code to nginx. @@ -4419,9 +4440,9 @@ ngx.exit(501) Note that while this method accepts all [HTTP status constants](#http-status-constants) as input, it only accepts `NGX_OK` and `NGX_ERROR` of the [core constants](#core-constants). -It is recommended, though not necessary (for contexts other than [header_filter_by_lua](#header_filter_by_lua)), to combine the `return` statement with this call, i.e., `return ngx.exit(...)`, to give a visual hint to others reading the code. +Also note that this method call terminates the processing of the current request and that it is recommended that a coding style that combines this method call with the `return` statement, i.e., `return ngx.exit(...)` be used to reinforce the fact that the request processing is being terminated. -When being used in the context of [header_filter_by_lua](#header_filter_by_lua), `ngx.exit()` is an asynchronous operation and will return immediately. This behavior might change in the future. So always use `return` at the same time, as suggested above. +When being used in the context of [header_filter_by_lua](#header_filter_by_lua), `ngx.exit()` is an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use `return` in combination as suggested above. [Back to TOC](#nginx-api-for-lua) @@ -5191,7 +5212,7 @@ Curly braces can also be used to disambiguate variable names from the background ```lua local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "${0}00") - -- newstr == "hello, 10034" + -- newstr == "hello, 100234" -- n == 1 ``` @@ -6151,6 +6172,8 @@ Idle connections in the pool will be monitored for any exceptional events like c In case of success, this method returns `1`; otherwise, it returns `nil` and a string describing the error. +When the system receive buffer for the current connection has unread data, then this method will return the "connection in dubious state" error message (as the second return value) because the previous session has unread data left behind for the next session and the connection is not safe to be reused. + This method also makes the current cosocket object enter the "closed" state, so there is no need to manually call the [close](#tcpsockclose) method on it afterwards. This feature was first introduced in the `v0.5.0rc1` release. @@ -6201,12 +6224,14 @@ ngx.get_phase ------------- **syntax:** *str = ngx.get_phase()* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Retrieves the current running phase name. Possible return values are * `init` for the context of [init_by_lua](#init_by_lua) or [init_by_lua_file](#init_by_lua_file). +* `init_worker` + for the context of [init_worker_by_lua](#init_worker_by_lua) or [init_worker_by_lua_file](#init_worker_by_lua_file). * `set` for the context of [set_by_lua](#set_by_lua) or [set_by_lua_file](#set_by_lua_file). * `rewrite` diff --git a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki index 1ee5aa4..1446805 100644 --- a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki @@ -6,11 +6,11 @@ ngx_lua - Embed the power of Lua into Nginx = Status = -This module is under active development and is production ready. +Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.9.12] released on 2 September 2014. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.9.13] released on 21 November 2014. = Synopsis = @@ -232,7 +232,7 @@ The Lua state (Lua VM instance) is shared across all the requests handled by a s = Nginx Compatibility = The latest module is compatible with the following versions of Nginx: -* 1.7.x (last tested: 1.7.4) +* 1.7.x (last tested: 1.7.7) * 1.6.x * 1.5.x (last tested: 1.5.12) * 1.4.x (last tested: 1.4.4) @@ -250,16 +250,16 @@ The [http://openresty.org ngx_openresty bundle] can be used to install Nginx, ng Alternatively, ngx_lua can be manually compiled into Nginx: # Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is ''not'' supported yet). LuaJIT can be downloaded from the [http://luajit.org/download.html the LuaJIT project website] and Lua 5.1, from the [http://www.lua.org/ Lua project website]. Some distribution package managers also distribute LuajIT and/or Lua. -# Download the latest version of the ngx_devel_kit (NDK) module [http://github.com/simpl/ngx_devel_kit/tags HERE]. -# Download the latest version of ngx_lua [http://github.com/openresty/lua-nginx-module/tags HERE]. +# Download the latest version of the ngx_devel_kit (NDK) module [https://github.com/simpl/ngx_devel_kit/tags HERE]. +# Download the latest version of ngx_lua [https://github.com/openresty/lua-nginx-module/tags HERE]. # Download the latest version of Nginx [http://nginx.org/ HERE] (See [[#Nginx Compatibility|Nginx Compatibility]]) Build the source with this module: - wget 'http://nginx.org/download/nginx-1.7.4.tar.gz' - tar -xzvf nginx-1.7.4.tar.gz - cd nginx-1.7.4/ + wget 'http://nginx.org/download/nginx-1.7.7.tar.gz' + tar -xzvf nginx-1.7.7.tar.gz + cd nginx-1.7.7/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib @@ -329,7 +329,7 @@ The [https://groups.google.com/group/openresty openresty] mailing list is for Ch = Code Repository = -The code repository of this project is hosted on github at [http://github.com/openresty/lua-nginx-module openresty/lua-nginx-module]. +The code repository of this project is hosted on github at [https://github.com/openresty/lua-nginx-module openresty/lua-nginx-module]. = Bugs and Patches = @@ -599,6 +599,14 @@ The [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_m will not work as expected. +== Cocockets Not Available Everywhere == + +Due the internal limitations in the nginx core, the cosocket API are disabled in the following contexts: [[#set_by_lua|set_by_lua*]], [[#log_by_lua|log_by_lua*]], [[#header_filter_by_lua|header_filter_by_lua*]], and [[#body_filter_by_lua|body_filter_by_lua]]. + +The cosockets are currently also disabled in the [[#init_by_lua|init_by_lua*]] and [[#init_worker_by_lua|init_worker_by_lua*]] directive contexts but we may add support for these contexts in the future because there is no limitation in the nginx core (or the limitation might be worked around). + +There exists a work-around, however, when the original context does *not* need to wait for the cosocket results. That is, creating a 0-delay timer via the [[#ngx.timer.at|ngx.timer.at]] API and do the cosocket results in the timer handler, which runs asynchronously as to the original context creating the timer. + == Special PCRE Sequences == PCRE sequences such as \d, \s, or \w, require special attention because in string literals, the backslash character, \, is stripped out by both the Lua language parser and by the Nginx config file parser before processing. So the following snippet will not work as expected: @@ -717,22 +725,22 @@ The following dependencies are required to run the test suite: * Nginx version >= 1.4.2 * Perl modules: -** Test::Nginx: http://github.com/openresty/test-nginx +** Test::Nginx: https://github.com/openresty/test-nginx * Nginx modules: ** [https://github.com/simpl/ngx_devel_kit ngx_devel_kit] -** [http://github.com/openresty/set-misc-nginx-module ngx_set_misc] +** [https://github.com/openresty/set-misc-nginx-module ngx_set_misc] ** [http://mdounin.ru/files/ngx_http_auth_request_module-0.2.tar.gz ngx_auth_request] (this is not needed if you're using Nginx 1.5.4+. -** [http://github.com/openresty/echo-nginx-module ngx_echo] -** [http://github.com/openresty/memc-nginx-module ngx_memc] -** [http://github.com/openresty/srcache-nginx-module ngx_srcache] +** [https://github.com/openresty/echo-nginx-module ngx_echo] +** [https://github.com/openresty/memc-nginx-module ngx_memc] +** [https://github.com/openresty/srcache-nginx-module ngx_srcache] ** ngx_lua (i.e., this module) -** [http://github.com/openresty/lua-upstream-nginx-module ngx_lua_upstream] -** [http://github.com/openresty/headers-more-nginx-module ngx_headers_more] -** [http://github.com/openresty/drizzle-nginx-module ngx_drizzle] -** [http://github.com/openresty/rds-json-nginx-module ngx_rds_json] +** [https://github.com/openresty/lua-upstream-nginx-module ngx_lua_upstream] +** [https://github.com/openresty/headers-more-nginx-module ngx_headers_more] +** [https://github.com/openresty/drizzle-nginx-module ngx_drizzle] +** [https://github.com/openresty/rds-json-nginx-module ngx_rds_json] ** [https://github.com/FRiCKLE/ngx_coolkit ngx_coolkit] -** [http://github.com/openresty/redis2-nginx-module ngx_redis2] +** [https://github.com/openresty/redis2-nginx-module ngx_redis2] The order in which these modules are added during configuration is important because the position of any filter module in the filtering chain determines the final output, for example. The correct adding order is shown above. @@ -785,22 +793,23 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND = See Also = -* [http://github.com/openresty/lua-resty-memcached lua-resty-memcached] library based on ngx_lua cosocket. -* [http://github.com/openresty/lua-resty-redis lua-resty-redis] library based on ngx_lua cosocket. -* [http://github.com/openresty/lua-resty-mysql lua-resty-mysql] library based on ngx_lua cosocket. -* [http://github.com/openresty/lua-resty-upload lua-resty-upload] library based on ngx_lua cosocket. -* [http://github.com/openresty/lua-resty-dns lua-resty-dns] library based on ngx_lua cosocket. -* [http://github.com/openresty/lua-resty-websocket lua-resty-websocket] library for both WebSocket server and client, based on ngx_lua cosocket. -* [http://github.com/openresty/lua-resty-string lua-resty-string] library based on [http://luajit.org/ext_ffi.html LuaJIT FFI]. -* [http://github.com/openresty/lua-resty-lock lua-resty-lock] library for a nonblocking simple lock API. +* [https://github.com/openresty/lua-resty-memcached lua-resty-memcached] library based on ngx_lua cosocket. +* [https://github.com/openresty/lua-resty-redis lua-resty-redis] library based on ngx_lua cosocket. +* [https://github.com/openresty/lua-resty-mysql lua-resty-mysql] library based on ngx_lua cosocket. +* [https://github.com/openresty/lua-resty-upload lua-resty-upload] library based on ngx_lua cosocket. +* [https://github.com/openresty/lua-resty-dns lua-resty-dns] library based on ngx_lua cosocket. +* [https://github.com/openresty/lua-resty-websocket lua-resty-websocket] library for both WebSocket server and client, based on ngx_lua cosocket. +* [https://github.com/openresty/lua-resty-string lua-resty-string] library based on [http://luajit.org/ext_ffi.html LuaJIT FFI]. +* [https://github.com/openresty/lua-resty-lock lua-resty-lock] library for a nonblocking simple lock API. +* [https://github.com/cloudflare/lua-resty-cookie lua-resty-cookie] library for HTTP cookie manipulation. * [http://openresty.org/#RoutingMySQLQueriesBasedOnURIArgs Routing requests to different MySQL queries based on URI arguments] * [http://openresty.org/#DynamicRoutingBasedOnRedis Dynamic Routing Based on Redis and Lua] * [http://openresty.org/#UsingLuaRocks Using LuaRocks with ngx_lua] * [https://github.com/openresty/lua-nginx-module/wiki/Introduction Introduction to ngx_lua] -* [http://github.com/simpl/ngx_devel_kit ngx_devel_kit] +* [https://github.com/simpl/ngx_devel_kit ngx_devel_kit] * [[HttpEchoModule]] * [[HttpDrizzleModule]] -* [http://github.com/FRiCKLE/ngx_postgres postgres-nginx-module] +* [https://github.com/FRiCKLE/ngx_postgres postgres-nginx-module] * [[HttpMemcModule]] * [http://openresty.org The ngx_openresty bundle] * [https://github.com/openresty/nginx-systemtap-toolkit Nginx Systemtap Toolkit] @@ -1976,7 +1985,7 @@ Here is an example set $a 32; set $b 56; - set_by_lua $res + set_by_lua $sum 'return tonumber(ngx.arg[1]) + tonumber(ngx.arg[2])' $a $b; @@ -3414,7 +3423,7 @@ This function was first introduced in the v0.5.0rc1 release. '''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' -Does an internal redirect to uri with args. +Does an internal redirect to uri with args and is similar to the [[HttpEchoModule#echo_exec|echo_exec]] directive of the [[HttpEchoModule]]. ngx.exec('/some-location'); @@ -3422,20 +3431,6 @@ Does an internal redirect to uri with args. ngx.exec('/some-location?a=3&b=5', 'c=6'); -Named locations are also supported, but query strings are ignored. For example, - - - location /foo { - content_by_lua ' - ngx.exec("@bar"); - '; - } - - location @bar { - ... - } - - The optional second args can be used to specify extra URI query arguments, for example: @@ -3448,19 +3443,40 @@ Alternatively, a Lua table can be passed for the args argument for ngx.exec("/foo", { a = 3, b = "hello world" }) -The result is exactly the same as the previous example. The format for the Lua table passed as the args argument is identical to the format used in the [[#ngx.encode_args|ngx.encode_args]] method. +The result is exactly the same as the previous example. -Note that this is very different from [[#ngx.redirect|ngx.redirect]] in that -it is just an internal redirect and no new HTTP traffic is involved. +The format for the Lua table passed as the args argument is identical to the format used in the [[#ngx.encode_args|ngx.encode_args]] method. -This method never returns. +Named locations are also supported but the second args argument will be ignored if present and the querystring for the new target is inherited from the referring location (if any). -This method ''must'' be called before [[#ngx.send_headers|ngx.send_headers]] or explicit response body +GET /foo/file.php?a=hello will return "hello" and not "goodbye" in the example below + + + location /foo { + content_by_lua ' + ngx.exec("@bar", "a=goodbye"); + '; + } + + location @bar { + content_by_lua ' + local args = ngx.req.get_uri_args() + for key, val in pairs(args) do + if key == "a" then + ngx.say(val) + end + end + '; + } + + +Note that the ngx.exec method is different from [[#ngx.redirect|ngx.redirect]] in that +it is purely an internal redirect and that no new external HTTP traffic is involved. + +Also note that this method call terminates the processing of the current request and that it ''must'' be called before [[#ngx.send_headers|ngx.send_headers]] or explicit response body outputs by either [[#ngx.print|ngx.print]] or [[#ngx.say|ngx.say]]. -It is strongly recommended to combine the return statement with this call, i.e., return ngx.exec(...). - -This method is similar to the [[HttpEchoModule#echo_exec|echo_exec]] directive of the [[HttpEchoModule]]. +It is recommended that a coding style that combines this method call with the return statement, i.e., return ngx.exec(...) be adopted when this method call is used in contexts other than [[#header_filter_by_lua|header_filter_by_lua]] to reinforce the fact that the request processing is being terminated. == ngx.redirect == '''syntax:''' ''ngx.redirect(uri, status?)'' @@ -3472,7 +3488,7 @@ Issue an HTTP 301 or 302 redirection to uristatus parameter specifies whether 301 or 302 to be used. It is 302 (ngx.HTTP_MOVED_TEMPORARILY) by default. -Here is an example assuming the current server name is localhost and that it is listening on Port 1984: +Here is an example assuming the current server name is localhost and that it is listening on port 1984: return ngx.redirect("/foo") @@ -3496,9 +3512,7 @@ We can also use the numerical code directly as the second status ar return ngx.redirect("/foo", 301) -This method ''must'' be called before [[#ngx.send_headers|ngx.send_headers]] or explicit response body outputs by either [[#ngx.print|ngx.print]] or [[#ngx.say|ngx.say]]. - -This method is very much like the [[HttpRewriteModule#rewrite|rewrite]] directive with the redirect modifier in the standard +This method is similar to the [[HttpRewriteModule#rewrite|rewrite]] directive with the redirect modifier in the standard [[HttpRewriteModule]], for example, this nginx.conf snippet @@ -3529,7 +3543,10 @@ URI arguments can be specified as well, for example: return ngx.redirect('/foo?a=3&b=4') -This method call terminates the current request's processing and never returns. It is recommended to combine the return statement with this call, i.e., return ngx.redirect(...), so as to be more explicit. +Note that this method call terminates the processing of the current request and that it ''must'' be called before [[#ngx.send_headers|ngx.send_headers]] or explicit response body +outputs by either [[#ngx.print|ngx.print]] or [[#ngx.say|ngx.say]]. + +It is recommended that a coding style that combines this method call with the return statement, i.e., return ngx.redirect(...) be adopted when this method call is used in contexts other than [[#header_filter_by_lua|header_filter_by_lua]] to reinforce the fact that the request processing is being terminated. == ngx.send_headers == '''syntax:''' ''ok, err = ngx.send_headers()'' @@ -3628,7 +3645,7 @@ Since v0.8.3 this function returns 1 on success, or re == ngx.exit == '''syntax:''' ''ngx.exit(status)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, ngx.timer.*'' When status >= 200 (i.e., ngx.HTTP_OK and above), it will interrupt the execution of the current request and return status code to nginx. @@ -3668,9 +3685,9 @@ Number literals can be used directly as the argument, for instance, Note that while this method accepts all [[#HTTP status constants|HTTP status constants]] as input, it only accepts NGX_OK and NGX_ERROR of the [[#core constants|core constants]]. -It is recommended, though not necessary (for contexts other than [[#header_filter_by_lua|header_filter_by_lua]]), to combine the return statement with this call, i.e., return ngx.exit(...), to give a visual hint to others reading the code. +Also note that this method call terminates the processing of the current request and that it is recommended that a coding style that combines this method call with the return statement, i.e., return ngx.exit(...) be used to reinforce the fact that the request processing is being terminated. -When being used in the context of [[#header_filter_by_lua|header_filter_by_lua]], ngx.exit() is an asynchronous operation and will return immediately. This behavior might change in the future. So always use return at the same time, as suggested above. +When being used in the context of [[#header_filter_by_lua|header_filter_by_lua]], ngx.exit() is an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use return in combination as suggested above. == ngx.eof == '''syntax:''' ''ok, err = ngx.eof()'' @@ -4327,7 +4344,7 @@ Curly braces can also be used to disambiguate variable names from the background local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "${0}00") - -- newstr == "hello, 10034" + -- newstr == "hello, 100234" -- n == 1 @@ -5173,6 +5190,8 @@ Idle connections in the pool will be monitored for any exceptional events like c In case of success, this method returns 1; otherwise, it returns nil and a string describing the error. +When the system receive buffer for the current connection has unread data, then this method will return the "connection in dubious state" error message (as the second return value) because the previous session has unread data left behind for the next session and the connection is not safe to be reused. + This method also makes the current cosocket object enter the "closed" state, so there is no need to manually call the [[#tcpsock:close|close]] method on it afterwards. This feature was first introduced in the v0.5.0rc1 release. @@ -5213,12 +5232,14 @@ This feature was first introduced in the v0.5.0rc1 release. == ngx.get_phase == '''syntax:''' ''str = ngx.get_phase()'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Retrieves the current running phase name. Possible return values are * init : for the context of [[#init_by_lua|init_by_lua]] or [[#init_by_lua_file|init_by_lua_file]]. +* init_worker +: for the context of [[#init_worker_by_lua|init_worker_by_lua]] or [[#init_worker_by_lua_file|init_worker_by_lua_file]]. * set : for the context of [[#set_by_lua|set_by_lua]] or [[#set_by_lua_file|set_by_lua_file]]. * rewrite diff --git a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h index e971938..814754b 100644 --- a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 9012 +#define ngx_http_lua_version 9013 typedef struct { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c b/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c index 081c550..8a82e07 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c @@ -179,7 +179,7 @@ ngx_http_lua_access_handler_inline(ngx_http_request_t *r) rc = ngx_http_lua_cache_loadbuffer(r, L, llcf->access_src.value.data, llcf->access_src.value.len, llcf->access_src_key, - "=access_by_lua"); + (const char *) llcf->access_chunkname); if (rc != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_common.h b/debian/modules/nginx-lua/src/ngx_http_lua_common.h index dd69d1c..6111b3f 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_common.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_common.h @@ -189,18 +189,21 @@ typedef struct { ngx_http_output_body_filter_pt body_filter_handler; + u_char *rewrite_chunkname; ngx_http_complex_value_t rewrite_src; /* rewrite_by_lua inline script/script file path */ u_char *rewrite_src_key; /* cached key for rewrite_src */ + u_char *access_chunkname; ngx_http_complex_value_t access_src; /* access_by_lua inline script/script file path */ u_char *access_src_key; /* cached key for access_src */ + u_char *content_chunkname; ngx_http_complex_value_t content_src; /* content_by_lua inline script/script file path */ @@ -208,6 +211,7 @@ typedef struct { u_char *content_src_key; /* cached key for content_src */ + u_char *log_chunkname; ngx_http_complex_value_t log_src; /* log_by_lua inline script/script file path */ @@ -367,7 +371,6 @@ typedef struct ngx_http_lua_ctx_s { ngx_chain_t *free_bufs; ngx_chain_t *busy_bufs; ngx_chain_t *free_recv_bufs; - ngx_chain_t *flush_buf; ngx_http_cleanup_pt *cleanup; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c b/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c index fda9a39..9234dd9 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c @@ -180,7 +180,7 @@ ngx_http_lua_content_handler(ngx_http_request_t *r) r->request_body_in_clean_file = 1; rc = ngx_http_read_client_request_body(r, - ngx_http_lua_content_phase_post_read); + ngx_http_lua_content_phase_post_read); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { #if (nginx_version < 1002006) || \ @@ -242,7 +242,7 @@ ngx_http_lua_content_handler_file(ngx_http_request_t *r) } script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data, - eval_src.len); + eval_src.len); if (script_path == NULL) { return NGX_ERROR; @@ -283,7 +283,8 @@ ngx_http_lua_content_handler_inline(ngx_http_request_t *r) rc = ngx_http_lua_cache_loadbuffer(r, L, llcf->content_src.value.data, llcf->content_src.value.len, llcf->content_src_key, - "=content_by_lua"); + (const char *) + llcf->content_chunkname); if (rc != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c b/debian/modules/nginx-lua/src/ngx_http_lua_directive.c index ef0751f..a83136c 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_directive.c @@ -33,6 +33,9 @@ static ngx_int_t ngx_http_lua_set_by_lua_init(ngx_http_request_t *r); #endif +static u_char * ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, + size_t tag_len); + char * ngx_http_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) @@ -372,7 +375,7 @@ ngx_http_lua_filter_set_by_lua_file(ngx_http_request_t *r, ngx_str_t *val, char * ngx_http_lua_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - u_char *p; + u_char *p, *chunkname; ngx_str_t *value; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf = conf; @@ -405,7 +408,16 @@ ngx_http_lua_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } if (cmd->post == ngx_http_lua_rewrite_handler_inline) { + chunkname = ngx_http_lua_gen_chunk_name(cf, "rewrite_by_lua", + sizeof("rewrite_by_lua") - 1); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + + llcf->rewrite_chunkname = chunkname; + /* Don't eval nginx variables for inline lua code */ + llcf->rewrite_src.value = value[1]; p = ngx_palloc(cf->pool, NGX_HTTP_LUA_INLINE_KEY_LEN + 1); @@ -458,7 +470,7 @@ ngx_http_lua_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) char * ngx_http_lua_access_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - u_char *p; + u_char *p, *chunkname; ngx_str_t *value; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf = conf; @@ -487,7 +499,16 @@ ngx_http_lua_access_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } if (cmd->post == ngx_http_lua_access_handler_inline) { + chunkname = ngx_http_lua_gen_chunk_name(cf, "access_by_lua", + sizeof("access_by_lua") - 1); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + + llcf->access_chunkname = chunkname; + /* Don't eval nginx variables for inline lua code */ + llcf->access_src.value = value[1]; p = ngx_palloc(cf->pool, NGX_HTTP_LUA_INLINE_KEY_LEN + 1); @@ -541,6 +562,7 @@ char * ngx_http_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { u_char *p; + u_char *chunkname; ngx_str_t *value; ngx_http_core_loc_conf_t *clcf; ngx_http_lua_main_conf_t *lmcf; @@ -569,7 +591,18 @@ ngx_http_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } if (cmd->post == ngx_http_lua_content_handler_inline) { + chunkname = ngx_http_lua_gen_chunk_name(cf, "content_by_lua", + sizeof("content_by_lua") - 1); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + + llcf->content_chunkname = chunkname; + + dd("chunkname: %s", chunkname); + /* Don't eval nginx variables for inline lua code */ + llcf->content_src.value = value[1]; p = ngx_palloc(cf->pool, NGX_HTTP_LUA_INLINE_KEY_LEN + 1); @@ -629,7 +662,7 @@ ngx_http_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) char * ngx_http_lua_log_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - u_char *p; + u_char *p, *chunkname; ngx_str_t *value; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf = conf; @@ -658,7 +691,16 @@ ngx_http_lua_log_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } if (cmd->post == ngx_http_lua_log_handler_inline) { + chunkname = ngx_http_lua_gen_chunk_name(cf, "log_by_lua", + sizeof("log_by_lua") - 1); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + + llcf->log_chunkname = chunkname; + /* Don't eval nginx variables for inline lua code */ + llcf->log_src.value = value[1]; p = ngx_palloc(cf->pool, NGX_HTTP_LUA_INLINE_KEY_LEN + 1); @@ -995,4 +1037,45 @@ ngx_http_lua_set_by_lua_init(ngx_http_request_t *r) } #endif + +static u_char * +ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len) +{ + u_char *p, *out; + size_t len; + + len = sizeof("=(:)") - 1 + tag_len + cf->conf_file->file.name.len + + NGX_INT64_LEN + 1; + + out = ngx_palloc(cf->pool, len); + if (out == NULL) { + return NULL; + } + + if (cf->conf_file->file.name.len) { + p = cf->conf_file->file.name.data + cf->conf_file->file.name.len; + while (--p >= cf->conf_file->file.name.data) { + if (*p == '/' || *p == '\\') { + p++; + goto found; + } + } + + p++; + + } else { + p = cf->conf_file->file.name.data; + } + +found: + + ngx_snprintf(out, len, "=%*s(%*s:%d)%Z", + tag_len, tag, cf->conf_file->file.name.data + + cf->conf_file->file.name.len - p, + p, cf->conf_file->line); + + return out; +} + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers.c b/debian/modules/nginx-lua/src/ngx_http_lua_headers.c index e604e2e..c186864 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headers.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headers.c @@ -128,24 +128,7 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) + line_break_len <= b->pos) { first = b; - - if (mr->header_in == b) { - size += mr->header_in->pos - mr->request_line.data; - - } else { - /* the subsequent part of the header is in the large header - * buffers */ -#if 1 - p = b->pos; - size += p - mr->request_line.data; - - /* skip truncated header entries (if any) */ - while (b->pos > b->start && b->pos[-1] != LF) { - b->pos--; - size--; - } -#endif - } + size += b->pos - mr->request_line.data; } dd("size: %d", (int) size); @@ -171,11 +154,7 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) first = b; } - if (b == mr->header_in) { - size += mr->header_in->pos - b->start; - break; - } - + dd("adding size %d", (int) (b->pos - b->start)); size += b->pos - b->start; } } @@ -189,13 +168,11 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) last = data; b = c->buffer; - if (first == b) { - if (mr->header_in == b) { - pos = mr->header_in->pos; + found = 0; - } else { - pos = b->pos; - } + if (first == b) { + found = 1; + pos = b->pos; if (no_req_line) { last = ngx_copy(data, @@ -209,6 +186,13 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) pos - mr->request_line.data); } + if (b != mr->header_in) { + /* skip truncated header entries (if any) */ + while (last > data && last[-1] != LF) { + last--; + } + } + i = 0; for (p = data; p != last; p++) { if (*p == '\0') { @@ -227,7 +211,6 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) } if (hc->nbusy) { - found = (b == c->buffer); for (i = 0; i < hc->nbusy; i++) { b = hc->busy[i]; @@ -242,12 +225,7 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) p = last; - if (b == mr->header_in) { - pos = mr->header_in->pos; - - } else { - pos = b->pos; - } + pos = b->pos; if (b == first) { dd("request line: %.*s", (int) mr->request_line.len, diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c b/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c index ec7a893..6b5292d 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c @@ -207,7 +207,7 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) ngx_destroy_pool(conf.temp_pool); conf.temp_pool = NULL; - c = ngx_http_lua_create_fake_connection(); + c = ngx_http_lua_create_fake_connection(NULL); if (c == NULL) { goto failed; } @@ -224,11 +224,21 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) r->loc_conf = http_ctx.loc_conf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + +#if defined(nginx_version) && nginx_version >= 1003014 + + ngx_http_set_connection_log(r->connection, clcf->error_log); + +#else + c->log->file = clcf->error_log->file; + if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { c->log->log_level = clcf->error_log->log_level; } +#endif + if (top_clcf->resolver) { clcf->resolver = top_clcf->resolver; } @@ -251,7 +261,6 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) (void) lmcf->init_worker_handler(cycle->log, lmcf, lmcf->lua); - ngx_destroy_pool(r->pool); ngx_destroy_pool(c->pool); return NGX_OK; @@ -261,10 +270,6 @@ failed: ngx_destroy_pool(conf.temp_pool); } - if (r && r->pool) { - ngx_destroy_pool(r->pool); - } - if (c) { ngx_http_lua_close_fake_connection(c); } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_logby.c b/debian/modules/nginx-lua/src/ngx_http_lua_logby.c index 46c64eb..9d06323 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_logby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_logby.c @@ -115,7 +115,8 @@ ngx_http_lua_log_handler_inline(ngx_http_request_t *r) /* load Lua inline script (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadbuffer(r, L, llcf->log_src.value.data, llcf->log_src.value.len, - llcf->log_src_key, "=log_by_lua"); + llcf->log_src_key, + (const char *) llcf->log_chunkname); if (rc != NGX_OK) { return NGX_ERROR; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_module.c b/debian/modules/nginx-lua/src/ngx_http_lua_module.c index 1c57d90..6f43b23 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_module.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_module.c @@ -754,24 +754,28 @@ ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) conf->rewrite_src = prev->rewrite_src; conf->rewrite_handler = prev->rewrite_handler; conf->rewrite_src_key = prev->rewrite_src_key; + conf->rewrite_chunkname = prev->rewrite_chunkname; } if (conf->access_src.value.len == 0) { conf->access_src = prev->access_src; conf->access_handler = prev->access_handler; conf->access_src_key = prev->access_src_key; + conf->access_chunkname = prev->access_chunkname; } if (conf->content_src.value.len == 0) { conf->content_src = prev->content_src; conf->content_handler = prev->content_handler; conf->content_src_key = prev->content_src_key; + conf->content_chunkname = prev->content_chunkname; } if (conf->log_src.value.len == 0) { conf->log_src = prev->log_src; conf->log_handler = prev->log_handler; conf->log_src_key = prev->log_src_key; + conf->log_chunkname = prev->log_chunkname; } if (conf->header_filter_src.value.len == 0) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_output.c b/debian/modules/nginx-lua/src/ngx_http_lua_output.c index 34850e1..a3feb7d 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_output.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_output.c @@ -232,20 +232,6 @@ ngx_http_lua_ngx_echo(lua_State *L, unsigned newline) dd("downstream write: %d, buf len: %d", (int) rc, (int) (b->last - b->pos)); - if (!ctx->out) { -#if nginx_version >= 1001004 - ngx_chain_update_chains(r->pool, -#else - ngx_chain_update_chains( -#endif - &ctx->free_bufs, &ctx->busy_bufs, &cl, - (ngx_buf_tag_t) &ngx_http_lua_module); - - dd("out lua buf tag: %p, buffered: 0x%x, busy bufs: %p", - &ngx_http_lua_module, (int) r->connection->buffered, - ctx->busy_bufs); - } - lua_pushinteger(L, 1); return 1; } @@ -461,7 +447,6 @@ ngx_http_lua_ngx_flush(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; - ngx_buf_t *buf; ngx_chain_t *cl; ngx_int_t rc; int n; @@ -532,28 +517,9 @@ ngx_http_lua_ngx_flush(lua_State *L) } #endif - if (ctx->flush_buf) { - cl = ctx->flush_buf; - - } else { - dd("allocating new flush buf"); - buf = ngx_calloc_buf(r->pool); - if (buf == NULL) { - return luaL_error(L, "no memory"); - } - - buf->flush = 1; - - dd("allocating new flush chain"); - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return luaL_error(L, "no memory"); - } - - cl->next = NULL; - cl->buf = buf; - - ctx->flush_buf = cl; + cl = ngx_http_lua_get_flush_chain(r, ctx); + if (cl == NULL) { + return luaL_error(L, "no memory"); } rc = ngx_http_lua_send_chain_link(r, ctx, cl); @@ -569,10 +535,15 @@ ngx_http_lua_ngx_flush(lua_State *L) dd("wait:%d, rc:%d, buffered:0x%x", wait, (int) rc, r->connection->buffered); - if (wait && (r->connection->buffered & NGX_HTTP_LOWLEVEL_BUFFERED)) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua flush requires waiting: buffered 0x%uxd", - (unsigned) r->connection->buffered); + wev = r->connection->write; + + if (wait && (r->connection->buffered & NGX_HTTP_LOWLEVEL_BUFFERED + || wev->delayed)) + { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua flush requires waiting: buffered 0x%uxd, " + "delayed:%d", (unsigned) r->connection->buffered, + wev->delayed); coctx->flushing = 1; ctx->flushing_coros++; @@ -585,14 +556,6 @@ ngx_http_lua_ngx_flush(lua_State *L) r->write_event_handler = ngx_http_core_run_phases; } - wev = r->connection->write; - - if (wev->ready && wev->delayed) { - lua_pushnil(L); - lua_pushliteral(L, "delayed"); - return 2; - } - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (!wev->delayed) { @@ -601,6 +564,7 @@ ngx_http_lua_ngx_flush(lua_State *L) if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { if (wev->timer_set) { + wev->delayed = 0; ngx_del_timer(wev); } @@ -746,6 +710,7 @@ ngx_http_lua_ngx_send_headers(lua_State *L) ngx_int_t ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) { + int n; lua_State *vm; ngx_int_t rc; ngx_connection_t *c; @@ -754,11 +719,25 @@ ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) ctx->cur_co_ctx->cleanup = NULL; - /* push the return value 1 */ - lua_pushinteger(ctx->cur_co_ctx->co, 1); + /* push the return values */ + + if (c->timedout) { + lua_pushnil(ctx->cur_co_ctx->co); + lua_pushliteral(ctx->cur_co_ctx->co, "timeout"); + n = 2; + + } else if (c->error) { + lua_pushnil(ctx->cur_co_ctx->co); + lua_pushliteral(ctx->cur_co_ctx->co, "client aborted"); + n = 2; + + } else { + lua_pushinteger(ctx->cur_co_ctx->co, 1); + n = 1; + } vm = ngx_http_lua_get_lua_vm(r, ctx); - rc = ngx_http_lua_run_thread(vm, r, ctx, 1); + rc = ngx_http_lua_run_thread(vm, r, ctx, n); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua run thread returned %d", rc); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_phase.c b/debian/modules/nginx-lua/src/ngx_http_lua_phase.c index 880ee76..6053a39 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_phase.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_phase.c @@ -40,6 +40,10 @@ ngx_http_lua_ngx_get_phase(lua_State *L) } switch (ctx->context) { + case NGX_HTTP_LUA_CONTEXT_INIT_WORKER: + lua_pushliteral(L, "init_worker"); + break; + case NGX_HTTP_LUA_CONTEXT_SET: lua_pushliteral(L, "set"); break; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c b/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c index 78d5ca2..af3b499 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c @@ -179,7 +179,8 @@ ngx_http_lua_rewrite_handler_inline(ngx_http_request_t *r) rc = ngx_http_lua_cache_loadbuffer(r, L, llcf->rewrite_src.value.data, llcf->rewrite_src.value.len, llcf->rewrite_src_key, - "=rewrite_by_lua"); + (const char *) + llcf->rewrite_chunkname); if (rc != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c b/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c index c667af5..b59b9e7 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c @@ -102,8 +102,10 @@ ngx_http_lua_sleep_handler(ngx_event_t *ev) return; } - log_ctx = c->log->data; - log_ctx->current_request = r; + if (c->fd != -1) { /* not a fake connection */ + log_ctx = c->log->data; + log_ctx->current_request = r; + } coctx->cleanup = NULL; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c index 52cc89d..b0bf4fa 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c @@ -1314,7 +1314,43 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) } } - u->ssl_name = name; + dd("found sni name: %.*s %p", (int) name.len, name.data, name.data); + + if (name.len == 0) { + u->ssl_name.len = 0; + + } else { + if (u->ssl_name.data) { + /* buffer already allocated */ + + if (u->ssl_name.len >= name.len) { + /* reuse it */ + ngx_memcpy(u->ssl_name.data, name.data, name.len); + u->ssl_name.len = name.len; + + } else { + ngx_free(u->ssl_name.data); + goto new_ssl_name; + } + + } else { + +new_ssl_name: + + u->ssl_name.data = ngx_alloc(name.len, ngx_cycle->log); + if (u->ssl_name.data == NULL) { + u->ssl_name.len = 0; + + lua_pushnil(L); + lua_pushliteral(L, "no memory"); + return 2; + } + + ngx_memcpy(u->ssl_name.data, name.data, name.len); + u->ssl_name.len = name.len; + } + } + u->write_co_ctx = coctx; rc = ngx_ssl_handshake(c); @@ -2651,8 +2687,10 @@ ngx_http_lua_socket_tcp_handler(ngx_event_t *ev) r = u->request; c = r->connection; - ctx = c->log->data; - ctx->current_request = r; + if (c->fd != -1) { /* not a fake connection */ + ctx = c->log->data; + ctx->current_request = r; + } ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua tcp socket handler for \"%V?%V\", wev %d", &r->uri, @@ -3212,7 +3250,11 @@ ngx_http_lua_socket_tcp_finalize_read_part(ngx_http_request_t *r, ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); } +#if defined(nginx_version) && nginx_version >= 1007005 + if (c->read->posted) { +#else if (c->read->prev) { +#endif ngx_delete_posted_event(c->read); } @@ -3261,7 +3303,11 @@ ngx_http_lua_socket_tcp_finalize_write_part(ngx_http_request_t *r, ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); } +#if defined(nginx_version) && nginx_version >= 1007005 + if (c->write->posted) { +#else if (c->write->prev) { +#endif ngx_delete_posted_event(c->write); } @@ -3306,6 +3352,14 @@ ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, u->peer.free(&u->peer, u->peer.data, 0); } +#if (NGX_HTTP_SSL) + if (u->ssl_name.data) { + ngx_free(u->ssl_name.data); + u->ssl_name.data = NULL; + u->ssl_name.len = 0; + } +#endif + c = u->peer.connection; if (c) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c b/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c index 21d35a8..6410b1e 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c @@ -1299,8 +1299,10 @@ ngx_http_lua_socket_udp_handler(ngx_event_t *ev) r = u->request; c = r->connection; - ctx = c->log->data; - ctx->current_request = r; + if (c->fd != -1) { /* not a fake connection */ + ctx = c->log->data; + ctx->current_request = r; + } ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua udp socket handler for \"%V?%V\", wev %d", &r->uri, diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c index 3608332..6dda007 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c @@ -26,12 +26,22 @@ typedef struct { void **srv_conf; void **loc_conf; + ngx_pool_t *pool; + + ngx_listening_t *listening; + ngx_str_t client_addr_text; + ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_vm_state_t *vm_state; } ngx_http_lua_timer_ctx_t; +typedef struct { + ngx_connection_t *connection; +} ngx_http_lua_timer_log_ctx_t; + + static int ngx_http_lua_ngx_timer_at(lua_State *L); static void ngx_http_lua_timer_handler(ngx_event_t *ev); static u_char * ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, @@ -67,7 +77,7 @@ ngx_http_lua_ngx_timer_at(lua_State *L) ngx_http_connection_t *hc; #endif - ngx_http_lua_timer_ctx_t *tctx; + ngx_http_lua_timer_ctx_t *tctx = NULL; ngx_http_lua_main_conf_t *lmcf; #if 0 ngx_http_core_main_conf_t *cmcf; @@ -201,10 +211,7 @@ ngx_http_lua_ngx_timer_at(lua_State *L) p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_http_lua_timer_ctx_t), r->connection->log); if (p == NULL) { - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); - lua_rawget(L, LUA_REGISTRYINDEX); - luaL_unref(L, -1, co_ref); - return luaL_error(L, "no memory"); + goto nomem; } ev = (ngx_event_t *) p; @@ -223,6 +230,34 @@ ngx_http_lua_ngx_timer_at(lua_State *L) tctx->loc_conf = r->loc_conf; tctx->lmcf = lmcf; + tctx->pool = ngx_create_pool(128, ngx_cycle->log); + if (tctx->pool == NULL) { + goto nomem; + } + + if (r->connection) { + tctx->listening = r->connection->listening; + + } else { + tctx->listening = NULL; + } + + if (r->connection->addr_text.len) { + tctx->client_addr_text.data = ngx_palloc(tctx->pool, + r->connection->addr_text.len); + if (tctx->client_addr_text.data == NULL) { + goto nomem; + } + + ngx_memcpy(tctx->client_addr_text.data, r->connection->addr_text.data, + r->connection->addr_text.len); + tctx->client_addr_text.len = r->connection->addr_text.len; + + } else { + tctx->client_addr_text.len = 0; + tctx->client_addr_text.data = NULL; + } + if (ctx && ctx->vm_state) { tctx->vm_state = ctx->vm_state; tctx->vm_state->count++; @@ -241,6 +276,18 @@ ngx_http_lua_ngx_timer_at(lua_State *L) lua_pushinteger(L, 1); return 1; + +nomem: + + if (tctx && tctx->pool) { + ngx_destroy_pool(tctx->pool); + } + + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_rawget(L, LUA_REGISTRYINDEX); + luaL_unref(L, -1, co_ref); + + return luaL_error(L, "no memory"); } @@ -259,6 +306,7 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) ngx_http_lua_timer_ctx_t tctx; ngx_http_lua_main_conf_t *lmcf; ngx_http_core_loc_conf_t *clcf; + ngx_http_lua_timer_log_ctx_t *logctx; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua ngx.timer expired"); @@ -278,12 +326,23 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) goto failed; } - c = ngx_http_lua_create_fake_connection(); + c = ngx_http_lua_create_fake_connection(tctx.pool); if (c == NULL) { goto failed; } + logctx = ngx_palloc(c->pool, sizeof(ngx_http_lua_timer_log_ctx_t)); + if (logctx == NULL) { + goto failed; + } + + logctx->connection = c; + c->log->handler = ngx_http_lua_log_timer_error; + c->log->data = logctx; + + c->listening = tctx.listening; + c->addr_text = tctx.client_addr_text; r = ngx_http_lua_create_fake_request(c); if (r == NULL) { @@ -295,11 +354,21 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) r->loc_conf = tctx.loc_conf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + +#if defined(nginx_version) && nginx_version >= 1003014 + + ngx_http_set_connection_log(r->connection, clcf->error_log); + +#else + c->log->file = clcf->error_log->file; + if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { c->log->log_level = clcf->error_log->log_level; } +#endif + dd("lmcf: %p", lmcf); ctx = ngx_http_lua_create_ctx(r); @@ -392,12 +461,11 @@ failed: ngx_http_lua_cleanup_vm(tctx.vm_state); } - if (r && r->pool) { - ngx_destroy_pool(r->pool); - } - if (c) { ngx_http_lua_close_fake_connection(c); + + } else if (tctx.pool) { + ngx_destroy_pool(tctx.pool); } } @@ -406,6 +474,9 @@ static u_char * ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, size_t len) { u_char *p; + ngx_connection_t *c; + + ngx_http_lua_timer_log_ctx_t *ctx; if (log->action) { p = ngx_snprintf(buf, len, " while %s", log->action); @@ -413,7 +484,29 @@ ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, size_t len) buf = p; } - return ngx_snprintf(buf, len, ", context: ngx.timer"); + ctx = log->data; + + dd("ctx = %p", ctx); + + p = ngx_snprintf(buf, len, ", context: ngx.timer"); + len -= p - buf; + buf = p; + + c = ctx->connection; + + if (c->addr_text.len) { + p = ngx_snprintf(buf, len, ", client: %V", &c->addr_text); + len -= p - buf; + buf = p; + } + + if (c && c->listening && c->listening->addr_text.len) { + p = ngx_snprintf(buf, len, ", server: %V", &c->listening->addr_text); + /* len -= p - buf; */ + buf = p; + } + + return buf; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.c b/debian/modules/nginx-lua/src/ngx_http_lua_util.c index 794d085..d1b59b2 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_util.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_util.c @@ -570,6 +570,7 @@ static ngx_int_t ngx_http_lua_output_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_int_t rc; + ngx_http_lua_ctx_t *ctx; ngx_http_request_t *ar; /* active request */ ar = r->connection->data; @@ -584,7 +585,23 @@ ngx_http_lua_output_filter(ngx_http_request_t *r, ngx_chain_t *in) return rc; } - return ngx_http_output_filter(r, in); + rc = ngx_http_output_filter(r, in); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + +#if nginx_version >= 1001004 + ngx_chain_update_chains(r->pool, +#else + ngx_chain_update_chains( +#endif + &ctx->free_bufs, &ctx->busy_bufs, &in, + (ngx_buf_tag_t) &ngx_http_lua_module); + + return rc; } @@ -1490,11 +1507,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) "client timed out"); c->timedout = 1; - if (ctx->entered_content_phase) { - ngx_http_lua_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT); - } - - return NGX_HTTP_REQUEST_TIME_OUT; + goto flush_coros; } wev->timedout = 0; @@ -1535,11 +1548,21 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) if (c->buffered & NGX_HTTP_LOWLEVEL_BUFFERED) { rc = ngx_http_lua_flush_pending_output(r, ctx); - if (rc != NGX_OK) { - return rc; + + dd("flush pending output returned %d, c->error: %d", (int) rc, + c->error); + + if (rc != NGX_ERROR && rc != NGX_OK) { + goto useless; } + + /* when rc == NGX_ERROR, c->error must be set */ } +flush_coros: + + dd("ctx->flushing_coros: %d", (int) ctx->flushing_coros); + if (ctx->flushing_coros) { return ngx_http_lua_process_flushing_coroutines(r, ctx); } @@ -1655,31 +1678,22 @@ ngx_http_lua_flush_pending_output(ngx_http_request_t *r, "lua flushing output: buffered 0x%uxd", c->buffered); - rc = ngx_http_lua_output_filter(r, NULL); + if (ctx->busy_bufs) { + rc = ngx_http_lua_output_filter(r, NULL); - if (rc == NGX_ERROR || rc > NGX_OK) { - if (ctx->entered_content_phase) { - ngx_http_lua_finalize_request(r, rc); + } else { + cl = ngx_http_lua_get_flush_chain(r, ctx); + if (cl == NULL) { + return NGX_ERROR; } - return rc; + rc = ngx_http_lua_output_filter(r, cl); } - if (ctx->busy_bufs) { - cl = NULL; + dd("output filter returned %d", (int) rc); - dd("updating chains..."); - -#if nginx_version >= 1001004 - ngx_chain_update_chains(r->pool, -#else - ngx_chain_update_chains( -#endif - &ctx->free_bufs, &ctx->busy_bufs, &cl, - (ngx_buf_tag_t) &ngx_http_lua_module); - - dd("update lua buf tag: %p, buffered: %x, busy bufs: %p", - &ngx_http_lua_module, (int) c->buffered, ctx->busy_bufs); + if (rc == NGX_ERROR || rc > NGX_OK) { + return rc; } if (c->buffered & NGX_HTTP_LOWLEVEL_BUFFERED) { @@ -1708,7 +1722,7 @@ ngx_http_lua_flush_pending_output(ngx_http_request_t *r, } else { #if 1 - if (wev->timer_set) { + if (wev->timer_set && !wev->delayed) { ngx_del_timer(wev); } #endif @@ -2680,7 +2694,7 @@ ngx_http_lua_chain_get_free_buf(ngx_log_t *log, ngx_pool_t *p, b = cl->buf; start = b->start; end = b->end; - if ((size_t) (end - start) >= len) { + if (start && (size_t) (end - start) >= len) { ngx_log_debug4(NGX_LOG_DEBUG_HTTP, log, 0, "lua reuse free buf memory %O >= %uz, cl:%p, p:%p", (off_t) (end - start), len, cl, start); @@ -3570,7 +3584,6 @@ ngx_http_lua_free_fake_request(ngx_http_request_t *r) { ngx_log_t *log; ngx_http_cleanup_t *cln; - ngx_http_log_ctx_t *ctx; log = r->connection->log; @@ -3589,15 +3602,9 @@ ngx_http_lua_free_fake_request(ngx_http_request_t *r) } } - /* the various request strings were allocated from r->pool */ - ctx = log->data; - ctx->request = NULL; - r->request_line.len = 0; r->connection->destroyed = 1; - - ngx_destroy_pool(r->pool); } @@ -3741,12 +3748,11 @@ ngx_http_lua_cleanup_vm(void *data) ngx_connection_t * -ngx_http_lua_create_fake_connection(void) +ngx_http_lua_create_fake_connection(ngx_pool_t *pool) { ngx_log_t *log; ngx_connection_t *c; ngx_connection_t *saved_c = NULL; - ngx_http_log_ctx_t *logctx; /* (we temporarily use a valid fd (0) to make ngx_get_connection happy) */ if (ngx_cycle->files) { @@ -3765,9 +3771,14 @@ ngx_http_lua_create_fake_connection(void) c->fd = (ngx_socket_t) -1; - c->pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, c->log); - if (c->pool == NULL) { - goto failed; + if (pool) { + c->pool = pool; + + } else { + c->pool = ngx_create_pool(128, c->log); + if (c->pool == NULL) { + goto failed; + } } log = ngx_pcalloc(c->pool, sizeof(ngx_log_t)); @@ -3775,22 +3786,10 @@ ngx_http_lua_create_fake_connection(void) goto failed; } - logctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t)); - if (logctx == NULL) { - goto failed; - } - - dd("c pool allocated: %d", (int) (sizeof(ngx_log_t) - + sizeof(ngx_http_log_ctx_t) + sizeof(ngx_http_request_t))); - - logctx->connection = c; - logctx->request = NULL; - logctx->current_request = NULL; - c->log = log; c->log->connection = c->number; - c->log->data = logctx; c->log->action = NULL; + c->log->data = NULL; c->log_error = NGX_ERROR_INFO; @@ -3818,7 +3817,6 @@ failed: ngx_http_request_t * ngx_http_lua_create_fake_request(ngx_connection_t *c) { - ngx_http_log_ctx_t *logctx; ngx_http_request_t *r; r = ngx_pcalloc(c->pool, sizeof(ngx_http_request_t)); @@ -3828,14 +3826,7 @@ ngx_http_lua_create_fake_request(ngx_connection_t *c) c->requests++; - logctx = c->log->data; - logctx->request = r; - logctx->current_request = r; - - r->pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, c->log); - if (r->pool == NULL) { - return NULL; - } + r->pool = c->pool; dd("r pool allocated: %d", (int) (sizeof(ngx_http_lua_ctx_t) + sizeof(void *) * ngx_http_max_module + sizeof(ngx_http_cleanup_t))); @@ -3866,7 +3857,7 @@ ngx_http_lua_create_fake_request(ngx_connection_t *c) r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module); if (r->ctx == NULL) { - goto failed; + return NULL; } #if 0 @@ -3901,14 +3892,6 @@ ngx_http_lua_create_fake_request(ngx_connection_t *c) r->discard_body = 1; return r; - -failed: - - if (r->pool) { - ngx_destroy_pool(r->pool); - } - - return NULL; } @@ -3939,15 +3922,23 @@ int ngx_http_lua_do_call(ngx_log_t *log, lua_State *L) { int status, base; +#if (NGX_PCRE) ngx_pool_t *old_pool; +#endif base = lua_gettop(L); /* function index */ lua_pushcfunction(L, ngx_http_lua_traceback); /* push traceback function */ lua_insert(L, base); /* put it under chunk and args */ +#if (NGX_PCRE) old_pool = ngx_http_lua_pcre_malloc_init(ngx_cycle->pool); +#endif + status = lua_pcall(L, 0, 0, base); + +#if (NGX_PCRE) ngx_http_lua_pcre_malloc_done(old_pool); +#endif lua_remove(L, base); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.h b/debian/modules/nginx-lua/src/ngx_http_lua_util.h index f735ffb..163395e 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_util.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_util.h @@ -220,7 +220,7 @@ void ngx_http_lua_release_ngx_ctx_table(ngx_log_t *log, lua_State *L, void ngx_http_lua_cleanup_vm(void *data); -ngx_connection_t * ngx_http_lua_create_fake_connection(void); +ngx_connection_t * ngx_http_lua_create_fake_connection(ngx_pool_t *pool); ngx_http_request_t * ngx_http_lua_create_fake_request(ngx_connection_t *c); @@ -396,6 +396,23 @@ ngx_http_lua_cleanup_pending_operation(ngx_http_lua_co_ctx_t *coctx) } +static ngx_inline ngx_chain_t * +ngx_http_lua_get_flush_chain(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) +{ + ngx_chain_t *cl; + + cl = ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool, + &ctx->free_bufs, 0); + if (cl == NULL) { + return NULL; + } + + cl->buf->flush = 1; + + return cl; +} + + extern ngx_uint_t ngx_http_lua_location_hash; extern ngx_uint_t ngx_http_lua_content_length_hash; diff --git a/debian/modules/nginx-lua/t/002-content.t b/debian/modules/nginx-lua/t/002-content.t index fe695a1..706083a 100644 --- a/debian/modules/nginx-lua/t/002-content.t +++ b/debian/modules/nginx-lua/t/002-content.t @@ -10,7 +10,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 18); +plan tests => repeat_each() * (blocks() * 2 + 19); #no_diff(); #no_long_string(); @@ -76,6 +76,8 @@ Yay! 123 GET /lua --- response_body_like: 500 Internal Server Error --- error_code: 500 +--- error_log eval +qr/content_by_lua\(nginx\.conf:\d+\):1: attempt to call field 'echo' \(a nil value\)/ diff --git a/debian/modules/nginx-lua/t/009-log.t b/debian/modules/nginx-lua/t/009-log.t index c2b9088..70202ee 100644 --- a/debian/modules/nginx-lua/t/009-log.t +++ b/debian/modules/nginx-lua/t/009-log.t @@ -31,7 +31,7 @@ GET /log before log after log --- error_log eval -qr/\[\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ +qr/\[\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):3: hello, log12343.14159/ @@ -50,7 +50,7 @@ GET /log before log after log --- error_log eval -qr/\[emerg\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ +qr/\[emerg\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):3: hello, log12343.14159/ @@ -69,7 +69,7 @@ GET /log before log after log --- error_log eval -qr/\[alert\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ +qr/\[alert\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):3: hello, log12343.14159/ @@ -88,7 +88,7 @@ GET /log before log after log --- error_log eval -qr/\[crit\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ +qr/\[crit\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):3: hello, log12343.14159/ @@ -107,7 +107,7 @@ GET /log before log after log --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):3: hello, log12343.14159/ @@ -126,7 +126,7 @@ GET /log before log after log --- error_log eval -qr/\[warn\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ +qr/\[warn\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):3: hello, log12343.14159/ @@ -145,7 +145,7 @@ GET /log before log after log --- error_log eval -qr/\[notice\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ +qr/\[notice\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):3: hello, log12343.14159/ @@ -164,7 +164,7 @@ GET /log before log after log --- error_log eval -qr/\[info\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ +qr/\[info\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):3: hello, log12343.14159/ @@ -183,7 +183,7 @@ GET /log before log after log --- error_log eval -qr/\[debug\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ +qr/\[debug\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):3: hello, log12343.14159/ @@ -202,7 +202,7 @@ GET /log before log after log --- error_log eval -qr/\[notice\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ +qr/\[notice\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):3: hello, log12343.14159/ @@ -222,9 +222,9 @@ GET /log hi --- error_log eval [ -'[lua] content_by_lua:2: ,', -'[lua] content_by_lua:3: nil,', -'[lua] content_by_lua:4: nil: nil,', +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):2: ,/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):3: nil,/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):4: nil: nil,/, ] @@ -342,7 +342,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] content_by_lua:7: bar\(\): hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):7: bar\(\): hello, log12343.14159/ @@ -372,7 +372,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] content_by_lua:8:(?: foo\(\):)? hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):8:(?: foo\(\):)? hello, log12343.14159/ diff --git a/debian/modules/nginx-lua/t/014-bugs.t b/debian/modules/nginx-lua/t/014-bugs.t index a09f0ad..e5fa86f 100644 --- a/debian/modules/nginx-lua/t/014-bugs.t +++ b/debian/modules/nginx-lua/t/014-bugs.t @@ -784,7 +784,7 @@ See more details here: http://mailman.nginx.org/pipermail/nginx-devel/2013-Janua --- no_error_log [alert] --- error_log eval -qr/recv\(\) failed \(\d+: Connection refused\) while resolving/ +qr/send\(\) failed \(\d+: Connection refused\) while resolving/ @@ -859,6 +859,7 @@ GET /t --- response_body_like: An example for a vimrc file --- no_error_log [error] +--- timeout: 10 diff --git a/debian/modules/nginx-lua/t/020-subrequest.t b/debian/modules/nginx-lua/t/020-subrequest.t index 2616b33..e36d1f4 100644 --- a/debian/modules/nginx-lua/t/020-subrequest.t +++ b/debian/modules/nginx-lua/t/020-subrequest.t @@ -2463,7 +2463,6 @@ capture body filter end "; - resolver 8.8.8.8; proxy_http_version 1.1; proxy_pass $_url; } @@ -2534,7 +2533,6 @@ qr/Assertion .*? failed/ end "; - resolver 8.8.8.8; proxy_http_version 1.1; proxy_pass $_url; } diff --git a/debian/modules/nginx-lua/t/023-rewrite/on-abort.t b/debian/modules/nginx-lua/t/023-rewrite/on-abort.t index 7da8332..f5a5ef8 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/on-abort.t +++ b/debian/modules/nginx-lua/t/023-rewrite/on-abort.t @@ -307,11 +307,13 @@ $/ --- abort --- wait: 0.6 --- ignore_response ---- error_log -client prematurely closed connection -on abort called -lua user thread aborted: runtime error: rewrite_by_lua:4: attempt to abort with pending subrequests -main handler done +--- error_log eval +[ +'client prematurely closed connection', +'on abort called', +qr/lua user thread aborted: runtime error: rewrite_by_lua\(nginx\.conf:\d+\):4: attempt to abort with pending subrequests/, +'main handler done', +] diff --git a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t b/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t index bea57b9..fdac782 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t +++ b/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t @@ -2088,8 +2088,9 @@ GET /main qr/^connected blocks() * repeat_each() * 2; +plan tests => repeat_each() * (2 * blocks() + 1); $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); @@ -45,6 +45,8 @@ connect: nil no such file or directory send: nil closed receive: nil closed close: nil closed +--- error_log eval +qr{\[crit\] .*? connect\(\) to unix:/tmp/nosuchfile\.sock failed} diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t b/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t index 548c176..b65e748 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t +++ b/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t @@ -233,8 +233,8 @@ delete thread 1 --- response_body after ---- error_log -lua user thread aborted: runtime error: rewrite_by_lua:3: attempt to call field 'blah' (a nil value) +--- error_log eval +qr/lua user thread aborted: runtime error: rewrite_by_lua\(nginx\.conf:\d+\):3: attempt to call field 'blah' \(a nil value\)/ diff --git a/debian/modules/nginx-lua/t/024-access/on-abort.t b/debian/modules/nginx-lua/t/024-access/on-abort.t index 7936edb..638c644 100644 --- a/debian/modules/nginx-lua/t/024-access/on-abort.t +++ b/debian/modules/nginx-lua/t/024-access/on-abort.t @@ -304,11 +304,13 @@ lua req cleanup --- abort --- wait: 0.6 --- ignore_response ---- error_log -client prematurely closed connection -on abort called -lua user thread aborted: runtime error: access_by_lua:4: attempt to abort with pending subrequests -main handler done +--- error_log eval +[ +'client prematurely closed connection', +'on abort called', +qr/lua user thread aborted: runtime error: access_by_lua\(nginx\.conf:\d+\):4: attempt to abort with pending subrequests/, +'main handler done', +] diff --git a/debian/modules/nginx-lua/t/024-access/uthread-spawn.t b/debian/modules/nginx-lua/t/024-access/uthread-spawn.t index db70499..4f52019 100644 --- a/debian/modules/nginx-lua/t/024-access/uthread-spawn.t +++ b/debian/modules/nginx-lua/t/024-access/uthread-spawn.t @@ -233,8 +233,8 @@ delete thread 1 --- response_body after ---- error_log -lua user thread aborted: runtime error: access_by_lua:3: attempt to call field 'blah' (a nil value) +--- error_log eval +qr/lua user thread aborted: runtime error: access_by_lua\(nginx\.conf:\d+\):3: attempt to call field 'blah' \(a nil value\)/ diff --git a/debian/modules/nginx-lua/t/044-req-body.t b/debian/modules/nginx-lua/t/044-req-body.t index 18c53aa..8c309a0 100644 --- a/debian/modules/nginx-lua/t/044-req-body.t +++ b/debian/modules/nginx-lua/t/044-req-body.t @@ -315,8 +315,8 @@ POST /test yeah --- response_body_like: 500 Internal Server Error --- error_code: 500 ---- error_log -lua entry thread aborted: runtime error: content_by_lua:2: request body not read yet +--- error_log eval +qr/lua entry thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):2: request body not read yet/ --- no_error_log [alert] @@ -573,8 +573,9 @@ hello, world Will you change this world? --- response_body_like: 500 Internal Server Error --- error_code: 500 ---- error_log -lua entry thread aborted: runtime error: rewrite_by_lua:3: request body not read yet +--- error_log eval +qr/lua entry thread aborted: runtime error: rewrite_by_lua\(nginx\.conf:\d+\):3: request body not read yet/ + --- no_error_log [alert] @@ -976,8 +977,9 @@ a client request body is buffered to a temporary file GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 ---- error_log -lua entry thread aborted: runtime error: content_by_lua:2: request body not read yet +--- error_log eval +qr/lua entry thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):2: request body not read yet/ + --- no_error_log [alert] diff --git a/debian/modules/nginx-lua/t/056-flush.t b/debian/modules/nginx-lua/t/056-flush.t index d893652..8b8ee0d 100644 --- a/debian/modules/nginx-lua/t/056-flush.t +++ b/debian/modules/nginx-lua/t/056-flush.t @@ -14,7 +14,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 55; +plan tests => repeat_each() * 60; #no_diff(); no_long_string(); @@ -489,3 +489,36 @@ GET /test --- no_error_log [error] + + +=== TEST 17: limit_rate +--- config + location /test { + limit_rate 150; + content_by_lua ' + local begin = ngx.now() + for i = 1, 2 do + ngx.print(string.rep("a", 100)) + local ok, err = ngx.flush(true) + if not ok then + ngx.log(ngx.ERR, "failed to flush: ", err) + end + end + local elapsed = ngx.now() - begin + ngx.log(ngx.WARN, "lua writes elapsed ", elapsed, " sec") + '; + } +--- request +GET /test +--- response_body eval +"a" x 200 +--- error_log eval +[ +qr/lua writes elapsed [12](?:\.\d+)? sec/, +qr/lua flush requires waiting: buffered 0x[0-9a-f]+, delayed:1/, +] + +--- no_error_log +[error] +--- timeout: 4 + diff --git a/debian/modules/nginx-lua/t/057-flush-timeout.t b/debian/modules/nginx-lua/t/057-flush-timeout.t index 7a8adc0..7420e8e 100644 --- a/debian/modules/nginx-lua/t/057-flush-timeout.t +++ b/debian/modules/nginx-lua/t/057-flush-timeout.t @@ -35,7 +35,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 1 + 2); +plan tests => repeat_each() * 17; #no_diff(); no_long_string(); @@ -57,7 +57,9 @@ __DATA__ GET /test --- ignore_response --- error_log eval -[qr/client timed out \(\d+: .*?timed out\)/] +qr/client timed out \(\d+: .*?timed out\)/ +--- no_error_log +[error] @@ -216,3 +218,105 @@ free request --- no_error_log [error] + + +=== TEST 4: flush wait - return "timeout" error +--- config + send_timeout 100ms; + location /test { + content_by_lua ' + ngx.say("hello, world") + local ok, err = ngx.flush(true) + if not ok then + ngx.log(ngx.ERR, "failed to flush: ", err) + return + end + ngx.say("hiya") + '; + } +--- request +GET /test +--- ignore_response +--- error_log eval +[ +qr/client timed out \(\d+: .*?timed out\)/, +'failed to flush: timeout', +] +--- no_error_log +[alert] + + + +=== TEST 5: flush wait in multiple user threads - return "timeout" error +--- config + send_timeout 100ms; + location /test { + content_by_lua ' + ngx.say("hello, world") + + local function run(tag) + local ok, err = ngx.flush(true) + if not ok then + ngx.log(ngx.ERR, "thread ", tag, ": failed to flush: ", err) + return + end + ngx.say("hiya") + end + + local function new_thread(tag) + local ok, err = ngx.thread.spawn(run, tag) + if not ok then + return error("failed to spawn thread: ", err) + end + end + + new_thread("A") + new_thread("B") + run("main") + '; + } +--- request +GET /test +--- ignore_response +--- error_log eval +[ +qr/client timed out \(\d+: .*?timed out\)/, +'thread main: failed to flush: timeout', +'thread A: failed to flush: timeout', +'thread B: failed to flush: timeout', +] +--- no_error_log +[alert] + + + +=== TEST 6: flush wait - client abort connection prematurely +--- config + #send_timeout 100ms; + location /test { + limit_rate 2; + content_by_lua ' + ngx.say("hello, lua") + local ok, err = ngx.flush(true) + if not ok then + ngx.log(ngx.ERR, "failed to flush: ", err) + return + end + ngx.say("hiya") + '; + } +--- request +GET /test +--- ignore_response +--- error_log eval +[ +qr/writev\(\) failed .*? Broken pipe/i, +qr/failed to flush: client aborted/, +] +--- no_error_log +[alert] + +--- timeout: 0.2 +--- abort +--- wait: 1 + diff --git a/debian/modules/nginx-lua/t/058-tcp-socket.t b/debian/modules/nginx-lua/t/058-tcp-socket.t index 04892bb..8e764cf 100644 --- a/debian/modules/nginx-lua/t/058-tcp-socket.t +++ b/debian/modules/nginx-lua/t/058-tcp-socket.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 169; +plan tests => repeat_each() * 172; our $HtmlDir = html_dir; @@ -404,7 +404,7 @@ attempt to send data on a closed socket === TEST 9: resolver error (timeout) --- config server_tokens off; - resolver 8.8.8.8; + resolver $TEST_NGINX_RESOLVER; resolver_timeout 1ms; location /t { content_by_lua ' @@ -1996,7 +1996,7 @@ close: 1 nil === TEST 33: github issue #215: Handle the posted requests in lua cosocket api (failed to resolve) --- config - resolver 8.8.8.8; + resolver $TEST_NGINX_RESOLVER; location = /sub { content_by_lua ' @@ -2039,7 +2039,7 @@ resolve name done === TEST 34: github issue #215: Handle the posted requests in lua cosocket api (successfully resolved) --- config - resolver 8.8.8.8; + resolver $TEST_NGINX_RESOLVER; location = /sub { content_by_lua ' @@ -2716,8 +2716,9 @@ GET /main qr/^connected blocks() * repeat_each() * 2; +plan tests => repeat_each() * (blocks() * 2 + 1); $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); @@ -43,6 +43,8 @@ connect: nil no such file or directory send: nil closed receive: nil closed close: nil closed +--- error_log eval +qr{\[crit\] .*? connect\(\) to unix:/tmp/nosuchfile\.sock failed} diff --git a/debian/modules/nginx-lua/t/064-pcall.t b/debian/modules/nginx-lua/t/064-pcall.t index 3f9c419..cfa344d 100644 --- a/debian/modules/nginx-lua/t/064-pcall.t +++ b/debian/modules/nginx-lua/t/064-pcall.t @@ -46,11 +46,12 @@ __DATA__ } --- request GET /test ---- response_body -res len: 2 -res: falsecontent_by_lua:4: zero error +--- response_body eval +qr/^res len: 2 +res: falsecontent_by_lua\(nginx\.conf:\d+\):4: zero error res len: 4 res: true23hellotrue +$/s --- no_error_log [error] @@ -94,12 +95,14 @@ res: true23hellotrue } --- request GET /test ---- response_body -error handler called: content_by_lua:4: zero error +--- response_body eval +qr/^error handler called: content_by_lua\(nginx\.conf:\d+\):4: zero error res len: 2 res: falsethis is the new err res len: 4 res: true23hellotrue +$/ + --- no_error_log [error] diff --git a/debian/modules/nginx-lua/t/073-backtrace.t b/debian/modules/nginx-lua/t/073-backtrace.t index a852e4b..914fa15 100644 --- a/debian/modules/nginx-lua/t/073-backtrace.t +++ b/debian/modules/nginx-lua/t/073-backtrace.t @@ -58,13 +58,15 @@ attempt to call global 'lua_concat' --- request GET /lua --- ignore_response ---- error_log -lua entry thread aborted: runtime error: unknown reason -stack traceback: - in function 'error' -: in function 'bar' -:5: in function 'foo' -:7: in function +--- error_log eval +[ +'lua entry thread aborted: runtime error: unknown reason', +'stack traceback:', +" in function 'error'", +": in function 'bar'", +":5: in function 'foo'", +qr/:7: in function /, +] diff --git a/debian/modules/nginx-lua/t/075-logby.t b/debian/modules/nginx-lua/t/075-logby.t index 3a4cc47..5dadb9f 100644 --- a/debian/modules/nginx-lua/t/075-logby.t +++ b/debian/modules/nginx-lua/t/075-logby.t @@ -201,8 +201,8 @@ lua release ngx.ctx GET /lua --- response_body ok ---- error_log -failed to run log_by_lua*: log_by_lua:1: Bad +--- error_log eval +qr/failed to run log_by_lua\*: log_by_lua\(nginx\.conf:\d+\):1: Bad/ @@ -577,8 +577,9 @@ GET /lua --- response_body ok ---- error_log -log_by_lua:1: content-type: text/plain +--- error_log eval +qr{log_by_lua\(nginx\.conf:\d+\):1: content-type: text/plain} + --- no_error_log [error] diff --git a/debian/modules/nginx-lua/t/082-body-filter.t b/debian/modules/nginx-lua/t/082-body-filter.t index c6c70f2..3f7b6da 100644 --- a/debian/modules/nginx-lua/t/082-body-filter.t +++ b/debian/modules/nginx-lua/t/082-body-filter.t @@ -700,8 +700,10 @@ F(ngx_http_write_filter) { } } ---- stap_out eval -("seen flush buf.\n" x 10) . "seen last buf.\n" +--- stap_out_like eval +qr/^(?:seen flush buf\. +){10,}seen last buf\. +$/ --- stap2 global active = 1 diff --git a/debian/modules/nginx-lua/t/087-udp-socket.t b/debian/modules/nginx-lua/t/087-udp-socket.t index 4a4d70a..fd07ff9 100644 --- a/debian/modules/nginx-lua/t/087-udp-socket.t +++ b/debian/modules/nginx-lua/t/087-udp-socket.t @@ -262,8 +262,8 @@ M(http-lua-info) { --- request GET /main --- response_body_like: \b500\b ---- error_log -content_by_lua:8: bad request +--- error_log eval +qr/content_by_lua\(nginx\.conf:\d+\):8: bad request/ @@ -327,8 +327,8 @@ end --- request GET /main --- response_body_like: \b500\b ---- error_log -content_by_lua:6: bad request +--- error_log eval +qr/content_by_lua\(nginx\.conf:\d+\):6: bad request/ @@ -558,7 +558,7 @@ lua udp socket read timed out udp:settimeout(2000) -- 2 sec - local ok, err = udp:setpeername("8.8.8.8", 53) + local ok, err = udp:setpeername("$TEST_NGINX_RESOLVER", 53) if not ok then ngx.say("failed to connect: ", err) return @@ -603,9 +603,20 @@ lua udp socket receive buffer size: 8192 === TEST 11: access the google DNS server (using domain names) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' + -- avoid flushing google in "check leak" testing mode: + local counter = package.loaded.counter + if not counter then + counter = 1 + elseif counter >= 2 then + return ngx.exit(503) + else + counter = counter + 1 + end + package.loaded.counter = counter + local socket = ngx.socket -- local socket = require "socket" @@ -657,7 +668,7 @@ lua udp socket receive buffer size: 8192 === TEST 12: github issue #215: Handle the posted requests in lua cosocket api (failed to resolve) --- config - resolver 8.8.8.8; + resolver $TEST_NGINX_RESOLVER; location = /sub { content_by_lua ' @@ -699,7 +710,7 @@ resolve name done === TEST 13: github issue #215: Handle the posted requests in lua cosocket api (successfully resolved) --- config - resolver 8.8.8.8; + resolver $TEST_NGINX_RESOLVER; resolver_timeout 3s; location = /sub { @@ -857,8 +868,9 @@ GET /main qr/^peer set repeat_each() * (blocks() * 2); +plan tests => repeat_each() * (blocks() * 2 + 1); #no_diff(); #no_long_string(); @@ -160,3 +159,21 @@ GET /lua --- error_log current phase: timer + + +=== TEST 10: get_phase in init_worker_by_lua +--- http_config + init_worker_by_lua 'phase = ngx.get_phase()'; +--- config + location /lua { + content_by_lua ' + ngx.say(phase) + '; + } +--- request +GET /lua +--- response_body +init_worker +--- no_error_log +[error] + diff --git a/debian/modules/nginx-lua/t/091-coroutine.t b/debian/modules/nginx-lua/t/091-coroutine.t index 57685b9..c7c5922 100644 --- a/debian/modules/nginx-lua/t/091-coroutine.t +++ b/debian/modules/nginx-lua/t/091-coroutine.t @@ -897,12 +897,13 @@ chunk: true } --- request GET /t ---- response_body -child: resume: falsecontent_by_lua:4: bad +--- response_body eval +qr/^child: resume: falsecontent_by_lua\(nginx\.conf:\d+\):4: bad child: status: dead parent: status: running ---- error_log -lua coroutine: runtime error: content_by_lua:4: bad +$/s +--- error_log eval +qr/lua coroutine: runtime error: content_by_lua\(nginx\.conf:\d+\):4: bad/ diff --git a/debian/modules/nginx-lua/t/093-uthread-spawn.t b/debian/modules/nginx-lua/t/093-uthread-spawn.t index 4e1a2e3..e6dba5f 100644 --- a/debian/modules/nginx-lua/t/093-uthread-spawn.t +++ b/debian/modules/nginx-lua/t/093-uthread-spawn.t @@ -223,8 +223,8 @@ delete thread 1 --- response_body after ---- error_log -lua user thread aborted: runtime error: content_by_lua:3: attempt to call field 'blah' (a nil value) +--- error_log eval +qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):3: attempt to call field 'blah' \(a nil value\)/ diff --git a/debian/modules/nginx-lua/t/098-uthread-wait.t b/debian/modules/nginx-lua/t/098-uthread-wait.t index 276c8f8..1f064f3 100644 --- a/debian/modules/nginx-lua/t/098-uthread-wait.t +++ b/debian/modules/nginx-lua/t/098-uthread-wait.t @@ -419,8 +419,8 @@ delete thread 1 hello in thread thread created: zombie failed to wait thread: bad bad! ---- error_log -lua user thread aborted: runtime error: content_by_lua:4: bad bad! +--- error_log eval +qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):4: bad bad!/ @@ -469,8 +469,8 @@ delete thread 1 thread created: running hello in thread failed to wait thread: bad bad! ---- error_log -lua user thread aborted: runtime error: content_by_lua:5: bad bad! +--- error_log eval +qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):5: bad bad!/ @@ -885,8 +885,8 @@ failed to wait thread: f done f status: dead g status: zombie ---- error_log -lua user thread aborted: runtime error: content_by_lua:7: f done +--- error_log eval +qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):7: f done/ @@ -961,8 +961,8 @@ f status: dead g status: running g: hello ---- error_log -lua user thread aborted: runtime error: content_by_lua:8: f done +--- error_log eval +qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):8: f done/ @@ -1184,8 +1184,8 @@ delete thread 1 --- response_body_like: 500 Internal Server Error --- error_code: 500 ---- error_log -lua entry thread aborted: runtime error: content_by_lua:11: attempt to wait on a coroutine that is not a user thread +--- error_log eval +qr/lua entry thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):11: attempt to wait on a coroutine that is not a user thread/ @@ -1220,8 +1220,8 @@ delete thread 2 --- response_body ok ---- error_log -lua user thread aborted: runtime error: content_by_lua:5: f done +--- error_log eval +qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):5: f done/ diff --git a/debian/modules/nginx-lua/t/101-on-abort.t b/debian/modules/nginx-lua/t/101-on-abort.t index f84dc00..6eed29d 100644 --- a/debian/modules/nginx-lua/t/101-on-abort.t +++ b/debian/modules/nginx-lua/t/101-on-abort.t @@ -296,11 +296,13 @@ lua req cleanup --- abort --- wait: 0.7 --- ignore_response ---- error_log -client prematurely closed connection -on abort called -lua user thread aborted: runtime error: content_by_lua:4: attempt to abort with pending subrequests -main handler done +--- error_log eval +[ +'client prematurely closed connection', +'on abort called', +qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):4: attempt to abort with pending subrequests/, +'main handler done', +] diff --git a/debian/modules/nginx-lua/t/104-req-raw-header.t b/debian/modules/nginx-lua/t/104-req-raw-header.t index 31c2b70..5fe326b 100644 --- a/debian/modules/nginx-lua/t/104-req-raw-header.t +++ b/debian/modules/nginx-lua/t/104-req-raw-header.t @@ -9,10 +9,10 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 6); +plan tests => repeat_each() * (blocks() * 3 + 15); #no_diff(); -#no_long_string(); +no_long_string(); run_tests(); __DATA__ @@ -776,3 +776,105 @@ Content-Length: 5 --- no_error_log [error] + + +=== TEST 27: two pipelined requests with large headers +--- config + client_header_buffer_size 10; + large_client_header_buffers 3 5610; + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header()) + '; + } +--- pipelined_requests eval +["GET /t", "GET /t"] +--- more_headers eval +CORE::join "\n", map { "Header$_: value-$_" } 1..585 + +--- response_body eval +[qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: keep-alive\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..585) . "\r\n\r\n", +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..585) . "\r\n\r\n", +, +] + +--- no_error_log +[error] +--- timeout: 5 + + + +=== TEST 28: a request with large header and a smaller pipelined request following +--- config + client_header_buffer_size 10; + large_client_header_buffers 2 1921; + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header()) + '; + } +--- pipelined_requests eval +["GET /t", "GET /t"] +--- more_headers eval +[CORE::join("\n", map { "Header$_: value-$_" } 1..170), "Foo: bar\n"] + +--- response_body eval +[qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: keep-alive\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..170) . "\r\n\r\n", +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +Foo: bar\r +\r +}, +] + +--- no_error_log +[error] +--- timeout: 5 + + + +=== TEST 29: a request with large header and a smaller pipelined request following +--- config + client_header_buffer_size 10; + large_client_header_buffers 2 1921; + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header()) + '; + } +--- pipelined_requests eval +["GET /t", "GET /t" . ("a" x 512)] +--- more_headers eval +[CORE::join("\n", map { "Header$_: value-$_" } 1..170), "Foo: bar\n"] + +--- response_body eval +[qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: keep-alive\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..170) . "\r\n\r\n", +qq{GET /t} . ("a" x 512) . qq{ HTTP/1.1\r +Host: localhost\r +Connection: close\r +Foo: bar\r +\r +}, +] + +--- no_error_log +[error] +--- timeout: 5 + diff --git a/debian/modules/nginx-lua/t/106-timer.t b/debian/modules/nginx-lua/t/106-timer.t index a10f30f..497ffa2 100644 --- a/debian/modules/nginx-lua/t/106-timer.t +++ b/debian/modules/nginx-lua/t/106-timer.t @@ -13,7 +13,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 8 + 76); +plan tests => repeat_each() * (blocks() * 8 + 72); #no_diff(); no_long_string(); @@ -69,7 +69,7 @@ timer prematurely expired: true --- error_log eval [ -qr/\[lua\] content_by_lua:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])\d*, context: ngx\.timer/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])\d*, context: ngx\.timer, client: \d+\.\d+\.\d+\.\d+, server: 0\.0\.0\.0:\d+/, "lua ngx.timer expired", "http lua close fake http connection", "timer prematurely expired: false", @@ -115,7 +115,7 @@ foo = nil --- error_log eval [ -qr/\[lua\] content_by_lua:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -161,7 +161,7 @@ foo = 3 --- error_log eval [ -qr/\[lua\] content_by_lua:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -209,7 +209,7 @@ registered timer --- error_log eval [ qr/\[lua\] .*? my lua timer handler/, -qr/\[lua\] content_by_lua:\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -455,7 +455,7 @@ registered timer --- error_log eval [ -qr/\[lua\] content_by_lua:\d+: elapsed: 0(?:[^.]|\.00)/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0(?:[^.]|\.00)/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -588,7 +588,7 @@ hello world [ "registered timer", qr/\[lua\] .*? my lua timer handler/, -qr/\[lua\] log_by_lua:\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, +qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1482,10 +1482,12 @@ registered timer [alert] [crit] ---- error_log -lua ngx.timer expired -http lua close fake http connection -trace: [m][f][g] +--- error_log eval +[ +'lua ngx.timer expired', +'http lua close fake http connection', +qr/trace: \[m\]\[f\]\[g\], context: ngx\.timer, client: \d+\.\d+\.\d+\.\d+, server: 0\.0\.0\.0:\d+/, +] @@ -1929,10 +1931,12 @@ registered timer [crit] [error] ---- error_log -1 lua_max_running_timers are not enough -lua ngx.timer expired -http lua close fake http connection +--- error_log eval +[ +qr/\[alert\] .*? 1 lua_max_running_timers are not enough/, +"lua ngx.timer expired", +"http lua close fake http connection", +] @@ -2112,7 +2116,7 @@ timer prematurely expired: true --- error_log eval [ -qr/\[lua\] content_by_lua:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])\d*, context: ngx\.timer/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])\d*, context: ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection", "timer prematurely expired: false", @@ -2155,10 +2159,40 @@ timer prematurely expired: true --- error_log eval [ -qr/\[lua\] content_by_lua:\d+: elapsed: .*?, context: ngx\.timer/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: .*?, context: ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection", "timer prematurely expired: false", "lua release ngx.ctx at ref ", ] + + +=== TEST 32: syslog error log +--- http_config + #error_log syslog:server=127.0.0.1:12345 error; +--- config + location /t { + content_by_lua ' + local function f() + ngx.log(ngx.ERR, "Bad bad bad") + end + ngx.timer.at(0, f) + ngx.sleep(0.001) + ngx.say("ok") + '; + } +--- log_level: error +--- error_log_file: syslog:server=127.0.0.1:12345 +--- udp_listen: 12345 +--- udp_query eval: qr/Bad bad bad/ +--- udp_reply: hello +--- wait: 0.1 +--- request + GET /t +--- response_body +ok +--- error_log +Bad bad bad +--- skip_nginx: 4: < 1.7.1 + diff --git a/debian/modules/nginx-lua/t/107-timer-errors.t b/debian/modules/nginx-lua/t/107-timer-errors.t index 12e6564..5e9b664 100644 --- a/debian/modules/nginx-lua/t/107-timer-errors.t +++ b/debian/modules/nginx-lua/t/107-timer-errors.t @@ -49,7 +49,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -88,7 +88,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -127,7 +127,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -166,7 +166,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -205,7 +205,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -244,7 +244,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -283,7 +283,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -322,7 +322,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -361,7 +361,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -400,7 +400,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -439,7 +439,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -478,7 +478,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -517,7 +517,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -556,7 +556,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -595,7 +595,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -634,7 +634,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -673,7 +673,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -712,7 +712,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -751,7 +751,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -790,7 +790,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -829,7 +829,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -868,7 +868,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -907,7 +907,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -946,7 +946,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -985,7 +985,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1024,7 +1024,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1063,7 +1063,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1102,7 +1102,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1141,7 +1141,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1180,7 +1180,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1219,7 +1219,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1258,7 +1258,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1297,7 +1297,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1336,7 +1336,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1375,7 +1375,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1417,7 +1417,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] diff --git a/debian/modules/nginx-lua/t/108-timer-safe.t b/debian/modules/nginx-lua/t/108-timer-safe.t index 1f13455..94c322d 100644 --- a/debian/modules/nginx-lua/t/108-timer-safe.t +++ b/debian/modules/nginx-lua/t/108-timer-safe.t @@ -68,7 +68,7 @@ registered timer --- error_log eval [ -qr/\[lua\] content_by_lua:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -117,7 +117,7 @@ registered timer --- error_log eval [ qr/\[lua\] .*? my lua timer handler/, -qr/\[lua\] content_by_lua:\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -365,7 +365,7 @@ registered timer --- error_log eval [ -qr/\[lua\] content_by_lua:\d+: elapsed: 0(?:[^.]|\.00)/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0(?:[^.]|\.00)/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -500,7 +500,7 @@ hello world [ "registered timer", qr/\[lua\] .*? my lua timer handler/, -qr/\[lua\] log_by_lua:\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, +qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] diff --git a/debian/modules/nginx-lua/t/124-init-worker.t b/debian/modules/nginx-lua/t/124-init-worker.t index a35b8e9..ce86fee 100644 --- a/debian/modules/nginx-lua/t/124-init-worker.t +++ b/debian/modules/nginx-lua/t/124-init-worker.t @@ -578,7 +578,7 @@ second line received: Server: openresty timer created failed to connect: connection refused --- error_log eval -qr/connect\(\) failed \(\d+: Connection refused\)/ +qr/connect\(\) failed \(\d+: Connection refused\), context: ngx\.timer$/ @@ -706,3 +706,37 @@ ok [alert] [emerg] + + +=== TEST 18: syslog error log +--- http_config + #error_log syslog:server=127.0.0.1:12345 error; + init_worker_by_lua ' + done = false + os.execute("sleep 0.1") + ngx.log(ngx.ERR, "Bad bad bad") + done = true + '; +--- config + location /t { + content_by_lua ' + while not done do + ngx.sleep(0.001) + end + ngx.say("ok") + '; + } +--- log_level: error +--- error_log_file: syslog:server=127.0.0.1:12345 +--- udp_listen: 12345 +--- udp_query eval: qr/Bad bad bad/ +--- udp_reply: hello +--- wait: 0.1 +--- request + GET /t +--- response_body +ok +--- error_log +Bad bad bad +--- skip_nginx: 4: < 1.7.1 + diff --git a/debian/modules/nginx-lua/t/129-ssl-socket.t b/debian/modules/nginx-lua/t/129-ssl-socket.t index 8bc0487..bb04110 100644 --- a/debian/modules/nginx-lua/t/129-ssl-socket.t +++ b/debian/modules/nginx-lua/t/129-ssl-socket.t @@ -40,7 +40,7 @@ __DATA__ === TEST 1: www.google.com --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -59,6 +59,7 @@ __DATA__ do local sock = ngx.socket.tcp() + sock:settimeout(2000) local ok, err = sock:connect("www.google.com", 443) if not ok then ngx.say("failed to connect: ", err) @@ -132,6 +133,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) do local ok, err = sock:connect("g.sregex.org", 443) @@ -208,6 +210,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) do local ok, err = sock:connect("iscribblet.org", 443) @@ -285,6 +288,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) do @@ -379,6 +383,7 @@ lua ssl free session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) do local ok, err = sock:connect("agentzh.org", 443) @@ -457,6 +462,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) do local ok, err = sock:connect("agentzh.org", 443) @@ -532,6 +538,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) do local ok, err = sock:connect("agentzh.org", 443) @@ -612,6 +619,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) do local ok, err = sock:connect("iscribblet.org", 443) @@ -696,6 +704,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) do local ok, err = sock:connect("iscribblet.org", 443) @@ -774,6 +783,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) do local ok, err = sock:connect("iscribblet.org", 443) @@ -842,7 +852,7 @@ SSL reused session === TEST 11: www.google.com (SSL verify passes) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 3; location /t { @@ -863,6 +873,7 @@ SSL reused session do local sock = ngx.socket.tcp() + sock:settimeout(2000) local ok, err = sock:connect("www.google.com", 443) if not ok then ngx.say("failed to connect: ", err) @@ -934,7 +945,7 @@ SSL reused session === TEST 12: www.google.com (SSL verify enabled and no corresponding trusted certificates) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 3; location /t { @@ -955,6 +966,7 @@ SSL reused session do local sock = ngx.socket.tcp() + sock:settimeout(2000) local ok, err = sock:connect("www.google.com", 443) if not ok then ngx.say("failed to connect: ", err) @@ -1029,6 +1041,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) do local ok, err = sock:connect("iscribblet.org", 443) @@ -1112,6 +1125,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) do local ok, err = sock:connect("iscribblet.org", 443) @@ -1191,6 +1205,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) do local ok, err = sock:connect("iscribblet.org", 443) @@ -1270,6 +1285,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) do local ok, err = sock:connect("iscribblet.org", 443) @@ -1350,6 +1366,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) do local ok, err = sock:connect("iscribblet.org", 443) @@ -1426,6 +1443,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) do @@ -1502,6 +1520,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) do @@ -1635,6 +1654,7 @@ attempt to call method 'sslhandshake' (a nil value) content_by_lua ' do local sock = ngx.socket.tcp() + sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) @@ -1708,7 +1728,7 @@ lua ssl server name: SSL reused session [error] [alert] ---- timeout: 3 +--- timeout: 5 @@ -1739,6 +1759,7 @@ SSL reused session content_by_lua ' do local sock = ngx.socket.tcp() + sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) @@ -1813,7 +1834,7 @@ lua ssl server name: "test.com" SSL reused session [error] [alert] ---- timeout: 3 +--- timeout: 5 @@ -1840,6 +1861,9 @@ SSL reused session content_by_lua ' do local sock = ngx.socket.tcp() + + sock:settimeout(2000) + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) @@ -1932,6 +1956,9 @@ SSL reused session content_by_lua ' do local sock = ngx.socket.tcp() + + sock:settimeout(3000) + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) @@ -1996,7 +2023,7 @@ lua ssl server name: "test.com" SSL reused session [error] [alert] ---- timeout: 3 +--- timeout: 5 @@ -2011,6 +2038,8 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) + do local ok, err = sock:connect("iscribblet.org", 443) if not ok then @@ -2093,6 +2122,8 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(2000) + do local ok, err = sock:connect("iscribblet.org", 443) if not ok then @@ -2159,6 +2190,7 @@ SSL reused session content_by_lua ' do local sock = ngx.socket.tcp() + sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) @@ -2200,7 +2232,7 @@ lua ssl server name: SSL reused session [error] [alert] ---- timeout: 3 +--- timeout: 5 @@ -2229,6 +2261,7 @@ SSL reused session content_by_lua ' do local sock = ngx.socket.tcp() + sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) @@ -2273,7 +2306,7 @@ lua ssl server name: SSL reused session [error] [alert] ---- timeout: 3 +--- timeout: 5 @@ -2301,6 +2334,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() + sock:settimeout(3000) for i = 1, 2 do local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then @@ -2349,7 +2383,7 @@ lua ssl server name: SSL reused session [error] [alert] ---- timeout: 3 +--- timeout: 5 @@ -2380,6 +2414,7 @@ SSL reused session content_by_lua ' do local sock = ngx.socket.tcp() + sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) @@ -2453,7 +2488,7 @@ $/ SSL reused session [error] [alert] ---- timeout: 3 +--- timeout: 5 @@ -2484,6 +2519,7 @@ SSL reused session content_by_lua ' do local sock = ngx.socket.tcp() + sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) @@ -2545,5 +2581,5 @@ lua ssl certificate verify error: (18: self signed certificate) --- no_error_log SSL reused session [alert] ---- timeout: 3 +--- timeout: 5 diff --git a/debian/modules/nginx-lua/util/build2.sh b/debian/modules/nginx-lua/util/build2.sh index 4643ddd..c426035 100755 --- a/debian/modules/nginx-lua/util/build2.sh +++ b/debian/modules/nginx-lua/util/build2.sh @@ -19,6 +19,7 @@ force=$2 #--without-http_referer_module \ time ngx-build $force $version \ + --with-ipv6 \ --with-cc-opt="-I$PCRE_INC" \ --with-http_realip_module \ --with-http_ssl_module \ diff --git a/debian/modules/nginx-lua/valgrind.suppress b/debian/modules/nginx-lua/valgrind.suppress index 36ecf14..a69e606 100644 --- a/debian/modules/nginx-lua/valgrind.suppress +++ b/debian/modules/nginx-lua/valgrind.suppress @@ -132,3 +132,13 @@ fun:main fun:_dl_sysdep_start fun:_dl_start } +{ + + Memcheck:Param + sendmsg(mmsg[0].msg_hdr) + fun:sendmmsg + fun:__libc_res_nsend + fun:__libc_res_nquery + fun:__libc_res_nquerydomain + fun:__libc_res_nsearch +} From e3cd58d651d9ee920d2557ab70cdd2997958db23 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Sun, 11 Jan 2015 17:31:09 -0600 Subject: [PATCH 008/651] Added comment about ssl_ciphers --- debian/changelog | 1 + debian/conf/sites-available/default | 2 ++ 2 files changed, 3 insertions(+) diff --git a/debian/changelog b/debian/changelog index 37922fa..b41824d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,7 @@ nginx (1.6.2-6) UNRELEASED; urgency=medium * debian/conf/sites-available/default: + Add comment about disabling gzip in HTTPS. (Closes: #773332) + + Add comment about checking ssl_ciphers. (Closes: #765782) * debian/nginx-common.{dirs,install}, debian/vim/*: + Installing vim syntax highlighting from package. (Closes: #771609) Thanks Emmanuel Bouthenot for building this patch. diff --git a/debian/conf/sites-available/default b/debian/conf/sites-available/default index d63660c..54accbc 100644 --- a/debian/conf/sites-available/default +++ b/debian/conf/sites-available/default @@ -25,6 +25,8 @@ server { # Note: You should disable gzip for SSL traffic. # See: https://bugs.debian.org/773332 # + # Read up on ssl_ciphers to ensure a secure configuration. + # # Self signed certs generated by the ssl-cert package # Don't use them in a production server! # From 16c3177924bd26b99b2b8a6dca0eab255091e3ef Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Sun, 11 Jan 2015 17:31:52 -0600 Subject: [PATCH 009/651] Updated comment about ssl_ciphers --- debian/conf/sites-available/default | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/conf/sites-available/default b/debian/conf/sites-available/default index 54accbc..79e41e8 100644 --- a/debian/conf/sites-available/default +++ b/debian/conf/sites-available/default @@ -26,6 +26,7 @@ server { # See: https://bugs.debian.org/773332 # # Read up on ssl_ciphers to ensure a secure configuration. + # See: https://bugs.debian.org/765782 # # Self signed certs generated by the ssl-cert package # Don't use them in a production server! From 3e4a3d9160cf47710e77cc9d6f7f6d11bb4a53b3 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Wed, 21 Jan 2015 22:45:15 -0600 Subject: [PATCH 010/651] Added ngx-conf configuration utility... finally. --- debian/changelog | 3 + debian/nginx-common.install | 1 + debian/nginx-common.manpages | 1 + debian/ngx-conf/README.rst | 104 +++++++++++++ debian/ngx-conf/ngx-conf | 275 +++++++++++++++++++++++++++++++++++ debian/ngx-conf/ngx-conf.1 | 135 +++++++++++++++++ 6 files changed, 519 insertions(+) create mode 100644 debian/ngx-conf/README.rst create mode 100755 debian/ngx-conf/ngx-conf create mode 100644 debian/ngx-conf/ngx-conf.1 diff --git a/debian/changelog b/debian/changelog index b41824d..e5efd5b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,6 @@ nginx (1.6.2-6) UNRELEASED; urgency=medium + [Michael Lustfield] * debian/conf/sites-available/default: + Add comment about disabling gzip in HTTPS. (Closes: #773332) + Add comment about checking ssl_ciphers. (Closes: #765782) @@ -13,6 +14,8 @@ nginx (1.6.2-6) UNRELEASED; urgency=medium + Added -fPIE -pie to build. (Closes: #747025) * debian/modules/nginx-lua/*: + Updated module version. (Closes: #762494) + * debian/ngx-conf/* + + Added configuration utility. (Closes: #652108) -- Michael Lustfield Sun, 11 Jan 2015 14:49:36 -0600 diff --git a/debian/nginx-common.install b/debian/nginx-common.install index 9148328..a320780 100644 --- a/debian/nginx-common.install +++ b/debian/nginx-common.install @@ -3,3 +3,4 @@ debian/ufw/nginx etc/ufw/applications.d debian/index.html usr/share/nginx/html/ debian/vim/nginx.yaml usr/share/vim/registry contrib/vim/* usr/share/vim/addons +debian/ngx-conf/ngx-conf usr/sbin/ngx-conf diff --git a/debian/nginx-common.manpages b/debian/nginx-common.manpages index 1fa27c2..1dd9286 100644 --- a/debian/nginx-common.manpages +++ b/debian/nginx-common.manpages @@ -1 +1,2 @@ debian/nginx.1 +debian/ngx-conf/ngx-conf.1 diff --git a/debian/ngx-conf/README.rst b/debian/ngx-conf/README.rst new file mode 100644 index 0000000..e78caf0 --- /dev/null +++ b/debian/ngx-conf/README.rst @@ -0,0 +1,104 @@ +Nginx Configuration Tool (ngx-conf) +=================================== + +A tool to help manage nginx confuration files. + +Synopsis +-------- + +ngx-conf [-h] (-e | -d | -x | -l) [-f] [-r] [-v] FILE [FILES] + +Description +----------- + +Ngx-conf is a relatively simple tool to help manage Nginx configuration files. +It can be used to enable, disable, remove, and list configuration files. In the +case of configuration files in conf.d/\*.conf, it will handle renaming files to +an enabled/disabled state. In sites-{enabled,available}/\*, it will handle the +creation and removal of symbolic links. + +**-h, --help** + show a help message and exit +**-e, --enable** + enable a configuration files +**-d, --disable** + disable a configuration files +**-x, --remove** + remove a configuration files; will prompt without -f +**-l, --list** + list configuration files +**-f, --force** + force change, even if doing so will destroy data +**-r, --reload** + reload configuration after change +**-v, --verbose** + show verbose output; default is quiet unless errors +**FILES** + a list of configuration files to update + +Using --force: + +* In --remove will not prompt you to delete the file(s). +* In --enable will ignore conflicts. +* In --disable will ignore conflicts. +* In --disable will also delete files from sites-enabled. + +Only one action (enable|disable|remove|list) can be performed at one time. + +Examples +-------- + +ngx-conf -e site1 site2 site3 + enable "site{1,2,3}" configurations +ngx-conf -r -d site + disable "site" configuration and reload nginx +ngx-conf -f -r -x site1 site2 + remove "site{1,2}" configurations without prompting and reload nginx + +Configuration Files +------------------- + +Three configuration files, if present, will be read. They will be read in the +following order; the next read file will always override the previous. + +1. /etc/nginx/ngx.cfg +#. /etc/ngx.cfg +#. ngx.cfg + +A sample configuration file with all options set to default:: + + [DEFAULT] + base_dir = /etc/nginx/ + conf_dir = conf.d/ + sites_en = sites-enabled/ + sites_dis = sites-available/ + conf_ext = .conf + verbose = no + reload = no + force = no + +Make sure that base_dir always has a trailing slash. + +Any arguments given to the command will override configuration options. + +Aliases +------- + +If you're interested in any sort of a2{dis,en}{conf,mod,site}, you can create +some nice aliases. Examples: + +* a2ensite -- alias ngxensite='ngx-conf -e' +* a2enconf -- alias ngxenconf='ngx-conf -e' +* a2dissite -- alias ngxdissite='ngx-conf -d' +* a2disconf -- alias ngxdisconf='ngx-conf -d' + +Bugs +---- + +If you experience bugs, the best way to report them is to the upstream bug +tracker. This can be found at https://github.com/ngx/ngx-conf. + +Authors +------- + +The ngx-conf tool and manual page were written by Michael Lustfield . diff --git a/debian/ngx-conf/ngx-conf b/debian/ngx-conf/ngx-conf new file mode 100755 index 0000000..16e95a8 --- /dev/null +++ b/debian/ngx-conf/ngx-conf @@ -0,0 +1,275 @@ +#!/usr/bin/env python + +## +# copyright (c) 2015 Michael Lustfield +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# Except as contained in this notice, the name(s) of the above copyright +# holders shall not be used in advertising or otherwise to promote the sale, +# use or other dealings in this Software without prior written authorization. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +## + +import argparse +import ConfigParser +import glob +import os +import subprocess + + +# Read configuration values +config_opts = ConfigParser.SafeConfigParser({ + 'base_dir': '/etc/nginx/', + 'conf_dir': 'conf.d/', + 'sites_en': 'sites-enabled/', + 'sites_dis': 'sites-available/', + 'conf_ext': '.conf', + 'verbose': 'no', + 'reload': 'no', + 'force': 'no'}) +config_opts.read('/etc/nginx/ngx.cfg') +config_opts.read('/etc/ngx.cfg') +config_opts.read('ngx.cfg') + +# Variable that we'll use a lot. +sites_en = config_opts.get('DEFAULT', 'base_dir') + config_opts.get('DEFAULT', 'sites_en') +sites_dis = config_opts.get('DEFAULT', 'base_dir') + config_opts.get('DEFAULT', 'sites_dis') +conf_dir = config_opts.get('DEFAULT', 'base_dir') + config_opts.get('DEFAULT', 'conf_dir') +conf_ext = config_opts.get('DEFAULT', 'conf_ext') + + +def parse_arguments(): + '''Parse arguments supplied by the user.''' + parser = argparse.ArgumentParser(description='nginx configuration helper', + epilog='Only one in group (enable|disable|remove|list) is allowed.', + usage='ngx-conf [-h] (-e | -d | -x | -l) [-f] [-r] [-v] FILE [FILES]') + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('-e', '--enable', action='store_true', + help='enable a configuration files') + group.add_argument('-d', '--disable', action='store_true', + help='disable a configuration files') + group.add_argument('-x', '--remove', action='store_true', + help='remove a configuration files; will prompt without -f') + group.add_argument('-l', '--list', action='store_true', + help='list configuration files') + parser.add_argument('-f', '--force', action='store_true', + default=config_opts.getboolean('DEFAULT', 'force'), + help='force change, even if doing so will destroy data') + parser.add_argument('-r', '--reload', action='store_true', + default=config_opts.getboolean('DEFAULT', 'reload'), + help='reload configuration after change') + parser.add_argument('-v', '--verbose', action='store_true', + default=config_opts.getboolean('DEFAULT', 'verbose'), + help='show verbose output; default is quite unless errors') + parser.add_argument('FILES', nargs=argparse.REMAINDER, + help='a list of configuration files to update') + return parser.parse_args() + + +def main(): + '''Main execution; read arguments and act accordingly.''' + args = parse_arguments() + if args.FILES == [] and not args.list: + print('No files specified. These are required.') + return False + if args.enable: + enable_configs(args.FILES, args.verbose, args.force) + elif args.disable: + disable_configs(args.FILES, args.verbose, args.force) + elif args.remove: + remove_configs(args.FILES, args.verbose, args.force) + elif args.list: + list_configs() + if args.reload and not args.list: + reload_nginx() + + +def enable_configs(configs, verbose, force): + '''Enable configurtion files specified.''' + if type(configs) != list: + print('Configuration list is in an incorrect format.') + return 1 + + for conf in configs: + if os.path.isfile(conf_dir + conf + conf_ext) or os.path.islink(sites_en + conf) or os.path.isfile(sites_en + conf): + if verbose: + print('Configuration file "{}" is already enabled.'.format(conf)) + elif os.path.isfile(conf_dir + conf + conf_ext + '_disabled'): + if not force and os.path.isfile(sites_dis + conf): + print('Configuration file "{}" has conflicts.'.format(conf)) + else: + try: + os.rename(conf_dir + conf + conf_ext + '_disabled', conf_dir + conf + conf_ext) + if verbose: + print('Configuration file "{}" has been enabled.'.format(conf)) + except: + print('Error occured when trying to enable "{}". Permissions?'.format(conf)) + elif os.path.isfile(sites_dis + conf): + try: + os.symlink(sites_dis + conf, sites_en + conf) + if verbose: + print('Configuration file "{}" has been enabled.'.format(conf)) + except: + print('Error occured when trying to enable "{}". Permissions?'.format(conf)) + else: + print('Configuration file for "{}" was not found.'.format(conf)) + + +def disable_configs(configs, verbose, force): + '''Disable configurtion files specified.''' + if type(configs) != list: + print('Configuration list is in an incorrect format.') + return 1 + + for conf in configs: + if not force and os.path.isfile(conf_dir + conf + conf_ext) and os.path.islink(sites_en + conf): + print('Configuration file "{}" has conflicts.'.format(conf)) + elif not force and os.path.isfile(conf_dir + conf + conf_ext) and os.path.isfile(sites_en + conf): + print('Configuration file "{}" has conflicts.'.format(conf)) + elif os.path.isfile(conf_dir + conf + conf_ext): + if not force and os.path.isfile(conf_dir + conf + conf_ext + '_disabled'): + print('Unable to disable "{}". It appears to have a disabled version.'.format(conf)) + break + elif os.path.isfile(conf_dir + conf + conf_ext + '_disabled'): + if verbose: + print('Attempting to remove disabled config for {}.'.format(conf)) + try: + os.remove(conf_dir + conf + conf_ext + '_disabled') + except: + print('Error trying to remove configuration for disabled "{}".'.format(conf)) + break + try: + os.rename(conf_dir + conf + conf_ext, conf_dir + conf + conf_ext + '_disabled') + if verbose: + print('Configuration file "{}" has been disabled.'.format(conf)) + except: + print('Error occured when trying to disable "{}". Permissions?'.format(conf)) + elif os.path.islink(sites_en + conf): + try: + os.remove(sites_en + conf) + if verbose: + print('Configuration file "{}" has been disabled.'.format(conf)) + except: + print('Error occured when trying to disable "{}". Permissions?'.format(conf)) + elif os.path.isfile(sites_en + conf): + if not force and os.path.isfile(sites_dis + conf): + print('Unable to disable "{}". It appears to have a disabled version.'.format(conf)) + break + elif os.path.isfile(sites_dis + conf): + if verbose: + print('Attempting to remove disabled config for {}.'.format(conf)) + try: + os.remove(sites_dis + conf) + except: + print('Error trying to remove configuration for disabled "{}".'.format(conf)) + break + try: + os.rename(sites_en + conf, sites_dis + conf) + if verbose: + print('Configuration file "{}" has been disabled.'.format(conf)) + except: + print('Error occured when trying to disable "{}". Permissions?'.format(conf)) + else: + print('Configuration file for "{}" was not found.'.format(conf)) + + +def remove_configs(configs, verbose, force): + '''Remove configurtion files specified.''' + if type(configs) != list: + print('Configuration list is in an incorrect format.') + return 1 + + for conf in configs: + if os.path.islink(sites_en + conf): + try: + os.remove(sites_en + conf) + if verbose: + print('Symlink for "{}" removed.'.format(conf)) + except: + print('Error occured when trying to remove symlink for "{}". Permissions?'.format(conf)) + files = [sites_en + conf, sites_dis + conf, conf_dir + conf + conf_ext, + conf_dir + conf + conf_ext + '_disabled'] + for f in files: + if os.path.isfile(f): + if not force: + answer = str(raw_input('Are you sure you want to delete {}? (y/N) '.format(f))) + if answer.lower() != 'y' and answer.lower() != 'yes': + break + try: + os.remove(f) + if verbose: + print('Configuration file for "{}" was removed.'.format(f)) + except: + print('Error occured when trying to remove file for "{}". Permissions?'.format(f)) + + +def list_configs(): + '''List configuration files.''' + configs = get_configs() + for key, verb in [ + ('conf_en', 'Configs enabled in {}:'.format(config_opts.get('DEFAULT', 'conf_dir'))), + ('conf_dis', 'Configs disabled in {}:'.format(config_opts.get('DEFAULT', 'conf_dir'))), + ('sites_en', 'Configs enabled in {}:'.format(config_opts.get('DEFAULT', 'sites_en'))), + ('sites_dis', 'Configs disabled in {}:'.format(config_opts.get('DEFAULT', 'sites_dis'))), + ('sites_avail', 'All confis available in {}:'.format(config_opts.get('DEFAULT', 'sites_dis')))]: + if configs[key] == []: + print(verb + '\n\t') + else: + print(verb) + for conf in configs[key]: + print('\t' + conf) + + +def get_configs(): + '''Returns a list of configuration files.''' + cd = [os.path.basename(f).replace(conf_ext + '_disabled', '') + for f in glob.glob(conf_dir + '*' + conf_ext + '_disabled') + if os.path.isfile(f)] + ce = [os.path.basename(f).replace(conf_ext, '') + for f in glob.glob(conf_dir + '*' + conf_ext) + if os.path.isfile(f)] + se = [os.path.basename(f) + for f in glob.glob(sites_en + '*') + if os.path.isfile(f) or os.path.islink(f)] + sd = [os.path.basename(f) + for f in glob.glob(sites_dis + '*') + if os.path.isfile(f) and os.path.basename(f) not in se] + sa = [os.path.basename(f) + for f in glob.glob(sites_dis + '*') + if os.path.isfile(f)] + return {'conf_dis': cd, 'conf_en': ce, 'sites_en': se, 'sites_dis': sd, 'sites_avail': sa} + + +def reload_nginx(): + '''Reload Nginx after configuration changes.''' + child = subprocess.Popen( + ['service', 'nginx', 'reload'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = child.communicate() + if int(child.returncode) != 0: + print('Error reloading nginx configs.') + return False + elif verbose: + print('Nginx config reloaded successfully.') + return True + + +if __name__ == '__main__': + main() diff --git a/debian/ngx-conf/ngx-conf.1 b/debian/ngx-conf/ngx-conf.1 new file mode 100644 index 0000000..3228f59 --- /dev/null +++ b/debian/ngx-conf/ngx-conf.1 @@ -0,0 +1,135 @@ +.\" Title: ngx-conf +.\" Author: Michael Lustfield +.\" Date: 01/14/2015 +.\" Manual: User Commands +.\" +.TH "NGX-CONF" "1" "01/14/2015" "ngx-conf" "User Commands" +.\" disable hyphenation +.NH +.\" disable justification (adjust text to left margin only) +.AD l +.SH "NAME" +ngx - a tool to help manage nginx confuration files +.SH "SYNOPSIS" +.B ngx-conf +[-h] (-e | -d | -x | -l) [-f] [-r] [-v] FILE [FILES] +.br +.SH "DESCRIPTION" +.PP +Ngx-conf is a relatively simple tool to help manage Nginx configuration files. +It can be used to enable, disable, remove, and list configuration files. In the +case of configuration files in conf.d/*.conf, it will handle renaming files to +an enabled/disabled state. In sites-{enabled,available}/*, it will handle the +creation and removal of symbolic links. +.SH "OPTIONS" +.PP +This program follows the usual command line syntax, with long options starting +with two dashes (`\-'). A summary of options is included below. +.TP +.B \-h, \-\-help +show a help message and exit +.TP +.B \-e, \-\-enable +enable a configuration files +.TP +.B \-d, \-\-disable +disable a configuration files +.TP +.B \-x, \-\-remove +remove a configuration files; will prompt without -f +.TP +.B \-l, \-\-list +list configuration files +.TP +.B \-f, \-\-force +force change, even if doing so will destroy data +.TP +.B \-r, \-\-reload +reload configuration after change +.TP +.B \-v, \-\-verbose +show verbose output; default is quiet unless errors +.B FILES +a list of configuration files to update +.PP +Using --force: +.IP +In --remove will not prompt you to delete the file(s). +.br +In --enable will ignore conflicts. +.br +In --disable will ignore conflicts. +.br +In --disable will also delete files from sites-enabled. +.PP +Only one action (enable|disable|remove|list) can be performed at one time. +.SH "EXAMPLES" +.PP +ngx-conf -e site1 site2 site3 + enable "site{1,2,3}" configurations +.br +ngx-conf -r -d site + disable "site" configuration and reload nginx +.br +ngx-conf -f -r -x site1 site2 + remove "site{1,2}" configurations without prompting and reload nginx +.SH "CONFIGURATION FILES" +.PP +Three configuration files, if present, will be read. They will be read in the +following order; the next read file will always override the previous. +.IP +1. /etc/nginx/ngx.cfg +.br +2. /etc/ngx.cfg +.br +3. ngx.cfg +.PP +A sample configuration file with all options set to default: +.IP +[DEFAULT] +.br +base_dir = /etc/nginx/ +.br +conf_dir = conf.d/ +.br +sites_en = sites-enabled/ +.br +sites_dis = sites-available/ +.br +conf_ext = .conf +.br +verbose = no +.br +reload = no +.br +force = no +.PP +Make sure that base_dir always has a trailing slash. +.br +Any arguments given to the command will override configuration options. +.SH "ALIASES" +.PP +If you're interested in any sort of a2{dis,en}{conf,mod,site}, you can create +some nice aliases. Examples: +.TP +.B a2ensite +alias ngxensite='ngx-conf -e' +.br +.TP +.B a2enconf +alias ngxenconf='ngx-conf -e' +.br +.TP +.B a2dissite +alias ngxdissite='ngx-conf -d' +.br +.TP +.B a2disconf +alias ngxdisconf='ngx-conf -d' +.SH "BUGS" +.PP +If you experience bugs, the best way to report them is to the upstream bug +tracker. This can be found at https://github.com/ngx/ngx-conf. +.SH "AUTHORS" +.PP +The ngx-conf tool and manual page were written by Michael Lustfield . From c761600ea98f2c44e62b1d4174d00a45a7c7fea7 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Thu, 22 Jan 2015 00:04:50 -0600 Subject: [PATCH 011/651] Adding python as requirement for nginx-common (ngx-conf) --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 36b663e..58f951d 100644 --- a/debian/control +++ b/debian/control @@ -60,7 +60,7 @@ Description: small, powerful, scalable web/proxy server - documentation Package: nginx-common Architecture: all -Depends: lsb-base (>= 3.2-14), ${misc:Depends} +Depends: lsb-base (>= 3.2-14), ${misc:Depends}, python Replaces: nginx (<< 0.8.54-4), nginx-extras (<< 0.8.54-4), nginx-full (<< 0.8.54-4), From 4a01f573799c9ff0b342eb1469892c2122503448 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Sat, 28 Mar 2015 09:50:11 -0500 Subject: [PATCH 012/651] Replaced man page with upstream maintained version. --- debian/changelog | 6 +++-- debian/nginx-common.manpages | 2 +- debian/nginx.1 | 47 ------------------------------------ 3 files changed, 5 insertions(+), 50 deletions(-) delete mode 100644 debian/nginx.1 diff --git a/debian/changelog b/debian/changelog index e5efd5b..7702ba3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.6.2-6) UNRELEASED; urgency=medium +nginx (1.6.2-7) UNRELEASED; urgency=medium [Michael Lustfield] * debian/conf/sites-available/default: @@ -16,8 +16,10 @@ nginx (1.6.2-6) UNRELEASED; urgency=medium + Updated module version. (Closes: #762494) * debian/ngx-conf/* + Added configuration utility. (Closes: #652108) + * debian/nginx-common.manpages: + + Replaced man page with upstream maintained version. (Closes: #781345) - -- Michael Lustfield Sun, 11 Jan 2015 14:49:36 -0600 + -- Michael Lustfield Sat, 28 Mar 2015 09:47:27 -0500 nginx (1.6.2-5) unstable; urgency=medium diff --git a/debian/nginx-common.manpages b/debian/nginx-common.manpages index 1dd9286..faaf162 100644 --- a/debian/nginx-common.manpages +++ b/debian/nginx-common.manpages @@ -1,2 +1,2 @@ -debian/nginx.1 +man/nginx.8 debian/ngx-conf/ngx-conf.1 diff --git a/debian/nginx.1 b/debian/nginx.1 deleted file mode 100644 index 1a9eed2..0000000 --- a/debian/nginx.1 +++ /dev/null @@ -1,47 +0,0 @@ -.TH "nginx" "1" "" "" "" -.SH "NAME" -nginx \- small, powerful, scalable web/proxy server -.SH "SYNOPSIS" -\fBnginx\fR [\fIoptions\fR] <\fIconfiguration file\fR> -.SH "DESCRIPTION" -.PP -\fBNginx\fR ("engine X") is a high\-performance web and reverse proxy server -created by Igor Sysoev. It can be used both as a standalone web server and as a -proxy to reduce the load on back\-end HTTP or mail servers. -.SH "OPTIONS" -.TP -A summary of options is included below: -.TP -\fB\-?\fR,\fB\-h\fR -Show this help. -.TP -\fB\-v\fR -Show version and exit. -.TP -\fB\-V\fR -Show version and configure options then exit. -.TP -\fB\-s\fR \fIsignal\fR -Send signal to a master process: stop, quit, reopen, reload. -.TP -\fB\-p\fR \fIprefix\fR -Set prefix path. -.TP -\fB\-g\fR \fIdirectives\fR -Set global directives out of configuration file. -.TP -\fB\-c\fR <\fIconfiguration file\fR> -Specifies a particular configuration file for nginx to load. -.TP -\fB\-t\fR -Tests nginx configuration and exit. -.TP -.SH "SEE ALSO" -Website: -.TP -.SH "AUTHORS" -\fBnginx\fR was written by Igor Sysoev . -.TP -This manual page was written by Jose Parrella and -Kartik Mistry , for the Debian project (but may be used -by others). From 6502d238f88b3616957f2bcd9efa63284c944e76 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Sat, 28 Mar 2015 10:36:44 -0500 Subject: [PATCH 013/651] Fixing small typo --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 7702ba3..e2aca44 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,6 @@ nginx (1.6.2-7) UNRELEASED; urgency=medium - [Michael Lustfield] + [ Michael Lustfield ] * debian/conf/sites-available/default: + Add comment about disabling gzip in HTTPS. (Closes: #773332) + Add comment about checking ssl_ciphers. (Closes: #765782) From 4f31089dd23c85732a25c40d93d454efd0c15da9 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Wed, 1 Apr 2015 18:00:45 -0500 Subject: [PATCH 014/651] Changing PIE stuff after talking to Thomas Ward --- debian/changelog | 5 ++++- debian/rules | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index e2aca44..8682e01 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,7 +11,10 @@ nginx (1.6.2-7) UNRELEASED; urgency=medium + Created file to support upstart jobs. (Closes: #745483) Thanks Cameron Norman for building this file. * debian/rules: - + Added -fPIE -pie to build. (Closes: #747025) + + Add hardening flags with dpkg-buildflags (Closes: #747025, #781703) + Thanks Thomas Ward + + Supply custom DEB_BUILD_MAINT_OPTIONS for debian_ldflags generation. + Thanks Thomas Ward * debian/modules/nginx-lua/*: + Updated module version. (Closes: #762494) * debian/ngx-conf/* diff --git a/debian/rules b/debian/rules index 16f6701..e56a47c 100755 --- a/debian/rules +++ b/debian/rules @@ -1,12 +1,13 @@ #!/usr/bin/make -f export DH_VERBOSE=1 +export DEB_BUILD_MAINT_OPTIONS=hardening=+all debian_cflags:=$(shell dpkg-buildflags --get CFLAGS) $(shell dpkg-buildflags --get CPPFLAGS) debian_ldflags:=$(shell dpkg-buildflags --get LDFLAGS) # export necessary perl hardenging flags # see: src/http/modules/perl/Makefile.PL -DEBIAN_NGINX_PERL_LDFLAGS:= $(debian_ldflags) +DEBIAN_NGINX_PERL_LDFLAGS:= $(shell DEB_BUILD_MAINT_OPTIONS=hardening=+all,-pie dpkg-buildflags --get LDFLAGS) export DEBIAN_NGINX_PERL_LDFLAGS FLAVOURS := full light extras @@ -29,7 +30,6 @@ endif common_configure_flags := \ --with-cc-opt="$(debian_cflags)" \ --with-ld-opt="$(debian_ldflags)" \ - -fPIE -pie \ --prefix=/usr/share/nginx \ --conf-path=/etc/nginx/nginx.conf \ --http-log-path=/var/log/nginx/access.log \ From 18315ad1e244b9523d7d480e6b1743bbb8308028 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Wed, 1 Apr 2015 18:24:30 -0500 Subject: [PATCH 015/651] Switch worker_processes to auto. --- debian/changelog | 2 ++ debian/conf/nginx.conf | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 8682e01..d9c42a2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,8 @@ nginx (1.6.2-7) UNRELEASED; urgency=medium [ Michael Lustfield ] + * debian/conf/nginx.conf: + + Switch worker_processes to auto. (Closes: #781711) * debian/conf/sites-available/default: + Add comment about disabling gzip in HTTPS. (Closes: #773332) + Add comment about checking ssl_ciphers. (Closes: #765782) diff --git a/debian/conf/nginx.conf b/debian/conf/nginx.conf index 785360a..01a4a21 100644 --- a/debian/conf/nginx.conf +++ b/debian/conf/nginx.conf @@ -1,5 +1,5 @@ user www-data; -worker_processes 4; +worker_processes auto; pid /run/nginx.pid; events { From 153ef732c44002bdbb4b758ce21b319e82fde4c2 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Tue, 7 Apr 2015 08:23:38 -0500 Subject: [PATCH 016/651] Adding gunzip to -full and -extras --- debian/changelog | 12 +++++++----- debian/control | 14 +++++++------- debian/rules | 2 ++ 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/debian/changelog b/debian/changelog index d9c42a2..5d3b367 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.6.2-7) UNRELEASED; urgency=medium +nginx (1.6.2-8) UNRELEASED; urgency=medium [ Michael Lustfield ] * debian/conf/nginx.conf: @@ -13,10 +13,12 @@ nginx (1.6.2-7) UNRELEASED; urgency=medium + Created file to support upstart jobs. (Closes: #745483) Thanks Cameron Norman for building this file. * debian/rules: - + Add hardening flags with dpkg-buildflags (Closes: #747025, #781703) - Thanks Thomas Ward + + Add hardening flags with dpkg-buildflags. (Closes: #747025, #781703) + Thanks Thomas Ward. + Supply custom DEB_BUILD_MAINT_OPTIONS for debian_ldflags generation. - Thanks Thomas Ward + Thanks Thomas Ward. + + Added back missing module gunzip. (Closes: #782065) + Thanks Peter Wu for the initial patch. * debian/modules/nginx-lua/*: + Updated module version. (Closes: #762494) * debian/ngx-conf/* @@ -24,7 +26,7 @@ nginx (1.6.2-7) UNRELEASED; urgency=medium * debian/nginx-common.manpages: + Replaced man page with upstream maintained version. (Closes: #781345) - -- Michael Lustfield Sat, 28 Mar 2015 09:47:27 -0500 + -- Michael Lustfield Tue, 07 Apr 2015 08:23:00 -0500 nginx (1.6.2-5) unstable; urgency=medium diff --git a/debian/control b/debian/control index 58f951d..3cbad02 100644 --- a/debian/control +++ b/debian/control @@ -95,8 +95,8 @@ Description: nginx web/proxy server (standard version) nginx-extra). . STANDARD HTTP MODULES: Core, Access, Auth Basic, Auto Index, Browser, - Charset, Empty GIF, FastCGI, Geo, Gzip, Headers, Index, Limit Requests, - Limit Zone, Log, Map, Memcached, Proxy, Referer, Rewrite, SCGI, + Charset, Empty GIF, FastCGI, Geo, Gunzip, Gzip, Headers, Index, Limit + Requests, Limit Zone, Log, Map, Memcached, Proxy, Referer, Rewrite, SCGI, Split Clients, SSI, Upstream, User ID, UWSGI. . OPTIONAL HTTP MODULES: Addition, Auth Request, Debug, GeoIP, Gzip @@ -141,8 +141,8 @@ Description: nginx web/proxy server (basic version) STANDARD HTTP MODULES: Core, Access, Auth Basic, Auto Index, Charset, Empty GIF, FastCGI, Gzip, Headers, Index, Log, Map, Proxy, Rewrite, Upstream. . - OPTIONAL HTTP MODULES: Auth Request, Debug, Gzip Precompression, IPv6, Real - Ip, SSL, Stub Status. + OPTIONAL HTTP MODULES: Auth Request, Debug, Gzip Precompression, IPv6, + Real IP, SSL, Stub Status. . THIRD PARTY MODULES: Echo. @@ -182,9 +182,9 @@ Description: nginx web/proxy server (extended version) addition of Perl in configuration files. . STANDARD HTTP MODULES: Core, Access, Auth Basic, Auto Index, Browser, - Charset, Empty GIF, FastCGI, Geo, Gzip, Headers, Index, Limit Requests, - Limit Zone, Log, Map, Memcached, Proxy, Referer, Rewrite, SCGI, - Split Clients, SSI, Upstream, User ID, UWSGI. + Charset, Empty GIF, FastCGI, Geo, Gzip, Gunzip, Headers, Index, + Limit Requests, Limit Zone, Log, Map, Memcached, Proxy, Referer, Rewrite, + SCGI, Split Clients, SSI, Upstream, User ID, UWSGI. . OPTIONAL HTTP MODULES: Addition, Auth Request, Debug, Embedded Perl, FLV, GeoIP, Gzip Precompression, Image Filter, IPv6, MP4, Random Index, Real IP, diff --git a/debian/rules b/debian/rules index e56a47c..48f81d9 100755 --- a/debian/rules +++ b/debian/rules @@ -70,6 +70,7 @@ full_configure_flags := \ --with-http_addition_module \ --with-http_dav_module \ --with-http_geoip_module \ + --with-http_gunzip_module \ --with-http_gzip_static_module \ --with-http_image_filter_module \ --with-http_spdy_module \ @@ -89,6 +90,7 @@ extras_configure_flags := \ --with-http_dav_module \ --with-http_flv_module \ --with-http_geoip_module \ + --with-http_gunzip_module \ --with-http_gzip_static_module \ --with-http_image_filter_module \ --with-http_mp4_module \ From a5bbc3a1c68241e0db0257bfa34c9ce55c090285 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Tue, 7 Apr 2015 08:28:28 -0500 Subject: [PATCH 017/651] Updating module list --- debian/control | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/control b/debian/control index 3cbad02..e81c040 100644 --- a/debian/control +++ b/debian/control @@ -192,9 +192,9 @@ Description: nginx web/proxy server (extended version) . MAIL MODULES: Mail Core, IMAP, POP3, SMTP, SSL. . - THIRD PARTY MODULES: Auth PAM, Chunkin, DAV Ext, Echo, Embedded Lua, - Fancy Index, HttpHeadersMore, HTTP Substitution Filter, http push, - Nginx Development Kit, Upload Progress, Upstream Fair Queue. + THIRD PARTY MODULES: Auth PAM, DAV Ext, Echo, Embedded Lua, Fancy Index, + HttpHeadersMore, HTTP Substitution Filter, HTTP Push, Nginx Development Kit, + Upload Progress, Upstream Fair Queue. Package: nginx-extras-dbg Architecture: any From 4d43fb0c644d7b8485360805dae2f6919474a4e5 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Tue, 7 Apr 2015 09:42:46 -0500 Subject: [PATCH 018/651] Updating modules --- debian/changelog | 10 +- debian/modules/README.Modules-versions | 27 +- debian/modules/nginx-auth-pam/ChangeLog | 6 + debian/modules/nginx-auth-pam/LICENSE | 2 +- .../nginx-auth-pam/{README => README.md} | 71 +- .../nginx-auth-pam/ngx_http_auth_pam_module.c | 31 +- debian/modules/nginx-cache-purge/CHANGES | 10 + debian/modules/nginx-cache-purge/LICENSE | 4 +- debian/modules/nginx-cache-purge/README.md | 15 +- .../ngx_cache_purge_module.c | 624 +++- .../nginx-cache-purge/t/{proxy.t => proxy1.t} | 26 +- .../modules/nginx-cache-purge/t/proxy1_vars.t | 138 + debian/modules/nginx-cache-purge/t/proxy2.t | 56 +- .../modules/nginx-cache-purge/t/proxy2_vars.t | 353 +++ debian/modules/nginx-echo/.gitignore | 65 + debian/modules/nginx-echo/LICENSE | 7 +- debian/modules/nginx-echo/README.markdown | 14 +- .../nginx-echo/doc/HttpEchoModule.wiki | 14 +- .../src/ngx_http_echo_request_info.c | 49 +- debian/modules/nginx-echo/t/request-info.t | 98 +- debian/modules/nginx-echo/util/build.sh | 2 +- debian/modules/nginx-echo/util/releng | 8 - debian/modules/nginx-lua/.gitignore | 164 + debian/modules/nginx-lua/README.markdown | 2795 +++++++++-------- .../modules/nginx-lua/doc/HttpLuaModule.wiki | 96 +- .../nginx-lua/misc/recv-until-pm/Makefile | 3 - .../nginx-lua/src/api/ngx_http_lua_api.h | 2 +- .../nginx-lua/src/ngx_http_lua_common.h | 10 +- .../nginx-lua/src/ngx_http_lua_control.c | 26 +- .../src/ngx_http_lua_headerfilterby.c | 18 +- .../nginx-lua/src/ngx_http_lua_headers_out.c | 30 +- .../nginx-lua/src/ngx_http_lua_regex.c | 9 +- .../nginx-lua/src/ngx_http_lua_shdict.c | 8 +- .../nginx-lua/src/ngx_http_lua_socket_tcp.c | 11 +- .../nginx-lua/src/ngx_http_lua_string.c | 4 +- .../nginx-lua/src/ngx_http_lua_timer.c | 41 +- .../modules/nginx-lua/src/ngx_http_lua_util.c | 11 +- .../modules/nginx-lua/src/ngx_http_lua_util.h | 1 + debian/modules/nginx-lua/t/014-bugs.t | 2 +- debian/modules/nginx-lua/t/016-resp-header.t | 40 +- debian/modules/nginx-lua/t/022-redirect.t | 2 +- .../nginx-lua/t/023-rewrite/redirect.t | 2 +- debian/modules/nginx-lua/t/024-access/auth.t | 2 +- .../modules/nginx-lua/t/024-access/redirect.t | 2 +- debian/modules/nginx-lua/t/036-sub.t | 84 +- debian/modules/nginx-lua/t/037-gsub.t | 104 +- .../modules/nginx-lua/t/041-header-filter.t | 27 +- debian/modules/nginx-lua/t/058-tcp-socket.t | 46 +- .../modules/nginx-lua/t/115-quote-sql-str.t | 4 +- .../nginx-lua/t/128-duplex-tcp-socket.t | 2 +- debian/modules/nginx-lua/t/130-internal-api.t | 50 + debian/modules/nginx-lua/util/reindex | 64 - debian/modules/nginx-lua/util/releng | 8 - debian/modules/ngx-fancyindex/.gitignore | 1 + debian/modules/ngx-fancyindex/.todo | 42 - debian/modules/ngx-fancyindex/CHANGELOG.md | 37 + debian/modules/ngx-fancyindex/HACKING.md | 24 + debian/modules/ngx-fancyindex/HACKING.rst | 33 - debian/modules/ngx-fancyindex/NEWS.rst | 25 - debian/modules/ngx-fancyindex/README.rst | 29 + .../ngx_http_fancyindex_module.c | 97 +- 61 files changed, 3700 insertions(+), 1886 deletions(-) rename debian/modules/nginx-auth-pam/{README => README.md} (61%) rename debian/modules/nginx-cache-purge/t/{proxy.t => proxy1.t} (81%) create mode 100644 debian/modules/nginx-cache-purge/t/proxy1_vars.t create mode 100644 debian/modules/nginx-cache-purge/t/proxy2_vars.t create mode 100644 debian/modules/nginx-echo/.gitignore delete mode 100755 debian/modules/nginx-echo/util/releng create mode 100644 debian/modules/nginx-lua/.gitignore delete mode 100644 debian/modules/nginx-lua/misc/recv-until-pm/Makefile create mode 100644 debian/modules/nginx-lua/t/130-internal-api.t delete mode 100755 debian/modules/nginx-lua/util/reindex delete mode 100755 debian/modules/nginx-lua/util/releng create mode 100644 debian/modules/ngx-fancyindex/.gitignore delete mode 100644 debian/modules/ngx-fancyindex/.todo create mode 100644 debian/modules/ngx-fancyindex/CHANGELOG.md create mode 100644 debian/modules/ngx-fancyindex/HACKING.md delete mode 100644 debian/modules/ngx-fancyindex/HACKING.rst delete mode 100644 debian/modules/ngx-fancyindex/NEWS.rst diff --git a/debian/changelog b/debian/changelog index 5d3b367..6fb9f11 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.6.2-8) UNRELEASED; urgency=medium +nginx (1.6.2-9) UNRELEASED; urgency=medium [ Michael Lustfield ] * debian/conf/nginx.conf: @@ -6,6 +6,12 @@ nginx (1.6.2-8) UNRELEASED; urgency=medium * debian/conf/sites-available/default: + Add comment about disabling gzip in HTTPS. (Closes: #773332) + Add comment about checking ssl_ciphers. (Closes: #765782) + * debian/modules/*: + + Updated nginx-auth-pam 1.3 -> 1.4. (Closes: #777120) + + Updated nginx-echo v0.56 -> v0.57. + + Updated nginx-lua v0.9.13 -> v0.9.15. + + Updated nginx-cache-purge 2.1 -> 2.3. + + Updated ngx-fancyindex v0.3.4 -> v0.3.5. * debian/nginx-common.{dirs,install}, debian/vim/*: + Installing vim syntax highlighting from package. (Closes: #771609) Thanks Emmanuel Bouthenot for building this patch. @@ -26,7 +32,7 @@ nginx (1.6.2-8) UNRELEASED; urgency=medium * debian/nginx-common.manpages: + Replaced man page with upstream maintained version. (Closes: #781345) - -- Michael Lustfield Tue, 07 Apr 2015 08:23:00 -0500 + -- Michael Lustfield Tue, 07 Apr 2015 09:39:52 -0500 nginx (1.6.2-5) unstable; urgency=medium diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index d4bd95c..c95c897 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -5,44 +5,41 @@ README for Modules versions version. headers-more-nginx-module - https://github.com/agentzh/headers-more-nginx-module + Homepage: https://github.com/agentzh/headers-more-nginx-module Version: v0.25 nginx-development-kit - https://github.com/simpl/ngx_devel_kit/ + Homepage: https://github.com/simpl/ngx_devel_kit/ Version: v0.2.19 nginx-auth-pam - http://web.iti.upv.es/~sto/nginx/ - Version: 1.3 + Homepage: https://github.com/stogh/ngx_http_auth_pam_module + Version: 1.4 nginx-echo - https://github.com/agentzh/echo-nginx-module - Version: v0.56 + Homepage: https://github.com/agentzh/echo-nginx-module + Version: v0.57 nginx-lua Homepage: https://github.com/openresty/lua-nginx-module - https://github.com/openresty/lua-nginx-module.git - Version: v0.9.13 + Version: v0.9.15 nginx-upstream-fair Homepage: https://github.com/gnosek/nginx-upstream-fair Version: a18b409 nginx-push - Homepage: http://pushmodule.slact.net/#download - https://github.com/slact/nginx_http_push_module/archive/v0.711.tar.gz + Homepage: https://github.com/slact/nginx_http_push_module Version: 0.73 nginx-upload-progress Homepage: https://github.com/masterzen/nginx-upload-progress-module - https://nodeload.github.com/masterzen/nginx-upload-progress-module/tarball/master - rm -r debian/nginx-upload-progress/test + rm -r debian/nginx-upload-progress/test Version: v0.9.1 nginx-cache-purge - Homepage: http://labs.frickle.com/nginx_ngx_cache_purge/ - Version: 2.1 + Homepage: https://github.com/FRiCKLE/ngx_cache_purge/ + Version: 2.3 nginx-dav-ext-module Homepage: https://github.com/arut/nginx-dav-ext-module @@ -50,7 +47,7 @@ README for Modules versions ngx-fancyindex Homepage: https://github.com/aperezdc/ngx-fancyindex - Version: v0.3.4 + Version: v0.3.5 ngx_http_substitutions_filter_module Homepage: https://github.com/yaoweibin/ngx_http_substitutions_filter_module diff --git a/debian/modules/nginx-auth-pam/ChangeLog b/debian/modules/nginx-auth-pam/ChangeLog index 5c49312..466bd9c 100644 --- a/debian/modules/nginx-auth-pam/ChangeLog +++ b/debian/modules/nginx-auth-pam/ChangeLog @@ -1,3 +1,9 @@ +2015-02-04 sto@iti.es + + * Version 1.4. + * Cleanup PAM responses on error, the module was not doing it, causing + memory leaks (thanks to Michael Koziarski for the report). + 2013-09-17 sto@iti.es * Version 1.3. diff --git a/debian/modules/nginx-auth-pam/LICENSE b/debian/modules/nginx-auth-pam/LICENSE index fd15a67..f5be528 100644 --- a/debian/modules/nginx-auth-pam/LICENSE +++ b/debian/modules/nginx-auth-pam/LICENSE @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 Sergio Talens Oliag + * Copyright (C) 2008-2015 Sergio Talens Oliag * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/debian/modules/nginx-auth-pam/README b/debian/modules/nginx-auth-pam/README.md similarity index 61% rename from debian/modules/nginx-auth-pam/README rename to debian/modules/nginx-auth-pam/README.md index b47f167..c6d58f0 100644 --- a/debian/modules/nginx-auth-pam/README +++ b/debian/modules/nginx-auth-pam/README.md @@ -1,15 +1,12 @@ -Nginx module to use PAM for simple http authentication -====================================================== +# ngx_http_auth_pam_module -:Date: $Date: 2013-09-17 12:00:49 +0200 (dt 17 de set de 2013) $ -:Revision: $Rev: 7626 $ +## Nginx module to use PAM for simple http authentication -Compilation ------------ +### Compilation -When compiling from source build as usual adding the -add-module option:: +When compiling from source build as usual adding the -add-module option: - ./configure --add-module=$PATH_TO_MODULE + ./configure --add-module=$PATH_TO_MODULE If you are using a Debian GNU/Linux distribution install the nginx-full package; the module has been included in the nginx debian package since version 1.1.6-1 @@ -17,8 +14,7 @@ and there are newer packages on the stable distribution (wheezy) and the wheezy version is also available from the oldstable backports repository (squeeze-backports). -Configuration -------------- +### Configuration The module only has two directives: @@ -29,16 +25,15 @@ The module only has two directives: - ``auth_pam_service_name``: this is the PAM service name and by default it is set to ``nginx``. -Examples --------- +### Examples To protect everything under ``/secure`` you will add the following to the -``nginx.conf`` file:: +``nginx.conf`` file: - location /secure { - auth_pam "Secure Zone"; - auth_pam_service_name "nginx"; - } + location /secure { + auth_pam "Secure Zone"; + auth_pam_service_name "nginx"; + } Note that the module runs as the web server user, so the PAM modules used must be able to authenticate the users without being root; that means that if you @@ -47,33 +42,32 @@ web server user to read the ``/etc/shadow`` file if that does not scare you (on Debian like systems you can add the ``www-data`` user to the ``shadow`` group). As an example, to authenticate users against an LDAP server (using the -``pam_ldap.so`` module) you will use an ``/etc/pam.d/nginx`` like the following:: +``pam_ldap.so`` module) you will use an ``/etc/pam.d/nginx`` like the +following: - auth required /lib/security/pam_ldap.so - account required /lib/security/pam_ldap.so + auth required /lib/security/pam_ldap.so + account required /lib/security/pam_ldap.so If you also want to limit the users from LDAP that can authenticate you can use the ``pam_listfile.so`` module; to limit who can access resources under -``/restricted`` add the following to the ``nginx.conf`` file:: +``/restricted`` add the following to the ``nginx.conf`` file: - location /restricted { - auth_pam "Restricted Zone"; - auth_pam_service_name "nginx_restricted"; - } + location /restricted { + auth_pam "Restricted Zone"; + auth_pam_service_name "nginx_restricted"; + } -Use the following ``/etc/pam.d/nginx_restricted`` file:: +Use the following ``/etc/pam.d/nginx_restricted`` file: - auth required /lib/security/pam_listfile.so onerr=fail item=user \ - sense=allow file=/etc/nginx/restricted_users - auth required /lib/security/pam_ldap.so - account required /lib/security/pam_ldap.so + auth required /lib/security/pam_listfile.so onerr=fail item=user \ + sense=allow file=/etc/nginx/restricted_users + auth required /lib/security/pam_ldap.so + account required /lib/security/pam_ldap.so And add the users allowed to authenticate to the ``/etc/nginx/restricted_users`` (remember that the web server user has to be able to read this file). - -PAM Environment ---------------- +### PAM Environment If you want use the ``pam_exec.so`` plugin for request based authentication the module can add to the PAM environment the ``HOST`` and ``REQUEST`` variables if @@ -87,16 +81,13 @@ you set the ``auth_pam_set_pam_env`` flag:: With this configuration if you access an URL like: - http://localhost:8000/pam_exec_protected/page?foo=yes&bar=too + http://localhost:8000/pam_exec_protected/page?foo=yes&bar=too -the PAM environment will include the following variables:: +the PAM environment will include the following variables: - HOST=localhost:8000 - REQUEST=GET /pam_exec_protected/page?foo=yes&bar=too HTTP/1.1 + HOST=localhost:8000 + REQUEST=GET /pam_exec_protected/page?foo=yes&bar=too HTTP/1.1 You may use this information for request based authentication. You need a recent pam release (>= version 1.0.90) to expose environment variables to pam_exec. - -.. ...... -.. SVN Id: $Id: README 7626 2013-09-17 10:00:49Z sto $ diff --git a/debian/modules/nginx-auth-pam/ngx_http_auth_pam_module.c b/debian/modules/nginx-auth-pam/ngx_http_auth_pam_module.c index 08fe1f6..a49d7a6 100644 --- a/debian/modules/nginx-auth-pam/ngx_http_auth_pam_module.c +++ b/debian/modules/nginx-auth-pam/ngx_http_auth_pam_module.c @@ -1,10 +1,10 @@ /* - * Copyright (C) 2008-2013 Sergio Talens-Oliag + * Copyright (C) 2008-2015 Sergio Talens-Oliag * * Based on nginx's 'ngx_http_auth_basic_module.c' by Igor Sysoev and apache's * 'mod_auth_pam.c' by Ingo Luetkebolhe. * - * SVN Id: $Id: ngx_http_auth_pam_module.c 7626 2013-09-17 10:00:49Z sto $ + * File: ngx_http_auth_pam_module.c */ #include @@ -118,6 +118,27 @@ ngx_module_t ngx_http_auth_pam_module = { NGX_MODULE_V1_PADDING }; + +/* + * Function to free PAM_CONV responses if an error is returned. + */ +static void +free_resp(int num_msg, struct pam_response *response) +{ + int i; + if (response == NULL) + return; + for (i = 0; i < num_msg; i++) { + if (response[i].resp) { + /* clear before freeing -- may be a password */ + bzero(response[i].resp, strlen(response[i].resp)); + free(response[i].resp); + response[i].resp = NULL; + } + } + free(response); +} + /* * ngx_auth_pam_talker: supply authentication information to PAM when asked * @@ -161,9 +182,7 @@ ngx_auth_pam_talker(int num_msg, const struct pam_message ** msg, response[i].resp = strdup((const char *)uinfo->password.data); break; default: - if (response) { - free(response); - } + free_resp(i, response); return PAM_CONV_ERR; } } @@ -440,4 +459,4 @@ ngx_http_auth_pam(ngx_conf_t *cf, void *post, void *data) return NGX_CONF_OK; } -/* SVN Id: $Id: ngx_http_auth_pam_module.c 7626 2013-09-17 10:00:49Z sto $ */ +/* File: ngx_http_auth_pam_module.c */ diff --git a/debian/modules/nginx-cache-purge/CHANGES b/debian/modules/nginx-cache-purge/CHANGES index 4dea592..ead3cdf 100644 --- a/debian/modules/nginx-cache-purge/CHANGES +++ b/debian/modules/nginx-cache-purge/CHANGES @@ -1,3 +1,13 @@ +2014-12-23 VERSION 2.3 + * Fix compatibility with nginx-1.7.9+. + +2014-12-02 VERSION 2.2 + * Fix compatibility with nginx-1.7.8+. + +2014-05-19 + * Fix build on Solaris with SunCC (Solaris Studio). + Reported by Jussi Sallinen. + 2013-03-19 VERSION 2.1 * When enabled, cache purge will now catch all requests with PURGE (or specified) method, even if cache isn't configured. diff --git a/debian/modules/nginx-cache-purge/LICENSE b/debian/modules/nginx-cache-purge/LICENSE index a9bd6ee..0047538 100644 --- a/debian/modules/nginx-cache-purge/LICENSE +++ b/debian/modules/nginx-cache-purge/LICENSE @@ -1,5 +1,5 @@ -Copyright (c) 2009-2012, FRiCKLE -Copyright (c) 2009-2012, Piotr Sikora +Copyright (c) 2009-2014, FRiCKLE +Copyright (c) 2009-2014, Piotr Sikora All rights reserved. This project was fully funded by yo.se. diff --git a/debian/modules/nginx-cache-purge/README.md b/debian/modules/nginx-cache-purge/README.md index 89d84e0..3b42e32 100644 --- a/debian/modules/nginx-cache-purge/README.md +++ b/debian/modules/nginx-cache-purge/README.md @@ -11,16 +11,7 @@ Work on the original patch was fully funded by [yo.se](http://yo.se). Status ====== -This module is production-ready and it's compatible with following nginx -releases: - -- 0.7.x (tested with 0.7.60 to 0.7.69), -- 0.8.x (tested with 0.8.0 to 0.8.55), -- 0.9.x (tested with 0.9.0 to 0.9.7), -- 1.0.x (tested with 1.0.0 to 1.0.15), -- 1.1.x (tested with 1.1.0 to 1.1.19), -- 1.2.x (tested with 1.2.0 to 1.2.7), -- 1.3.x (tested with 1.3.0 to 1.3.14). +This module is production-ready. Configuration directives (same location syntax) @@ -147,8 +138,8 @@ You can test it by running: License ======= - Copyright (c) 2009-2012, FRiCKLE - Copyright (c) 2009-2012, Piotr Sikora + Copyright (c) 2009-2014, FRiCKLE + Copyright (c) 2009-2014, Piotr Sikora All rights reserved. This project was fully funded by yo.se. diff --git a/debian/modules/nginx-cache-purge/ngx_cache_purge_module.c b/debian/modules/nginx-cache-purge/ngx_cache_purge_module.c index be51a7d..62d3818 100644 --- a/debian/modules/nginx-cache-purge/ngx_cache_purge_module.c +++ b/debian/modules/nginx-cache-purge/ngx_cache_purge_module.c @@ -1,6 +1,6 @@ /* - * Copyright (c) 2009-2012, FRiCKLE - * Copyright (c) 2009-2012, Piotr Sikora + * Copyright (c) 2009-2014, FRiCKLE + * Copyright (c) 2009-2014, Piotr Sikora * All rights reserved. * * This project was fully funded by yo.se. @@ -33,6 +33,11 @@ #include +#ifndef nginx_version +#error This module cannot be build against an unknown nginx version. +#endif + + #if (NGX_HTTP_CACHE) typedef struct { @@ -90,6 +95,10 @@ ngx_int_t ngx_http_cache_purge_access(ngx_array_t *a, ngx_array_t *a6, struct sockaddr *s); ngx_int_t ngx_http_cache_purge_send_response(ngx_http_request_t *r); +# if (nginx_version >= 1007009) +ngx_int_t ngx_http_cache_purge_cache_get(ngx_http_request_t *r, + ngx_http_upstream_t *u, ngx_http_file_cache_t **cache); +# endif /* nginx_version >= 1007009 */ ngx_int_t ngx_http_cache_purge_init(ngx_http_request_t *r, ngx_http_file_cache_t *cache, ngx_http_complex_value_t *cache_key); void ngx_http_cache_purge_handler(ngx_http_request_t *r); @@ -190,26 +199,52 @@ CRLF "" CRLF # if (NGX_HTTP_FASTCGI) extern ngx_module_t ngx_http_fastcgi_module; +# if (nginx_version >= 1007009) + +typedef struct { + ngx_array_t caches; /* ngx_http_file_cache_t * */ +} ngx_http_fastcgi_main_conf_t; + +# endif /* nginx_version >= 1007009 */ + +# if (nginx_version >= 1007008) + +typedef struct { + ngx_array_t *flushes; + ngx_array_t *lengths; + ngx_array_t *values; + ngx_uint_t number; + ngx_hash_t hash; +} ngx_http_fastcgi_params_t; + +# endif /* nginx_version >= 1007008 */ + typedef struct { ngx_http_upstream_conf_t upstream; ngx_str_t index; +# if (nginx_version >= 1007008) + ngx_http_fastcgi_params_t params; + ngx_http_fastcgi_params_t params_cache; +# else ngx_array_t *flushes; ngx_array_t *params_len; ngx_array_t *params; +# endif /* nginx_version >= 1007008 */ + ngx_array_t *params_source; ngx_array_t *catch_stderr; ngx_array_t *fastcgi_lengths; ngx_array_t *fastcgi_values; -# if defined(nginx_version) && (nginx_version >= 8040) +# if (nginx_version >= 8040) && (nginx_version < 1007008) ngx_hash_t headers_hash; ngx_uint_t header_params; -# endif /* nginx_version >= 8040 */ +# endif /* nginx_version >= 8040 && nginx_version < 1007008 */ -# if defined(nginx_version) && (nginx_version >= 1001004) +# if (nginx_version >= 1001004) ngx_flag_t keep_conn; # endif /* nginx_version >= 1001004 */ @@ -230,6 +265,9 @@ ngx_http_fastcgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, ngx_http_core_loc_conf_t *clcf; ngx_http_fastcgi_loc_conf_t *flcf; ngx_str_t *value; +# if (nginx_version >= 1007009) + ngx_http_complex_value_t cv; +# endif /* nginx_version >= 1007009 */ cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); @@ -248,8 +286,12 @@ ngx_http_fastcgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, flcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_fastcgi_module); +# if (nginx_version >= 1007009) + if (flcf->upstream.cache > 0) +# else if (flcf->upstream.cache != NGX_CONF_UNSET_PTR && flcf->upstream.cache != NULL) +# endif /* nginx_version >= 1007009 */ { return "is incompatible with \"fastcgi_cache\""; } @@ -258,19 +300,61 @@ ngx_http_fastcgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, return "is incompatible with \"fastcgi_pass\""; } - if (flcf->upstream.store > 0 || flcf->upstream.store_lengths) { + if (flcf->upstream.store > 0 +# if (nginx_version < 1007009) + || flcf->upstream.store_lengths +# endif /* nginx_version >= 1007009 */ + ) + { return "is incompatible with \"fastcgi_store\""; } value = cf->args->elts; /* set fastcgi_cache part */ +# if (nginx_version >= 1007009) + + flcf->upstream.cache = 1; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + + flcf->upstream.cache_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (flcf->upstream.cache_value == NULL) { + return NGX_CONF_ERROR; + } + + *flcf->upstream.cache_value = cv; + + } else { + + flcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_fastcgi_module); + if (flcf->upstream.cache_zone == NULL) { + return NGX_CONF_ERROR; + } + } + +# else + flcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, &ngx_http_fastcgi_module); if (flcf->upstream.cache == NULL) { return NGX_CONF_ERROR; } +# endif /* nginx_version >= 1007009 */ + /* set fastcgi_cache_key part */ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); @@ -294,18 +378,43 @@ ngx_http_fastcgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, ngx_int_t ngx_http_fastcgi_cache_purge_handler(ngx_http_request_t *r) { - ngx_http_fastcgi_loc_conf_t *flcf; + ngx_http_file_cache_t *cache; + ngx_http_fastcgi_loc_conf_t *flcf; +# if (nginx_version >= 1007009) + ngx_http_fastcgi_main_conf_t *fmcf; + ngx_int_t rc; +# endif /* nginx_version >= 1007009 */ - flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); - - if (ngx_http_cache_purge_init(r, flcf->upstream.cache->data, - &flcf->cache_key) - != NGX_OK) - { + if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } -# if defined(nginx_version) && (nginx_version >= 8011) + flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); + + r->upstream->conf = &flcf->upstream; + +# if (nginx_version >= 1007009) + + fmcf = ngx_http_get_module_main_conf(r, ngx_http_fastcgi_module); + + r->upstream->caches = &fmcf->caches; + + rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); + if (rc != NGX_OK) { + return rc; + } + +# else + + cache = flcf->upstream.cache->data; + +# endif /* nginx_version >= 1007009 */ + + if (ngx_http_cache_purge_init(r, cache, &flcf->cache_key) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + +# if (nginx_version >= 8011) r->main->count++; # endif @@ -326,18 +435,47 @@ typedef struct { ngx_str_t uri; } ngx_http_proxy_vars_t; +# if (nginx_version >= 1007009) + +typedef struct { + ngx_array_t caches; /* ngx_http_file_cache_t * */ +} ngx_http_proxy_main_conf_t; + +# endif /* nginx_version >= 1007009 */ + +# if (nginx_version >= 1007008) + +typedef struct { + ngx_array_t *flushes; + ngx_array_t *lengths; + ngx_array_t *values; + ngx_hash_t hash; +} ngx_http_proxy_headers_t; + +# endif /* nginx_version >= 1007008 */ + typedef struct { ngx_http_upstream_conf_t upstream; +# if (nginx_version >= 1007008) + ngx_array_t *body_flushes; + ngx_array_t *body_lengths; + ngx_array_t *body_values; + ngx_str_t body_source; + + ngx_http_proxy_headers_t headers; + ngx_http_proxy_headers_t headers_cache; +# else ngx_array_t *flushes; ngx_array_t *body_set_len; ngx_array_t *body_set; ngx_array_t *headers_set_len; ngx_array_t *headers_set; ngx_hash_t headers_set_hash; +# endif /* nginx_version >= 1007008 */ ngx_array_t *headers_source; -# if defined(nginx_version) && (nginx_version < 8040) +# if (nginx_version < 8040) ngx_array_t *headers_names; # endif /* nginx_version < 8040 */ @@ -345,12 +483,14 @@ typedef struct { ngx_array_t *proxy_values; ngx_array_t *redirects; -# if defined(nginx_version) && (nginx_version >= 1001015) +# if (nginx_version >= 1001015) ngx_array_t *cookie_domains; ngx_array_t *cookie_paths; # endif /* nginx_version >= 1001015 */ +# if (nginx_version < 1007008) ngx_str_t body_source; +# endif /* nginx_version < 1007008 */ ngx_str_t method; ngx_str_t location; @@ -362,12 +502,30 @@ typedef struct { ngx_flag_t redirect; -# if defined(nginx_version) && (nginx_version >= 1001004) +# if (nginx_version >= 1001004) ngx_uint_t http_version; # endif /* nginx_version >= 1001004 */ ngx_uint_t headers_hash_max_size; ngx_uint_t headers_hash_bucket_size; + +# if (NGX_HTTP_SSL) +# if (nginx_version >= 1005006) + ngx_uint_t ssl; + ngx_uint_t ssl_protocols; + ngx_str_t ssl_ciphers; +# endif /* nginx_version >= 1005006 */ +# if (nginx_version >= 1007000) + ngx_uint_t ssl_verify_depth; + ngx_str_t ssl_trusted_certificate; + ngx_str_t ssl_crl; +# endif /* nginx_version >= 1007000 */ +# if (nginx_version >= 1007008) + ngx_str_t ssl_certificate; + ngx_str_t ssl_certificate_key; + ngx_array_t *ssl_passwords; +# endif /* nginx_version >= 1007008 */ +# endif } ngx_http_proxy_loc_conf_t; char * @@ -378,6 +536,9 @@ ngx_http_proxy_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_http_core_loc_conf_t *clcf; ngx_http_proxy_loc_conf_t *plcf; ngx_str_t *value; +# if (nginx_version >= 1007009) + ngx_http_complex_value_t cv; +# endif /* nginx_version >= 1007009 */ cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); @@ -396,8 +557,12 @@ ngx_http_proxy_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) plcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_proxy_module); +# if (nginx_version >= 1007009) + if (plcf->upstream.cache > 0) +# else if (plcf->upstream.cache != NGX_CONF_UNSET_PTR && plcf->upstream.cache != NULL) +# endif /* nginx_version >= 1007009 */ { return "is incompatible with \"proxy_cache\""; } @@ -406,19 +571,61 @@ ngx_http_proxy_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return "is incompatible with \"proxy_pass\""; } - if (plcf->upstream.store > 0 || plcf->upstream.store_lengths) { + if (plcf->upstream.store > 0 +# if (nginx_version < 1007009) + || plcf->upstream.store_lengths +# endif /* nginx_version >= 1007009 */ + ) + { return "is incompatible with \"proxy_store\""; } value = cf->args->elts; /* set proxy_cache part */ +# if (nginx_version >= 1007009) + + plcf->upstream.cache = 1; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + + plcf->upstream.cache_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (plcf->upstream.cache_value == NULL) { + return NGX_CONF_ERROR; + } + + *plcf->upstream.cache_value = cv; + + } else { + + plcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_proxy_module); + if (plcf->upstream.cache_zone == NULL) { + return NGX_CONF_ERROR; + } + } + +# else + plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, &ngx_http_proxy_module); if (plcf->upstream.cache == NULL) { return NGX_CONF_ERROR; } +# endif /* nginx_version >= 1007009 */ + /* set proxy_cache_key part */ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); @@ -442,18 +649,43 @@ ngx_http_proxy_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_int_t ngx_http_proxy_cache_purge_handler(ngx_http_request_t *r) { - ngx_http_proxy_loc_conf_t *plcf; + ngx_http_file_cache_t *cache; + ngx_http_proxy_loc_conf_t *plcf; +# if (nginx_version >= 1007009) + ngx_http_proxy_main_conf_t *pmcf; + ngx_int_t rc; +# endif /* nginx_version >= 1007009 */ - plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); - - if (ngx_http_cache_purge_init(r, plcf->upstream.cache->data, - &plcf->cache_key) - != NGX_OK) - { + if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } -# if defined(nginx_version) && (nginx_version >= 8011) + plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); + + r->upstream->conf = &plcf->upstream; + +# if (nginx_version >= 1007009) + + pmcf = ngx_http_get_module_main_conf(r, ngx_http_proxy_module); + + r->upstream->caches = &pmcf->caches; + + rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); + if (rc != NGX_OK) { + return rc; + } + +# else + + cache = plcf->upstream.cache->data; + +# endif /* nginx_version >= 1007009 */ + + if (ngx_http_cache_purge_init(r, cache, &plcf->cache_key) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + +# if (nginx_version >= 8011) r->main->count++; # endif @@ -466,9 +698,34 @@ ngx_http_proxy_cache_purge_handler(ngx_http_request_t *r) # if (NGX_HTTP_SCGI) extern ngx_module_t ngx_http_scgi_module; +# if (nginx_version >= 1007009) + +typedef struct { + ngx_array_t caches; /* ngx_http_file_cache_t * */ +} ngx_http_scgi_main_conf_t; + +# endif /* nginx_version >= 1007009 */ + +# if (nginx_version >= 1007008) + +typedef struct { + ngx_array_t *flushes; + ngx_array_t *lengths; + ngx_array_t *values; + ngx_uint_t number; + ngx_hash_t hash; +} ngx_http_scgi_params_t; + +# endif /* nginx_version >= 1007008 */ + typedef struct { ngx_http_upstream_conf_t upstream; +# if (nginx_version >= 1007008) + ngx_http_scgi_params_t params; + ngx_http_scgi_params_t params_cache; + ngx_array_t *params_source; +# else ngx_array_t *flushes; ngx_array_t *params_len; ngx_array_t *params; @@ -476,6 +733,7 @@ typedef struct { ngx_hash_t headers_hash; ngx_uint_t header_params; +# endif /* nginx_version >= 1007008 */ ngx_array_t *scgi_lengths; ngx_array_t *scgi_values; @@ -491,6 +749,9 @@ ngx_http_scgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_http_core_loc_conf_t *clcf; ngx_http_scgi_loc_conf_t *slcf; ngx_str_t *value; +# if (nginx_version >= 1007009) + ngx_http_complex_value_t cv; +# endif /* nginx_version >= 1007009 */ cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); @@ -509,8 +770,12 @@ ngx_http_scgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) slcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_scgi_module); +# if (nginx_version >= 1007009) + if (slcf->upstream.cache > 0) +# else if (slcf->upstream.cache != NGX_CONF_UNSET_PTR && slcf->upstream.cache != NULL) +# endif /* nginx_version >= 1007009 */ { return "is incompatible with \"scgi_cache\""; } @@ -519,19 +784,61 @@ ngx_http_scgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return "is incompatible with \"scgi_pass\""; } - if (slcf->upstream.store > 0 || slcf->upstream.store_lengths) { + if (slcf->upstream.store > 0 +# if (nginx_version < 1007009) + || slcf->upstream.store_lengths +# endif /* nginx_version >= 1007009 */ + ) + { return "is incompatible with \"scgi_store\""; } value = cf->args->elts; /* set scgi_cache part */ +# if (nginx_version >= 1007009) + + slcf->upstream.cache = 1; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + + slcf->upstream.cache_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (slcf->upstream.cache_value == NULL) { + return NGX_CONF_ERROR; + } + + *slcf->upstream.cache_value = cv; + + } else { + + slcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_scgi_module); + if (slcf->upstream.cache_zone == NULL) { + return NGX_CONF_ERROR; + } + } + +# else + slcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, &ngx_http_scgi_module); if (slcf->upstream.cache == NULL) { return NGX_CONF_ERROR; } +# endif /* nginx_version >= 1007009 */ + /* set scgi_cache_key part */ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); @@ -555,18 +862,43 @@ ngx_http_scgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_int_t ngx_http_scgi_cache_purge_handler(ngx_http_request_t *r) { - ngx_http_scgi_loc_conf_t *slcf; + ngx_http_file_cache_t *cache; + ngx_http_scgi_loc_conf_t *slcf; +# if (nginx_version >= 1007009) + ngx_http_scgi_main_conf_t *smcf; + ngx_int_t rc; +# endif /* nginx_version >= 1007009 */ - slcf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module); - - if (ngx_http_cache_purge_init(r, slcf->upstream.cache->data, - &slcf->cache_key) - != NGX_OK) - { + if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } -# if defined(nginx_version) && (nginx_version >= 8011) + slcf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module); + + r->upstream->conf = &slcf->upstream; + +# if (nginx_version >= 1007009) + + smcf = ngx_http_get_module_main_conf(r, ngx_http_scgi_module); + + r->upstream->caches = &smcf->caches; + + rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); + if (rc != NGX_OK) { + return rc; + } + +# else + + cache = slcf->upstream.cache->data; + +# endif /* nginx_version >= 1007009 */ + + if (ngx_http_cache_purge_init(r, cache, &slcf->cache_key) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + +# if (nginx_version >= 8011) r->main->count++; # endif @@ -579,9 +911,34 @@ ngx_http_scgi_cache_purge_handler(ngx_http_request_t *r) # if (NGX_HTTP_UWSGI) extern ngx_module_t ngx_http_uwsgi_module; +# if (nginx_version >= 1007009) + +typedef struct { + ngx_array_t caches; /* ngx_http_file_cache_t * */ +} ngx_http_uwsgi_main_conf_t; + +# endif /* nginx_version >= 1007009 */ + +# if (nginx_version >= 1007008) + +typedef struct { + ngx_array_t *flushes; + ngx_array_t *lengths; + ngx_array_t *values; + ngx_uint_t number; + ngx_hash_t hash; +} ngx_http_uwsgi_params_t; + +# endif /* nginx_version >= 1007008 */ + typedef struct { ngx_http_upstream_conf_t upstream; +# if (nginx_version >= 1007008) + ngx_http_uwsgi_params_t params; + ngx_http_uwsgi_params_t params_cache; + ngx_array_t *params_source; +# else ngx_array_t *flushes; ngx_array_t *params_len; ngx_array_t *params; @@ -589,6 +946,7 @@ typedef struct { ngx_hash_t headers_hash; ngx_uint_t header_params; +# endif /* nginx_version >= 1007008 */ ngx_array_t *uwsgi_lengths; ngx_array_t *uwsgi_values; @@ -599,6 +957,24 @@ typedef struct { ngx_uint_t modifier1; ngx_uint_t modifier2; + +# if (NGX_HTTP_SSL) +# if (nginx_version >= 1005008) + ngx_uint_t ssl; + ngx_uint_t ssl_protocols; + ngx_str_t ssl_ciphers; +# endif /* nginx_version >= 1005008 */ +# if (nginx_version >= 1007000) + ngx_uint_t ssl_verify_depth; + ngx_str_t ssl_trusted_certificate; + ngx_str_t ssl_crl; +# endif /* nginx_version >= 1007000 */ +# if (nginx_version >= 1007008) + ngx_str_t ssl_certificate; + ngx_str_t ssl_certificate_key; + ngx_array_t *ssl_passwords; +# endif /* nginx_version >= 1007008 */ +# endif } ngx_http_uwsgi_loc_conf_t; char * @@ -609,6 +985,9 @@ ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_http_core_loc_conf_t *clcf; ngx_http_uwsgi_loc_conf_t *ulcf; ngx_str_t *value; +# if (nginx_version >= 1007009) + ngx_http_complex_value_t cv; +# endif /* nginx_version >= 1007009 */ cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); @@ -627,8 +1006,12 @@ ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ulcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_uwsgi_module); +# if (nginx_version >= 1007009) + if (ulcf->upstream.cache > 0) +# else if (ulcf->upstream.cache != NGX_CONF_UNSET_PTR && ulcf->upstream.cache != NULL) +# endif /* nginx_version >= 1007009 */ { return "is incompatible with \"uwsgi_cache\""; } @@ -637,19 +1020,61 @@ ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return "is incompatible with \"uwsgi_pass\""; } - if (ulcf->upstream.store > 0 || ulcf->upstream.store_lengths) { + if (ulcf->upstream.store > 0 +# if (nginx_version < 1007009) + || ulcf->upstream.store_lengths +# endif /* nginx_version >= 1007009 */ + ) + { return "is incompatible with \"uwsgi_store\""; } value = cf->args->elts; /* set uwsgi_cache part */ +# if (nginx_version >= 1007009) + + ulcf->upstream.cache = 1; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + + ulcf->upstream.cache_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (ulcf->upstream.cache_value == NULL) { + return NGX_CONF_ERROR; + } + + *ulcf->upstream.cache_value = cv; + + } else { + + ulcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_uwsgi_module); + if (ulcf->upstream.cache_zone == NULL) { + return NGX_CONF_ERROR; + } + } + +# else + ulcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, &ngx_http_uwsgi_module); if (ulcf->upstream.cache == NULL) { return NGX_CONF_ERROR; } +# endif /* nginx_version >= 1007009 */ + /* set uwsgi_cache_key part */ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); @@ -673,18 +1098,43 @@ ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_int_t ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r) { - ngx_http_uwsgi_loc_conf_t *ulcf; + ngx_http_file_cache_t *cache; + ngx_http_uwsgi_loc_conf_t *ulcf; +# if (nginx_version >= 1007009) + ngx_http_uwsgi_main_conf_t *umcf; + ngx_int_t rc; +# endif /* nginx_version >= 1007009 */ - ulcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module); - - if (ngx_http_cache_purge_init(r, ulcf->upstream.cache->data, - &ulcf->cache_key) - != NGX_OK) - { + if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } -# if defined(nginx_version) && (nginx_version >= 8011) + ulcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module); + + r->upstream->conf = &ulcf->upstream; + +# if (nginx_version >= 1007009) + + umcf = ngx_http_get_module_main_conf(r, ngx_http_uwsgi_module); + + r->upstream->caches = &umcf->caches; + + rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); + if (rc != NGX_OK) { + return rc; + } + +# else + + cache = ulcf->upstream.cache->data; + +# endif /* nginx_version >= 1007009 */ + + if (ngx_http_cache_purge_init(r, cache, &ulcf->cache_key) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + +# if (nginx_version >= 8011) r->main->count++; # endif @@ -854,6 +1304,57 @@ ngx_http_cache_purge_send_response(ngx_http_request_t *r) return ngx_http_output_filter(r, &out); } +# if (nginx_version >= 1007009) + +/* + * Based on: ngx_http_upstream.c/ngx_http_upstream_cache_get + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ +ngx_int_t +ngx_http_cache_purge_cache_get(ngx_http_request_t *r, ngx_http_upstream_t *u, + ngx_http_file_cache_t **cache) +{ + ngx_str_t *name, val; + ngx_uint_t i; + ngx_http_file_cache_t **caches; + + if (u->conf->cache_zone) { + *cache = u->conf->cache_zone->data; + return NGX_OK; + } + + if (ngx_http_complex_value(r, u->conf->cache_value, &val) != NGX_OK) { + return NGX_ERROR; + } + + if (val.len == 0 + || (val.len == 3 && ngx_strncmp(val.data, "off", 3) == 0)) + { + return NGX_DECLINED; + } + + caches = u->caches->elts; + + for (i = 0; i < u->caches->nelts; i++) { + name = &caches[i]->shm_zone->shm.name; + + if (name->len == val.len + && ngx_strncmp(name->data, val.data, val.len) == 0) + { + *cache = caches[i]; + return NGX_OK; + } + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "cache \"%V\" not found", &val); + + return NGX_ERROR; +} + +# endif /* nginx_version >= 1007009 */ + ngx_int_t ngx_http_cache_purge_init(ngx_http_request_t *r, ngx_http_file_cache_t *cache, ngx_http_complex_value_t *cache_key) @@ -941,9 +1442,8 @@ ngx_http_file_cache_purge(ngx_http_request_t *r) switch (ngx_http_file_cache_open(r)) { case NGX_OK: case NGX_HTTP_CACHE_STALE: -# if defined(nginx_version) \ - && ((nginx_version >= 8001) \ - || ((nginx_version < 8000) && (nginx_version >= 7060))) +# if (nginx_version >= 8001) \ + || ((nginx_version < 8000) && (nginx_version >= 7060)) case NGX_HTTP_CACHE_UPDATING: # endif break; @@ -973,7 +1473,7 @@ ngx_http_file_cache_purge(ngx_http_request_t *r) return NGX_DECLINED; } -# if defined(nginx_version) && (nginx_version >= 1000001) +# if (nginx_version >= 1000001) cache->sh->size -= c->node->fs_size; c->node->fs_size = 0; # else @@ -982,9 +1482,8 @@ ngx_http_file_cache_purge(ngx_http_request_t *r) # endif c->node->exists = 0; -# if defined(nginx_version) \ - && ((nginx_version >= 8001) \ - || ((nginx_version < 8000) && (nginx_version >= 7060))) +# if (nginx_version >= 8001) \ + || ((nginx_version < 8000) && (nginx_version >= 7060)) c->node->updating = 0; # endif @@ -1014,11 +1513,11 @@ ngx_http_cache_purge_conf(ngx_conf_t *cf, ngx_http_cache_purge_conf_t *cpcf) value = cf->args->elts; - if (ngx_strcmp(value[1].data, (u_char *) "off") == 0) { + if (ngx_strcmp(value[1].data, "off") == 0) { cpcf->enable = 0; return NGX_CONF_OK; - } else if (ngx_strcmp(value[1].data, (u_char *) "on") == 0) { + } else if (ngx_strcmp(value[1].data, "on") == 0) { ngx_str_set(&cpcf->method, "PURGE"); } else { @@ -1031,14 +1530,14 @@ ngx_http_cache_purge_conf(ngx_conf_t *cf, ngx_http_cache_purge_conf_t *cpcf) } /* sanity check */ - if (ngx_strcmp(value[2].data, (u_char *) "from") != 0) { + if (ngx_strcmp(value[2].data, "from") != 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\", expected" " \"from\" keyword", &value[2]); return NGX_CONF_ERROR; } - if (ngx_strcmp(value[3].data, (u_char *) "all") == 0) { + if (ngx_strcmp(value[3].data, "all") == 0) { cpcf->enable = 1; return NGX_CONF_OK; } @@ -1139,6 +1638,8 @@ ngx_http_cache_purge_create_loc_conf(ngx_conf_t *cf) * conf->*.method = { 0, NULL } * conf->*.access = NULL * conf->*.access6 = NULL + * conf->handler = NULL + * conf->original_handler = NULL */ # if (NGX_HTTP_FASTCGI) @@ -1155,8 +1656,6 @@ ngx_http_cache_purge_create_loc_conf(ngx_conf_t *cf) # endif /* NGX_HTTP_UWSGI */ conf->conf = NGX_CONF_UNSET_PTR; - conf->handler = NGX_CONF_UNSET_PTR; - conf->original_handler = NGX_CONF_UNSET_PTR; return conf; } @@ -1258,9 +1757,14 @@ ngx_http_cache_purge_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) # endif /* NGX_HTTP_UWSGI */ ngx_conf_merge_ptr_value(conf->conf, prev->conf, NULL); - ngx_conf_merge_ptr_value(conf->handler, prev->handler, NULL); - ngx_conf_merge_ptr_value(conf->original_handler, prev->original_handler, - NULL); + + if (conf->handler == NULL) { + conf->handler = prev->handler; + } + + if (conf->original_handler == NULL) { + conf->original_handler = prev->original_handler; + } return NGX_CONF_OK; } diff --git a/debian/modules/nginx-cache-purge/t/proxy.t b/debian/modules/nginx-cache-purge/t/proxy1.t similarity index 81% rename from debian/modules/nginx-cache-purge/t/proxy.t rename to debian/modules/nginx-cache-purge/t/proxy1.t index d2d3b8a..e5c0054 100644 --- a/debian/modules/nginx-cache-purge/t/proxy.t +++ b/debian/modules/nginx-cache-purge/t/proxy1.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket; repeat_each(1); -plan tests => repeat_each() * (blocks() * 3 + 3 * 1); +plan tests => repeat_each() * (blocks() * 4 + 3 * 1); our $http_config = <<'_EOC_'; proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; @@ -48,7 +48,9 @@ GET /proxy/passwd Content-Type: text/plain --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -63,7 +65,9 @@ Content-Type: text/plain X-Cache-Status: HIT --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 @@ -77,7 +81,9 @@ PURGE /purge/proxy/passwd Content-Type: text/html --- response_body_like: Successful purge --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -91,7 +97,9 @@ PURGE /purge/proxy/passwd Content-Type: text/html --- response_body_like: 404 Not Found --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -106,7 +114,9 @@ Content-Type: text/plain X-Cache-Status: MISS --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 @@ -121,4 +131,6 @@ Content-Type: text/plain X-Cache-Status: HIT --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 diff --git a/debian/modules/nginx-cache-purge/t/proxy1_vars.t b/debian/modules/nginx-cache-purge/t/proxy1_vars.t new file mode 100644 index 0000000..af3553d --- /dev/null +++ b/debian/modules/nginx-cache-purge/t/proxy1_vars.t @@ -0,0 +1,138 @@ +# vi:filetype=perl + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(1); + +plan tests => repeat_each() * (blocks() * 4 + 3 * 1); + +our $http_config = <<'_EOC_'; + proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; + proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; +_EOC_ + +our $config = <<'_EOC_'; + set $cache test_cache; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache $cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + } + + location ~ /purge(/.*) { + proxy_cache_purge $cache $1$is_args$args; + } + + location = /etc/passwd { + root /; + } +_EOC_ + +worker_connections(128); +no_shuffle(); +run_tests(); + +no_diff(); + +__DATA__ + +=== TEST 1: prepare +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 2: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 3: purge from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /purge/proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 4: purge from empty cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /purge/proxy/passwd +--- error_code: 404 +--- response_headers +Content-Type: text/html +--- response_body_like: 404 Not Found +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 5: get from source +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: MISS +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 6: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 diff --git a/debian/modules/nginx-cache-purge/t/proxy2.t b/debian/modules/nginx-cache-purge/t/proxy2.t index ad78d62..c07b042 100644 --- a/debian/modules/nginx-cache-purge/t/proxy2.t +++ b/debian/modules/nginx-cache-purge/t/proxy2.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket; repeat_each(1); -plan tests => repeat_each() * (blocks() * 3 + 6 * 1); +plan tests => repeat_each() * (blocks() * 4 + 6 * 1); our $http_config = <<'_EOC_'; proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; @@ -80,7 +80,9 @@ GET /proxy/passwd Content-Type: text/plain --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -95,7 +97,9 @@ Content-Type: text/plain X-Cache-Status: HIT --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 @@ -109,7 +113,9 @@ PURGE /proxy/passwd Content-Type: text/html --- response_body_like: Successful purge --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -123,7 +129,9 @@ PURGE /proxy/passwd Content-Type: text/html --- response_body_like: 404 Not Found --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -138,7 +146,9 @@ Content-Type: text/plain X-Cache-Status: MISS --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 @@ -153,7 +163,9 @@ Content-Type: text/plain X-Cache-Status: HIT --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 @@ -167,7 +179,9 @@ PURGE /proxy/passwd Content-Type: text/html --- response_body_like: Successful purge --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -181,7 +195,9 @@ PURGE /proxy/passwd Content-Type: text/html --- response_body_like: 404 Not Found --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -196,7 +212,9 @@ Content-Type: text/plain X-Cache-Status: MISS --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 @@ -211,7 +229,9 @@ Content-Type: text/plain X-Cache-Status: HIT --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 @@ -225,7 +245,9 @@ PURGE /proxy/passwd Content-Type: text/html --- response_body_like: 403 Forbidden --- timeout: 10 ---- skip_nginx2: 3: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -240,7 +262,9 @@ Content-Type: text/plain X-Cache-Status: HIT --- response_body_like: root --- timeout: 10 ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx2: 5: < 0.8.3 or < 0.7.62 @@ -263,6 +287,8 @@ PURGE /proxy/passwd Content-Type: text/html --- response_body_like: 404 Not Found --- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -286,6 +312,8 @@ PURGE /proxy/passwd Content-Type: text/html --- response_body_like: 403 Forbidden --- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 @@ -316,4 +344,6 @@ PURGE /proxy/passwd Content-Type: text/html --- response_body_like: Successful purge --- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ --- skip_nginx2: 4: < 0.8.3 or < 0.7.62 diff --git a/debian/modules/nginx-cache-purge/t/proxy2_vars.t b/debian/modules/nginx-cache-purge/t/proxy2_vars.t new file mode 100644 index 0000000..d09c08e --- /dev/null +++ b/debian/modules/nginx-cache-purge/t/proxy2_vars.t @@ -0,0 +1,353 @@ +# vi:filetype=perl + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(1); + +plan tests => repeat_each() * (blocks() * 4 + 6 * 1); + +our $http_config = <<'_EOC_'; + proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; + proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; +_EOC_ + +our $config = <<'_EOC_'; + proxy_cache_purge on; + set $cache test_cache; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache $cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + + if ($uri) { } + } + + location = /etc/passwd { + root /; + } +_EOC_ + +our $config_allowed = <<'_EOC_'; + proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; + set $cache test_cache; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache $cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + } + + location = /etc/passwd { + root /; + } +_EOC_ + +our $config_forbidden = <<'_EOC_'; + proxy_cache_purge PURGE from 1.0.0.0/8; + set $cache test_cache; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache $cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + } + + location = /etc/passwd { + root /; + } +_EOC_ + +worker_connections(128); +no_shuffle(); +run_tests(); + +no_diff(); + +__DATA__ + +=== TEST 1: prepare +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 2: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 3: purge from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 4: purge from empty cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +PURGE /proxy/passwd +--- error_code: 404 +--- response_headers +Content-Type: text/html +--- response_body_like: 404 Not Found +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 5: get from source +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: MISS +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 6: get from cache +--- http_config eval: $::http_config +--- config eval: $::config +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 7: purge from cache (PURGE allowed) +--- http_config eval: $::http_config +--- config eval: $::config_allowed +--- request +PURGE /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 8: purge from empty cache (PURGE allowed) +--- http_config eval: $::http_config +--- config eval: $::config_allowed +--- request +PURGE /proxy/passwd +--- error_code: 404 +--- response_headers +Content-Type: text/html +--- response_body_like: 404 Not Found +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 9: get from source (PURGE allowed) +--- http_config eval: $::http_config +--- config eval: $::config_allowed +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: MISS +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 10: get from cache (PURGE allowed) +--- http_config eval: $::http_config +--- config eval: $::config_allowed +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 11: purge from cache (PURGE not allowed) +--- http_config eval: $::http_config +--- config eval: $::config_forbidden +--- request +PURGE /proxy/passwd +--- error_code: 403 +--- response_headers +Content-Type: text/html +--- response_body_like: 403 Forbidden +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 12: get from cache (PURGE not allowed) +--- http_config eval: $::http_config +--- config eval: $::config_forbidden +--- request +GET /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/plain +X-Cache-Status: HIT +--- response_body_like: root +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 5: < 1.7.9 + + + +=== TEST 13: no cache (PURGE allowed) +--- http_config eval: $::http_config +--- config + proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + } + + location = /etc/passwd { + root /; + } +--- request +PURGE /proxy/passwd +--- error_code: 404 +--- response_headers +Content-Type: text/html +--- response_body_like: 404 Not Found +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 14: no cache (PURGE not allowed) +--- http_config eval: $::http_config +--- config + proxy_cache_purge PURGE from 1.0.0.0/8; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + } + + location = /etc/passwd { + root /; + } +--- request +PURGE /proxy/passwd +--- error_code: 403 +--- response_headers +Content-Type: text/html +--- response_body_like: 403 Forbidden +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 + + + +=== TEST 15: multiple cache purge directives +--- http_config eval: $::http_config +--- config + fastcgi_cache_purge on; + proxy_cache_purge on; + set $cache test_cache; + + location /proxy { + proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; + proxy_cache $cache; + proxy_cache_key $uri$is_args$args; + proxy_cache_valid 3m; + add_header X-Cache-Status $upstream_cache_status; + + if ($uri) { } + } + + location = /etc/passwd { + root /; + } +--- request +PURGE /proxy/passwd +--- error_code: 200 +--- response_headers +Content-Type: text/html +--- response_body_like: Successful purge +--- timeout: 10 +--- no_error_log eval +qr/\[(warn|error|crit|alert|emerg)\]/ +--- skip_nginx: 4: < 1.7.9 diff --git a/debian/modules/nginx-echo/.gitignore b/debian/modules/nginx-echo/.gitignore new file mode 100644 index 0000000..a9948e4 --- /dev/null +++ b/debian/modules/nginx-echo/.gitignore @@ -0,0 +1,65 @@ +.libs +*.swp +*.slo +*.la +*.swo +*.lo +*.mobi +genmobi.sh +*~ +*.o +print.txt +.rsync +*.tar.gz +dist +build[789] +build +tags +update-readme +*.tmp +test/Makefile +test/blib +test.sh +t.sh +t/t.sh +test/t/servroot/ +releng +reset +*.t_ +reindex +src/location.h +src/filter.c +src/subrequest.h +src/sleep.h +src/util.c +src/echo.c +src/info.c +src/util.h +src/var.h +src/filter.h +src/sleep.c +src/var.c +src/timer.c +src/module.h +src/echo.h +src/info.h +src/foreach.c +src/location.c +src/timer.h +src/module.c +src/subrequest.c +src/handler.h +src/foreach.h +src/handler.c +nginx +*.html +ctags +t/servroot +all +buildroot/ +go +Changes +build1[0-9] +analyze +Makefile +*.plist diff --git a/debian/modules/nginx-echo/LICENSE b/debian/modules/nginx-echo/LICENSE index 0403cb3..6feffbf 100644 --- a/debian/modules/nginx-echo/LICENSE +++ b/debian/modules/nginx-echo/LICENSE @@ -1,5 +1,4 @@ -Copyright (c) 2009, Taobao Inc., Alibaba Group ( http://www.taobao.com ). -Copyright (c) 2009, agentzh . +Copyright (C) 2009-2014, Yichun "agentzh" Zhang . All rights reserved. Redistribution and use in source and binary forms, with or without @@ -13,10 +12,6 @@ are met: 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 Taobao Inc. 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 diff --git a/debian/modules/nginx-echo/README.markdown b/debian/modules/nginx-echo/README.markdown index d94fae6..c9768c2 100644 --- a/debian/modules/nginx-echo/README.markdown +++ b/debian/modules/nginx-echo/README.markdown @@ -73,7 +73,7 @@ This module is production ready. Version ======= -This document describes ngx_echo [v0.56](https://github.com/agentzh/echo-nginx-module/tags) released on 2 September 2014. +This document describes ngx_echo [v0.57](https://github.com/agentzh/echo-nginx-module/tags) released on 21 November 2014. Synopsis ======== @@ -1575,13 +1575,13 @@ You're recommended to install this module (as well as the Nginx core and many ot Alternatively, you can install this module manually with the Nginx source: Grab the nginx source code from [nginx.org](http://nginx.org/), for example, -the version 1.7.4 (see [nginx compatibility](#compatibility)), and then build the source with this module: +the version 1.7.7 (see [nginx compatibility](#compatibility)), and then build the source with this module: ```bash -$ wget 'http://nginx.org/download/nginx-1.7.4.tar.gz' -$ tar -xzvf nginx-1.7.4.tar.gz -$ cd nginx-1.7.4/ +$ wget 'http://nginx.org/download/nginx-1.7.7.tar.gz' +$ tar -xzvf nginx-1.7.7.tar.gz +$ cd nginx-1.7.7/ # Here we assume you would install you nginx under /opt/nginx/. $ ./configure --prefix=/opt/nginx \ @@ -1602,7 +1602,7 @@ Compatibility The following versions of Nginx should work with this module: -* **1.7.x** (last tested: 1.7.4) +* **1.7.x** (last tested: 1.7.7) * **1.6.x** * **1.5.x** (last tested: 1.5.12) * **1.4.x** (last tested: 1.4.4) @@ -1629,7 +1629,7 @@ If you find that any particular version of Nginx above 0.7.21 does not work with Known Issues ============ -Due to an unknown bug in Nginx (it still exists in Nginx 1.7.4), the [standard SSI module](http://nginx.org/en/docs/http/ngx_http_ssi_module.html) is required to ensure that the contents of the subrequests issued by [echo_locatoin_async](#echo_location_async) and [echo_subrequest_async](#echo_subrequest_async) are correctly merged into the output chains of the main one. Fortunately, the SSI module is enabled by default during Nginx's `configure` process. +Due to an unknown bug in Nginx (it still exists in Nginx 1.7.7), the [standard SSI module](http://nginx.org/en/docs/http/ngx_http_ssi_module.html) is required to ensure that the contents of the subrequests issued by [echo_locatoin_async](#echo_location_async) and [echo_subrequest_async](#echo_subrequest_async) are correctly merged into the output chains of the main one. Fortunately, the SSI module is enabled by default during Nginx's `configure` process. If calling this directive without SSI module enabled, you'll get truncated response without contents of any subrequests and get an alert message in your Nginx's `error.log`, like this: diff --git a/debian/modules/nginx-echo/doc/HttpEchoModule.wiki b/debian/modules/nginx-echo/doc/HttpEchoModule.wiki index 0f03b10..59c7f47 100644 --- a/debian/modules/nginx-echo/doc/HttpEchoModule.wiki +++ b/debian/modules/nginx-echo/doc/HttpEchoModule.wiki @@ -10,7 +10,7 @@ This module is production ready. = Version = -This document describes ngx_echo [https://github.com/agentzh/echo-nginx-module/tags v0.56] released on 2 September 2014. +This document describes ngx_echo [https://github.com/agentzh/echo-nginx-module/tags v0.57] released on 21 November 2014. = Synopsis = @@ -1338,12 +1338,12 @@ You're recommended to install this module (as well as the Nginx core and many ot Alternatively, you can install this module manually with the Nginx source: Grab the nginx source code from [http://nginx.org/ nginx.org], for example, -the version 1.7.4 (see [[#Compatibility|nginx compatibility]]), and then build the source with this module: +the version 1.7.7 (see [[#Compatibility|nginx compatibility]]), and then build the source with this module: - $ wget 'http://nginx.org/download/nginx-1.7.4.tar.gz' - $ tar -xzvf nginx-1.7.4.tar.gz - $ cd nginx-1.7.4/ + $ wget 'http://nginx.org/download/nginx-1.7.7.tar.gz' + $ tar -xzvf nginx-1.7.7.tar.gz + $ cd nginx-1.7.7/ # Here we assume you would install you nginx under /opt/nginx/. $ ./configure --prefix=/opt/nginx \ @@ -1361,7 +1361,7 @@ Also, this module is included and enabled by default in the [http://openresty.or The following versions of Nginx should work with this module: -* '''1.7.x''' (last tested: 1.7.4) +* '''1.7.x''' (last tested: 1.7.7) * '''1.6.x''' * '''1.5.x''' (last tested: 1.5.12) * '''1.4.x''' (last tested: 1.4.4) @@ -1385,7 +1385,7 @@ If you find that any particular version of Nginx above 0.7.21 does not work with = Known Issues = -Due to an unknown bug in Nginx (it still exists in Nginx 1.7.4), the [[HttpSsiModule|standard SSI module]] is required to ensure that the contents of the subrequests issued by [[#echo_location_async|echo_locatoin_async]] and [[#echo_subrequest_async|echo_subrequest_async]] are correctly merged into the output chains of the main one. Fortunately, the SSI module is enabled by default during Nginx's configure process. +Due to an unknown bug in Nginx (it still exists in Nginx 1.7.7), the [[HttpSsiModule|standard SSI module]] is required to ensure that the contents of the subrequests issued by [[#echo_location_async|echo_locatoin_async]] and [[#echo_subrequest_async|echo_subrequest_async]] are correctly merged into the output chains of the main one. Fortunately, the SSI module is enabled by default during Nginx's configure process. If calling this directive without SSI module enabled, you'll get truncated response without contents of any subrequests and get an alert message in your Nginx's error.log, like this: diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_request_info.c b/debian/modules/nginx-echo/src/ngx_http_echo_request_info.c index 9e75ac2..6e00ab1 100644 --- a/debian/modules/nginx-echo/src/ngx_http_echo_request_info.c +++ b/debian/modules/nginx-echo/src/ngx_http_echo_request_info.c @@ -202,24 +202,7 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, <= b->pos) { first = b; - - if (mr->header_in == b) { - size += mr->header_in->pos - mr->request_line.data; - - } else { - /* the subsequent part of the header is in the large header - * buffers */ -#if 1 - p = b->pos; - size += p - mr->request_line.data; - - /* skip truncated header entries (if any) */ - while (b->pos > b->start && b->pos[-1] != LF) { - b->pos--; - size--; - } -#endif - } + size += b->pos - mr->request_line.data; } if (hc->nbusy) { @@ -239,11 +222,6 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, first = b; } - if (b == mr->header_in) { - size += mr->header_in->pos - b->start; - break; - } - size += b->pos - b->start; } } @@ -260,17 +238,22 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, last = v->data; b = c->buffer; - if (first == b) { - if (mr->header_in == b) { - pos = mr->header_in->pos; + found = 0; - } else { - pos = b->pos; - } + if (first == b) { + found = 1; + pos = b->pos; last = ngx_copy(v->data, mr->request_line.data, pos - mr->request_line.data); + if (b != mr->header_in) { + /* skip truncated header entries (if any) */ + while (last > v->data && last[-1] != LF) { + last--; + } + } + i = 0; for (p = v->data; p != last; p++) { if (*p == '\0') { @@ -289,7 +272,6 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, } if (hc->nbusy) { - found = (b == c->buffer); for (i = 0; i < hc->nbusy; i++) { b = hc->busy[i]; @@ -304,12 +286,7 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, p = last; - if (b == mr->header_in) { - pos = mr->header_in->pos; - - } else { - pos = b->pos; - } + pos = b->pos; if (b == first) { dd("request line: %.*s", (int) mr->request_line.len, diff --git a/debian/modules/nginx-echo/t/request-info.t b/debian/modules/nginx-echo/t/request-info.t index 77e01a9..8fd015e 100644 --- a/debian/modules/nginx-echo/t/request-info.t +++ b/debian/modules/nginx-echo/t/request-info.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (3 * blocks() + 6); +plan tests => repeat_each() * (3 * blocks() + 15); run_tests(); @@ -743,3 +743,99 @@ Content-Length: 5 --- no_error_log [error] + + +=== TEST 31: two pipelined requests with large headers +--- config + client_header_buffer_size 10; + large_client_header_buffers 3 5610; + location /t { + echo -n $echo_client_request_headers; + } +--- pipelined_requests eval +["GET /t", "GET /t"] +--- more_headers eval +CORE::join "\n", map { "Header$_: value-$_" } 1..585 + +--- response_body eval +[qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: keep-alive\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..585) . "\r\n\r\n", +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..585) . "\r\n\r\n", +, +] + +--- no_error_log +[error] +--- timeout: 5 + + + +=== TEST 32: a request with large header and a smaller pipelined request following +--- config + client_header_buffer_size 10; + large_client_header_buffers 2 1921; + location /t { + echo -n $echo_client_request_headers; + } +--- pipelined_requests eval +["GET /t", "GET /t"] +--- more_headers eval +[CORE::join("\n", map { "Header$_: value-$_" } 1..170), "Foo: bar\n"] + +--- response_body eval +[qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: keep-alive\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..170) . "\r\n\r\n", +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +Foo: bar\r +\r +}, +] + +--- no_error_log +[error] +--- timeout: 5 + + + +=== TEST 33: a request with large header and a smaller pipelined request following +--- config + client_header_buffer_size 10; + large_client_header_buffers 2 1921; + location /t { + echo -n $echo_client_request_headers; + } +--- pipelined_requests eval +["GET /t", "GET /t" . ("a" x 512)] +--- more_headers eval +[CORE::join("\n", map { "Header$_: value-$_" } 1..170), "Foo: bar\n"] + +--- response_body eval +[qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: keep-alive\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..170) . "\r\n\r\n", +qq{GET /t} . ("a" x 512) . qq{ HTTP/1.1\r +Host: localhost\r +Connection: close\r +Foo: bar\r +\r +}, +] + +--- no_error_log +[error] +--- timeout: 5 + diff --git a/debian/modules/nginx-echo/util/build.sh b/debian/modules/nginx-echo/util/build.sh index d96527c..09a3914 100755 --- a/debian/modules/nginx-echo/util/build.sh +++ b/debian/modules/nginx-echo/util/build.sh @@ -11,7 +11,7 @@ home=~ #--with-cc=gcc46 \ ngx-build $force $version \ - --with-ld-opt="-L$PCRE_LIB -Wl,-rpath,$PCRE_LIB:$LIBDRIZZLE_LIB:$LUAJIT_LIB:/usr/local/lib" \ + --with-ld-opt="-L$PCRE_LIB -Wl,-rpath,$PCRE_LIB:$LIBDRIZZLE_LIB:/usr/local/lib" \ --with-cc-opt="-DDEBUG_MALLOC" \ --with-http_stub_status_module \ --without-mail_pop3_module \ diff --git a/debian/modules/nginx-echo/util/releng b/debian/modules/nginx-echo/util/releng deleted file mode 100755 index b3ad9f2..0000000 --- a/debian/modules/nginx-echo/util/releng +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -./update-readme -ack '.{81}' src/ngx_http_*.[ch] -ack '(?<=\#define)\s*DDEBUG\s*[12]' src -echo ======================================= -ack '(?<=This document describes echo-nginx-module v)\d+\.\d+' README - diff --git a/debian/modules/nginx-lua/.gitignore b/debian/modules/nginx-lua/.gitignore new file mode 100644 index 0000000..61613b2 --- /dev/null +++ b/debian/modules/nginx-lua/.gitignore @@ -0,0 +1,164 @@ +build/ +work/ +tags +cscope.* +*.mobi +genmobi.sh +.libs +*.swp +*.slo +*.la +*.swo +*.lo +*~ +*.o +print.txt +.rsync +*.tar.gz +dist +build[789] +build +tags +update-readme +*.tmp +test/Makefile +test/blib +test.sh +t.sh +t/t.sh +test/t/servroot/ +releng +reset +*.t_ +src/handler.h +src/util.c +src/module.h +src/module.c +src/drizzle.c +src/processor.h +src/handler.c +src/util.h +src/drizzle.h +src/processor.c +src/output.c +src/output.h +libdrizzle +ctags +src/stream.h +nginx +keepalive +reindex +src/keepalive.c +src/keepalive.h +src/checker.h +src/checker.c +src/quoting.h +src/quoting.c +src/module.h +src/module.c +src/util.h +src/util.c +src/processor.h +src/processor.c +src/rds.h +src/utils.h +src/handler.c +src/handler.h +util/bench +*.html +trace.out* +try.sh +src/cache.c +src/cache.h +src/common.h +src/directive.c +src/directive.h +src/consts.[ch] +src/contentby.[ch] +src/pcrefix.[ch] +src/util.c +src/clfactory.c +src/directive.c +src/conf.h +src/setby.h +src/cache.h +src/hook.c +src/util.h +src/hook.h +src/common.h +src/directive.h +src/conf.c +src/setby.c +src/cache.c +src/module.c +src/clfactory.h +src/capturefilter.[ch] +src/contentby.c +pack +b.sh +src/in.[ch] +src/out.[ch] +go +all.sh +src/accessby.[ch] +src/rewriteby.[ch] +src/patch.[ch] +src/ndk.[ch] +src/control.[ch] +src/output.[ch] +src/variable.[ch] +src/string.[ch] +src/misc.[ch] +src/log.[ch] +src/exception.[ch] +src/subrequest.[ch] +src/time.[ch] +src/regex.[ch] +src/ctx.[ch] +src/args.[ch] +src/headers.[ch] +src/script.[ch] +src/filter.[ch] +src/shdict.[ch] +src/body.[ch] +src/uri.[ch] +src/api.[ch] +src/coroutine.[ch] +src/logby.[ch] +src/sleep.[ch] +a.patch +all +build1[0-9] +g +buildroot/ +src/headerfilterby.[ch] +*.patch +analyze +tsock +a.c +test.lua +build12 +ERRORS +src/bodyfilterby.[ch] +src/tcp.[ch] +src/initby.[ch] +src/initworkerby.[ch] +src/socket.[ch] +src/udp.[ch] +src/method.[ch] +tre +src/phase.[ch] +src/probe.h +src/uthread.[ch] +src/timer.[ch] +src/config.[ch] +src/worker.[ch] +*.plist +lua +ttimer +Makefile +tsubreq +tthread +addr2line +hup +theaders diff --git a/debian/modules/nginx-lua/README.markdown b/debian/modules/nginx-lua/README.markdown index d620ec4..70c60dd 100644 --- a/debian/modules/nginx-lua/README.markdown +++ b/debian/modules/nginx-lua/README.markdown @@ -37,13 +37,11 @@ Table of Contents * [Lua Coroutine Yielding/Resuming](#lua-coroutine-yieldingresuming) * [Lua Variable Scope](#lua-variable-scope) * [Locations Configured by Subrequest Directives of Other Modules](#locations-configured-by-subrequest-directives-of-other-modules) - * [Cocockets Not Available Everywhere](#cocockets-not-available-everywhere) + * [Cosockets Not Available Everywhere](#cosockets-not-available-everywhere) * [Special PCRE Sequences](#special-pcre-sequences) * [Mixing with SSI Not Supported](#mixing-with-ssi-not-supported) * [SPDY Mode Not Fully Supported](#spdy-mode-not-fully-supported) * [TODO](#todo) - * [Short Term](#short-term) - * [Longer Term](#longer-term) * [Changes](#changes) * [Test Suite](#test-suite) * [Copyright and License](#copyright-and-license) @@ -59,177 +57,178 @@ Production ready. Version ======= -This document describes ngx_lua [v0.9.13](https://github.com/openresty/lua-nginx-module/tags) released on 21 November 2014. +This document describes ngx_lua [v0.9.15](https://github.com/openresty/lua-nginx-module/tags) released on 18 February 2015. Synopsis ======== ```nginx -# set search paths for pure Lua external libraries (';;' is the default path): -lua_package_path '/foo/bar/?.lua;/blah/?.lua;;'; - -# set search paths for Lua external libraries written in C (can also use ';;'): -lua_package_cpath '/bar/baz/?.so;/blah/blah/?.so;;'; - -server { - location /inline_concat { - # MIME type determined by default_type: - default_type 'text/plain'; - - set $a "hello"; - set $b "world"; - # inline Lua script - set_by_lua $res "return ngx.arg[1]..ngx.arg[2]" $a $b; - echo $res; - } - - location /rel_file_concat { - set $a "foo"; - set $b "bar"; - # script path relative to nginx prefix - # $ngx_prefix/conf/concat.lua contents: - # - # return ngx.arg[1]..ngx.arg[2] - # - set_by_lua_file $res conf/concat.lua $a $b; - echo $res; - } - - location /abs_file_concat { - set $a "fee"; - set $b "baz"; - # absolute script path not modified - set_by_lua_file $res /usr/nginx/conf/concat.lua $a $b; - echo $res; - } - - location /lua_content { - # MIME type determined by default_type: - default_type 'text/plain'; - - content_by_lua "ngx.say('Hello,world!')"; - } - - location /nginx_var { - # MIME type determined by default_type: - default_type 'text/plain'; - - # try access /nginx_var?a=hello,world - content_by_lua "ngx.print(ngx.var['arg_a'], '\\n')"; - } - - location /request_body { - # force reading request body (default off) - lua_need_request_body on; - client_max_body_size 50k; - client_body_buffer_size 50k; - - content_by_lua 'ngx.print(ngx.var.request_body)'; - } - - # transparent non-blocking I/O in Lua via subrequests - location /lua { - # MIME type determined by default_type: - default_type 'text/plain'; - - content_by_lua ' - local res = ngx.location.capture("/some_other_location") - if res.status == 200 then - ngx.print(res.body) - end'; - } - - # GET /recur?num=5 - location /recur { - # MIME type determined by default_type: - default_type 'text/plain'; - - content_by_lua ' - local num = tonumber(ngx.var.arg_num) or 0 + # set search paths for pure Lua external libraries (';;' is the default path): + lua_package_path '/foo/bar/?.lua;/blah/?.lua;;'; - if num > 50 then - ngx.say("num too big") - return - end + # set search paths for Lua external libraries written in C (can also use ';;'): + lua_package_cpath '/bar/baz/?.so;/blah/blah/?.so;;'; - ngx.say("num is: ", num) - - if num > 0 then - res = ngx.location.capture("/recur?num=" .. tostring(num - 1)) - ngx.print("status=", res.status, " ") - ngx.print("body=", res.body) - else - ngx.say("end") - end - '; - } - - location /foo { - rewrite_by_lua ' - res = ngx.location.capture("/memc", - { args = { cmd = "incr", key = ngx.var.uri } } - ) - '; - - proxy_pass http://blah.blah.com; - } - - location /blah { - access_by_lua ' - local res = ngx.location.capture("/auth") - - if res.status == ngx.HTTP_OK then + server { + location /inline_concat { + # MIME type determined by default_type: + default_type 'text/plain'; + + set $a "hello"; + set $b "world"; + # inline Lua script + set_by_lua $res "return ngx.arg[1]..ngx.arg[2]" $a $b; + echo $res; + } + + location /rel_file_concat { + set $a "foo"; + set $b "bar"; + # script path relative to nginx prefix + # $ngx_prefix/conf/concat.lua contents: + # + # return ngx.arg[1]..ngx.arg[2] + # + set_by_lua_file $res conf/concat.lua $a $b; + echo $res; + } + + location /abs_file_concat { + set $a "fee"; + set $b "baz"; + # absolute script path not modified + set_by_lua_file $res /usr/nginx/conf/concat.lua $a $b; + echo $res; + } + + location /lua_content { + # MIME type determined by default_type: + default_type 'text/plain'; + + content_by_lua "ngx.say('Hello,world!')"; + } + + location /nginx_var { + # MIME type determined by default_type: + default_type 'text/plain'; + + # try access /nginx_var?a=hello,world + content_by_lua "ngx.print(ngx.var['arg_a'], '\\n')"; + } + + location /request_body { + # force reading request body (default off) + lua_need_request_body on; + client_max_body_size 50k; + client_body_buffer_size 50k; + + content_by_lua 'ngx.print(ngx.var.request_body)'; + } + + # transparent non-blocking I/O in Lua via subrequests + location /lua { + # MIME type determined by default_type: + default_type 'text/plain'; + + content_by_lua ' + local res = ngx.location.capture("/some_other_location") + if res.status == 200 then + ngx.print(res.body) + end'; + } + + # GET /recur?num=5 + location /recur { + # MIME type determined by default_type: + default_type 'text/plain'; + + content_by_lua ' + local num = tonumber(ngx.var.arg_num) or 0 + + if num > 50 then + ngx.say("num too big") return end - - if res.status == ngx.HTTP_FORBIDDEN then - ngx.exit(res.status) + + ngx.say("num is: ", num) + + if num > 0 then + res = ngx.location.capture("/recur?num=" .. tostring(num - 1)) + ngx.print("status=", res.status, " ") + ngx.print("body=", res.body) + else + ngx.say("end") end - - ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) + '; + } + + location /foo { + rewrite_by_lua ' + res = ngx.location.capture("/memc", + { args = { cmd = "incr", key = ngx.var.uri } } + ) + '; + + proxy_pass http://blah.blah.com; + } + + location /blah { + access_by_lua ' + local res = ngx.location.capture("/auth") + + if res.status == ngx.HTTP_OK then + return + end + + if res.status == ngx.HTTP_FORBIDDEN then + ngx.exit(res.status) + end + + ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) + '; + + # proxy_pass/fastcgi_pass/postgres_pass/... + } + + location /mixed { + rewrite_by_lua_file /path/to/rewrite.lua; + access_by_lua_file /path/to/access.lua; + content_by_lua_file /path/to/content.lua; + } + + # use nginx var in code path + # WARNING: contents in nginx var must be carefully filtered, + # otherwise there'll be great security risk! + location ~ ^/app/([-_a-zA-Z0-9/]+) { + set $path $1; + content_by_lua_file /path/to/lua/app/root/$path.lua; + } + + location / { + lua_need_request_body on; + + client_max_body_size 100k; + client_body_buffer_size 100k; + + access_by_lua ' + -- check the client IP address is in our black list + if ngx.var.remote_addr == "132.5.72.3" then + ngx.exit(ngx.HTTP_FORBIDDEN) + end + + -- check if the request body contains bad words + if ngx.var.request_body and + string.match(ngx.var.request_body, "fsck") + then + return ngx.redirect("/terms_of_use.html") + end + + -- tests passed '; - - # proxy_pass/fastcgi_pass/postgres_pass/... - } - - location /mixed { - rewrite_by_lua_file /path/to/rewrite.lua; - access_by_lua_file /path/to/access.lua; - content_by_lua_file /path/to/content.lua; - } - - # use nginx var in code path - # WARN: contents in nginx var must be carefully filtered, - # otherwise there'll be great security risk! - location ~ ^/app/(.+) { - content_by_lua_file /path/to/lua/app/root/$1.lua; - } - - location / { - lua_need_request_body on; - - client_max_body_size 100k; - client_body_buffer_size 100k; - - access_by_lua ' - -- check the client IP address is in our black list - if ngx.var.remote_addr == "132.5.72.3" then - ngx.exit(ngx.HTTP_FORBIDDEN) - end - - -- check if the request body contains bad words - if ngx.var.request_body and - string.match(ngx.var.request_body, "fsck") - then - return ngx.redirect("/terms_of_use.html") - end - - -- tests passed - '; - - # proxy_pass/fastcgi_pass/etc settings - } -} + + # proxy_pass/fastcgi_pass/etc settings + } + } ``` [Back to TOC](#table-of-contents) @@ -292,7 +291,7 @@ Nginx Compatibility =================== The latest module is compatible with the following versions of Nginx: -* 1.7.x (last tested: 1.7.7) +* 1.7.x (last tested: 1.7.10) * 1.6.x * 1.5.x (last tested: 1.5.12) * 1.4.x (last tested: 1.4.4) @@ -308,7 +307,7 @@ The latest module is compatible with the following versions of Nginx: Installation ============ -The [ngx_openresty bundle](http://openresty.org) can be used to install Nginx, ngx_lua, either one of the standard Lua 5.1 interpreter or LuaJIT 2.0/2.1, as well as a package of powerful companion Nginx modules. The basic installation step is a simple `./configure --with-luajit && make && make install`. +It is highly recommended to use the [ngx_openresty bundle](http://openresty.org) that bundles Nginx, ngx_lua, LuaJIT 2.0/2.1 (or the optional standard Lua 5.1 interpreter), as well as a package of powerful companion Nginx modules. The basic installation step is a simple command: `./configure --with-luajit && make && make install`. Alternatively, ngx_lua can be manually compiled into Nginx: @@ -321,29 +320,30 @@ Build the source with this module: ```bash -wget 'http://nginx.org/download/nginx-1.7.7.tar.gz' -tar -xzvf nginx-1.7.7.tar.gz -cd nginx-1.7.7/ + wget 'http://nginx.org/download/nginx-1.7.10.tar.gz' + tar -xzvf nginx-1.7.10.tar.gz + cd nginx-1.7.10/ -# tell nginx's build system where to find LuaJIT 2.0: -export LUAJIT_LIB=/path/to/luajit/lib -export LUAJIT_INC=/path/to/luajit/include/luajit-2.0 + # tell nginx's build system where to find LuaJIT 2.0: + export LUAJIT_LIB=/path/to/luajit/lib + export LUAJIT_INC=/path/to/luajit/include/luajit-2.0 -# tell nginx's build system where to find LuaJIT 2.1: -export LUAJIT_LIB=/path/to/luajit/lib -export LUAJIT_INC=/path/to/luajit/include/luajit-2.1 - -# or tell where to find Lua if using Lua instead: -#export LUA_LIB=/path/to/lua/lib -#export LUA_INC=/path/to/lua/include - -# Here we assume Nginx is to be installed under /opt/nginx/. -./configure --prefix=/opt/nginx \ - --add-module=/path/to/ngx_devel_kit \ - --add-module=/path/to/lua-nginx-module - -make -j2 -make install + # tell nginx's build system where to find LuaJIT 2.1: + export LUAJIT_LIB=/path/to/luajit/lib + export LUAJIT_INC=/path/to/luajit/include/luajit-2.1 + + # or tell where to find Lua if using Lua instead: + #export LUA_LIB=/path/to/lua/lib + #export LUA_INC=/path/to/lua/include + + # Here we assume Nginx is to be installed under /opt/nginx/. + ./configure --prefix=/opt/nginx \ + --with-ld-opt='-Wl,-rpath,/path/to/luajit-or-lua/lib" \ + --add-module=/path/to/ngx_devel_kit \ + --add-module=/path/to/lua-nginx-module + + make -j2 + make install ``` [Back to TOC](#table-of-contents) @@ -377,7 +377,7 @@ If the standard Lua 5.1 interpreter is required however, run the following comma ```bash -apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev + apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev ``` Everything should be installed correctly, except for one small tweak. @@ -386,7 +386,7 @@ Library name `liblua.so` has been changed in liblua5.1 package, it only comes wi ```bash -ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so + ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so ``` [Back to TOC](#table-of-contents) @@ -436,14 +436,14 @@ Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible wi ```bash -/path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.luac + /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.luac ``` The `-bg` option can be used to include debug information in the LuaJIT bytecode file: ```bash -/path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.luac + /path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.luac ``` Please refer to the official LuaJIT documentation on the `-b` option for more details: @@ -456,14 +456,14 @@ Similarly, if using the standard Lua 5.1 interpreter with ngx_lua, Lua compatibl ```bash -luac -o /path/to/output_file.luac /path/to/input_file.lua + luac -o /path/to/output_file.luac /path/to/input_file.lua ``` Unlike as with LuaJIT, debug information is included in standard Lua 5.1 bytecode files by default. This can be striped out by specifying the `-s` option as shown: ```bash -luac -s -o /path/to/output_file.luac /path/to/input_file.lua + luac -s -o /path/to/output_file.luac /path/to/input_file.lua ``` Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0/2.1 or vice versa, will result in an error message, such as that below, being logged into the Nginx `error.log` file: @@ -483,7 +483,7 @@ If you want to access the system environment variable, say, `foo`, in Lua via th ```nginx -env foo; + env foo; ``` [Back to TOC](#table-of-contents) @@ -515,14 +515,14 @@ Below is a trivial example to demonstrate this. Consider that we have the follow ```lua --- foo.lua -local _M = {} + -- foo.lua + local _M = {} -function _M.go() - print("Hello from foo") -end + function _M.go() + print("Hello from foo") + end -return _M + return _M ``` And then we compile this `.lua` file to `foo.o` file: @@ -535,15 +535,15 @@ Then when building Nginx or OpenResty, pass the `--with-ld-opt="foo.o"` option t ```bash -./configure --with-ld-opt="/path/to/foo.o" ... + ./configure --with-ld-opt="/path/to/foo.o" ... ``` Finally, you can just do the following in any Lua code run by ngx_lua: ```lua -local foo = require "foo" -foo.go() + local foo = require "foo" + foo.go() ``` And this piece of code no longer depends on the external `foo.lua` file any more because it has already been compiled into the `nginx` executable. @@ -552,7 +552,7 @@ If you want to use dot in the Lua module name when calling `require`, as in ```lua -local foo = require "resty.foo" + local foo = require "resty.foo" ``` then you need to rename the `foo.lua` file to `resty_foo.lua` before compiling it down to a `.o` file with the `luajit` command-line utility. @@ -563,22 +563,22 @@ When you have multiple `.lua` files to compile and link, then just specify their ```bash -./configure --with-ld-opt="/path/to/foo.o /path/to/bar.o" ... + ./configure --with-ld-opt="/path/to/foo.o /path/to/bar.o" ... ``` If you have just too many `.o` files, then it might not be feasible to name them all in a single command. In this case, you can build a static library (or archive) for your `.o` files, as in ```bash -ar rcus libmyluafiles.a *.o + ar rcus libmyluafiles.a *.o ``` then you can link the `myluafiles` archive as a whole to your nginx executable: ```bash -./configure \ - --with-ld-opt="-L/path/to/lib -Wl,--whole-archive -lmyluafiles -Wl,--no-whole-archive" + ./configure \ + --with-ld-opt="-L/path/to/lib -Wl,--whole-archive -lmyluafiles -Wl,--no-whole-archive" ``` where `/path/to/lib` is the path of the directory containing the `libmyluafiles.a` file. It should be noted that the linker option `--whole-archive` is required here because otherwise our archive will be skipped because no symbols in our archive are mentioned in the main parts of the nginx executable. @@ -594,32 +594,32 @@ Here is a complete small example: ```lua --- mydata.lua -local _M = {} + -- mydata.lua + local _M = {} -local data = { - dog = 3, - cat = 4, - pig = 5, -} - -function _M.get_age(name) - return data[name] -end + local data = { + dog = 3, + cat = 4, + pig = 5, + } -return _M + function _M.get_age(name) + return data[name] + end + + return _M ``` and then accessing it from `nginx.conf`: ```nginx -location /lua { - content_by_lua ' - local mydata = require "mydata" - ngx.say(mydata.get_age("dog")) - '; -} + location /lua { + content_by_lua ' + local mydata = require "mydata" + ngx.say(mydata.get_age("dog")) + '; + } ``` The `mydata` module in this example will only be loaded and run on the first request to the location `/lua`, @@ -674,14 +674,14 @@ Care must be taken when importing modules and this form should be used: ```lua -local xxx = require('xxx') + local xxx = require('xxx') ``` instead of the old deprecated form: ```lua -require('xxx') + require('xxx') ``` Here is the reason: by design, the global environment has exactly the same lifetime as the Nginx request handler associated with it. Each request handler has its own set of Lua global variables and that is the idea of request isolation. The Lua module is actually loaded by the first Nginx request handler and is cached by the `require()` built-in in the `package.loaded` table for later reference, and the `module()` builtin used by some Lua modules has the side effect of setting a global variable to the loaded module table. But this global variable will be cleared at the end of the request handler, and every subsequent request handler all has its own (clean) global environment. So one will get Lua exception for accessing the `nil` value. @@ -714,29 +714,29 @@ The [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi] ```nginx -location /foo { - content_by_lua ' - res = ngx.location.capture("/bar") - '; -} -location /bar { - echo_location /blah; -} -location /blah { - echo "Success!"; -} + location /foo { + content_by_lua ' + res = ngx.location.capture("/bar") + '; + } + location /bar { + echo_location /blah; + } + location /blah { + echo "Success!"; + } ``` ```nginx -$ curl -i http://example.com/foo + $ curl -i http://example.com/foo ``` will not work as expected. [Back to TOC](#table-of-contents) -Cocockets Not Available Everywhere +Cosockets Not Available Everywhere ---------------------------------- Due the internal limitations in the nginx core, the cosocket API are disabled in the following contexts: [set_by_lua*](#set_by_lua), [log_by_lua*](#log_by_lua), [header_filter_by_lua*](#header_filter_by_lua), and [body_filter_by_lua](#body_filter_by_lua). @@ -753,30 +753,30 @@ PCRE sequences such as `\d`, `\s`, or `\w`, require special attention because in ```nginx -# nginx.conf -? location /test { -? content_by_lua ' -? local regex = "\d+" -- THIS IS WRONG!! -? local m = ngx.re.match("hello, 1234", regex) -? if m then ngx.say(m[0]) else ngx.say("not matched!") end -? '; -? } -# evaluates to "not matched!" + # nginx.conf + ? location /test { + ? content_by_lua ' + ? local regex = "\d+" -- THIS IS WRONG!! + ? local m = ngx.re.match("hello, 1234", regex) + ? if m then ngx.say(m[0]) else ngx.say("not matched!") end + ? '; + ? } + # evaluates to "not matched!" ``` To avoid this, *double* escape the backslash: ```nginx -# nginx.conf -location /test { - content_by_lua ' - local regex = "\\\\d+" - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - '; -} -# evaluates to "1234" + # nginx.conf + location /test { + content_by_lua ' + local regex = "\\\\d+" + local m = ngx.re.match("hello, 1234", regex) + if m then ngx.say(m[0]) else ngx.say("not matched!") end + '; + } + # evaluates to "1234" ``` Here, `\\\\d+` is stripped down to `\\d+` by the Nginx config file parser and this is further stripped down to `\d+` by the Lua language parser before running. @@ -785,15 +785,15 @@ Alternatively, the regex pattern can be presented as a long-bracketed Lua string ```nginx -# nginx.conf -location /test { - content_by_lua ' - local regex = [[\\d+]] - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - '; -} -# evaluates to "1234" + # nginx.conf + location /test { + content_by_lua ' + local regex = [[\\d+]] + local m = ngx.re.match("hello, 1234", regex) + if m then ngx.say(m[0]) else ngx.say("not matched!") end + '; + } + # evaluates to "1234" ``` Here, `[[\\d+]]` is stripped down to `[[\d+]]` by the Nginx config file parser and this is processed correctly. @@ -803,15 +803,15 @@ The `[=[...]=]` form may be used as the default form if desired. ```nginx -# nginx.conf -location /test { - content_by_lua ' - local regex = [=[[0-9]+]=] - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - '; -} -# evaluates to "1234" + # nginx.conf + location /test { + content_by_lua ' + local regex = [=[[0-9]+]=] + local m = ngx.re.match("hello, 1234", regex) + if m then ngx.say(m[0]) else ngx.say("not matched!") end + '; + } + # evaluates to "1234" ``` An alternative approach to escaping PCRE sequences is to ensure that Lua code is placed in external script files and executed using the various `*_by_lua_file` directives. @@ -819,22 +819,22 @@ With this approach, the backslashes are only stripped by the Lua language parser ```lua --- test.lua -local regex = "\\d+" -local m = ngx.re.match("hello, 1234", regex) -if m then ngx.say(m[0]) else ngx.say("not matched!") end --- evaluates to "1234" + -- test.lua + local regex = "\\d+" + local m = ngx.re.match("hello, 1234", regex) + if m then ngx.say(m[0]) else ngx.say("not matched!") end + -- evaluates to "1234" ``` Within external script files, PCRE sequences presented as long-bracketed Lua string literals do not require modification. ```lua --- test.lua -local regex = [[\d+]] -local m = ngx.re.match("hello, 1234", regex) -if m then ngx.say(m[0]) else ngx.say("not matched!") end --- evaluates to "1234" + -- test.lua + local regex = [[\d+]] + local m = ngx.re.match("hello, 1234", regex) + if m then ngx.say(m[0]) else ngx.say("not matched!") end + -- evaluates to "1234" ``` [Back to TOC](#table-of-contents) @@ -856,21 +856,60 @@ Certain Lua APIs provided by ngx_lua do not work in Nginx's SPDY mode yet: [ngx. TODO ==== -[Back to TOC](#table-of-contents) +* add `*_by_lua_block` directives for existing `*_by_lua` directives so that we put literal Lua code directly in curly braces instead of an nginx literal string. For example, +```nginx -Short Term ----------- + content_by_lua_block { + ngx.say("hello, world\r\n") + } +``` + which is equivalent to +```nginx + + content_by_lua ' + ngx.say("hello, world\\r\\n") + '; +``` + but the former is much cleaner and nicer. +* cosocket: implement LuaSocket's unconnected UDP API. +* add support for implementing general TCP servers instead of HTTP servers in Lua. For example, +```lua + + tcp { + server { + listen 11212; + handler_by_lua ' + -- custom Lua code implementing the special TCP server... + '; + } + } +``` +* add support for implementing general UDP servers instead of HTTP servers in Lua. For example, +```lua + + udp { + server { + listen 1953; + handler_by_lua ' + -- custom Lua code implementing the special UDP server... + '; + } + } +``` +* ssl: implement directives `ssl_certificate_by_lua` and `ssl_certificate_by_lua_file` to allow using Lua to dynamically serve SSL certificates and keys for downstream SSL handshake. (already done in CloudFlare's private branch and powering CloudFlare's SSL gateway of its global network. expected to be opensourced in March 2015.) +* shm: implement a "shared queue API" to complement the existing [shared dict](#lua_shared_dict) API. +* cosocket: add support in the context of [init_by_lua*](#init_by_lua). +* cosocket: implement the `bind()` method for stream-typed cosockets. +* cosocket: pool-based backend concurrency level control: implement automatic `connect` queueing when the backend concurrency exceeds its connection pool limit. +* cosocket: review and merge aviramc's [patch](https://github.com/openresty/lua-nginx-module/pull/290) for adding the `bsdrecv` method. +* add new API function `ngx.resp.add_header` to emulate the standard `add_header` config directive. +* [ngx.re](#ngxrematch) API: use `false` instead of `nil` in the resulting match table to indicate non-existent submatch captures, such that we can avoid "holes" in the array table. * review and apply Jader H. Silva's patch for `ngx.re.split()`. * review and apply vadim-pavlov's patch for [ngx.location.capture](#ngxlocationcapture)'s `extra_headers` option * use `ngx_hash_t` to optimize the built-in header look-up process for [ngx.req.set_header](#ngxreqset_header), [ngx.header.HEADER](#ngxheaderheader), and etc. * add configure options for different strategies of handling the cosocket connection exceeding in the pools. * add directives to run Lua codes when nginx stops. * add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) methods, to allow micro performance tuning on the user side. - -[Back to TOC](#table-of-contents) - -Longer Term ------------ * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add `stat` mode similar to [mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html). @@ -948,9 +987,9 @@ Copyright and License This module is licensed under the BSD license. -Copyright (C) 2009-2014, by Xiaozhe Wang (chaoslawful) . +Copyright (C) 2009-2015, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2014, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +Copyright (C) 2009-2015, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. All rights reserved. @@ -1185,36 +1224,36 @@ Usually you can register (true) Lua global variables or pre-load Lua modules at ```nginx -init_by_lua 'cjson = require "cjson"'; + init_by_lua 'cjson = require "cjson"'; -server { - location = /api { - content_by_lua ' - ngx.say(cjson.encode({dog = 5, cat = 6})) - '; - } -} + server { + location = /api { + content_by_lua ' + ngx.say(cjson.encode({dog = 5, cat = 6})) + '; + } + } ``` You can also initialize the [lua_shared_dict](#lua_shared_dict) shm storage at this phase. Here is an example for this: ```nginx -lua_shared_dict dogs 1m; + lua_shared_dict dogs 1m; -init_by_lua ' - local dogs = ngx.shared.dogs; - dogs:set("Tom", 56) -'; + init_by_lua ' + local dogs = ngx.shared.dogs; + dogs:set("Tom", 56) + '; -server { - location = /api { - content_by_lua ' - local dogs = ngx.shared.dogs; - ngx.say(dogs:get("Tom")) - '; - } -} + server { + location = /api { + content_by_lua ' + local dogs = ngx.shared.dogs; + ngx.say(dogs:get("Tom")) + '; + } + } ``` But note that, the [lua_shared_dict](#lua_shared_dict)'s shm storage will not be cleared through a config reload (via the `HUP` signal, for example). So if you do *not* want to re-initialize the shm storage in your `init_by_lua` code in this case, then you just need to set a custom flag in the shm storage and always check the flag in your `init_by_lua` code. @@ -1270,30 +1309,30 @@ This hook is often used to create per-worker reoccurring timers (via the [ngx.ti ```nginx -init_worker_by_lua ' - local delay = 3 -- in seconds - local new_timer = ngx.timer.at - local log = ngx.log - local ERR = ngx.ERR - local check + init_worker_by_lua ' + local delay = 3 -- in seconds + local new_timer = ngx.timer.at + local log = ngx.log + local ERR = ngx.ERR + local check - check = function(premature) - if not premature then - -- do the health check or other routine work - local ok, err = new_timer(delay, check) - if not ok then - log(ERR, "failed to create timer: ", err) - return - end - end - end + check = function(premature) + if not premature then + -- do the health check or other routine work + local ok, err = new_timer(delay, check) + if not ok then + log(ERR, "failed to create timer: ", err) + return + end + end + end - local ok, err = new_timer(delay, check) - if not ok then - log(ERR, "failed to create timer: ", err) - return - end -'; + local ok, err = new_timer(delay, check) + if not ok then + log(ERR, "failed to create timer: ", err) + return + end + '; ``` This directive was first introduced in the `v0.9.5` release. @@ -1344,28 +1383,28 @@ a time. However, a workaround is possible using the [ngx.var.VARIABLE](#ngxvarva ```nginx -location /foo { - set $diff ''; # we have to predefine the $diff variable here - - set_by_lua $sum ' - local a = 32 - local b = 56 - - ngx.var.diff = a - b; -- write to $diff directly - return a + b; -- return the $sum value normally - '; - - echo "sum = $sum, diff = $diff"; -} + location /foo { + set $diff ''; # we have to predefine the $diff variable here + + set_by_lua $sum ' + local a = 32 + local b = 56 + + ngx.var.diff = a - b; -- write to $diff directly + return a + b; -- return the $sum value normally + '; + + echo "sum = $sum, diff = $diff"; + } ``` This directive can be freely mixed with all directives of the [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html), [set-misc-nginx-module](http://github.com/openresty/set-misc-nginx-module), and [array-var-nginx-module](http://github.com/openresty/array-var-nginx-module) modules. All of these directives will run in the same order as they appear in the config file. ```nginx -set $foo 32; -set_by_lua $bar 'tonumber(ngx.var.foo) + 1'; -set $baz "bar: $bar"; # $baz == "bar: 33" + set $foo 32; + set_by_lua $bar 'tonumber(ngx.var.foo) + 1'; + set $baz "bar: $bar"; # $baz == "bar: 33" ``` As from the `v0.5.0rc29` release, Nginx variable interpolation is disabled in the `` argument of this directive and therefore, the dollar sign character (`$`) can be used directly. @@ -1433,6 +1472,20 @@ and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. +Nginx variables are supported in the file path for dynamic dispatch, for example: + +```nginx + + # WARNING: contents in nginx var must be carefully filtered, + # otherwise there'll be great security risk! + location ~ ^/app/([-_a-zA-Z0-9/]+) { + set $path $1; + content_by_lua_file /path/to/lua/app/root/$path.lua; + } +``` + +But be very careful about malicious user inputs and always carefully validate or filter out the user-supplied path components. + [Back to TOC](#directives) rewrite_by_lua @@ -1451,12 +1504,12 @@ Note that this handler always runs *after* the standard [ngx_http_rewrite_module ```nginx -location /foo { - set $a 12; # create and initialize $a - set $b ""; # create and initialize $b - rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; - echo "res = $b"; -} + location /foo { + set $a 12; # create and initialize $a + set $b ""; # create and initialize $b + rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; + echo "res = $b"; + } ``` because `set $a 12` and `set $b ""` run *before* [rewrite_by_lua](#rewrite_by_lua). @@ -1465,17 +1518,17 @@ On the other hand, the following will not work as expected: ```nginx -? location /foo { -? set $a 12; # create and initialize $a -? set $b ''; # create and initialize $b -? rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; -? if ($b = '13') { -? rewrite ^ /bar redirect; -? break; -? } -? -? echo "res = $b"; -? } + ? location /foo { + ? set $a 12; # create and initialize $a + ? set $b ''; # create and initialize $b + ? rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; + ? if ($b = '13') { + ? rewrite ^ /bar redirect; + ? break; + ? } + ? + ? echo "res = $b"; + ? } ``` because `if` runs *before* [rewrite_by_lua](#rewrite_by_lua) even if it is placed after [rewrite_by_lua](#rewrite_by_lua) in the config. @@ -1484,56 +1537,56 @@ The right way of doing this is as follows: ```nginx -location /foo { - set $a 12; # create and initialize $a - set $b ''; # create and initialize $b - rewrite_by_lua ' - ngx.var.b = tonumber(ngx.var.a) + 1 - if tonumber(ngx.var.b) == 13 then - return ngx.redirect("/bar"); - end - '; - - echo "res = $b"; -} + location /foo { + set $a 12; # create and initialize $a + set $b ''; # create and initialize $b + rewrite_by_lua ' + ngx.var.b = tonumber(ngx.var.a) + 1 + if tonumber(ngx.var.b) == 13 then + return ngx.redirect("/bar"); + end + '; + + echo "res = $b"; + } ``` Note that the [ngx_eval](http://www.grid.net.ru/nginx/eval.en.html) module can be approximated by using [rewrite_by_lua](#rewrite_by_lua). For example, ```nginx -location / { - eval $res { - proxy_pass http://foo.com/check-spam; - } - - if ($res = 'spam') { - rewrite ^ /terms-of-use.html redirect; - } - - fastcgi_pass ...; -} + location / { + eval $res { + proxy_pass http://foo.com/check-spam; + } + + if ($res = 'spam') { + rewrite ^ /terms-of-use.html redirect; + } + + fastcgi_pass ...; + } ``` can be implemented in ngx_lua as: ```nginx -location = /check-spam { - internal; - proxy_pass http://foo.com/check-spam; -} - -location / { - rewrite_by_lua ' - local res = ngx.location.capture("/check-spam") - if res.body == "spam" then - return ngx.redirect("/terms-of-use.html") - end - '; - - fastcgi_pass ...; -} + location = /check-spam { + internal; + proxy_pass http://foo.com/check-spam; + } + + location / { + rewrite_by_lua ' + local res = ngx.location.capture("/check-spam") + if res.body == "spam" then + return ngx.redirect("/terms-of-use.html") + end + '; + + fastcgi_pass ...; + } ``` Just as any other rewrite phase handlers, [rewrite_by_lua](#rewrite_by_lua) also runs in subrequests. @@ -1544,13 +1597,13 @@ If the [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_ ```nginx -location /foo { - rewrite ^ /bar; - rewrite_by_lua 'ngx.exit(503)'; -} -location /bar { - ... -} + location /foo { + rewrite ^ /bar; + rewrite_by_lua 'ngx.exit(503)'; + } + location /bar { + ... + } ``` Here the Lua code `ngx.exit(503)` will never run. This will be the case if `rewrite ^ /bar last` is used as this will similarly initiate an internal redirection. If the `break` modifier is used instead, there will be no internal redirection and the `rewrite_by_lua` code will be executed. @@ -1578,6 +1631,8 @@ When the Lua code cache is turned on (by default), the user code is loaded once The `rewrite_by_lua_file` code will always run at the end of the `rewrite` request-processing phase unless [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone) is turned on. +Nginx variables are supported in the file path for dynamic dispatch just as in [content_by_lua_file](#content_by_lua_file). + [Back to TOC](#directives) access_by_lua @@ -1596,19 +1651,19 @@ Note that this handler always runs *after* the standard [ngx_http_access_module] ```nginx -location / { - deny 192.168.1.1; - allow 192.168.1.0/24; - allow 10.1.1.0/16; - deny all; - - access_by_lua ' - local res = ngx.location.capture("/mysql", { ... }) - ... - '; - - # proxy_pass/fastcgi_pass/... -} + location / { + deny 192.168.1.1; + allow 192.168.1.0/24; + allow 10.1.1.0/16; + deny all; + + access_by_lua ' + local res = ngx.location.capture("/mysql", { ... }) + ... + '; + + # proxy_pass/fastcgi_pass/... + } ``` That is, if a client IP address is in the blacklist, it will be denied before the MySQL query for more complex authentication is executed by [access_by_lua](#access_by_lua). @@ -1617,34 +1672,34 @@ Note that the [ngx_auth_request](http://mdounin.ru/hg/ngx_http_auth_request_modu ```nginx -location / { - auth_request /auth; - - # proxy_pass/fastcgi_pass/postgres_pass/... -} + location / { + auth_request /auth; + + # proxy_pass/fastcgi_pass/postgres_pass/... + } ``` can be implemented in ngx_lua as: ```nginx -location / { - access_by_lua ' - local res = ngx.location.capture("/auth") - - if res.status == ngx.HTTP_OK then - return - end - - if res.status == ngx.HTTP_FORBIDDEN then - ngx.exit(res.status) - end - - ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) - '; - - # proxy_pass/fastcgi_pass/postgres_pass/... -} + location / { + access_by_lua ' + local res = ngx.location.capture("/auth") + + if res.status == ngx.HTTP_OK then + return + end + + if res.status == ngx.HTTP_FORBIDDEN then + ngx.exit(res.status) + end + + ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) + '; + + # proxy_pass/fastcgi_pass/postgres_pass/... + } ``` As with other access phase handlers, [access_by_lua](#access_by_lua) will *not* run in subrequests. @@ -1672,6 +1727,8 @@ When the Lua code cache is turned on (by default), the user code is loaded once and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid repeatedly reloading Nginx. +Nginx variables are supported in the file path for dynamic dispatch just as in [content_by_lua_file](#content_by_lua_file). + [Back to TOC](#directives) header_filter_by_lua @@ -1696,10 +1753,10 @@ Here is an example of overriding a response header (or adding one if absent) in ```nginx -location / { - proxy_pass http://mybackend; - header_filter_by_lua 'ngx.header.Foo = "blah"'; -} + location / { + proxy_pass http://mybackend; + header_filter_by_lua 'ngx.header.Foo = "blah"'; + } ``` This directive was first introduced in the `v0.2.1rc20` release. @@ -1734,7 +1791,7 @@ body_filter_by_lua Uses Lua code specified in `` to define an output body filter. -The input data chunk is passed via [ngx.arg](#ngxarg)[1] (as a Lua string value) and the "eof" flag indicating the end of the response body data stream is passed via [ngx.arg](#ngxarg)[2] (as a Lua boolean value). +The input data chunk is passed via [ngx.arg](#ngxarg)\[1\] (as a Lua string value) and the "eof" flag indicating the end of the response body data stream is passed via [ngx.arg](#ngxarg)\[2\] (as a Lua boolean value). Behind the scene, the "eof" flag is just the `last_buf` (for main requests) or `last_in_chain` (for subrequests) flag of the Nginx chain link buffers. (Before the `v0.7.14` release, the "eof" flag does not work at all in subrequests.) @@ -1742,42 +1799,42 @@ The output data stream can be aborted immediately by running the following Lua s ```lua -return ngx.ERROR + return ngx.ERROR ``` This will truncate the response body and usually result in incomplete and also invalid responses. -The Lua code can pass its own modified version of the input data chunk to the downstream Nginx output body filters by overriding [ngx.arg](#ngxarg)[1] with a Lua string or a Lua table of strings. For example, to transform all the lowercase letters in the response body, we can just write: +The Lua code can pass its own modified version of the input data chunk to the downstream Nginx output body filters by overriding [ngx.arg](#ngxarg)\[1\] with a Lua string or a Lua table of strings. For example, to transform all the lowercase letters in the response body, we can just write: ```nginx -location / { - proxy_pass http://mybackend; - body_filter_by_lua 'ngx.arg[1] = string.upper(ngx.arg[1])'; -} + location / { + proxy_pass http://mybackend; + body_filter_by_lua 'ngx.arg[1] = string.upper(ngx.arg[1])'; + } ``` When setting `nil` or an empty Lua string value to `ngx.arg[1]`, no data chunk will be passed to the downstream Nginx output filters at all. -Likewise, new "eof" flag can also be specified by setting a boolean value to [ngx.arg](#ngxarg)[2]. For example, +Likewise, new "eof" flag can also be specified by setting a boolean value to [ngx.arg](#ngxarg)\[2\]. For example, ```nginx -location /t { - echo hello world; - echo hiya globe; + location /t { + echo hello world; + echo hiya globe; - body_filter_by_lua ' - local chunk = ngx.arg[1] - if string.match(chunk, "hello") then - ngx.arg[2] = true -- new eof - return - end + body_filter_by_lua ' + local chunk = ngx.arg[1] + if string.match(chunk, "hello") then + ngx.arg[2] = true -- new eof + return + end - -- just throw away any remaining chunk data - ngx.arg[1] = nil - '; -} + -- just throw away any remaining chunk data + ngx.arg[1] = nil + '; + } ``` Then `GET /t` will just return the output @@ -1792,12 +1849,12 @@ When the Lua code may change the length of the response body, then it is require ```nginx -location /foo { - # fastcgi_pass/proxy_pass/... + location /foo { + # fastcgi_pass/proxy_pass/... - header_filter_by_lua 'ngx.header.content_length = nil'; - body_filter_by_lua 'ngx.arg[1] = string.len(ngx.arg[1]) .. "\\n"'; -} + header_filter_by_lua 'ngx.header.content_length = nil'; + body_filter_by_lua 'ngx.arg[1] = string.len(ngx.arg[1]) .. "\\n"'; + } ``` Note that the following API functions are currently disabled within this context due to the limitations in NGINX output filter's current implementation: @@ -1852,43 +1909,43 @@ Here is an example of gathering average data for [$upstream_response_time](http: ```nginx -lua_shared_dict log_dict 5M; + lua_shared_dict log_dict 5M; -server { - location / { - proxy_pass http://mybackend; + server { + location / { + proxy_pass http://mybackend; - log_by_lua ' - local log_dict = ngx.shared.log_dict - local upstream_time = tonumber(ngx.var.upstream_response_time) + log_by_lua ' + local log_dict = ngx.shared.log_dict + local upstream_time = tonumber(ngx.var.upstream_response_time) - local sum = log_dict:get("upstream_time-sum") or 0 - sum = sum + upstream_time - log_dict:set("upstream_time-sum", sum) + local sum = log_dict:get("upstream_time-sum") or 0 + sum = sum + upstream_time + log_dict:set("upstream_time-sum", sum) - local newval, err = log_dict:incr("upstream_time-nb", 1) - if not newval and err == "not found" then - log_dict:add("upstream_time-nb", 0) - log_dict:incr("upstream_time-nb", 1) - end - '; - } + local newval, err = log_dict:incr("upstream_time-nb", 1) + if not newval and err == "not found" then + log_dict:add("upstream_time-nb", 0) + log_dict:incr("upstream_time-nb", 1) + end + '; + } - location = /status { - content_by_lua ' - local log_dict = ngx.shared.log_dict - local sum = log_dict:get("upstream_time-sum") - local nb = log_dict:get("upstream_time-nb") + location = /status { + content_by_lua ' + local log_dict = ngx.shared.log_dict + local sum = log_dict:get("upstream_time-sum") + local nb = log_dict:get("upstream_time-nb") - if nb and sum then - ngx.say("average upstream response time: ", sum / nb, - " (", nb, " reqs)") - else - ngx.say("no data yet") - end - '; - } -} + if nb and sum then + ngx.say("average upstream response time: ", sum / nb, + " (", nb, " reqs)") + else + ngx.say("no data yet") + end + '; + } + } ``` This directive was first introduced in the `v0.5.0rc31` release. @@ -1959,10 +2016,10 @@ The `` argument accepts size units such as `k` and `m`: ```nginx -http { - lua_shared_dict dogs 10m; - ... -} + http { + lua_shared_dict dogs 10m; + ... + } ``` See [ngx.shared.DICT](#ngxshareddict) for details. @@ -2142,7 +2199,7 @@ This directive was first introduced in the `v0.9.11` release. lua_ssl_protocols ----------------- -**syntax:** *lua_ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2]* +**syntax:** *lua_ssl_protocols \[SSLv2\] \[SSLv3\] \[TLSv1\] [TLSv1.1] [TLSv1.2]* **default:** *lua_ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2* @@ -2260,7 +2317,7 @@ For example, on Linux, you can configure the standard [listen](http://nginx.org/ ```nginx -listen 80 so_keepalive=2s:2s:8; + listen 80 so_keepalive=2s:2s:8; ``` On FreeBSD, you can only tune the system-wide configuration for TCP keepalive, for example: @@ -2455,15 +2512,15 @@ The packages can be introduced into external Lua modules like this: ```lua -local say = ngx.say + local say = ngx.say -local _M = {} + local _M = {} -function _M.foo(a) - say(a) -end + function _M.foo(a) + say(a) + end -return _M + return _M ``` Use of the [package.seeall](http://www.lua.org/manual/5.1/manual.html#pdf-package.seeall) flag is strongly discouraged due to its various bad side-effects. @@ -2472,8 +2529,8 @@ It is also possible to directly require the packages in external Lua modules: ```lua -local ngx = require "ngx" -local ndk = require "ndk" + local ngx = require "ngx" + local ndk = require "ndk" ``` The ability to require these packages was introduced in the `v0.2.1rc19` release. @@ -2484,7 +2541,7 @@ Network I/O operations in user code should only be done through the Nginx Lua AP ngx.arg ------- -**syntax:** *val = ngx.arg[index]* +**syntax:** *val = ngx.arg\[index\]* **context:** *set_by_lua*, body_filter_by_lua** @@ -2492,23 +2549,23 @@ When this is used in the context of the [set_by_lua](#set_by_lua) or [set_by_lua ```lua -value = ngx.arg[n] + value = ngx.arg[n] ``` Here is an example ```nginx -location /foo { - set $a 32; - set $b 56; - - set_by_lua $sum - 'return tonumber(ngx.arg[1]) + tonumber(ngx.arg[2])' - $a $b; - - echo $sum; -} + location /foo { + set $a 32; + set $b 56; + + set_by_lua $sum + 'return tonumber(ngx.arg[1]) + tonumber(ngx.arg[2])' + $a $b; + + echo $sum; + } ``` that writes out `88`, the sum of `32` and `56`. @@ -2529,8 +2586,8 @@ Read and write Nginx variable values. ```nginx -value = ngx.var.some_nginx_variable_name -ngx.var.some_nginx_variable_name = value + value = ngx.var.some_nginx_variable_name + ngx.var.some_nginx_variable_name = value ``` Note that only already defined nginx variables can be written to. @@ -2538,19 +2595,19 @@ For example: ```nginx -location /foo { - set $my_var ''; # this line is required to create $my_var at config time - content_by_lua ' - ngx.var.my_var = 123; - ... - '; -} + location /foo { + set $my_var ''; # this line is required to create $my_var at config time + content_by_lua ' + ngx.var.my_var = 123; + ... + '; + } ``` That is, nginx variables cannot be created on-the-fly. Some special nginx variables like `$args` and `$limit_rate` can be assigned a value, -some are not, like `$arg_PARAMETER`. +many others are not, like `$query_string`, `$arg_PARAMETER`, and `$http_NAME`. Nginx regex group capturing variables `$1`, `$2`, `$3`, and etc, can be read by this interface as well, by writing `ngx.var[1]`, `ngx.var[2]`, `ngx.var[3]`, and etc. @@ -2559,15 +2616,15 @@ Setting `ngx.var.Foo` to a `nil` value will unset the `$Foo` Nginx variable. ```lua -ngx.var.args = nil + ngx.var.args = nil ``` **WARNING** When reading from an Nginx variable, Nginx will allocate memory in the per-request memory pool which is freed only at request termination. So when you need to read from an Nginx variable repeatedly in your Lua code, cache the Nginx variable value to your own Lua variable, for example, ```lua -local val = ngx.var.some_var ---- use the val repeatedly later + local val = ngx.var.some_var + --- use the val repeatedly later ``` to prevent (temporary) memory leaking within the current request's lifetime. Another way of caching the result is to use the [ngx.ctx](#ngxctx) table. @@ -2582,18 +2639,18 @@ Core constants ```lua - ngx.OK (0) - ngx.ERROR (-1) - ngx.AGAIN (-2) - ngx.DONE (-4) - ngx.DECLINED (-5) + ngx.OK (0) + ngx.ERROR (-1) + ngx.AGAIN (-2) + ngx.DONE (-4) + ngx.DECLINED (-5) ``` Note that only three of these constants are utilized by the [Nginx API for Lua](#nginx-api-for-lua) (i.e., [ngx.exit](#ngxexit) accepts `NGX_OK`, `NGX_ERROR`, and `NGX_DECLINED` as input). ```lua - ngx.null + ngx.null ``` The `ngx.null` constant is a `NULL` light userdata usually used to represent nil values in Lua tables etc and is similar to the [lua-cjson](http://www.kyne.com.au/~mark/software/lua-cjson.php) library's `cjson.null` constant. This constant was first introduced in the `v0.5.0rc5` release. @@ -2634,23 +2691,23 @@ HTTP status constants ```nginx - value = ngx.HTTP_OK (200) - value = ngx.HTTP_CREATED (201) - value = ngx.HTTP_SPECIAL_RESPONSE (300) - value = ngx.HTTP_MOVED_PERMANENTLY (301) - value = ngx.HTTP_MOVED_TEMPORARILY (302) - value = ngx.HTTP_SEE_OTHER (303) - value = ngx.HTTP_NOT_MODIFIED (304) - value = ngx.HTTP_BAD_REQUEST (400) - value = ngx.HTTP_UNAUTHORIZED (401) - value = ngx.HTTP_FORBIDDEN (403) - value = ngx.HTTP_NOT_FOUND (404) - value = ngx.HTTP_NOT_ALLOWED (405) - value = ngx.HTTP_GONE (410) - value = ngx.HTTP_INTERNAL_SERVER_ERROR (500) - value = ngx.HTTP_METHOD_NOT_IMPLEMENTED (501) - value = ngx.HTTP_SERVICE_UNAVAILABLE (503) - value = ngx.HTTP_GATEWAY_TIMEOUT (504) (first added in the v0.3.1rc38 release) + value = ngx.HTTP_OK (200) + value = ngx.HTTP_CREATED (201) + value = ngx.HTTP_SPECIAL_RESPONSE (300) + value = ngx.HTTP_MOVED_PERMANENTLY (301) + value = ngx.HTTP_MOVED_TEMPORARILY (302) + value = ngx.HTTP_SEE_OTHER (303) + value = ngx.HTTP_NOT_MODIFIED (304) + value = ngx.HTTP_BAD_REQUEST (400) + value = ngx.HTTP_UNAUTHORIZED (401) + value = ngx.HTTP_FORBIDDEN (403) + value = ngx.HTTP_NOT_FOUND (404) + value = ngx.HTTP_NOT_ALLOWED (405) + value = ngx.HTTP_GONE (410) + value = ngx.HTTP_INTERNAL_SERVER_ERROR (500) + value = ngx.HTTP_METHOD_NOT_IMPLEMENTED (501) + value = ngx.HTTP_SERVICE_UNAVAILABLE (503) + value = ngx.HTTP_GATEWAY_TIMEOUT (504) (first added in the v0.3.1rc38 release) ``` [Back to TOC](#nginx-api-for-lua) @@ -2661,15 +2718,15 @@ Nginx log level constants ```lua - ngx.STDERR - ngx.EMERG - ngx.ALERT - ngx.CRIT - ngx.ERR - ngx.WARN - ngx.NOTICE - ngx.INFO - ngx.DEBUG + ngx.STDERR + ngx.EMERG + ngx.ALERT + ngx.CRIT + ngx.ERR + ngx.WARN + ngx.NOTICE + ngx.INFO + ngx.DEBUG ``` These constants are usually used by the [ngx.log](#ngxlog) method. @@ -2688,7 +2745,7 @@ It is equivalent to ```lua -ngx.log(ngx.NOTICE, ...) + ngx.log(ngx.NOTICE, ...) ``` Lua `nil` arguments are accepted and result in literal `"nil"` strings while Lua booleans result in literal `"true"` or `"false"` strings. And the `ngx.null` constant will yield the `"null"` string output. @@ -2707,26 +2764,26 @@ Consider the following example, ```nginx -location /test { - rewrite_by_lua ' - ngx.say("foo = ", ngx.ctx.foo) - ngx.ctx.foo = 76 - '; - access_by_lua ' - ngx.ctx.foo = ngx.ctx.foo + 3 - '; - content_by_lua ' - ngx.say(ngx.ctx.foo) - '; -} + location /test { + rewrite_by_lua ' + ngx.say("foo = ", ngx.ctx.foo) + ngx.ctx.foo = 76 + '; + access_by_lua ' + ngx.ctx.foo = ngx.ctx.foo + 3 + '; + content_by_lua ' + ngx.say(ngx.ctx.foo) + '; + } ``` Then `GET /test` will yield the output ```bash -foo = nil -79 + foo = nil + 79 ``` That is, the `ngx.ctx.foo` entry persists across the rewrite, access, and content phases of a request. @@ -2735,33 +2792,33 @@ Every request, including subrequests, has its own copy of the table. For example ```nginx -location /sub { - content_by_lua ' - ngx.say("sub pre: ", ngx.ctx.blah) - ngx.ctx.blah = 32 - ngx.say("sub post: ", ngx.ctx.blah) - '; -} - -location /main { - content_by_lua ' - ngx.ctx.blah = 73 - ngx.say("main pre: ", ngx.ctx.blah) - local res = ngx.location.capture("/sub") - ngx.print(res.body) - ngx.say("main post: ", ngx.ctx.blah) - '; -} + location /sub { + content_by_lua ' + ngx.say("sub pre: ", ngx.ctx.blah) + ngx.ctx.blah = 32 + ngx.say("sub post: ", ngx.ctx.blah) + '; + } + + location /main { + content_by_lua ' + ngx.ctx.blah = 73 + ngx.say("main pre: ", ngx.ctx.blah) + local res = ngx.location.capture("/sub") + ngx.print(res.body) + ngx.say("main post: ", ngx.ctx.blah) + '; + } ``` Then `GET /main` will give the output ```bash -main pre: 73 -sub pre: nil -sub post: 32 -main post: 73 + main pre: 73 + sub pre: nil + sub post: 32 + main post: 73 ``` Here, modification of the `ngx.ctx.blah` entry in the subrequest does not affect the one in the parent request. This is because they have two separate versions of `ngx.ctx.blah`. @@ -2770,25 +2827,25 @@ Internal redirection will destroy the original request `ngx.ctx` data (if any) a ```nginx -location /new { - content_by_lua ' - ngx.say(ngx.ctx.foo) - '; -} - -location /orig { - content_by_lua ' - ngx.ctx.foo = "hello" - ngx.exec("/new") - '; -} + location /new { + content_by_lua ' + ngx.say(ngx.ctx.foo) + '; + } + + location /orig { + content_by_lua ' + ngx.ctx.foo = "hello" + ngx.exec("/new") + '; + } ``` Then `GET /orig` will give ```bash -nil + nil ``` rather than the original `"hello"` value. @@ -2799,7 +2856,7 @@ Overriding `ngx.ctx` with a new Lua table is also supported, for example, ```lua -ngx.ctx = { foo = 32, bar = 54 } + ngx.ctx = { foo = 32, bar = 54 } ``` When being used in the context of [init_worker_by_lua*](#init_worker_by_lua), this table just has the same lifetime of the current Lua handler. @@ -2829,7 +2886,7 @@ Here is a basic example: ```lua -res = ngx.location.capture(uri) + res = ngx.location.capture(uri) ``` Returns a Lua table with three slots (`res.status`, `res.header`, `res.body`, and `res.truncated`). @@ -2844,9 +2901,9 @@ lines: ```bash -Set-Cookie: a=3 -Set-Cookie: foo=bar -Set-Cookie: baz=blah + Set-Cookie: a=3 + Set-Cookie: foo=bar + Set-Cookie: baz=blah ``` Then `res.header["Set-Cookie"]` will be evaluated to the table value @@ -2858,7 +2915,7 @@ URI query strings can be concatenated to URI itself, for instance, ```lua -res = ngx.location.capture('/foo/bar?a=3&b=4') + res = ngx.location.capture('/foo/bar?a=3&b=4') ``` Named locations like `@foo` are not allowed due to a limitation in @@ -2881,7 +2938,7 @@ argument, which supports the options: * `copy_all_vars` specify whether to copy over all the Nginx variable values of the current request to the subrequest in question. modifications of the nginx variables in the subrequest will not affect the current (parent) request. This option was first introduced in the `v0.3.1rc31` release. * `share_all_vars` - specify whether to share all the Nginx variables of the subrequest with the current (parent) request. modifications of the Nginx variables in the subrequest will affect the current (parent) request. + specify whether to share all the Nginx variables of the subrequest with the current (parent) request. modifications of the Nginx variables in the subrequest will affect the current (parent) request. Enabling this option may lead to hard-to-debug issues due to bad side-effects and is considered bad and harmful. Only enable this option when you completely know what you are doing. * `always_forward_body` when set to true, the current (parent) request's request body will always be forwarded to the subrequest being created if the `body` option is not specified. The request body read by either [ngx.req.read_body()](#ngxreqread_body) or [lua_need_request_body on](#lua_need_request_body) will be directly forwarded to the subrequest without copying the whole request body data when creating the subrequest (no matter the request body data is buffered in memory buffers or temporary files). By default, this option is `false` and when the `body` option is not specified, the request body of the current (parent) request is only forwarded when the subrequest takes the `PUT` or `POST` request method. @@ -2889,10 +2946,10 @@ Issuing a POST subrequest, for example, can be done as follows ```lua -res = ngx.location.capture( - '/foo/bar', - { method = ngx.HTTP_POST, body = 'hello, world' } -) + res = ngx.location.capture( + '/foo/bar', + { method = ngx.HTTP_POST, body = 'hello, world' } + ) ``` See HTTP method constants methods other than POST. @@ -2902,16 +2959,16 @@ The `args` option can specify extra URI arguments, for instance, ```lua -ngx.location.capture('/foo?a=1', - { args = { b = 3, c = ':' } } -) + ngx.location.capture('/foo?a=1', + { args = { b = 3, c = ':' } } + ) ``` is equivalent to ```lua -ngx.location.capture('/foo?a=1&b=3&c=%3a') + ngx.location.capture('/foo?a=1&b=3&c=%3a') ``` that is, this method will escape argument keys and values according to URI rules and @@ -2921,9 +2978,9 @@ The `args` option can also take plain query strings: ```lua -ngx.location.capture('/foo?a=1', - { args = 'b=3&c=%3a' } } -) + ngx.location.capture('/foo?a=1', + { args = 'b=3&c=%3a' } } + ) ``` This is functionally identical to the previous examples. @@ -2937,21 +2994,21 @@ This option is set to `false` by default ```nginx -location /other { - set $dog "$dog world"; - echo "$uri dog: $dog"; -} + location /other { + set $dog "$dog world"; + echo "$uri dog: $dog"; + } -location /lua { - set $dog 'hello'; - content_by_lua ' - res = ngx.location.capture("/other", - { share_all_vars = true }); + location /lua { + set $dog 'hello'; + content_by_lua ' + res = ngx.location.capture("/other", + { share_all_vars = true }); - ngx.print(res.body) - ngx.say(ngx.var.uri, ": ", ngx.var.dog) - '; -} + ngx.print(res.body) + ngx.say(ngx.var.uri, ": ", ngx.var.dog) + '; + } ``` Accessing location `/lua` gives @@ -2965,21 +3022,21 @@ The `copy_all_vars` option provides a copy of the parent request's Nginx variabl ```nginx -location /other { - set $dog "$dog world"; - echo "$uri dog: $dog"; -} + location /other { + set $dog "$dog world"; + echo "$uri dog: $dog"; + } -location /lua { - set $dog 'hello'; - content_by_lua ' - res = ngx.location.capture("/other", - { copy_all_vars = true }); + location /lua { + set $dog 'hello'; + content_by_lua ' + res = ngx.location.capture("/other", + { copy_all_vars = true }); - ngx.print(res.body) - ngx.say(ngx.var.uri, ": ", ngx.var.dog) - '; -} + ngx.print(res.body) + ngx.say(ngx.var.uri, ": ", ngx.var.dog) + '; + } ``` Request `GET /lua` will give the output @@ -3000,23 +3057,23 @@ unescaping them in the Nginx config file. ```nginx -location /other { - content_by_lua ' - ngx.say("dog = ", ngx.var.dog) - ngx.say("cat = ", ngx.var.cat) - '; -} + location /other { + content_by_lua ' + ngx.say("dog = ", ngx.var.dog) + ngx.say("cat = ", ngx.var.cat) + '; + } -location /lua { - set $dog ''; - set $cat ''; - content_by_lua ' - res = ngx.location.capture("/other", - { vars = { dog = "hello", cat = 32 }}); + location /lua { + set $dog ''; + set $cat ''; + content_by_lua ' + res = ngx.location.capture("/other", + { vars = { dog = "hello", cat = 32 }}); - ngx.print(res.body) - '; -} + ngx.print(res.body) + '; + } ``` Accessing `/lua` will yield the output @@ -3030,20 +3087,20 @@ The `ctx` option can be used to specify a custom Lua table to serve as the [ngx. ```nginx -location /sub { - content_by_lua ' - ngx.ctx.foo = "bar"; - '; -} -location /lua { - content_by_lua ' - local ctx = {} - res = ngx.location.capture("/sub", { ctx = ctx }) + location /sub { + content_by_lua ' + ngx.ctx.foo = "bar"; + '; + } + location /lua { + content_by_lua ' + local ctx = {} + res = ngx.location.capture("/sub", { ctx = ctx }) - ngx.say(ctx.foo); - ngx.say(ngx.ctx.foo); - '; -} + ngx.say(ctx.foo); + ngx.say(ngx.ctx.foo); + '; + } ``` Then request `GET /lua` gives @@ -3057,17 +3114,17 @@ It is also possible to use this `ctx` option to share the same [ngx.ctx](#ngxctx ```nginx -location /sub { - content_by_lua ' - ngx.ctx.foo = "bar"; - '; -} -location /lua { - content_by_lua ' - res = ngx.location.capture("/sub", { ctx = ngx.ctx }) - ngx.say(ngx.ctx.foo); - '; -} + location /sub { + content_by_lua ' + ngx.ctx.foo = "bar"; + '; + } + location /lua { + content_by_lua ' + res = ngx.location.capture("/sub", { ctx = ngx.ctx }) + ngx.say(ngx.ctx.foo); + '; + } ``` Request `GET /lua` yields the output @@ -3109,19 +3166,19 @@ This function issues several parallel subrequests specified by the input table a ```lua -res1, res2, res3 = ngx.location.capture_multi{ - { "/foo", { args = "a=3&b=4" } }, - { "/bar" }, - { "/baz", { method = ngx.HTTP_POST, body = "hello" } }, -} - -if res1.status == ngx.HTTP_OK then - ... -end - -if res2.body == "BLAH" then - ... -end + res1, res2, res3 = ngx.location.capture_multi{ + { "/foo", { args = "a=3&b=4" } }, + { "/bar" }, + { "/baz", { method = ngx.HTTP_POST, body = "hello" } }, + } + + if res1.status == ngx.HTTP_OK then + ... + end + + if res2.body == "BLAH" then + ... + end ``` This function will not return until all the subrequests terminate. @@ -3131,20 +3188,20 @@ Lua tables can be used for both requests and responses when the number of subreq ```lua --- construct the requests table -local reqs = {} -table.insert(reqs, { "/mysql" }) -table.insert(reqs, { "/postgres" }) -table.insert(reqs, { "/redis" }) -table.insert(reqs, { "/memcached" }) - --- issue all the requests at once and wait until they all return -local resps = { ngx.location.capture_multi(reqs) } - --- loop over the responses table -for i, resp in ipairs(resps) do - -- process the response table "resp" -end + -- construct the requests table + local reqs = {} + table.insert(reqs, { "/mysql" }) + table.insert(reqs, { "/postgres" }) + table.insert(reqs, { "/redis" }) + table.insert(reqs, { "/memcached" }) + + -- issue all the requests at once and wait until they all return + local resps = { ngx.location.capture_multi(reqs) } + + -- loop over the responses table + for i, resp in ipairs(resps) do + -- process the response table "resp" + end ``` The [ngx.location.capture](#ngxlocationcapture) function is just a special form @@ -3152,10 +3209,10 @@ of this function. Logically speaking, the [ngx.location.capture](#ngxlocationcap ```lua -ngx.location.capture = - function (uri, args) - return ngx.location.capture_multi({ {uri, args} }) - end + ngx.location.capture = + function (uri, args) + return ngx.location.capture_multi({ {uri, args} }) + end ``` Please also refer to restrictions on capturing locations configured by [subrequest directives of other modules](#locations-configured-by-subrequest-directives-of-other-modules). @@ -3171,8 +3228,8 @@ before sending out the response headers. ```lua -ngx.status = ngx.HTTP_CREATED -status = ngx.status + ngx.status = ngx.HTTP_CREATED + status = ngx.status ``` Setting `ngx.status` after the response header is sent out has no effect but leaving an error message in your nginx's error log file: @@ -3199,25 +3256,25 @@ The header names are matched case-insensitively. ```lua --- equivalent to ngx.header["Content-Type"] = 'text/plain' -ngx.header.content_type = 'text/plain'; - -ngx.header["X-My-Header"] = 'blah blah'; + -- equivalent to ngx.header["Content-Type"] = 'text/plain' + ngx.header.content_type = 'text/plain'; + + ngx.header["X-My-Header"] = 'blah blah'; ``` Multi-value headers can be set this way: ```lua -ngx.header['Set-Cookie'] = {'a=32; path=/', 'b=4; path=/'} + ngx.header['Set-Cookie'] = {'a=32; path=/', 'b=4; path=/'} ``` will yield ```bash -Set-Cookie: a=32; path=/ -Set-Cookie: b=4; path=/ + Set-Cookie: a=32; path=/ + Set-Cookie: b=4; path=/ ``` in the response headers. @@ -3226,28 +3283,28 @@ Only Lua tables are accepted (Only the last element in the table will take effec ```lua -ngx.header.content_type = {'a', 'b'} + ngx.header.content_type = {'a', 'b'} ``` is equivalent to ```lua -ngx.header.content_type = 'b' + ngx.header.content_type = 'b' ``` Setting a slot to `nil` effectively removes it from the response headers: ```lua -ngx.header["X-My-Header"] = nil; + ngx.header["X-My-Header"] = nil; ``` The same applies to assigning an empty table: ```lua -ngx.header["X-My-Header"] = {}; + ngx.header["X-My-Header"] = {}; ``` Setting `ngx.header.HEADER` after sending out response headers (either explicitly with [ngx.send_headers](#ngxsend_headers) or implicitly with [ngx.print](#ngxprint) and similar) will throw out a Lua exception. @@ -3260,19 +3317,19 @@ This is particularly useful in the context of [header_filter_by_lua](#header_fil ```nginx -location /test { - set $footer ''; + location /test { + set $footer ''; - proxy_pass http://some-backend; + proxy_pass http://some-backend; - header_filter_by_lua ' - if ngx.header["X-My-Header"] == "blah" then - ngx.var.footer = "some value" - end - '; + header_filter_by_lua ' + if ngx.header["X-My-Header"] == "blah" then + ngx.var.footer = "some value" + end + '; - echo_after_body $footer; -} + echo_after_body $footer; + } ``` For multi-value headers, all of the values of header will be collected in order and returned as a Lua table. For example, response headers @@ -3286,7 +3343,7 @@ will result in ```lua -{"bar", "baz"} + {"bar", "baz"} ``` to be returned when reading `ngx.header.Foo`. @@ -3307,10 +3364,10 @@ Returns a Lua table holding all the current response headers for the current req ```lua -local h = ngx.resp.get_headers() -for k, v in pairs(h) do - ... -end + local h = ngx.resp.get_headers() + for k, v in pairs(h) do + ... + end ``` This function has the same signature as [ngx.req.get_headers](#ngxreqget_headers) except getting response headers instead of request headers. @@ -3331,7 +3388,7 @@ The following example emulates the `$request_time` variable value (provided by [ ```lua -local request_time = ngx.now() - ngx.req.start_time() + local request_time = ngx.now() - ngx.req.start_time() ``` This function was first introduced in the `v0.7.7` release. @@ -3366,7 +3423,7 @@ By default, the request line and trailing `CR LF` terminator will also be includ ```lua -ngx.print(ngx.req.raw_header()) + ngx.print(ngx.req.raw_header()) ``` gives something like this: @@ -3384,7 +3441,7 @@ You can specify the optional ```lua -ngx.print(ngx.req.raw_header(true)) + ngx.print(ngx.req.raw_header(true)) ``` outputs something like this: @@ -3448,35 +3505,35 @@ For example, the following nginx config snippet ```nginx -rewrite ^ /foo last; + rewrite ^ /foo last; ``` can be coded in Lua like this: ```lua -ngx.req.set_uri("/foo", true) + ngx.req.set_uri("/foo", true) ``` Similarly, Nginx config ```nginx -rewrite ^ /foo break; + rewrite ^ /foo break; ``` can be coded in Lua as ```lua -ngx.req.set_uri("/foo", false) + ngx.req.set_uri("/foo", false) ``` or equivalently, ```lua -ngx.req.set_uri("/foo") + ngx.req.set_uri("/foo") ``` The `jump` can only be set to `true` in [rewrite_by_lua](#rewrite_by_lua) and [rewrite_by_lua_file](#rewrite_by_lua_file). Use of jump in other contexts is prohibited and will throw out a Lua exception. @@ -3485,46 +3542,46 @@ A more sophisticated example involving regex substitutions is as follows ```nginx -location /test { - rewrite_by_lua ' - local uri = ngx.re.sub(ngx.var.uri, "^/test/(.*)", "$1", "o") - ngx.req.set_uri(uri) - '; - proxy_pass http://my_backend; -} + location /test { + rewrite_by_lua ' + local uri = ngx.re.sub(ngx.var.uri, "^/test/(.*)", "$1", "o") + ngx.req.set_uri(uri) + '; + proxy_pass http://my_backend; + } ``` which is functionally equivalent to ```nginx -location /test { - rewrite ^/test/(.*) /$1 break; - proxy_pass http://my_backend; -} + location /test { + rewrite ^/test/(.*) /$1 break; + proxy_pass http://my_backend; + } ``` Note that it is not possible to use this interface to rewrite URI arguments and that [ngx.req.set_uri_args](#ngxreqset_uri_args) should be used for this instead. For instance, Nginx config ```nginx -rewrite ^ /foo?a=3? last; + rewrite ^ /foo?a=3? last; ``` can be coded as ```nginx -ngx.req.set_uri_args("a=3") -ngx.req.set_uri("/foo", true) + ngx.req.set_uri_args("a=3") + ngx.req.set_uri("/foo", true) ``` or ```nginx -ngx.req.set_uri_args({a = 3}) -ngx.req.set_uri("/foo", true) + ngx.req.set_uri_args({a = 3}) + ngx.req.set_uri("/foo", true) ``` This interface was first introduced in the `v0.3.1rc14` release. @@ -3541,14 +3598,14 @@ Rewrite the current request's URI query arguments by the `args` argument. The `a ```lua -ngx.req.set_uri_args("a=3&b=hello%20world") + ngx.req.set_uri_args("a=3&b=hello%20world") ``` or a Lua table holding the query arguments' key-value pairs, as in ```lua -ngx.req.set_uri_args({ a = 3, b = "hello world" }) + ngx.req.set_uri_args({ a = 3, b = "hello world" }) ``` where in the latter case, this method will escape argument keys and values according to the URI escaping rule. @@ -3557,7 +3614,7 @@ Multi-value arguments are also supported: ```lua -ngx.req.set_uri_args({ a = 3, b = {5, 6} }) + ngx.req.set_uri_args({ a = 3, b = {5, 6} }) ``` which will result in a query string like `a=3&b=5&b=6`. @@ -3578,26 +3635,26 @@ Returns a Lua table holding all the current request URL query arguments. ```nginx -location = /test { - content_by_lua ' - local args = ngx.req.get_uri_args() - for key, val in pairs(args) do - if type(val) == "table" then - ngx.say(key, ": ", table.concat(val, ", ")) - else - ngx.say(key, ": ", val) - end - end - '; -} + location = /test { + content_by_lua ' + local args = ngx.req.get_uri_args() + for key, val in pairs(args) do + if type(val) == "table" then + ngx.say(key, ": ", table.concat(val, ", ")) + else + ngx.say(key, ": ", val) + end + end + '; + } ``` Then `GET /test?foo=bar&bar=baz&bar=blah` will yield the response body ```bash -foo: bar -bar: baz, blah + foo: bar + bar: baz, blah ``` Multiple occurrences of an argument key will result in a table value holding all the values for that key in order. @@ -3606,23 +3663,23 @@ Keys and values are unescaped according to URI escaping rules. In the settings a ```bash -a b: 1a 2 + a b: 1a 2 ``` Arguments without the `=` parts are treated as boolean arguments. `GET /test?foo&bar` will yield: ```bash -foo: true -bar: true + foo: true + bar: true ``` That is, they will take Lua boolean values `true`. However, they are different from arguments taking empty string values. `GET /test?foo=&bar=` will give something like ```bash -foo: -bar: + foo: + bar: ``` Empty key arguments are discarded. `GET /test?=hello&=world` will yield an empty output for instance. @@ -3631,15 +3688,15 @@ Updating query arguments via the nginx variable `$args` (or `ngx.var.args` in Lu ```lua -ngx.var.args = "a=3&b=42" -local args = ngx.req.get_uri_args() + ngx.var.args = "a=3&b=42" + local args = ngx.req.get_uri_args() ``` Here the `args` table will always look like ```lua -{a = 3, b = 42} + {a = 3, b = 42} ``` regardless of the actual request query string. @@ -3650,14 +3707,14 @@ However, the optional `max_args` function argument can be used to override this ```lua -local args = ngx.req.get_uri_args(10) + local args = ngx.req.get_uri_args(10) ``` This argument can be set to zero to remove the limit and to process all request arguments received: ```lua -local args = ngx.req.get_uri_args(0) + local args = ngx.req.get_uri_args(0) ``` Removing the `max_args` cap is strongly discouraged. @@ -3674,39 +3731,39 @@ Returns a Lua table holding all the current request POST query arguments (of the ```nginx -location = /test { - content_by_lua ' - ngx.req.read_body() - local args, err = ngx.req.get_post_args() - if not args then - ngx.say("failed to get post args: ", err) - return - end - for key, val in pairs(args) do - if type(val) == "table" then - ngx.say(key, ": ", table.concat(val, ", ")) - else - ngx.say(key, ": ", val) - end - end - '; -} + location = /test { + content_by_lua ' + ngx.req.read_body() + local args, err = ngx.req.get_post_args() + if not args then + ngx.say("failed to get post args: ", err) + return + end + for key, val in pairs(args) do + if type(val) == "table" then + ngx.say(key, ": ", table.concat(val, ", ")) + else + ngx.say(key, ": ", val) + end + end + '; + } ``` Then ```bash -# Post request with the body 'foo=bar&bar=baz&bar=blah' -$ curl --data 'foo=bar&bar=baz&bar=blah' localhost/test + # Post request with the body 'foo=bar&bar=baz&bar=blah' + $ curl --data 'foo=bar&bar=baz&bar=blah' localhost/test ``` will yield the response body like ```bash -foo: bar -bar: baz, blah + foo: bar + bar: baz, blah ``` Multiple occurrences of an argument key will result in a table value holding all of the values for that key in order. @@ -3717,31 +3774,31 @@ With the settings above, ```bash -# POST request with body 'a%20b=1%61+2' -$ curl -d 'a%20b=1%61+2' localhost/test + # POST request with body 'a%20b=1%61+2' + $ curl -d 'a%20b=1%61+2' localhost/test ``` will yield: ```bash -a b: 1a 2 + a b: 1a 2 ``` Arguments without the `=` parts are treated as boolean arguments. `GET /test?foo&bar` will yield: ```bash -foo: true -bar: true + foo: true + bar: true ``` That is, they will take Lua boolean values `true`. However, they are different from arguments taking empty string values. `POST /test` with request body `foo=&bar=` will return something like ```bash -foo: -bar: + foo: + bar: ``` Empty key arguments are discarded. `POST /test` with body `=hello&=world` will yield empty outputs for instance. @@ -3752,14 +3809,14 @@ However, the optional `max_args` function argument can be used to override this ```lua -local args = ngx.req.get_post_args(10) + local args = ngx.req.get_post_args(10) ``` This argument can be set to zero to remove the limit and to process all request arguments received: ```lua -local args = ngx.req.get_post_args(0) + local args = ngx.req.get_post_args(0) ``` Removing the `max_args` cap is strongly discouraged. @@ -3776,17 +3833,17 @@ Returns a Lua table holding all the current request headers. ```lua -local h = ngx.req.get_headers() -for k, v in pairs(h) do - ... -end + local h = ngx.req.get_headers() + for k, v in pairs(h) do + ... + end ``` To read an individual header: ```lua -ngx.say("Host: ", ngx.req.get_headers()["Host"]) + ngx.say("Host: ", ngx.req.get_headers()["Host"]) ``` Note that the [ngx.var.HEADER](#ngxvarvariable) API call, which uses core [$http_HEADER](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_http_) variables, may be more preferable for reading individual request headers. @@ -3795,16 +3852,16 @@ For multiple instances of request headers such as: ```bash -Foo: foo -Foo: bar -Foo: baz + Foo: foo + Foo: bar + Foo: baz ``` the value of `ngx.req.get_headers()["Foo"]` will be a Lua (array) table such as: ```lua -{"foo", "bar", "baz"} + {"foo", "bar", "baz"} ``` Note that a maximum of 100 request headers are parsed by default (including those with the same name) and that additional request headers are silently discarded to guard against potential denial of service attacks. @@ -3813,14 +3870,14 @@ However, the optional `max_headers` function argument can be used to override th ```lua -local args = ngx.req.get_headers(10) + local args = ngx.req.get_headers(10) ``` This argument can be set to zero to remove the limit and to process all request headers received: ```lua -local args = ngx.req.get_headers(0) + local args = ngx.req.get_headers(0) ``` Removing the `max_headers` cap is strongly discouraged. @@ -3831,9 +3888,9 @@ Also, by default, an `__index` metamethod is added to the resulting Lua table an ```lua -ngx.say(headers.my_foo_header) -ngx.say(headers["My-Foo-Header"]) -ngx.say(headers["my-foo-header"]) + ngx.say(headers.my_foo_header) + ngx.say(headers["My-Foo-Header"]) + ngx.say(headers["my-foo-header"]) ``` The `__index` metamethod will not be added when the `raw` argument is set to `true`. @@ -3850,11 +3907,11 @@ Set the current request's request header named `header_name` to value `header_va By default, all the subrequests subsequently initiated by [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) will inherit the new header. -Here is an example of setting the `Content-Length` header: +Here is an example of setting the `Content-Type` header: ```lua -ngx.req.set_header("Content-Type", "text/css") + ngx.req.set_header("Content-Type", "text/css") ``` The `header_value` can take an array list of values, @@ -3862,15 +3919,15 @@ for example, ```lua -ngx.req.set_header("Foo", {"a", "abc"}) + ngx.req.set_header("Foo", {"a", "abc"}) ``` will produce two new request headers: ```bash -Foo: a -Foo: abc + Foo: a + Foo: abc ``` and old `Foo` headers will be overridden if there is any. @@ -3879,14 +3936,14 @@ When the `header_value` argument is `nil`, the request header will be removed. S ```lua -ngx.req.set_header("X-Foo", nil) + ngx.req.set_header("X-Foo", nil) ``` is equivalent to ```lua -ngx.req.clear_header("X-Foo") + ngx.req.clear_header("X-Foo") ``` [Back to TOC](#nginx-api-for-lua) @@ -3911,8 +3968,8 @@ Reads the client request body synchronously without blocking the Nginx event loo ```lua -ngx.req.read_body() -local args = ngx.req.get_post_args() + ngx.req.read_body() + local args = ngx.req.get_post_args() ``` If the request body is already read previously by turning on [lua_need_request_body](#lua_need_request_body) or by using other modules, then this function does not run and returns immediately. @@ -4054,11 +4111,11 @@ The usage of this function is often like this: ```lua -ngx.req.init_body(128 * 1024) -- buffer is 128KB -for chunk in next_data_chunk() do - ngx.req.append_body(chunk) -- each chunk can be 4KB -end -ngx.req.finish_body() + ngx.req.init_body(128 * 1024) -- buffer is 128KB + for chunk in next_data_chunk() do + ngx.req.append_body(chunk) -- each chunk can be 4KB + end + ngx.req.finish_body() ``` This function can be used with [ngx.req.append_body](#ngxreqappend_body), [ngx.req.finish_body](#ngxreqfinish_body), and [ngx.req.socket](#ngxreqsocket) to implement efficient input filters in pure Lua (in the context of [rewrite_by_lua](#rewrite_by_lua)* or [access_by_lua](#access_by_lua)*), which can be used with other Nginx content handler or upstream modules like [ngx_http_proxy_module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html) and [ngx_http_fastcgi_module](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html). @@ -4140,23 +4197,23 @@ Does an internal redirect to `uri` with `args` and is similar to the [echo_exec] ```lua -ngx.exec('/some-location'); -ngx.exec('/some-location', 'a=3&b=5&c=6'); -ngx.exec('/some-location?a=3&b=5', 'c=6'); + ngx.exec('/some-location'); + ngx.exec('/some-location', 'a=3&b=5&c=6'); + ngx.exec('/some-location?a=3&b=5', 'c=6'); ``` The optional second `args` can be used to specify extra URI query arguments, for example: ```lua -ngx.exec("/foo", "a=3&b=hello%20world") + ngx.exec("/foo", "a=3&b=hello%20world") ``` Alternatively, a Lua table can be passed for the `args` argument for ngx_lua to carry out URI escaping and string concatenation. ```lua -ngx.exec("/foo", { a = 3, b = "hello world" }) + ngx.exec("/foo", { a = 3, b = "hello world" }) ``` The result is exactly the same as the previous example. @@ -4169,22 +4226,22 @@ Named locations are also supported but the second `args` argument will be ignore ```nginx -location /foo { - content_by_lua ' - ngx.exec("@bar", "a=goodbye"); - '; -} + location /foo { + content_by_lua ' + ngx.exec("@bar", "a=goodbye"); + '; + } -location @bar { - content_by_lua ' - local args = ngx.req.get_uri_args() - for key, val in pairs(args) do - if key == "a" then - ngx.say(val) - end - end - '; -} + location @bar { + content_by_lua ' + local args = ngx.req.get_uri_args() + for key, val in pairs(args) do + if key == "a" then + ngx.say(val) + end + end + '; + } ``` Note that the `ngx.exec` method is different from [ngx.redirect](#ngxredirect) in that @@ -4212,64 +4269,64 @@ Here is an example assuming the current server name is `localhost` and that it i ```lua -return ngx.redirect("/foo") + return ngx.redirect("/foo") ``` which is equivalent to ```lua -return ngx.redirect("http://localhost:1984/foo", ngx.HTTP_MOVED_TEMPORARILY) + return ngx.redirect("http://localhost:1984/foo", ngx.HTTP_MOVED_TEMPORARILY) ``` Redirecting arbitrary external URLs is also supported, for example: ```lua -return ngx.redirect("http://www.google.com") + return ngx.redirect("http://www.google.com") ``` We can also use the numerical code directly as the second `status` argument: ```lua -return ngx.redirect("/foo", 301) + return ngx.redirect("/foo", 301) ``` This method is similar to the [rewrite](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) directive with the `redirect` modifier in the standard -[[HttpRewriteModule]], for example, this `nginx.conf` snippet +[ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html), for example, this `nginx.conf` snippet ```nginx -rewrite ^ /foo? redirect; # nginx config + rewrite ^ /foo? redirect; # nginx config ``` is equivalent to the following Lua code ```lua -return ngx.redirect('/foo'); -- Lua code + return ngx.redirect('/foo'); -- Lua code ``` while ```nginx -rewrite ^ /foo? permanent; # nginx config + rewrite ^ /foo? permanent; # nginx config ``` is equivalent to ```lua -return ngx.redirect('/foo', ngx.HTTP_MOVED_PERMANENTLY) -- Lua code + return ngx.redirect('/foo', ngx.HTTP_MOVED_PERMANENTLY) -- Lua code ``` URI arguments can be specified as well, for example: ```lua -return ngx.redirect('/foo?a=3&b=4') + return ngx.redirect('/foo?a=3&b=4') ``` Note that this method call terminates the processing of the current request and that it *must* be called before [ngx.send_headers](#ngxsend_headers) or explicit response body @@ -4322,19 +4379,19 @@ Nested arrays of strings are permitted and the elements in the arrays will be se ```lua -local table = { - "hello, ", - {"world: ", true, " or ", false, - {": ", nil}} -} -ngx.print(table) + local table = { + "hello, ", + {"world: ", true, " or ", false, + {": ", nil}} + } + ngx.print(table) ``` will yield the output ```bash -hello, world: true or false: nil + hello, world: true or false: nil ``` Non-array table arguments will cause a Lua exception to be thrown. @@ -4410,32 +4467,32 @@ To return an error page with custom contents, use code snippets like this: ```lua -ngx.status = ngx.HTTP_GONE -ngx.say("This is our own content") --- to cause quit the whole request rather than the current phase handler -ngx.exit(ngx.HTTP_OK) + ngx.status = ngx.HTTP_GONE + ngx.say("This is our own content") + -- to cause quit the whole request rather than the current phase handler + ngx.exit(ngx.HTTP_OK) ``` The effect in action: ```bash -$ curl -i http://localhost/test -HTTP/1.1 410 Gone -Server: nginx/1.0.6 -Date: Thu, 15 Sep 2011 00:51:48 GMT -Content-Type: text/plain -Transfer-Encoding: chunked -Connection: keep-alive + $ curl -i http://localhost/test + HTTP/1.1 410 Gone + Server: nginx/1.0.6 + Date: Thu, 15 Sep 2011 00:51:48 GMT + Content-Type: text/plain + Transfer-Encoding: chunked + Connection: keep-alive -This is our own content + This is our own content ``` Number literals can be used directly as the argument, for instance, ```lua -ngx.exit(501) + ngx.exit(501) ``` Note that while this method accepts all [HTTP status constants](#http-status-constants) as input, it only accepts `NGX_OK` and `NGX_ERROR` of the [core constants](#core-constants). @@ -4458,21 +4515,21 @@ When you disable the HTTP 1.1 keep-alive feature for your downstream connections ```nginx -location = /async { - keepalive_timeout 0; - content_by_lua ' - ngx.say("got the task!") - ngx.eof() -- a descent HTTP client will close the connection at this point - -- access MySQL, PostgreSQL, Redis, Memcached, and etc here... - '; -} + location = /async { + keepalive_timeout 0; + content_by_lua ' + ngx.say("got the task!") + ngx.eof() -- a descent HTTP client will close the connection at this point + -- access MySQL, PostgreSQL, Redis, Memcached, and etc here... + '; + } ``` But if you create subrequests to access other locations configured by Nginx upstream modules, then you should configure those upstream modules to ignore client connection abortions if they are not by default. For example, by default the standard [ngx_http_proxy_module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html) will terminate both the subrequest and the main request as soon as the client closes the connection, so it is important to turn on the [proxy_ignore_client_abort](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_client_abort) directive in your location block configured by [ngx_http_proxy_module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html): ```nginx -proxy_ignore_client_abort on; + proxy_ignore_client_abort on; ``` A better way to do background jobs is to use the [ngx.timer.at](#ngxtimerat) API. @@ -4519,7 +4576,7 @@ For example, ```lua -ngx.say(ngx.unescape_uri("b%20r56+7")) + ngx.say(ngx.unescape_uri("b%20r56+7")) ``` gives the output @@ -4542,7 +4599,7 @@ For example, ```lua -ngx.encode_args({foo = 3, ["b r"] = "hello world"}) + ngx.encode_args({foo = 3, ["b r"] = "hello world"}) ``` yields @@ -4557,7 +4614,7 @@ Multi-value query args are also supported. Just use a Lua table for the argument ```lua -ngx.encode_args({baz = {32, "hello"}}) + ngx.encode_args({baz = {32, "hello"}}) ``` gives @@ -4572,7 +4629,7 @@ Boolean argument values are also supported, for instance, ```lua -ngx.encode_args({a = true, b = 1}) + ngx.encode_args({a = true, b = 1}) ``` yields @@ -4601,7 +4658,7 @@ This argument can be set to zero to remove the limit and to process all request ```lua -local args = ngx.decode_args(str, 0) + local args = ngx.decode_args(str, 0) ``` Removing the `max_args` cap is strongly discouraged. @@ -4676,10 +4733,10 @@ For example, ```lua -local key = "thisisverysecretstuff" -local src = "some string we want to sign" -local digest = ngx.hmac_sha1(key, src) -ngx.say(ngx.encode_base64(digest)) + local key = "thisisverysecretstuff" + local src = "some string we want to sign" + local digest = ngx.hmac_sha1(key, src) + ngx.say(ngx.encode_base64(digest)) ``` yields the output @@ -4706,9 +4763,9 @@ For example, ```nginx -location = /md5 { - content_by_lua 'ngx.say(ngx.md5("hello"))'; -} + location = /md5 { + content_by_lua 'ngx.say(ngx.md5("hello"))'; + } ``` yields the output @@ -4841,8 +4898,8 @@ Returns a formatted string can be used as the cookie expiration time. The parame ```nginx -ngx.say(ngx.cookie_time(1290079655)) - -- yields "Thu, 18-Nov-10 11:27:35 GMT" + ngx.say(ngx.cookie_time(1290079655)) + -- yields "Thu, 18-Nov-10 11:27:35 GMT" ``` [Back to TOC](#nginx-api-for-lua) @@ -4857,8 +4914,8 @@ Returns a formated string can be used as the http header time (for example, bein ```nginx -ngx.say(ngx.http_time(1290079655)) - -- yields "Thu, 18 Nov 2010 11:27:35 GMT" + ngx.say(ngx.http_time(1290079655)) + -- yields "Thu, 18 Nov 2010 11:27:35 GMT" ``` [Back to TOC](#nginx-api-for-lua) @@ -4873,10 +4930,10 @@ Parse the http time string (as returned by [ngx.http_time](#ngxhttp_time)) into ```nginx -local time = ngx.parse_http_time("Thu, 18 Nov 2010 11:27:35 GMT") -if time == nil then - ... -end + local time = ngx.parse_http_time("Thu, 18 Nov 2010 11:27:35 GMT") + if time == nil then + ... + end ``` [Back to TOC](#nginx-api-for-lua) @@ -4905,25 +4962,25 @@ When a match is found, a Lua table `captures` is returned, where `captures[0]` h ```lua -local m, err = ngx.re.match("hello, 1234", "[0-9]+") -if m then - -- m[0] == "1234" + local m, err = ngx.re.match("hello, 1234", "[0-9]+") + if m then + -- m[0] == "1234" -else - if err then - ngx.log(ngx.ERR, "error: ", err) - return - end + else + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end - ngx.say("match not found") -end + ngx.say("match not found") + end ``` ```lua -local m, err = ngx.re.match("hello, 1234", "([0-9])[0-9]+") --- m[0] == "1234" --- m[1] == "1" + local m, err = ngx.re.match("hello, 1234", "([0-9])[0-9]+") + -- m[0] == "1234" + -- m[1] == "1" ``` Named captures are also supported since the `v0.7.14` release @@ -4931,23 +4988,23 @@ and are returned in the same Lua table as key-value pairs as the numbered captur ```lua -local m, err = ngx.re.match("hello, 1234", "([0-9])(?[0-9]+)") --- m[0] == "1234" --- m[1] == "1" --- m[2] == "234" --- m["remaining"] == "234" + local m, err = ngx.re.match("hello, 1234", "([0-9])(?[0-9]+)") + -- m[0] == "1234" + -- m[1] == "1" + -- m[2] == "234" + -- m["remaining"] == "234" ``` Unmatched subpatterns will have `nil` values in their `captures` table fields. ```lua -local m, err = ngx.re.match("hello, world", "(world)|(hello)|(?howdy)") --- m[0] == "hello" --- m[1] == nil --- m[2] == "hello" --- m[3] == nil --- m["named"] == nil + local m, err = ngx.re.match("hello, world", "(world)|(hello)|(?howdy)") + -- m[0] == "hello" + -- m[1] == nil + -- m[2] == "hello" + -- m[3] == nil + -- m["named"] == nil ``` Specify `options` to control how the match operation will be performed. The following option characters are supported: @@ -5000,15 +5057,15 @@ These options can be combined: ```nginx -local m, err = ngx.re.match("hello, world", "HEL LO", "ix") --- m[0] == "hello" + local m, err = ngx.re.match("hello, world", "HEL LO", "ix") + -- m[0] == "hello" ``` ```nginx -local m, err = ngx.re.match("hello, 美好生活", "HELLO, (.{2})", "iu") --- m[0] == "hello, 美好" --- m[1] == "美好" + local m, err = ngx.re.match("hello, 美好生活", "HELLO, (.{2})", "iu") + -- m[0] == "hello, 美好" + -- m[1] == "美好" ``` The `o` option is useful for performance tuning, because the regex pattern in question will only be compiled once, cached in the worker-process level, and shared among all requests in the current Nginx worker process. The upper limit of the regex cache can be tuned via the [lua_regex_cache_max_entries](#lua_regex_cache_max_entries) directive. @@ -5017,18 +5074,18 @@ The optional fourth argument, `ctx`, can be a Lua table holding an optional `pos ```lua -local ctx = {} -local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) - -- m[0] = "1234" - -- ctx.pos == 5 + local ctx = {} + local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) + -- m[0] = "1234" + -- ctx.pos == 5 ``` ```lua -local ctx = { pos = 2 } -local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) - -- m[0] = "34" - -- ctx.pos == 5 + local ctx = { pos = 2 } + local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) + -- m[0] = "34" + -- ctx.pos == 5 ``` The `ctx` table argument combined with the `a` regex modifier can be used to construct a lexer atop `ngx.re.match`. @@ -5065,19 +5122,19 @@ Below is an example: ```lua -local s = "hello, 1234" -local from, to, err = ngx.re.find(s, "([0-9]+)", "jo") -if from then - ngx.say("from: ", from) - ngx.say("to: ", to) - ngx.say("matched: ", string.sub(s, from, to)) -else - if err then - ngx.say("error: ", err) - return - end - ngx.say("not matched!") -end + local s = "hello, 1234" + local from, to, err = ngx.re.find(s, "([0-9]+)", "jo") + if from then + ngx.say("from: ", from) + ngx.say("to: ", to) + ngx.say("matched: ", string.sub(s, from, to)) + else + if err then + ngx.say("error: ", err) + return + end + ngx.say("not matched!") + end ``` This example produces the output @@ -5092,11 +5149,11 @@ Since the `0.9.3` release, an optional 5th argument, `nth`, is supported to spec ```lua -local str = "hello, 1234" -local from, to = ngx.re.find(str, "([0-9])([0-9]+)", "jo", nil, 2) -if from then - ngx.say("matched 2nd submatch: ", string.sub(str, from, to)) -- yields "234" -end + local str = "hello, 1234" + local from, to = ngx.re.find(str, "([0-9])([0-9]+)", "jo", nil, 2) + if from then + ngx.say("matched 2nd submatch: ", string.sub(str, from, to)) -- yields "234" + end ``` This API function was first introduced in the `v0.9.2` release. @@ -5117,58 +5174,58 @@ Here is a small example to demonstrate its basic usage: ```lua -local iterator, err = ngx.re.gmatch("hello, world!", "([a-z]+)", "i") -if not iterator then - ngx.log(ngx.ERR, "error: ", err) - return -end + local iterator, err = ngx.re.gmatch("hello, world!", "([a-z]+)", "i") + if not iterator then + ngx.log(ngx.ERR, "error: ", err) + return + end -local m -m, err = iterator() -- m[0] == m[1] == "hello" -if err then - ngx.log(ngx.ERR, "error: ", err) - return -end + local m + m, err = iterator() -- m[0] == m[1] == "hello" + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end -m, err = iterator() -- m[0] == m[1] == "world" -if err then - ngx.log(ngx.ERR, "error: ", err) - return -end + m, err = iterator() -- m[0] == m[1] == "world" + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end -m, err = iterator() -- m == nil -if err then - ngx.log(ngx.ERR, "error: ", err) - return -end + m, err = iterator() -- m == nil + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end ``` More often we just put it into a Lua loop: ```lua -local it, err = ngx.re.gmatch("hello, world!", "([a-z]+)", "i") -if not it then - ngx.log(ngx.ERR, "error: ", err) - return -end + local it, err = ngx.re.gmatch("hello, world!", "([a-z]+)", "i") + if not it then + ngx.log(ngx.ERR, "error: ", err) + return + end -while true do - local m, err = it() - if err then - ngx.log(ngx.ERR, "error: ", err) - return - end + while true do + local m, err = it() + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end - if not m then - -- no match found (any more) - break - end + if not m then + -- no match found (any more) + break + end - -- found a match - ngx.say(m[0]) - ngx.say(m[1]) -end + -- found a match + ngx.say(m[0]) + ngx.say(m[1]) + end ``` The optional `options` argument takes exactly the same semantics as the [ngx.re.match](#ngxrematch) method. @@ -5195,14 +5252,14 @@ When the `replace` is a string, then it is treated as a special template for str ```lua -local newstr, n, err = ngx.re.sub("hello, 1234", "([0-9])[0-9]", "[$0][$1]") -if newstr then - -- newstr == "hello, [12][1]34" - -- n == 1 -else - ngx.log(ngx.ERR, "error: ", err) - return -end + local newstr, n, err = ngx.re.sub("hello, 1234", "([0-9])[0-9]", "[$0][$1]") + if newstr then + -- newstr == "hello, [12][1]34" + -- n == 1 + else + ngx.log(ngx.ERR, "error: ", err) + return + end ``` where `$0` referring to the whole substring matched by the pattern and `$1` referring to the first parenthesized capturing substring. @@ -5211,18 +5268,18 @@ Curly braces can also be used to disambiguate variable names from the background ```lua -local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "${0}00") - -- newstr == "hello, 100234" - -- n == 1 + local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "${0}00") + -- newstr == "hello, 100234" + -- n == 1 ``` Literal dollar sign characters (`$`) in the `replace` string argument can be escaped by another dollar sign, for instance, ```lua -local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "$$") - -- newstr == "hello, $234" - -- n == 1 + local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "$$") + -- newstr == "hello, $234" + -- n == 1 ``` Do not use backlashes to escape dollar signs; it will not work as expected. @@ -5231,12 +5288,12 @@ When the `replace` argument is of type "function", then it will be invoked with ```lua -local func = function (m) - return "[" .. m[0] .. "][" .. m[1] .. "]" -end -local newstr, n, err = ngx.re.sub("hello, 1234", "( [0-9] ) [0-9]", func, "x") - -- newstr == "hello, [12][1]34" - -- n == 1 + local func = function (m) + return "[" .. m[0] .. "][" .. m[1] .. "]" + end + local newstr, n, err = ngx.re.sub("hello, 1234", "( [0-9] ) [0-9]", func, "x") + -- newstr == "hello, [12][1]34" + -- n == 1 ``` The dollar sign characters in the return value of the `replace` function argument are not special at all. @@ -5259,24 +5316,24 @@ Here is some examples: ```lua -local newstr, n, err = ngx.re.gsub("hello, world", "([a-z])[a-z]+", "[$0,$1]", "i") -if newstr then - -- newstr == "[hello,h], [world,w]" - -- n == 2 -else - ngx.log(ngx.ERR, "error: ", err) - return -end + local newstr, n, err = ngx.re.gsub("hello, world", "([a-z])[a-z]+", "[$0,$1]", "i") + if newstr then + -- newstr == "[hello,h], [world,w]" + -- n == 2 + else + ngx.log(ngx.ERR, "error: ", err) + return + end ``` ```lua -local func = function (m) - return "[" .. m[0] .. "," .. m[1] .. "]" -end -local newstr, n, err = ngx.re.gsub("hello, world", "([a-z])[a-z]+", func, "i") - -- newstr == "[hello,h], [world,w]" - -- n == 2 + local func = function (m) + return "[" .. m[0] .. "," .. m[1] .. "]" + end + local newstr, n, err = ngx.re.gsub("hello, world", "([a-z])[a-z]+", func, "i") + -- newstr == "[hello,h], [world,w]" + -- n == 2 ``` This method requires the PCRE library enabled in Nginx. ([Known Issue With Special PCRE Sequences](#special-pcre-sequences)). @@ -5289,7 +5346,7 @@ ngx.shared.DICT --------------- **syntax:** *dict = ngx.shared.DICT* -**syntax:** *dict = ngx.shared[name_var]* +**syntax:** *dict = ngx.shared\[name_var\]* **context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** @@ -5316,38 +5373,38 @@ Here is an example: ```nginx -http { - lua_shared_dict dogs 10m; - server { - location /set { - content_by_lua ' - local dogs = ngx.shared.dogs - dogs:set("Jim", 8) - ngx.say("STORED") - '; - } - location /get { - content_by_lua ' - local dogs = ngx.shared.dogs - ngx.say(dogs:get("Jim")) - '; - } - } -} + http { + lua_shared_dict dogs 10m; + server { + location /set { + content_by_lua ' + local dogs = ngx.shared.dogs + dogs:set("Jim", 8) + ngx.say("STORED") + '; + } + location /get { + content_by_lua ' + local dogs = ngx.shared.dogs + ngx.say(dogs:get("Jim")) + '; + } + } + } ``` Let us test it: ```bash -$ curl localhost/set -STORED + $ curl localhost/set + STORED -$ curl localhost/get -8 + $ curl localhost/get + 8 -$ curl localhost/get -8 + $ curl localhost/get + 8 ``` The number `8` will be consistently output when accessing `/get` regardless of how many Nginx workers there are because the `dogs` dictionary resides in the shared memory and visible to *all* of the worker processes. @@ -5376,16 +5433,16 @@ The first argument to this method must be the dictionary object itself, for exam ```lua -local cats = ngx.shared.cats -local value, flags = cats.get(cats, "Marry") + local cats = ngx.shared.cats + local value, flags = cats.get(cats, "Marry") ``` or use Lua's syntactic sugar for method calls: ```lua -local cats = ngx.shared.cats -local value, flags = cats:get("Marry") + local cats = ngx.shared.cats + local value, flags = cats:get("Marry") ``` These two forms are fundamentally equivalent. @@ -5442,16 +5499,16 @@ The first argument to this method must be the dictionary object itself, for exam ```lua -local cats = ngx.shared.cats -local succ, err, forcible = cats.set(cats, "Marry", "it is a nice cat!") + local cats = ngx.shared.cats + local succ, err, forcible = cats.set(cats, "Marry", "it is a nice cat!") ``` or use Lua's syntactic sugar for method calls: ```lua -local cats = ngx.shared.cats -local succ, err, forcible = cats:set("Marry", "it is a nice cat!") + local cats = ngx.shared.cats + local succ, err, forcible = cats:set("Marry", "it is a nice cat!") ``` These two forms are fundamentally equivalent. @@ -5642,7 +5699,7 @@ Both IP addresses and domain names can be specified as the `host` argument. In c ```nginx -resolver 8.8.8.8; # use Google's public DNS nameserver + resolver 8.8.8.8; # use Google's public DNS nameserver ``` If the nameserver returns multiple IP addresses for the host name, this method will pick up one randomly. @@ -5653,32 +5710,32 @@ Here is an example for connecting to a UDP (memcached) server: ```nginx -location /test { - resolver 8.8.8.8; + location /test { + resolver 8.8.8.8; - content_by_lua ' - local sock = ngx.socket.udp() - local ok, err = sock:setpeername("my.memcached.server.domain", 11211) - if not ok then - ngx.say("failed to connect to memcached: ", err) - return - end - ngx.say("successfully connected to memcached!") - sock:close() - '; -} + content_by_lua ' + local sock = ngx.socket.udp() + local ok, err = sock:setpeername("my.memcached.server.domain", 11211) + if not ok then + ngx.say("failed to connect to memcached: ", err) + return + end + ngx.say("successfully connected to memcached!") + sock:close() + '; + } ``` Since the `v0.7.18` release, connecting to a datagram unix domain socket file is also possible on Linux: ```lua -local sock = ngx.socket.udp() -local ok, err = sock:setpeername("unix:/tmp/some-datagram-service.sock") -if not ok then - ngx.say("failed to connect to the datagram unix domain socket: ", err) - return -end + local sock = ngx.socket.udp() + local ok, err = sock:setpeername("unix:/tmp/some-datagram-service.sock") + if not ok then + ngx.say("failed to connect to the datagram unix domain socket: ", err) + return + end ``` assuming the datagram service is listening on the unix domain socket file `/tmp/some-datagram-service.sock` and the client socket will use the "autobind" feature on Linux. @@ -5725,13 +5782,13 @@ Timeout for the reading operation is controlled by the [lua_socket_read_timeout] ```lua -sock:settimeout(1000) -- one second timeout -local data, err = sock:receive() -if not data then - ngx.say("failed to read a packet: ", data) - return -end -ngx.say("successfully read a packet: ", data) + sock:settimeout(1000) -- one second timeout + local data, err = sock:receive() + if not data then + ngx.say("failed to read a packet: ", data) + return + end + ngx.say("successfully read a packet: ", data) ``` It is important here to call the [settimeout](#udpsocksettimeout) method *before* calling this method. @@ -5828,7 +5885,7 @@ Both IP addresses and domain names can be specified as the `host` argument. In c ```nginx -resolver 8.8.8.8; # use Google's public DNS nameserver + resolver 8.8.8.8; # use Google's public DNS nameserver ``` If the nameserver returns multiple IP addresses for the host name, this method will pick up one randomly. @@ -5839,32 +5896,32 @@ Here is an example for connecting to a TCP server: ```nginx -location /test { - resolver 8.8.8.8; + location /test { + resolver 8.8.8.8; - content_by_lua ' - local sock = ngx.socket.tcp() - local ok, err = sock:connect("www.google.com", 80) - if not ok then - ngx.say("failed to connect to google: ", err) - return - end - ngx.say("successfully connected to google!") - sock:close() - '; -} + content_by_lua ' + local sock = ngx.socket.tcp() + local ok, err = sock:connect("www.google.com", 80) + if not ok then + ngx.say("failed to connect to google: ", err) + return + end + ngx.say("successfully connected to google!") + sock:close() + '; + } ``` Connecting to a Unix Domain Socket file is also possible: ```lua -local sock = ngx.socket.tcp() -local ok, err = sock:connect("unix:/tmp/memcached.sock") -if not ok then - ngx.say("failed to connect to the memcached unix domain socket: ", err) - return -end + local sock = ngx.socket.tcp() + local ok, err = sock:connect("unix:/tmp/memcached.sock") + if not ok then + ngx.say("failed to connect to the memcached unix domain socket: ", err) + return + end ``` assuming memcached (or something else) is listening on the unix domain socket file `/tmp/memcached.sock`. @@ -5873,9 +5930,9 @@ Timeout for the connecting operation is controlled by the [lua_socket_connect_ti ```lua -local sock = ngx.socket.tcp() -sock:settimeout(1000) -- one second timeout -local ok, err = sock:connect(host, port) + local sock = ngx.socket.tcp() + sock:settimeout(1000) -- one second timeout + local ok, err = sock:connect(host, port) ``` It is important here to call the [settimeout](#tcpsocksettimeout) method *before* calling this method. @@ -5953,8 +6010,8 @@ Timeout for the sending operation is controlled by the [lua_socket_send_timeout] ```lua -sock:settimeout(1000) -- one second timeout -local bytes, err = sock:send(request) + sock:settimeout(1000) -- one second timeout + local bytes, err = sock:send(request) ``` It is important here to call the [settimeout](#tcpsocksettimeout) method *before* calling this method. @@ -5992,13 +6049,13 @@ Timeout for the reading operation is controlled by the [lua_socket_read_timeout] ```lua -sock:settimeout(1000) -- one second timeout -local line, err, partial = sock:receive() -if not line then - ngx.say("failed to read a line: ", err) - return -end -ngx.say("successfully read a line: ", line) + sock:settimeout(1000) -- one second timeout + local line, err, partial = sock:receive() + if not line then + ngx.say("failed to read a line: ", err) + return + end + ngx.say("successfully read a line: ", line) ``` It is important here to call the [settimeout](#tcpsocksettimeout) method *before* calling this method. @@ -6021,12 +6078,12 @@ Here is an example for using this method to read a data stream with the boundary ```lua -local reader = sock:receiveuntil("\r\n--abcedhb") -local data, err, partial = reader() -if not data then - ngx.say("failed to read the data stream: ", err) -end -ngx.say("read the data stream: ", data) + local reader = sock:receiveuntil("\r\n--abcedhb") + local data, err, partial = reader() + if not data then + ngx.say("failed to read the data stream: ", err) + end + ngx.say("read the data stream: ", data) ``` When called without any argument, the iterator function returns the received data right *before* the specified pattern string in the incoming data stream. So for the example above, if the incoming data stream is `'hello, world! -agentzh\r\n--abcedhb blah blah'`, then the string `'hello, world! -agentzh'` will be returned. @@ -6039,21 +6096,21 @@ The iterator function behaves differently (i.e., like a real iterator) when it i ```lua -local reader = sock:receiveuntil("\r\n--abcedhb") + local reader = sock:receiveuntil("\r\n--abcedhb") -while true do - local data, err, partial = reader(4) - if not data then - if err then - ngx.say("failed to read the data stream: ", err) - break - end + while true do + local data, err, partial = reader(4) + if not data then + if err then + ngx.say("failed to read the data stream: ", err) + break + end - ngx.say("read done") - break - end - ngx.say("read chunk: [", data, "]") -end + ngx.say("read done") + break + end + ngx.say("read chunk: [", data, "]") + end ``` Then for the incoming data stream `'hello, world! -agentzh\r\n--abcedhb blah blah'`, we shall get the following output from the sample code above: @@ -6074,15 +6131,15 @@ Timeout for the iterator function's reading operation is controlled by the [lua_ ```lua -local readline = sock:receiveuntil("\r\n") + local readline = sock:receiveuntil("\r\n") -sock:settimeout(1000) -- one second timeout -line, err, partial = readline() -if not line then - ngx.say("failed to read a line: ", err) - return -end -ngx.say("successfully read a line: ", line) + sock:settimeout(1000) -- one second timeout + line, err, partial = readline() + if not line then + ngx.say("failed to read a line: ", err) + return + end + ngx.say("successfully read a line: ", line) ``` It is important here to call the [settimeout](#tcpsocksettimeout) method *before* calling the iterator function (note that the `receiveuntil` call is irrelevant here). @@ -6095,9 +6152,9 @@ The `inclusive` takes a boolean value to control whether to include the pattern ```lua -local reader = tcpsock:receiveuntil("_END_", { inclusive = true }) -local data = reader() -ngx.say(data) + local reader = tcpsock:receiveuntil("_END_", { inclusive = true }) + local data = reader() + ngx.say(data) ``` Then for the input data stream `"hello world _END_ blah blah blah"`, then the example above will output `hello world _END_`, including the pattern string `_END_` itself. @@ -6206,12 +6263,12 @@ This function is a shortcut for combining [ngx.socket.tcp()](#ngxsockettcp) and ```lua -local sock = ngx.socket.tcp() -local ok, err = sock:connect(...) -if not ok then - return nil, err -end -return sock + local sock = ngx.socket.tcp() + local ok, err = sock:connect(...) + if not ok then + return nil, err + end + return sock ``` There is no way to use the [settimeout](#tcpsocksettimeout) method to specify connecting timeout for this method and the [lua_socket_connect_timeout](#lua_socket_connect_timeout) directive must be set at configure time instead. @@ -6304,31 +6361,31 @@ to do manual time-slicing: ```lua -local yield = coroutine.yield + local yield = coroutine.yield -function f() - local self = coroutine.running() - ngx.say("f 1") - yield(self) - ngx.say("f 2") - yield(self) - ngx.say("f 3") -end + function f() + local self = coroutine.running() + ngx.say("f 1") + yield(self) + ngx.say("f 2") + yield(self) + ngx.say("f 3") + end -local self = coroutine.running() -ngx.say("0") -yield(self) + local self = coroutine.running() + ngx.say("0") + yield(self) -ngx.say("1") -ngx.thread.spawn(f) + ngx.say("1") + ngx.thread.spawn(f) -ngx.say("2") -yield(self) + ngx.say("2") + yield(self) -ngx.say("3") -yield(self) + ngx.say("3") + yield(self) -ngx.say("4") + ngx.say("4") ``` Then it will generate the output @@ -6348,43 +6405,43 @@ Then it will generate the output ```lua --- query mysql, memcached, and a remote http service at the same time, --- output the results in the order that they --- actually return the results. + -- query mysql, memcached, and a remote http service at the same time, + -- output the results in the order that they + -- actually return the results. -local mysql = require "resty.mysql" -local memcached = require "resty.memcached" + local mysql = require "resty.mysql" + local memcached = require "resty.memcached" -local function query_mysql() - local db = mysql:new() - db:connect{ - host = "127.0.0.1", - port = 3306, - database = "test", - user = "monty", - password = "mypass" - } - local res, err, errno, sqlstate = - db:query("select * from cats order by id asc") - db:set_keepalive(0, 100) - ngx.say("mysql done: ", cjson.encode(res)) -end + local function query_mysql() + local db = mysql:new() + db:connect{ + host = "127.0.0.1", + port = 3306, + database = "test", + user = "monty", + password = "mypass" + } + local res, err, errno, sqlstate = + db:query("select * from cats order by id asc") + db:set_keepalive(0, 100) + ngx.say("mysql done: ", cjson.encode(res)) + end -local function query_memcached() - local memc = memcached:new() - memc:connect("127.0.0.1", 11211) - local res, err = memc:get("some_key") - ngx.say("memcached done: ", res) -end + local function query_memcached() + local memc = memcached:new() + memc:connect("127.0.0.1", 11211) + local res, err = memc:get("some_key") + ngx.say("memcached done: ", res) + end -local function query_http() - local res = ngx.location.capture("/my-http-proxy") - ngx.say("http done: ", res.body) -end + local function query_http() + local res = ngx.location.capture("/my-http-proxy") + ngx.say("http done: ", res.body) + end -ngx.thread.spawn(query_mysql) -- create thread 1 -ngx.thread.spawn(query_memcached) -- create thread 2 -ngx.thread.spawn(query_http) -- create thread 3 + ngx.thread.spawn(query_mysql) -- create thread 1 + ngx.thread.spawn(query_memcached) -- create thread 2 + ngx.thread.spawn(query_http) -- create thread 3 ``` This API was first enabled in the `v0.7.0` release. @@ -6409,30 +6466,30 @@ The following example demonstrates the use of `ngx.thread.wait` and [ngx.locatio ```lua -local capture = ngx.location.capture -local spawn = ngx.thread.spawn -local wait = ngx.thread.wait -local say = ngx.say + local capture = ngx.location.capture + local spawn = ngx.thread.spawn + local wait = ngx.thread.wait + local say = ngx.say -local function fetch(uri) - return capture(uri) -end + local function fetch(uri) + return capture(uri) + end -local threads = { - spawn(fetch, "/foo"), - spawn(fetch, "/bar"), - spawn(fetch, "/baz") -} + local threads = { + spawn(fetch, "/foo"), + spawn(fetch, "/bar"), + spawn(fetch, "/baz") + } -for i = 1, #threads do - local ok, res = wait(threads[i]) - if not ok then - say(i, ": failed to run: ", res) - else - say(i, ": status: ", res.status) - say(i, ": body: ", res.body) - end -end + for i = 1, #threads do + local ok, res = wait(threads[i]) + if not ok then + say(i, ": failed to run: ", res) + else + say(i, ": status: ", res.status) + say(i, ": body: ", res.body) + end + end ``` Here it essentially implements the "wait all" model. @@ -6441,44 +6498,44 @@ And below is an example demonstrating the "wait any" model: ```lua -function f() - ngx.sleep(0.2) - ngx.say("f: hello") - return "f done" -end + function f() + ngx.sleep(0.2) + ngx.say("f: hello") + return "f done" + end -function g() - ngx.sleep(0.1) - ngx.say("g: hello") - return "g done" -end + function g() + ngx.sleep(0.1) + ngx.say("g: hello") + return "g done" + end -local tf, err = ngx.thread.spawn(f) -if not tf then - ngx.say("failed to spawn thread f: ", err) - return -end + local tf, err = ngx.thread.spawn(f) + if not tf then + ngx.say("failed to spawn thread f: ", err) + return + end -ngx.say("f thread created: ", coroutine.status(tf)) + ngx.say("f thread created: ", coroutine.status(tf)) -local tg, err = ngx.thread.spawn(g) -if not tg then - ngx.say("failed to spawn thread g: ", err) - return -end + local tg, err = ngx.thread.spawn(g) + if not tg then + ngx.say("failed to spawn thread g: ", err) + return + end -ngx.say("g thread created: ", coroutine.status(tg)) + ngx.say("g thread created: ", coroutine.status(tg)) -ok, res = ngx.thread.wait(tf, tg) -if not ok then - ngx.say("failed to wait: ", res) - return -end + ok, res = ngx.thread.wait(tf, tg) + if not ok then + ngx.say("failed to wait: ", res) + return + end -ngx.say("res: ", res) + ngx.say("res: ", res) --- stop the "world", aborting other running threads -ngx.exit(ngx.OK) + -- stop the "world", aborting other running threads + ngx.exit(ngx.OK) ``` And it will generate the following output: @@ -6524,18 +6581,18 @@ The callback function can decide what to do with the client abortion event all b ```lua -local function my_cleanup() - -- custom cleanup work goes here, like cancelling a pending DB transaction + local function my_cleanup() + -- custom cleanup work goes here, like cancelling a pending DB transaction - -- now abort all the "light threads" running in the current request handler - ngx.exit(499) -end + -- now abort all the "light threads" running in the current request handler + ngx.exit(499) + end -local ok, err = ngx.on_abort(my_cleanup) -if not ok then - ngx.log(ngx.ERR, "failed to register the on_abort callback: ", err) - ngx.exit(500) -end + local ok, err = ngx.on_abort(my_cleanup) + if not ok then + ngx.log(ngx.ERR, "failed to register the on_abort callback: ", err) + ngx.exit(500) + end ``` When [lua_check_client_abort](#lua_check_client_abort) is set to `off` (which is the default), then this function call will always return the error message "lua_check_client_abort is off". @@ -6591,48 +6648,48 @@ Here is a simple example: ```nginx -location / { - ... - log_by_lua ' - local function push_data(premature, uri, args, status) - -- push the data uri, args, and status to the remote - -- via ngx.socket.tcp or ngx.socket.udp - -- (one may want to buffer the data in Lua a bit to - -- save I/O operations) - end - local ok, err = ngx.timer.at(0, push_data, - ngx.var.uri, ngx.var.args, ngx.header.status) - if not ok then - ngx.log(ngx.ERR, "failed to create timer: ", err) - return - end - '; -} + location / { + ... + log_by_lua ' + local function push_data(premature, uri, args, status) + -- push the data uri, args, and status to the remote + -- via ngx.socket.tcp or ngx.socket.udp + -- (one may want to buffer the data in Lua a bit to + -- save I/O operations) + end + local ok, err = ngx.timer.at(0, push_data, + ngx.var.uri, ngx.var.args, ngx.header.status) + if not ok then + ngx.log(ngx.ERR, "failed to create timer: ", err) + return + end + '; + } ``` One can also create infinite re-occuring timers, for instance, a timer getting triggered every `5` seconds, by calling `ngx.timer.at` recursively in the timer callback function. Here is such an example, ```lua -local delay = 5 -local handler -handler = function (premature) - -- do some routine job in Lua just like a cron job - if premature then - return - end - local ok, err = ngx.timer.at(delay, handler) - if not ok then - ngx.log(ngx.ERR, "failed to create the timer: ", err) - return - end -end + local delay = 5 + local handler + handler = function (premature) + -- do some routine job in Lua just like a cron job + if premature then + return + end + local ok, err = ngx.timer.at(delay, handler) + if not ok then + ngx.log(ngx.ERR, "failed to create the timer: ", err) + return + end + end -local ok, err = ngx.timer.at(delay, handler) -if not ok then - ngx.log(ngx.ERR, "failed to create the timer: ", err) - return -end + local ok, err = ngx.timer.at(delay, handler) + if not ok then + ngx.log(ngx.ERR, "failed to create the timer: ", err) + return + end ``` Because timer callbacks run in the background and their running time @@ -6792,8 +6849,8 @@ For instance, ```lua -local res = ndk.set_var.set_escape_uri('a/b'); --- now res == 'a%2fb' + local res = ndk.set_var.set_escape_uri('a/b'); + -- now res == 'a%2fb' ``` Similarly, the following directives provided by [encrypted-session-nginx-module](http://github.com/openresty/encrypted-session-nginx-module) can be invoked from within Lua too: diff --git a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki index 1446805..cfaa680 100644 --- a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.9.13] released on 21 November 2014. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.9.15] released on 18 February 2015. = Synopsis = @@ -148,10 +148,11 @@ This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/t } # use nginx var in code path - # WARN: contents in nginx var must be carefully filtered, + # WARNING: contents in nginx var must be carefully filtered, # otherwise there'll be great security risk! - location ~ ^/app/(.+) { - content_by_lua_file /path/to/lua/app/root/$1.lua; + location ~ ^/app/([-_a-zA-Z0-9/]+) { + set $path $1; + content_by_lua_file /path/to/lua/app/root/$path.lua; } location / { @@ -232,7 +233,7 @@ The Lua state (Lua VM instance) is shared across all the requests handled by a s = Nginx Compatibility = The latest module is compatible with the following versions of Nginx: -* 1.7.x (last tested: 1.7.7) +* 1.7.x (last tested: 1.7.10) * 1.6.x * 1.5.x (last tested: 1.5.12) * 1.4.x (last tested: 1.4.4) @@ -245,7 +246,7 @@ The latest module is compatible with the following versions of Nginx: = Installation = -The [http://openresty.org ngx_openresty bundle] can be used to install Nginx, ngx_lua, either one of the standard Lua 5.1 interpreter or LuaJIT 2.0/2.1, as well as a package of powerful companion Nginx modules. The basic installation step is a simple ./configure --with-luajit && make && make install. +It is highly recommended to use the [http://openresty.org ngx_openresty bundle] that bundles Nginx, ngx_lua, LuaJIT 2.0/2.1 (or the optional standard Lua 5.1 interpreter), as well as a package of powerful companion Nginx modules. The basic installation step is a simple command: ./configure --with-luajit && make && make install. Alternatively, ngx_lua can be manually compiled into Nginx: @@ -257,9 +258,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.7.7.tar.gz' - tar -xzvf nginx-1.7.7.tar.gz - cd nginx-1.7.7/ + wget 'http://nginx.org/download/nginx-1.7.10.tar.gz' + tar -xzvf nginx-1.7.10.tar.gz + cd nginx-1.7.10/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib @@ -275,6 +276,7 @@ Build the source with this module: # Here we assume Nginx is to be installed under /opt/nginx/. ./configure --prefix=/opt/nginx \ + --with-ld-opt='-Wl,-rpath,/path/to/luajit-or-lua/lib" \ --add-module=/path/to/ngx_devel_kit \ --add-module=/path/to/lua-nginx-module @@ -599,7 +601,7 @@ The [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_m will not work as expected. -== Cocockets Not Available Everywhere == +== Cosockets Not Available Everywhere == Due the internal limitations in the nginx core, the cosocket API are disabled in the following contexts: [[#set_by_lua|set_by_lua*]], [[#log_by_lua|log_by_lua*]], [[#header_filter_by_lua|header_filter_by_lua*]], and [[#body_filter_by_lua|body_filter_by_lua]]. @@ -700,15 +702,56 @@ Certain Lua APIs provided by ngx_lua do not work in Nginx's SPDY mode yet: [[#ng = TODO = -== Short Term == +* add *_by_lua_block directives for existing *_by_lua directives so that we put literal Lua code directly in curly braces instead of an nginx literal string. For example, + + content_by_lua_block { + ngx.say("hello, world\r\n") + } + +: which is equivalent to + + content_by_lua ' + ngx.say("hello, world\\r\\n") + '; + +: but the former is much cleaner and nicer. +* cosocket: implement LuaSocket's unconnected UDP API. +* add support for implementing general TCP servers instead of HTTP servers in Lua. For example, + + tcp { + server { + listen 11212; + handler_by_lua ' + -- custom Lua code implementing the special TCP server... + '; + } + } + +* add support for implementing general UDP servers instead of HTTP servers in Lua. For example, + + udp { + server { + listen 1953; + handler_by_lua ' + -- custom Lua code implementing the special UDP server... + '; + } + } + +* ssl: implement directives ssl_certificate_by_lua and ssl_certificate_by_lua_file to allow using Lua to dynamically serve SSL certificates and keys for downstream SSL handshake. (already done in CloudFlare's private branch and powering CloudFlare's SSL gateway of its global network. expected to be opensourced in March 2015.) +* shm: implement a "shared queue API" to complement the existing [[#lua_shared_dict|shared dict]] API. +* cosocket: add support in the context of [[#init_by_lua|init_by_lua*]]. +* cosocket: implement the bind() method for stream-typed cosockets. +* cosocket: pool-based backend concurrency level control: implement automatic connect queueing when the backend concurrency exceeds its connection pool limit. +* cosocket: review and merge aviramc's [https://github.com/openresty/lua-nginx-module/pull/290 patch] for adding the bsdrecv method. +* add new API function ngx.resp.add_header to emulate the standard add_header config directive. +* [[#ngx.re.match|ngx.re]] API: use false instead of nil in the resulting match table to indicate non-existent submatch captures, such that we can avoid "holes" in the array table. * review and apply Jader H. Silva's patch for ngx.re.split(). * review and apply vadim-pavlov's patch for [[#ngx.location.capture|ngx.location.capture]]'s extra_headers option * use ngx_hash_t to optimize the built-in header look-up process for [[#ngx.req.set_header|ngx.req.set_header]], [[#ngx.header.HEADER|ngx.header.HEADER]], and etc. * add configure options for different strategies of handling the cosocket connection exceeding in the pools. * add directives to run Lua codes when nginx stops. * add ignore_resp_headers, ignore_resp_body, and ignore_resp options to [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] methods, to allow micro performance tuning on the user side. - -== Longer Term == * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add stat mode similar to [https://httpd.apache.org/docs/trunk/mod/mod_lua.html mod_lua]. @@ -777,9 +820,9 @@ There are also various testing modes based on mockeagain, valgrind, and etc. Ref This module is licensed under the BSD license. -Copyright (C) 2009-2014, by Xiaozhe Wang (chaoslawful) . +Copyright (C) 2009-2015, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2014, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +Copyright (C) 2009-2015, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. All rights reserved. @@ -1164,6 +1207,19 @@ and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [[#lua_code_cache|lua_code_cache]] off in nginx.conf to avoid reloading Nginx. +Nginx variables are supported in the file path for dynamic dispatch, for example: + + + # WARNING: contents in nginx var must be carefully filtered, + # otherwise there'll be great security risk! + location ~ ^/app/([-_a-zA-Z0-9/]+) { + set $path $1; + content_by_lua_file /path/to/lua/app/root/$path.lua; + } + + +But be very careful about malicious user inputs and always carefully validate or filter out the user-supplied path components. + == rewrite_by_lua == '''syntax:''' ''rewrite_by_lua '' @@ -1297,6 +1353,8 @@ When the Lua code cache is turned on (by default), the user code is loaded once The rewrite_by_lua_file code will always run at the end of the rewrite request-processing phase unless [[#rewrite_by_lua_no_postpone|rewrite_by_lua_no_postpone]] is turned on. +Nginx variables are supported in the file path for dynamic dispatch just as in [[#content_by_lua_file|content_by_lua_file]]. + == access_by_lua == '''syntax:''' ''access_by_lua '' @@ -1382,6 +1440,8 @@ When the Lua code cache is turned on (by default), the user code is loaded once and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [[#lua_code_cache|lua_code_cache]] off in nginx.conf to avoid repeatedly reloading Nginx. +Nginx variables are supported in the file path for dynamic dispatch just as in [[#content_by_lua_file|content_by_lua_file]]. + == header_filter_by_lua == '''syntax:''' ''header_filter_by_lua '' @@ -2027,7 +2087,7 @@ For example: That is, nginx variables cannot be created on-the-fly. Some special nginx variables like $args and $limit_rate can be assigned a value, -some are not, like $arg_PARAMETER. +many others are not, like $query_string, $arg_PARAMETER, and $http_NAME. Nginx regex group capturing variables $1, $2, $3, and etc, can be read by this interface as well, by writing ngx.var[1], ngx.var[2], ngx.var[3], and etc. @@ -2320,7 +2380,7 @@ argument, which supports the options: * copy_all_vars : specify whether to copy over all the Nginx variable values of the current request to the subrequest in question. modifications of the nginx variables in the subrequest will not affect the current (parent) request. This option was first introduced in the v0.3.1rc31 release. * share_all_vars -: specify whether to share all the Nginx variables of the subrequest with the current (parent) request. modifications of the Nginx variables in the subrequest will affect the current (parent) request. +: specify whether to share all the Nginx variables of the subrequest with the current (parent) request. modifications of the Nginx variables in the subrequest will affect the current (parent) request. Enabling this option may lead to hard-to-debug issues due to bad side-effects and is considered bad and harmful. Only enable this option when you completely know what you are doing. * always_forward_body : when set to true, the current (parent) request's request body will always be forwarded to the subrequest being created if the body option is not specified. The request body read by either [[#ngx.req.read_body|ngx.req.read_body()]] or [[#lua_need_request_body|lua_need_request_body on]] will be directly forwarded to the subrequest without copying the whole request body data when creating the subrequest (no matter the request body data is buffered in memory buffers or temporary files). By default, this option is false and when the body option is not specified, the request body of the current (parent) request is only forwarded when the subrequest takes the PUT or POST request method. @@ -3180,7 +3240,7 @@ Set the current request's request header named header_name to value By default, all the subrequests subsequently initiated by [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] will inherit the new header. -Here is an example of setting the Content-Length header: +Here is an example of setting the Content-Type header: ngx.req.set_header("Content-Type", "text/css") diff --git a/debian/modules/nginx-lua/misc/recv-until-pm/Makefile b/debian/modules/nginx-lua/misc/recv-until-pm/Makefile deleted file mode 100644 index eb4d937..0000000 --- a/debian/modules/nginx-lua/misc/recv-until-pm/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -test: - prove -Ilib -r t - diff --git a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h index 814754b..3700c1f 100644 --- a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 9013 +#define ngx_http_lua_version 9015 typedef struct { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_common.h b/debian/modules/nginx-lua/src/ngx_http_lua_common.h index 6111b3f..ff1c0bc 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_common.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_common.h @@ -287,9 +287,6 @@ struct ngx_http_lua_co_ctx_s { ngx_http_cleanup_pt cleanup; - unsigned nsubreqs; /* number of subrequests of the - * current request */ - ngx_int_t *sr_statuses; /* all capture subrequest statuses */ ngx_http_headers_out_t **sr_headers; @@ -298,6 +295,9 @@ struct ngx_http_lua_co_ctx_s { uint8_t *sr_flags; + unsigned nsubreqs; /* number of subrequests of the + * current request */ + unsigned pending_subreqs; /* number of subrequests being waited */ @@ -365,8 +365,6 @@ typedef struct ngx_http_lua_ctx_s { unsigned flushing_coros; /* number of coroutines waiting on ngx.flush(true) */ - int uthreads; /* number of active user threads */ - ngx_chain_t *out; /* buffered output chain for HTTP 1.0 */ ngx_chain_t *free_bufs; ngx_chain_t *busy_bufs; @@ -393,6 +391,8 @@ typedef struct ngx_http_lua_ctx_s { ngx_http_lua_posted_thread_t *posted_threads; + int uthreads; /* number of active user threads */ + uint16_t context; /* the current running directive context (or running phase) for the current Lua chunk */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_control.c b/debian/modules/nginx-lua/src/ngx_http_lua_control.c index f164b0b..95a8227 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_control.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_control.c @@ -195,6 +195,7 @@ ngx_http_lua_ngx_redirect(lua_State *L) u_char *p; u_char *uri; size_t len; + ngx_table_elt_t *h; ngx_http_request_t *r; n = lua_gettop(L); @@ -246,23 +247,23 @@ ngx_http_lua_ngx_redirect(lua_State *L) ngx_memcpy(uri, p, len); - r->headers_out.location = ngx_list_push(&r->headers_out.headers); - if (r->headers_out.location == NULL) { + h = ngx_list_push(&r->headers_out.headers); + if (h == NULL) { return luaL_error(L, "no memory"); } - r->headers_out.location->hash = ngx_http_lua_location_hash; + h->hash = ngx_http_lua_location_hash; #if 0 dd("location hash: %lu == %lu", - (unsigned long) r->headers_out.location->hash, + (unsigned long) h->hash, (unsigned long) ngx_hash_key_lc((u_char *) "Location", sizeof("Location") - 1)); #endif - r->headers_out.location->value.len = len; - r->headers_out.location->value.data = uri; - ngx_str_set(&r->headers_out.location->key, "Location"); + h->value.len = len; + h->value.data = uri; + ngx_str_set(&h->key, "Location"); r->headers_out.status = rc; @@ -271,7 +272,16 @@ ngx_http_lua_ngx_redirect(lua_State *L) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua redirect to \"%V\" with code %i", - &r->headers_out.location->value, ctx->exit_code); + &h->value, ctx->exit_code); + + if (len && uri[0] != '/') { + r->headers_out.location = h; + } + + /* + * we do not set r->headers_out.location here to avoid the handling + * the local redirects without a host name by ngx_http_header_filter() + */ return lua_yield(L, 0); } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c b/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c index c54f54c..79bac65 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c @@ -28,10 +28,6 @@ static ngx_http_output_header_filter_pt ngx_http_next_header_filter; -/* light user data key for the "ngx" table in the Lua VM regsitry */ -static char ngx_http_lua_headerfilterby_ngx_key; - - /** * Set environment table for the given code closure. * @@ -64,12 +60,6 @@ ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r) * */ ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); - /* {{{ initialize ngx.* namespace */ - lua_pushlightuserdata(L, &ngx_http_lua_headerfilterby_ngx_key); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setfield(L, -2, "ngx"); - /* }}} */ - /* {{{ make new env inheriting main thread's globals table */ lua_createtable(L, 0, 1 /* nrec */); /* the metatable for the new env */ ngx_http_lua_get_globals_table(L); @@ -141,6 +131,11 @@ ngx_http_lua_header_filter_by_chunk(lua_State *L, ngx_http_request_t *r) dd("exited: %d, exit code: %d, old exit code: %d", (int) ctx->exited, (int) ctx->exit_code, (int) old_exit_code); +#if 1 + /* clear Lua stack */ + lua_settop(L, 0); +#endif + if (ctx->exited && ctx->exit_code != old_exit_code) { if (ctx->exit_code == NGX_ERROR) { return NGX_ERROR; @@ -157,9 +152,6 @@ ngx_http_lua_header_filter_by_chunk(lua_State *L, ngx_http_request_t *r) return NGX_DECLINED; } - /* clear Lua stack */ - lua_settop(L, 0); - return NGX_OK; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c b/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c index 862c444..5039c27 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c @@ -38,6 +38,8 @@ static ngx_int_t ngx_http_clear_last_modified_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_clear_content_length_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_set_location_header(ngx_http_request_t *r, + ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { @@ -58,7 +60,7 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { { ngx_string("Location"), offsetof(ngx_http_headers_out_t, location), - ngx_http_set_builtin_header }, + ngx_http_set_location_header }, { ngx_string("Refresh"), offsetof(ngx_http_headers_out_t, refresh), @@ -237,6 +239,32 @@ new_header: } +static ngx_int_t +ngx_http_set_location_header(ngx_http_request_t *r, + ngx_http_lua_header_val_t *hv, ngx_str_t *value) +{ + ngx_int_t rc; + ngx_table_elt_t *h; + + rc = ngx_http_set_builtin_header(r, hv, value); + if (rc != NGX_OK) { + return rc; + } + + /* + * we do not set r->headers_out.location here to avoid the handling + * the local redirects without a host name by ngx_http_header_filter() + */ + + h = r->headers_out.location; + if (h && h->value.len && h->value.data[0] == '/') { + r->headers_out.location = NULL; + } + + return NGX_OK; +} + + static ngx_int_t ngx_http_set_builtin_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value) diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c b/debian/modules/nginx-lua/src/ngx_http_lua_regex.c index 36b44f2..fd2d017 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_regex.c @@ -1850,11 +1850,12 @@ exec: } else { if (offset < (int) subj.len) { - dd("adding trailer: %s (len %d)", &subj.data[offset], - (int) (subj.len - offset)); + dd("adding trailer: %s (len %d)", &subj.data[cp_offset], + (int) (subj.len - cp_offset)); - luaL_addlstring(&luabuf, (char *) &subj.data[offset], - subj.len - offset); + + luaL_addlstring(&luabuf, (char *) &subj.data[cp_offset], + subj.len - cp_offset); } luaL_pushresult(&luabuf); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c b/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c index 377f9ce..8c666f7 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c @@ -481,7 +481,7 @@ ngx_http_lua_shdict_get_helper(lua_State *L, int get_stale) (unsigned long) value.len); } - num = *(double *) value.data; + ngx_memcpy(&num, value.data, sizeof(double)); lua_pushnumber(L, num); break; @@ -1220,7 +1220,7 @@ ngx_http_lua_shdict_incr(lua_State *L) p = sd->data + key.len; - num = *(double *) p; + ngx_memcpy(&num, p, sizeof(double)); num += value; ngx_memcpy(p, (double *) &num, sizeof(double)); @@ -1711,7 +1711,7 @@ ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, } *str_value_len = value.len; - *num_value = *(double *) value.data; + ngx_memcpy(num_value, value.data, sizeof(double)); break; case LUA_TBOOLEAN: @@ -1801,7 +1801,7 @@ ngx_http_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, p = sd->data + key_len; - num = *(double *) p; + ngx_memcpy(&num, p, sizeof(double)); num += *value; ngx_memcpy(p, (double *) &num, sizeof(double)); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c index b0bf4fa..e825308 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c @@ -4335,7 +4335,8 @@ ngx_http_lua_socket_tcp_getreusedtimes(lua_State *L) } -static int ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) +static int +ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) { ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_socket_tcp_upstream_t *u; @@ -4380,12 +4381,18 @@ static int ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) u = lua_touserdata(L, -1); lua_pop(L, 1); + if (u == NULL) { + lua_pushnil(L); + lua_pushliteral(L, "closed"); + return 2; + } + /* stack: obj cache key */ pc = &u->peer; c = pc->connection; - if (u == NULL || pc == NULL || u->read_closed || u->write_closed) { + if (c == NULL || u->read_closed || u->write_closed) { lua_pushnil(L); lua_pushliteral(L, "closed"); return 2; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_string.c b/debian/modules/nginx-lua/src/ngx_http_lua_string.c index e0f117c..52877bb 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_string.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_string.c @@ -238,7 +238,7 @@ ngx_http_lua_ngx_escape_sql_str(u_char *dst, u_char *src, size_t size) case '\n': case '\r': case '\t': - case 26: /* \z */ + case 26: /* \Z */ case '\\': case '\'': case '"': @@ -285,7 +285,7 @@ ngx_http_lua_ngx_escape_sql_str(u_char *dst, u_char *src, size_t size) case 26: *dst++ = '\\'; - *dst++ = 'z'; + *dst++ = 'Z'; break; case '\\': diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c index 6dda007..c0d66d6 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c @@ -17,15 +17,17 @@ typedef struct { - unsigned premature; /* :1 */ - - int co_ref; - lua_State *co; - void **main_conf; void **srv_conf; void **loc_conf; + /* event ident must be after 3 words (i.e. 3 pointers' size) as in + * ngx_connection_t. and we use the Lua coroutine reference number as + * the event ident */ + int co_ref; + unsigned premature; /* :1 */ + lua_State *co; + ngx_pool_t *pool; ngx_listening_t *listening; @@ -37,11 +39,6 @@ typedef struct { } ngx_http_lua_timer_ctx_t; -typedef struct { - ngx_connection_t *connection; -} ngx_http_lua_timer_log_ctx_t; - - static int ngx_http_lua_ngx_timer_at(lua_State *L); static void ngx_http_lua_timer_handler(ngx_event_t *ev); static u_char * ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, @@ -69,7 +66,7 @@ ngx_http_lua_ngx_timer_at(lua_State *L) lua_State *vm; /* the main thread */ lua_State *co; ngx_msec_t delay; - ngx_event_t *ev; + ngx_event_t *ev = NULL; ngx_http_request_t *r; ngx_connection_t *saved_c = NULL; ngx_http_lua_ctx_t *ctx; @@ -283,6 +280,10 @@ nomem: ngx_destroy_pool(tctx->pool); } + if (ev) { + ngx_free(ev); + } + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, co_ref); @@ -306,7 +307,6 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) ngx_http_lua_timer_ctx_t tctx; ngx_http_lua_main_conf_t *lmcf; ngx_http_core_loc_conf_t *clcf; - ngx_http_lua_timer_log_ctx_t *logctx; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua ngx.timer expired"); @@ -331,15 +331,8 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) goto failed; } - logctx = ngx_palloc(c->pool, sizeof(ngx_http_lua_timer_log_ctx_t)); - if (logctx == NULL) { - goto failed; - } - - logctx->connection = c; - c->log->handler = ngx_http_lua_log_timer_error; - c->log->data = logctx; + c->log->data = c; c->listening = tctx.listening; c->addr_text = tctx.client_addr_text; @@ -476,24 +469,20 @@ ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, size_t len) u_char *p; ngx_connection_t *c; - ngx_http_lua_timer_log_ctx_t *ctx; - if (log->action) { p = ngx_snprintf(buf, len, " while %s", log->action); len -= p - buf; buf = p; } - ctx = log->data; + c = log->data; - dd("ctx = %p", ctx); + dd("ctx = %p", c); p = ngx_snprintf(buf, len, ", context: ngx.timer"); len -= p - buf; buf = p; - c = ctx->connection; - if (c->addr_text.len) { p = ngx_snprintf(buf, len, ", client: %V", &c->addr_text); len -= p - buf; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.c b/debian/modules/nginx-lua/src/ngx_http_lua_util.c index d1b59b2..879608b 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_util.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_util.c @@ -81,7 +81,7 @@ ngx_uint_t ngx_http_lua_content_length_hash = 0; static ngx_int_t ngx_http_lua_send_http10_headers(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); static void ngx_http_lua_init_registry(lua_State *L, ngx_log_t *log); -static void ngx_http_lua_init_globals(lua_State *L, +static void ngx_http_lua_init_globals(lua_State *L, ngx_cycle_t *cycle, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log); static void ngx_http_lua_set_path(ngx_cycle_t *cycle, lua_State *L, int tab_idx, const char *fieldname, const char *path, const char *default_path, @@ -294,7 +294,7 @@ ngx_http_lua_new_state(lua_State *parent_vm, ngx_cycle_t *cycle, lua_pop(L, 1); /* remove the "package" table */ ngx_http_lua_init_registry(L, log); - ngx_http_lua_init_globals(L, lmcf, log); + ngx_http_lua_init_globals(L, cycle, lmcf, log); return L; } @@ -683,12 +683,15 @@ ngx_http_lua_init_registry(lua_State *L, ngx_log_t *log) static void -ngx_http_lua_init_globals(lua_State *L, ngx_http_lua_main_conf_t *lmcf, - ngx_log_t *log) +ngx_http_lua_init_globals(lua_State *L, ngx_cycle_t *cycle, + ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "lua initializing lua globals"); + lua_pushlightuserdata(L, cycle); + lua_setglobal(L, "__ngx_cycle"); + #if defined(NDK) && NDK ngx_http_lua_inject_ndk_api(L); #endif /* defined(NDK) && NDK */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.h b/debian/modules/nginx-lua/src/ngx_http_lua_util.h index 163395e..3dfb819 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_util.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_util.h @@ -20,6 +20,7 @@ #ifndef NGX_LUA_NO_FFI_API typedef struct { int len; + /* this padding hole on 64-bit systems is expected */ u_char *data; } ngx_http_lua_ffi_str_t; diff --git a/debian/modules/nginx-lua/t/014-bugs.t b/debian/modules/nginx-lua/t/014-bugs.t index e5fa86f..1042b29 100644 --- a/debian/modules/nginx-lua/t/014-bugs.t +++ b/debian/modules/nginx-lua/t/014-bugs.t @@ -773,7 +773,7 @@ See more details here: http://mailman.nginx.org/pipermail/nginx-devel/2013-Janua location /t { set $myserver nginx.org; proxy_pass http://$myserver/; - resolver 127.0.0.1; + resolver 127.0.0.1:6789; } --- request GET /t diff --git a/debian/modules/nginx-lua/t/016-resp-header.t b/debian/modules/nginx-lua/t/016-resp-header.t index df1ffa5..f119fb9 100644 --- a/debian/modules/nginx-lua/t/016-resp-header.t +++ b/debian/modules/nginx-lua/t/016-resp-header.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 24); +plan tests => repeat_each() * (blocks() * 3 + 26); #no_diff(); no_long_string(); @@ -1346,3 +1346,41 @@ hi --- error_log my Transfer-Encoding: nil + + +=== TEST 65: set Location (no host) +--- config + location = /t { + content_by_lua ' + ngx.header.location = "/foo/bar" + return ngx.exit(301) + '; + } +--- request +GET /t +--- response_headers +Location: /foo/bar +--- response_body_like: 301 Moved Permanently +--- error_code: 301 +--- no_error_log +[error] + + + +=== TEST 66: set Location (with host) +--- config + location = /t { + content_by_lua ' + ngx.header.location = "http://test.com/foo/bar" + return ngx.exit(301) + '; + } +--- request +GET /t +--- response_headers +Location: http://test.com/foo/bar +--- response_body_like: 301 Moved Permanently +--- error_code: 301 +--- no_error_log +[error] + diff --git a/debian/modules/nginx-lua/t/022-redirect.t b/debian/modules/nginx-lua/t/022-redirect.t index 6132f42..1f874ec 100644 --- a/debian/modules/nginx-lua/t/022-redirect.t +++ b/debian/modules/nginx-lua/t/022-redirect.t @@ -121,7 +121,7 @@ GET /read } --- request GET /read ---- raw_response_headers_like: Location: http://localhost(?::\d+)?/echo\r\n +--- raw_response_headers_like: Location: /echo\r\n --- response_body_like: 302 Found --- error_code: 302 diff --git a/debian/modules/nginx-lua/t/023-rewrite/redirect.t b/debian/modules/nginx-lua/t/023-rewrite/redirect.t index 3b93eee..e4a46cc 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/redirect.t +++ b/debian/modules/nginx-lua/t/023-rewrite/redirect.t @@ -120,7 +120,7 @@ GET /read } --- request GET /read ---- raw_response_headers_like: Location: http://localhost(?::\d+)?/foo\r\n +--- raw_response_headers_like: Location: /foo\r\n --- response_body_like: 302 Found --- error_code: 302 diff --git a/debian/modules/nginx-lua/t/024-access/auth.t b/debian/modules/nginx-lua/t/024-access/auth.t index 4b48afc..4b7927c 100644 --- a/debian/modules/nginx-lua/t/024-access/auth.t +++ b/debian/modules/nginx-lua/t/024-access/auth.t @@ -76,7 +76,7 @@ POST /lua He fucks himself! --- response_body_like: 302 Found --- response_headers_like -Location: http://[^:]+:\d+/terms_of_use\.html +Location: /terms_of_use\.html --- error_code: 302 diff --git a/debian/modules/nginx-lua/t/024-access/redirect.t b/debian/modules/nginx-lua/t/024-access/redirect.t index 0704c9a..b8c3519 100644 --- a/debian/modules/nginx-lua/t/024-access/redirect.t +++ b/debian/modules/nginx-lua/t/024-access/redirect.t @@ -120,7 +120,7 @@ GET /read } --- request GET /read ---- raw_response_headers_like: Location: http://localhost(?::\d+)?/foo\r\n +--- raw_response_headers_like: Location: /foo\r\n --- response_body_like: 302 Found --- error_code: 302 diff --git a/debian/modules/nginx-lua/t/036-sub.t b/debian/modules/nginx-lua/t/036-sub.t index 27ecd92..ad8638c 100644 --- a/debian/modules/nginx-lua/t/036-sub.t +++ b/debian/modules/nginx-lua/t/036-sub.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 15); +plan tests => repeat_each() * (blocks() * 2 + 18); #no_diff(); no_long_string(); @@ -651,3 +651,85 @@ ngx.say("sub: ", cnt) --- response_body sub: 0 + + +=== TEST 30: bug: sub incorrectly swallowed a character is the first character +Original bad result: estCase +--- config + location /re { + content_by_lua ' + local s, n = ngx.re.sub("TestCase", "^ *", "", "o") + if s then + ngx.say(s) + end + '; + } +--- request + GET /re +--- response_body +TestCase + + + +=== TEST 31: bug: sub incorrectly swallowed a character is not the first character +Original bad result: .b.d +--- config + location /re { + content_by_lua ' + local s, n = ngx.re.sub("abcd", "(?=c)", ".") + if s then + ngx.say(s) + end + '; + } +--- request + GET /re +--- response_body +ab.cd + + + +=== TEST 32: ngx.re.gsub: recursive calling (github #445) +--- config + +location = /t { + content_by_lua ' + function test() + local data = [[ + OUTER {FIRST} +]] + + local p1 = "(OUTER)(.+)" + local p2 = "{([A-Z]+)}" + + ngx.print(data) + + local res = ngx.re.gsub(data, p1, function(m) + -- ngx.say("pre: m[1]: [", m[1], "]") + -- ngx.say("pre: m[2]: [", m[2], "]") + + local res = ngx.re.gsub(m[2], p2, function(_) + return "REPLACED" + end, "") + + -- ngx.say("post: m[1]: [", m[1], "]") + -- ngx.say("post m[2]: [", m[2], "]") + return m[1] .. res + end, "") + + ngx.print(res) + end + + test() + '; +} +--- request +GET /t +--- response_body + OUTER {FIRST} + OUTER REPLACED +--- no_error_log +[error] +bad argument type +NYI + diff --git a/debian/modules/nginx-lua/t/037-gsub.t b/debian/modules/nginx-lua/t/037-gsub.t index b50edd2..fb4a706 100644 --- a/debian/modules/nginx-lua/t/037-gsub.t +++ b/debian/modules/nginx-lua/t/037-gsub.t @@ -9,7 +9,7 @@ log_level('warn'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 14); +plan tests => repeat_each() * (blocks() * 2 + 16); #no_diff(); no_long_string(); @@ -573,3 +573,105 @@ ngx.say("gsub: ", cnt) gsub: 0 --- timeout: 10 + + +=== TEST 25: bug: gsub incorrectly swallowed a character is the first character +Original bad result: estCase +--- config + location /re { + content_by_lua ' + local s, n = ngx.re.gsub("TestCase", "^ *", "", "o") + if s then + ngx.say(s) + end + '; + } +--- request + GET /re +--- response_body +TestCase + + + +=== TEST 26: bug: gsub incorrectly swallowed a character is not the first character +Original bad result: .b.d +--- config + location /re { + content_by_lua ' + local s, n = ngx.re.gsub("abcd", "a|(?=c)", ".") + if s then + ngx.say(s) + end + '; + } +--- request + GET /re +--- response_body +.b.cd + + + +=== TEST 27: use of ngx.req.get_headers in the user callback +--- config + +location = /t { + content_by_lua ' + local data = [[ + INNER + INNER +]] + + -- ngx.say(data) + + local res = ngx.re.gsub(data, "INNER", function(inner_matches) + local header = ngx.req.get_headers()["Host"] + -- local header = ngx.var["http_HEADER"] + return "INNER_REPLACED" + end, "s") + + ngx.print(res) + '; +} + +--- request +GET /t +--- response_body + INNER_REPLACED + INNER_REPLACED + +--- no_error_log +[error] + + + +=== TEST 28: use of ngx.var in the user callback +--- config + +location = /t { + content_by_lua ' + local data = [[ + INNER + INNER +]] + + -- ngx.say(data) + + local res = ngx.re.gsub(data, "INNER", function(inner_matches) + -- local header = ngx.req.get_headers()["Host"] + local header = ngx.var["http_HEADER"] + return "INNER_REPLACED" + end, "s") + + ngx.print(res) + '; +} + +--- request +GET /t +--- response_body + INNER_REPLACED + INNER_REPLACED + +--- no_error_log +[error] + diff --git a/debian/modules/nginx-lua/t/041-header-filter.t b/debian/modules/nginx-lua/t/041-header-filter.t index b81d5af..c3d495c 100644 --- a/debian/modules/nginx-lua/t/041-header-filter.t +++ b/debian/modules/nginx-lua/t/041-header-filter.t @@ -11,7 +11,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * 91; +plan tests => repeat_each() * 94; #no_diff(); #no_long_string(); @@ -767,3 +767,28 @@ GET /lua?a=1&b=2 --- error_log eval qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ + + +=== TEST 41: filter finalize +--- config + error_page 582 = /bar; + location = /t { + echo ok; + header_filter_by_lua ' + return ngx.exit(582) + '; + } + + location = /bar { + echo hi; + header_filter_by_lua ' + return ngx.exit(302) + '; + } +--- request +GET /t +--- response_body_like: 302 Found +--- error_code: 302 +--- no_error_log +[error] + diff --git a/debian/modules/nginx-lua/t/058-tcp-socket.t b/debian/modules/nginx-lua/t/058-tcp-socket.t index 8e764cf..a4e6a56 100644 --- a/debian/modules/nginx-lua/t/058-tcp-socket.t +++ b/debian/modules/nginx-lua/t/058-tcp-socket.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 172; +plan tests => repeat_each() * 175; our $HtmlDir = html_dir; @@ -3300,3 +3300,47 @@ close: 1 nil --- no_error_log [error] + + +=== TEST 55: kill a thread with a connecting socket +--- config + server_tokens off; + lua_socket_connect_timeout 1s; + resolver $TEST_NGINX_RESOLVER; + resolver_timeout 3s; + location /t { + content_by_lua ' + local sock + + local thr = ngx.thread.spawn(function () + sock = ngx.socket.tcp() + local ok, err = sock:connect("agentzh.org", 12345) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + end) + + ngx.sleep(0.002) + ngx.thread.kill(thr) + ngx.sleep(0.001) + + local ok, err = sock:setkeepalive() + if not ok then + ngx.say("failed to setkeepalive: ", err) + else + ngx.say("setkeepalive: ", ok) + end + '; + } + +--- request +GET /t +--- response_body +failed to setkeepalive: closed +--- error_log +lua tcp socket connect timeout: 100 +--- timeout: 10 + diff --git a/debian/modules/nginx-lua/t/115-quote-sql-str.t b/debian/modules/nginx-lua/t/115-quote-sql-str.t index 7c6785e..e473b21 100644 --- a/debian/modules/nginx-lua/t/115-quote-sql-str.t +++ b/debian/modules/nginx-lua/t/115-quote-sql-str.t @@ -62,7 +62,7 @@ GET /set -=== TEST 4: \z +=== TEST 4: \Z --- config location = /set { content_by_lua ' @@ -72,7 +72,7 @@ GET /set --- request GET /set --- response_body -'a\zb\z' +'a\Zb\Z' --- no_error_log [error] diff --git a/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t b/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t index 3853515..571bdc8 100644 --- a/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t +++ b/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t @@ -469,7 +469,7 @@ receive: nil closed send: nil closed close: nil closed getreusedtimes: nil closed -setkeepalive: nil socket busy connecting +setkeepalive: nil closed connect: nil socket busy connecting connect: nil some2.agentzh.org could not be resolved (110: Operation timed out) close: nil closed diff --git a/debian/modules/nginx-lua/t/130-internal-api.t b/debian/modules/nginx-lua/t/130-internal-api.t new file mode 100644 index 0000000..c40bf13 --- /dev/null +++ b/debian/modules/nginx-lua/t/130-internal-api.t @@ -0,0 +1,50 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_process_enabled(1); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * 3; + +#no_diff(); +no_long_string(); +#master_on(); +#workers(2); + +run_tests(); + +__DATA__ + +=== TEST 1: __ngx_req and __ngx_cycle +--- http_config + init_by_lua ' + my_cycle = __ngx_cycle + '; + +--- config + location = /t { + content_by_lua ' + local ffi = require "ffi" + local function tonum(ud) + return tonumber(ffi.cast("uintptr_t", ud)) + end + ngx.say(string.format("init: cycle=%#x", tonum(my_cycle))) + ngx.say(string.format("content cycle=%#x", tonum(__ngx_cycle))) + ngx.say(string.format("content req=%#x", tonum(__ngx_req))) + '; + } +--- request +GET /t + +--- response_body_like chop +^init: cycle=(0x[a-f0-9]{4,}) +content cycle=\1 +content req=0x[a-f0-9]{4,} +$ +--- no_error_log +[error] + diff --git a/debian/modules/nginx-lua/util/reindex b/debian/modules/nginx-lua/util/reindex deleted file mode 100755 index bd54c9d..0000000 --- a/debian/modules/nginx-lua/util/reindex +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/perl -#: reindex.pl -#: reindex .t files for Test::Base based test files -#: Copyright (c) 2006 Agent Zhang -#: 2006-04-27 2006-05-09 - -use strict; -use warnings; - -#use File::Copy; -use Getopt::Std; - -my %opts; -getopts('hb:', \%opts); -if ($opts{h} or ! @ARGV) { - die "Usage: reindex [-b 0] t/*.t\n"; -} - -my $init = $opts{b}; -$init = 1 if not defined $init; - -my @files = map glob, @ARGV; -for my $file (@files) { - next if -d $file or $file !~ /\.t_?$/; - reindex($file); -} - -sub reindex { - my $file = $_[0]; - open my $in, $file or - die "Can't open $file for reading: $!"; - my @lines; - my $counter = $init; - my $changed; - while (<$in>) { - s/\r$//; - my $num; - s/ ^ === \s+ TEST \s+ (\d+)/$num=$1; "=== TEST " . $counter++/xie; - next if !defined $num; - if ($num != $counter-1) { - $changed++; - } - } continue { - push @lines, $_; - } - close $in; - my $text = join '', @lines; - $text =~ s/(?x) \n+ === \s+ TEST/\n\n\n\n=== TEST/ixsg; - $text =~ s/__(DATA|END)__\n+=== TEST/__${1}__\n\n=== TEST/; - #$text =~ s/\n+$/\n\n/s; - if (! $changed and $text eq join '', @lines) { - warn "reindex: $file:\tskipped.\n"; - return; - } - #File::Copy::copy( $file, "$file.bak" ); - open my $out, "> $file" or - die "Can't open $file for writing: $!"; - binmode $out; - print $out $text; - close $out; - - warn "reindex: $file:\tdone.\n"; -} - diff --git a/debian/modules/nginx-lua/util/releng b/debian/modules/nginx-lua/util/releng deleted file mode 100755 index adc2f4d..0000000 --- a/debian/modules/nginx-lua/util/releng +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -./update-readme -ack '(?<=\#define)\s*DDEBUG\s*1' src -echo ==================================================== -ack '(?<=_version_string) "\d+\.\d+\.\d+"' src -ack '(?<=This document describes rds-json-nginx-module v)\d+\.\d+' README - diff --git a/debian/modules/ngx-fancyindex/.gitignore b/debian/modules/ngx-fancyindex/.gitignore new file mode 100644 index 0000000..dbec55f --- /dev/null +++ b/debian/modules/ngx-fancyindex/.gitignore @@ -0,0 +1 @@ +*.sw[op] diff --git a/debian/modules/ngx-fancyindex/.todo b/debian/modules/ngx-fancyindex/.todo deleted file mode 100644 index 7b15329..0000000 --- a/debian/modules/ngx-fancyindex/.todo +++ /dev/null @@ -1,42 +0,0 @@ - - - - readme:iframe - - done in r23 - - - - readme:div - - will not be done - - - - readme:pre - - will not be done - - - - header:inline - - - footer:inline - - - install handler *after* index handler - - done - - - - split big handler function into smaller pieces - - - proper error message on subrequest errors - - done - - - diff --git a/debian/modules/ngx-fancyindex/CHANGELOG.md b/debian/modules/ngx-fancyindex/CHANGELOG.md new file mode 100644 index 0000000..0028c8c --- /dev/null +++ b/debian/modules/ngx-fancyindex/CHANGELOG.md @@ -0,0 +1,37 @@ +# Change Log +All notable changes to this project will be documented in this file. + +## Unreleased +### Added +- New feature: Allow setting the default sort criterion using the + `fancyindex_default_sort` configuration directive. (Patch by + Алексей Урбанский). +- New feature: Allos changing the maximum length of file names, using + the `fancyindex_name_length` configuration directive. (Patch by + Martin Herkt). +### Changed +- Renames `NEWS.rst` to `CHANGELOG.md`, which follows the recommendations + from [Keep a Change Log](http://keepachangelog.com/). + +## 0.3.4 - 2014-09-03 +### Added +- Viewport is now defined in the generated HTML, which works better + for mobile devices. +### Changed +- Even-odd row styling moved to the CSS using :nth-child(). This + makes the HTML served to clients smaller. + +## 0.3.3 - 2013-10-25 +### Added +- New feature: table headers in the default template are now clickable + to set the sorting criteria and direction of the index entries. + (https://github.com/aperezdc/ngx-fancyindex/issues/7) + +## 0.3.2 - 2013-06-05 +### Fixed +- Solved a bug that would leave certain clients stalled forever. +- Improved handling of subrequests for non-builtin headers/footers. + +## 0.3.1 - 2011-04-04 +### Added +- `NEWS.rst` file, to act as change log. diff --git a/debian/modules/ngx-fancyindex/HACKING.md b/debian/modules/ngx-fancyindex/HACKING.md new file mode 100644 index 0000000..0748517 --- /dev/null +++ b/debian/modules/ngx-fancyindex/HACKING.md @@ -0,0 +1,24 @@ +# Fancy Index module Hacking HOW-TO + +## How to modify the template + +The template is in the `template.html` file. Note that comment markers are +used to control how the `template.awk` Awk script generates the C header +which gets ultimately included in the compiled object code. Comment markers +have the `` format. Here `identifier` must be +a valid C identifier. All the text following the marker until the next +marker will be flattened into a C string. + +If the identifier is `NONE` (capitalized) the text from that marker up to +the next marker will be discarded. + + +## Regenerating the C header + +You will need Awk. I hope any decent implementation will do, but the GNU one +is known to work flawlessly. Just do: + + $ awk -f template.awk template.html > template.h + +If your copy of `awk` is not the GNU implementation, you will need to +install it and use `gawk` instead in the command line above. diff --git a/debian/modules/ngx-fancyindex/HACKING.rst b/debian/modules/ngx-fancyindex/HACKING.rst deleted file mode 100644 index 8ffc76f..0000000 --- a/debian/modules/ngx-fancyindex/HACKING.rst +++ /dev/null @@ -1,33 +0,0 @@ -=================================== - Fancy Index module Hacking HOW-TO -=================================== - -.. contents:: - - -How to modify the template -========================== - -The template is in the ``template.html`` file. Note that comment markers are -used to control how the ``template.awk`` Awk script generates the C header -which gets ultimately included in the compiled object code. Comment markers -have the ```` format. Here ``identifier`` must be -a valid C identifier. All the text following the marker until the next -marker will be flattened into a C string. - -If the identifier is ``NONE`` (capitalized) the text from that marker up to -the next marker will be discarded. - - -Regenerating the C header -~~~~~~~~~~~~~~~~~~~~~~~~~ -You will need Awk. I hope any decent implementation will do, but the GNU one -is known to work flawlessly. Just do:: - - $ awk -f template.awk template.html > template.h - -If your copy of ``awk`` is not the GNU implementation, you will need to -install it and use ``gawk`` instead in the command line above. - -.. vim: spell spelllang=en expandtab - diff --git a/debian/modules/ngx-fancyindex/NEWS.rst b/debian/modules/ngx-fancyindex/NEWS.rst deleted file mode 100644 index 717345d..0000000 --- a/debian/modules/ngx-fancyindex/NEWS.rst +++ /dev/null @@ -1,25 +0,0 @@ -============================== - Major changes among versions -============================== - -v0.3.4 -====== -- Viewport is now defined in the generated HTML, which works better - for mobile devices. -- Even-odd row styling moved to the CSS using :nth-child(). This - makes the HTML served to clients smaller. - -v0.3.3 -====== -- New feature: table headers in the default template are now clickable - to set the sorting criteria and direction of the index entries. - (https://github.com/aperezdc/ngx-fancyindex/issues/7) - -v0.3.2 -====== -- Solved a bug that would leave certain clients stalled forever. -- Improved handling of subrequests for non-builtin headers/footers. - -v0.3.1 -====== -(First entry in the NEWS file.) diff --git a/debian/modules/ngx-fancyindex/README.rst b/debian/modules/ngx-fancyindex/README.rst index 8d9ebef..fd9f775 100644 --- a/debian/modules/ngx-fancyindex/README.rst +++ b/debian/modules/ngx-fancyindex/README.rst @@ -2,6 +2,10 @@ Nginx Fancy Index module ======================== +.. image:: https://drone.io/github.com/aperezdc/ngx-fancyindex/status.png + :target: https://drone.io/github.com/aperezdc/ngx-fancyindex/latest + :alt: Build Status + .. contents:: The Fancy Index module makes possible the generation of file listings, like @@ -70,6 +74,15 @@ a ``server`` section in your Nginx_ configuration file:: } +Advanced Theming +~~~~~~~~~~~~~~~~ + +For a more elaborate example using `fancyindex_header`_ and +`fancyindex_footer`_ you can check `nice theme +`__ +designed by `@TheInsomniac `__. + + Directives ========== @@ -81,6 +94,14 @@ fancyindex :Description: Enables or disables fancy directory indexes. +fancyindex_default_sort +~~~~~~~~~~~~~~~~~~~~~~~ +:Syntax: *fancyindex_default_sort* [*name* | *size* | *date* | *name_desc* | *size_desc* | *date_desc*] +:Default: fancyindex_default_sort name +:Context: http, server, location +:Description: + Defines sorting criterion by default. + fancyindex_css_href ~~~~~~~~~~~~~~~~~~~ :Syntax: *fancyindex_css_href uri* @@ -102,6 +123,14 @@ fancyindex_exact_size accurately, or rounding off to the kilobyte, the megabyte and the gigabyte. +fancyindex_name_length +~~~~~~~~~~~~~~~~~~~~~~ +:Syntax: *fancyindex_name_length length* +:Default: fancyindex_name_length 50 +:Context: http, server, location +:Description: + Defines the maximum file name length limit in bytes. + fancyindex_footer ~~~~~~~~~~~~~~~~~ :Syntax: *fancyindex_footer path* diff --git a/debian/modules/ngx-fancyindex/ngx_http_fancyindex_module.c b/debian/modules/ngx-fancyindex/ngx_http_fancyindex_module.c index 2ec239e..9675e92 100644 --- a/debian/modules/ngx-fancyindex/ngx_http_fancyindex_module.c +++ b/debian/modules/ngx-fancyindex/ngx_http_fancyindex_module.c @@ -40,8 +40,10 @@ */ typedef struct { ngx_flag_t enable; /**< Module is enabled. */ + ngx_uint_t default_sort; /**< Default sort criterion. */ ngx_flag_t localtime; /**< File mtime dates are sent in local time. */ ngx_flag_t exact_size; /**< Sizes are sent always in bytes. */ + ngx_uint_t name_length; /**< Maximum length of file names in bytes. */ ngx_str_t header; /**< File name for header, or empty if none. */ ngx_str_t footer; /**< File name for footer, or empty if none. */ @@ -50,9 +52,25 @@ typedef struct { ngx_array_t *ignore; /**< List of files to ignore in listings. */ } ngx_http_fancyindex_loc_conf_t; +#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME 0 +#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE 1 +#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE 2 +#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME_DESC 3 +#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE_DESC 4 +#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE_DESC 5 + +static ngx_conf_enum_t ngx_http_fancyindex_sort_criteria[] = { + { ngx_string("name"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME }, + { ngx_string("size"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE }, + { ngx_string("date"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE }, + { ngx_string("name_desc"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME_DESC }, + { ngx_string("size_desc"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE_DESC }, + { ngx_string("date_desc"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE_DESC }, + { ngx_null_string, 0 } +}; + #define NGX_HTTP_FANCYINDEX_PREALLOCATE 50 -#define NGX_HTTP_FANCYINDEX_NAME_LEN 50 /** @@ -149,6 +167,13 @@ static ngx_command_t ngx_http_fancyindex_commands[] = { offsetof(ngx_http_fancyindex_loc_conf_t, enable), NULL }, + { ngx_string("fancyindex_default_sort"), + 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_fancyindex_loc_conf_t, default_sort), + &ngx_http_fancyindex_sort_criteria }, + { ngx_string("fancyindex_localtime"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -163,6 +188,13 @@ static ngx_command_t ngx_http_fancyindex_commands[] = { offsetof(ngx_http_fancyindex_loc_conf_t, exact_size), NULL }, + { ngx_string("fancyindex_name_length"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fancyindex_loc_conf_t, name_length), + NULL }, + { ngx_string("fancyindex_header"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_str_slot, @@ -579,7 +611,7 @@ make_content_buf( + ngx_sizeof_ssz("?C=x&O=y") /* URL sorting arguments */ + ngx_sizeof_ssz("\">") + entry[i].name.len + entry[i].utf_len - + NGX_HTTP_FANCYINDEX_NAME_LEN + ngx_sizeof_ssz(">") + + alcf->name_length + ngx_sizeof_ssz(">") + ngx_sizeof_ssz("") + 20 /* File size */ + ngx_sizeof_ssz("") @@ -613,20 +645,24 @@ make_content_buf( case 'M': /* Sort by mtime */ if (sort_descending) { sort_cmp_func = ngx_http_fancyindex_cmp_entries_mtime_desc; - sort_url_args = "?C=M&O=D"; + if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE_DESC) + sort_url_args = "?C=M&O=D"; } else { sort_cmp_func = ngx_http_fancyindex_cmp_entries_mtime_asc; - sort_url_args = "?C=M&O=A"; + if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE) + sort_url_args = "?C=M&O=A"; } break; case 'S': /* Sort by size */ if (sort_descending) { sort_cmp_func = ngx_http_fancyindex_cmp_entries_size_desc; - sort_url_args = "?C=S&O=D"; + if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE_DESC) + sort_url_args = "?C=S&O=D"; } else { sort_cmp_func = ngx_http_fancyindex_cmp_entries_size_asc; + if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE) sort_url_args = "?C=S&O=A"; } break; @@ -634,16 +670,39 @@ make_content_buf( default: if (sort_descending) { sort_cmp_func = ngx_http_fancyindex_cmp_entries_name_desc; - sort_url_args = "?C=N&O=D"; + if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME_DESC) + sort_url_args = "?C=N&O=D"; } else { sort_cmp_func = ngx_http_fancyindex_cmp_entries_name_asc; + if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME) + sort_url_args = "?C=N&O=A"; } break; } } else { - sort_cmp_func = ngx_http_fancyindex_cmp_entries_name_asc; + switch (alcf->default_sort) { + case NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE_DESC: + sort_cmp_func = ngx_http_fancyindex_cmp_entries_mtime_desc; + break; + case NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE: + sort_cmp_func = ngx_http_fancyindex_cmp_entries_mtime_asc; + break; + case NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE_DESC: + sort_cmp_func = ngx_http_fancyindex_cmp_entries_size_desc; + break; + case NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE: + sort_cmp_func = ngx_http_fancyindex_cmp_entries_size_asc; + break; + case NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME_DESC: + sort_cmp_func = ngx_http_fancyindex_cmp_entries_name_desc; + break; + case NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME: + default: + sort_cmp_func = ngx_http_fancyindex_cmp_entries_name_asc; + break; + } } /* Sort entries, if needed */ @@ -704,10 +763,10 @@ make_content_buf( len = entry[i].utf_len; if (entry[i].name.len - len) { - if (len > NGX_HTTP_FANCYINDEX_NAME_LEN) { - copy = NGX_HTTP_FANCYINDEX_NAME_LEN - 3 + 1; + if (len > alcf->name_length) { + copy = alcf->name_length - 3 + 1; } else { - copy = NGX_HTTP_FANCYINDEX_NAME_LEN + 1; + copy = alcf->name_length + 1; } b->last = ngx_utf8_cpystrn(b->last, entry[i].name.data, @@ -716,15 +775,15 @@ make_content_buf( } else { b->last = ngx_cpystrn(b->last, entry[i].name.data, - NGX_HTTP_FANCYINDEX_NAME_LEN + 1); + alcf->name_length + 1); last = b->last - 3; } - if (len > NGX_HTTP_FANCYINDEX_NAME_LEN) { + if (len > alcf->name_length) { b->last = ngx_cpymem_ssz(last, "..>"); } else { - if (entry[i].dir && NGX_HTTP_FANCYINDEX_NAME_LEN - len > 0) { + if (entry[i].dir && alcf->name_length - len > 0) { *b->last++ = '/'; len++; } @@ -1117,10 +1176,12 @@ ngx_http_fancyindex_create_loc_conf(ngx_conf_t *cf) * conf->footer.len = 0 * conf->footer.data = NULL */ - conf->enable = NGX_CONF_UNSET; - conf->localtime = NGX_CONF_UNSET; - conf->exact_size = NGX_CONF_UNSET; - conf->ignore = NGX_CONF_UNSET_PTR; + conf->enable = NGX_CONF_UNSET; + conf->default_sort = NGX_CONF_UNSET_UINT; + conf->localtime = NGX_CONF_UNSET; + conf->name_length = NGX_CONF_UNSET_UINT; + conf->exact_size = NGX_CONF_UNSET; + conf->ignore = NGX_CONF_UNSET_PTR; return conf; } @@ -1133,8 +1194,10 @@ ngx_http_fancyindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_fancyindex_loc_conf_t *conf = child; ngx_conf_merge_value(conf->enable, prev->enable, 0); + ngx_conf_merge_uint_value(conf->default_sort, prev->default_sort, NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME); ngx_conf_merge_value(conf->localtime, prev->localtime, 0); ngx_conf_merge_value(conf->exact_size, prev->exact_size, 1); + ngx_conf_merge_uint_value(conf->name_length, prev->name_length, 50); ngx_conf_merge_str_value(conf->header, prev->header, ""); ngx_conf_merge_str_value(conf->footer, prev->footer, ""); From 841afb8eeb5ba8e9ee7ac7931c776495d368592a Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Tue, 7 Apr 2015 18:55:34 -0500 Subject: [PATCH 019/651] Updating list of modules. Thanks Peter Wu. --- debian/control | 49 ++++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/debian/control b/debian/control index e81c040..0a33572 100644 --- a/debian/control +++ b/debian/control @@ -94,19 +94,18 @@ Description: nginx web/proxy server (standard version) standard modules included (but omitting some of those included in nginx-extra). . - STANDARD HTTP MODULES: Core, Access, Auth Basic, Auto Index, Browser, - Charset, Empty GIF, FastCGI, Geo, Gunzip, Gzip, Headers, Index, Limit - Requests, Limit Zone, Log, Map, Memcached, Proxy, Referer, Rewrite, SCGI, - Split Clients, SSI, Upstream, User ID, UWSGI. + STANDARD HTTP MODULES: Core, Access, Auth Basic, Auto Index, Browser, Empty + GIF, FastCGI, Geo, Limit Connections, Limit Requests, Map, Memcached, Proxy, + Referer, Rewrite, SCGI, Split Clients, UWSGI. . - OPTIONAL HTTP MODULES: Addition, Auth Request, Debug, GeoIP, Gzip - Precompression, HTTP Sub, Image Filter, IPv6, Real IP, Spdy, SSL, Stub Status, - Substitution, WebDAV, XSLT. + OPTIONAL HTTP MODULES: Addition, Auth Request, Charset, WebDAV, GeoIP, Gunzip, + Gzip, Gzip Precompression, Headers, Image Filter, Index, Log, Real IP, Spdy, + SSI, SSL, Stub Status, Substitution, Upstream, User ID, XSLT. . - MAIL MODULES: Mail Core, IMAP, POP3, SMTP, SSL. + MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. . - THIRD PARTY MODULES: Auth PAM, DAV Ext, Echo, HTTP Substitution Filter, - Upstream Fair Queue. + THIRD PARTY MODULES: Auth PAM, DAV Ext, Echo, HTTP Substitutions, Upstream + Fair Queue. Package: nginx-full-dbg Architecture: any @@ -138,11 +137,11 @@ Description: nginx web/proxy server (basic version) This package provides a very light version of nginx with only the minimal set of features and modules. . - STANDARD HTTP MODULES: Core, Access, Auth Basic, Auto Index, Charset, - Empty GIF, FastCGI, Gzip, Headers, Index, Log, Map, Proxy, Rewrite, Upstream. + STANDARD HTTP MODULES: Core, Access, Auth Basic, Auto Index, Empty GIF, + FastCGI, Map, Proxy, Rewrite. . - OPTIONAL HTTP MODULES: Auth Request, Debug, Gzip Precompression, IPv6, - Real IP, SSL, Stub Status. + OPTIONAL HTTP MODULES: Auth Request, Charset, Gzip, Gzip Precompression, + Headers, Index, Log, Real IP, SSL, Stub Status, Upstream. . THIRD PARTY MODULES: Echo. @@ -181,20 +180,20 @@ Description: nginx web/proxy server (extended version) extra features and modules such as the Perl module, which allows the addition of Perl in configuration files. . - STANDARD HTTP MODULES: Core, Access, Auth Basic, Auto Index, Browser, - Charset, Empty GIF, FastCGI, Geo, Gzip, Gunzip, Headers, Index, - Limit Requests, Limit Zone, Log, Map, Memcached, Proxy, Referer, Rewrite, - SCGI, Split Clients, SSI, Upstream, User ID, UWSGI. + STANDARD HTTP MODULES: Core, Access, Auth Basic, Auto Index, Browser, Empty + GIF, FastCGI, Geo, Limit Connections, Limit Requests, Map, Memcached, Proxy, + Referer, Rewrite, SCGI, Split Clients, UWSGI. . - OPTIONAL HTTP MODULES: Addition, Auth Request, Debug, Embedded Perl, FLV, - GeoIP, Gzip Precompression, Image Filter, IPv6, MP4, Random Index, Real IP, - Secure Link, Spdy, SSL, Stub Status, Substitution, WebDAV, XSLT. + OPTIONAL HTTP MODULES: Addition, Auth Request, Charset, WebDAV, FLV, GeoIP, + Gunzip, Gzip, Gzip Precompression, Headers, Image Filter, Index, Log, MP4, + Embedded Perl, Random Index, Real IP, Secure Link, Spdy, SSI, SSL, Stub + Status, Substitution, Upstream, User ID, XSLT. . - MAIL MODULES: Mail Core, IMAP, POP3, SMTP, SSL. + MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. . - THIRD PARTY MODULES: Auth PAM, DAV Ext, Echo, Embedded Lua, Fancy Index, - HttpHeadersMore, HTTP Substitution Filter, HTTP Push, Nginx Development Kit, - Upload Progress, Upstream Fair Queue. + THIRD PARTY MODULES: Auth PAM, Cache Purge, DAV Ext, Echo, Fancy Index, + Headers More, Embedded Lua, HTTP Push, HTTP Substitutions, Upload Progress, + Upstream Fair Queue. Package: nginx-extras-dbg Architecture: any From c4cfd60f94c9afe7edcc913db2472e177168ac63 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Tue, 7 Apr 2015 19:21:00 -0500 Subject: [PATCH 020/651] Adding NEWS entry because of potential issues with i386 systems. --- debian/changelog | 6 ++++-- debian/nginx-common.NEWS | 11 +++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 6fb9f11..cc131dd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.6.2-9) UNRELEASED; urgency=medium +nginx (1.6.3-2) UNRELEASED; urgency=medium [ Michael Lustfield ] * debian/conf/nginx.conf: @@ -12,6 +12,8 @@ nginx (1.6.2-9) UNRELEASED; urgency=medium + Updated nginx-lua v0.9.13 -> v0.9.15. + Updated nginx-cache-purge 2.1 -> 2.3. + Updated ngx-fancyindex v0.3.4 -> v0.3.5. + * debian/nginx-common.NEWS: + + Document potential issues with newer versions on i386. * debian/nginx-common.{dirs,install}, debian/vim/*: + Installing vim syntax highlighting from package. (Closes: #771609) Thanks Emmanuel Bouthenot for building this patch. @@ -32,7 +34,7 @@ nginx (1.6.2-9) UNRELEASED; urgency=medium * debian/nginx-common.manpages: + Replaced man page with upstream maintained version. (Closes: #781345) - -- Michael Lustfield Tue, 07 Apr 2015 09:39:52 -0500 + -- Michael Lustfield Tue, 07 Apr 2015 18:57:45 -0500 nginx (1.6.2-5) unstable; urgency=medium diff --git a/debian/nginx-common.NEWS b/debian/nginx-common.NEWS index 8b44b63..3e4acc3 100644 --- a/debian/nginx-common.NEWS +++ b/debian/nginx-common.NEWS @@ -1,3 +1,14 @@ +nginx-common (1.6.3-1) unstable; urgency=medium + + Starting with this release, we have enabled PIE build features which allows + Address Space Layout Randomazation. This is a hardening feature that + prevents some potential security issues. + + While this will significantly help increase security, it can potentially cause + significant performance issues on i386 systems. + + -- Michael Lustfield Tue, 07 Apr 2015 18:57:45 -0500 + nginx-common (1.6.2-5) unstable; urgency=medium We have disabled SSLv3 in nginx.conf for security reasons (ref: POODLE), From 5070bfa62d2d44be49fc6e6d75af6652a5b5d3a8 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Wed, 8 Apr 2015 08:28:53 -0500 Subject: [PATCH 021/651] Fixing a minor typo. --- debian/nginx-common.NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/nginx-common.NEWS b/debian/nginx-common.NEWS index 3e4acc3..8eeeb58 100644 --- a/debian/nginx-common.NEWS +++ b/debian/nginx-common.NEWS @@ -1,7 +1,7 @@ nginx-common (1.6.3-1) unstable; urgency=medium Starting with this release, we have enabled PIE build features which allows - Address Space Layout Randomazation. This is a hardening feature that + Address Space Layout Randomization. This is a hardening feature that prevents some potential security issues. While this will significantly help increase security, it can potentially cause From 4e2c3fec32110a637c330e723d10d84cdf0d3177 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 9 Apr 2015 10:55:00 +0300 Subject: [PATCH 022/651] Imported Upstream version 1.6.3 --- CHANGES | 19 ++++ CHANGES.ru | 20 ++++ auto/unix | 1 + src/core/nginx.h | 4 +- src/core/ngx_config.h | 3 + src/core/ngx_hash.c | 2 + src/core/ngx_inet.c | 8 +- src/core/ngx_parse.c | 80 +++++++++------ src/core/ngx_resolver.c | 8 +- src/core/ngx_shmtx.c | 3 +- src/core/ngx_string.c | 99 +++++++++++-------- src/event/ngx_event_openssl.c | 3 + .../modules/ngx_http_range_filter_module.c | 13 ++- src/http/ngx_http_core_module.c | 4 + src/http/ngx_http_parse.c | 12 ++- src/http/ngx_http_request.c | 5 +- src/http/ngx_http_spdy.c | 52 +++++++++- 17 files changed, 248 insertions(+), 88 deletions(-) diff --git a/CHANGES b/CHANGES index 5b1242a..f329f24 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,23 @@ +Changes with nginx 1.6.3 07 Apr 2015 + + *) Feature: now the "tcp_nodelay" directive works with SPDY connections. + + *) Bugfix: in error handling. + Thanks to Yichun Zhang and Daniil Bondarev. + + *) Bugfix: alerts "header already sent" appeared in logs if the + "post_action" directive was used; the bug had appeared in 1.5.4. + + *) Bugfix: alerts "sem_post() failed" might appear in logs. + + *) Bugfix: in hash table handling. + Thanks to Chris West. + + *) Bugfix: in integer overflow handling. + Thanks to Régis Leroy. + + Changes with nginx 1.6.2 16 Sep 2014 *) Security: it was possible to reuse SSL sessions in unrelated contexts diff --git a/CHANGES.ru b/CHANGES.ru index aa15be6..054e033 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,24 @@ +Изменения в nginx 1.6.3 07.04.2015 + + *) Добавление: теперь директива tcp_nodelay работает для + SPDY-соединений. + + *) Исправление: в обработке ошибок. + Спасибо Yichun Zhang и Даниилу Бондареву. + + *) Исправление: при использовании директивы post_action в лог писались + сообщения "header already sent"; ошибка появилась в nginx 1.5.4. + + *) Исправление: в лог могли писаться сообщения "sem_post() failed". + + *) Исправление: в обработке хэш-таблиц. + Спасибо Chris West. + + *) Исправление: в обработке целочисленных переполнений. + Спасибо Régis Leroy. + + Изменения в nginx 1.6.2 16.09.2014 *) Безопасность: при использовании общего для нескольких блоков server diff --git a/auto/unix b/auto/unix index 10fd3d2..dfeb848 100755 --- a/auto/unix +++ b/auto/unix @@ -489,6 +489,7 @@ ngx_param=NGX_OFF_T_LEN; ngx_value=$ngx_max_len; . auto/types/value ngx_type="time_t"; . auto/types/sizeof ngx_param=NGX_TIME_T_SIZE; ngx_value=$ngx_size; . auto/types/value ngx_param=NGX_TIME_T_LEN; ngx_value=$ngx_max_len; . auto/types/value +ngx_param=NGX_MAX_TIME_T_VALUE; ngx_value=$ngx_max_value; . auto/types/value # syscalls, libc calls and some features diff --git a/src/core/nginx.h b/src/core/nginx.h index 20dcd1d..e56e541 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1006002 -#define NGINX_VERSION "1.6.2" +#define nginx_version 1006003 +#define NGINX_VERSION "1.6.3" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h index 1da71f8..145e43a 100644 --- a/src/core/ngx_config.h +++ b/src/core/ngx_config.h @@ -85,8 +85,11 @@ typedef intptr_t ngx_flag_t; #if (NGX_PTR_SIZE == 4) #define NGX_INT_T_LEN NGX_INT32_LEN +#define NGX_MAX_INT_T_VALUE 2147483647 + #else #define NGX_INT_T_LEN NGX_INT64_LEN +#define NGX_MAX_INT_T_VALUE 9223372036854775807 #endif diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c index c7bfed7..e707c09 100644 --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -312,6 +312,8 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) continue; } + size = hinit->max_size; + ngx_log_error(NGX_LOG_WARN, hinit->pool->log, 0, "could not build optimal %s, you should increase " "either %s_max_size: %i or %s_bucket_size: %i; " diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c index 26c5bc4..2c84daf 100644 --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -27,6 +27,10 @@ ngx_inet_addr(u_char *text, size_t len) for (p = text; p < text + len; p++) { + if (octet > 255) { + return INADDR_NONE; + } + c = *p; if (c >= '0' && c <= '9') { @@ -34,7 +38,7 @@ ngx_inet_addr(u_char *text, size_t len) continue; } - if (c == '.' && octet < 256) { + if (c == '.') { addr = (addr << 8) + octet; octet = 0; n++; @@ -44,7 +48,7 @@ ngx_inet_addr(u_char *text, size_t len) return INADDR_NONE; } - if (n == 3 && octet < 256) { + if (n == 3) { addr = (addr << 8) + octet; return htonl(addr); } diff --git a/src/core/ngx_parse.c b/src/core/ngx_parse.c index da24f4c..d7350d4 100644 --- a/src/core/ngx_parse.c +++ b/src/core/ngx_parse.c @@ -12,10 +12,9 @@ ssize_t ngx_parse_size(ngx_str_t *line) { - u_char unit; - size_t len; - ssize_t size; - ngx_int_t scale; + u_char unit; + size_t len; + ssize_t size, scale, max; len = line->len; unit = line->data[len - 1]; @@ -24,21 +23,24 @@ ngx_parse_size(ngx_str_t *line) case 'K': case 'k': len--; + max = NGX_MAX_SIZE_T_VALUE / 1024; scale = 1024; break; case 'M': case 'm': len--; + max = NGX_MAX_SIZE_T_VALUE / (1024 * 1024); scale = 1024 * 1024; break; default: + max = NGX_MAX_SIZE_T_VALUE; scale = 1; } size = ngx_atosz(line->data, len); - if (size == NGX_ERROR) { + if (size == NGX_ERROR || size > max) { return NGX_ERROR; } @@ -51,10 +53,9 @@ ngx_parse_size(ngx_str_t *line) off_t ngx_parse_offset(ngx_str_t *line) { - u_char unit; - off_t offset; - size_t len; - ngx_int_t scale; + u_char unit; + off_t offset, scale, max; + size_t len; len = line->len; unit = line->data[len - 1]; @@ -63,27 +64,31 @@ ngx_parse_offset(ngx_str_t *line) case 'K': case 'k': len--; + max = NGX_MAX_OFF_T_VALUE / 1024; scale = 1024; break; case 'M': case 'm': len--; + max = NGX_MAX_OFF_T_VALUE / (1024 * 1024); scale = 1024 * 1024; break; case 'G': case 'g': len--; + max = NGX_MAX_OFF_T_VALUE / (1024 * 1024 * 1024); scale = 1024 * 1024 * 1024; break; default: + max = NGX_MAX_OFF_T_VALUE; scale = 1; } offset = ngx_atoof(line->data, len); - if (offset == NGX_ERROR) { + if (offset == NGX_ERROR || offset > max) { return NGX_ERROR; } @@ -98,7 +103,8 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec) { u_char *p, *last; ngx_int_t value, total, scale; - ngx_uint_t max, valid; + ngx_int_t max, cutoff, cutlim; + ngx_uint_t valid; enum { st_start = 0, st_year, @@ -115,8 +121,9 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec) valid = 0; value = 0; total = 0; + cutoff = NGX_MAX_INT_T_VALUE / 10; + cutlim = NGX_MAX_INT_T_VALUE % 10; step = is_sec ? st_start : st_month; - scale = is_sec ? 1 : 1000; p = line->data; last = p + line->len; @@ -124,6 +131,10 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec) while (p < last) { if (*p >= '0' && *p <= '9') { + if (value >= cutoff && (value > cutoff || *p - '0' > cutlim)) { + return NGX_ERROR; + } + value = value * 10 + (*p++ - '0'); valid = 1; continue; @@ -136,7 +147,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec) return NGX_ERROR; } step = st_year; - max = NGX_MAX_INT32_VALUE / (60 * 60 * 24 * 365); + max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 365); scale = 60 * 60 * 24 * 365; break; @@ -145,7 +156,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec) return NGX_ERROR; } step = st_month; - max = NGX_MAX_INT32_VALUE / (60 * 60 * 24 * 30); + max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 30); scale = 60 * 60 * 24 * 30; break; @@ -154,7 +165,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec) return NGX_ERROR; } step = st_week; - max = NGX_MAX_INT32_VALUE / (60 * 60 * 24 * 7); + max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 7); scale = 60 * 60 * 24 * 7; break; @@ -163,7 +174,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec) return NGX_ERROR; } step = st_day; - max = NGX_MAX_INT32_VALUE / (60 * 60 * 24); + max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24); scale = 60 * 60 * 24; break; @@ -172,7 +183,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec) return NGX_ERROR; } step = st_hour; - max = NGX_MAX_INT32_VALUE / (60 * 60); + max = NGX_MAX_INT_T_VALUE / (60 * 60); scale = 60 * 60; break; @@ -183,7 +194,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec) } p++; step = st_msec; - max = NGX_MAX_INT32_VALUE; + max = NGX_MAX_INT_T_VALUE; scale = 1; break; } @@ -192,7 +203,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec) return NGX_ERROR; } step = st_min; - max = NGX_MAX_INT32_VALUE / 60; + max = NGX_MAX_INT_T_VALUE / 60; scale = 60; break; @@ -201,7 +212,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec) return NGX_ERROR; } step = st_sec; - max = NGX_MAX_INT32_VALUE; + max = NGX_MAX_INT_T_VALUE; scale = 1; break; @@ -210,7 +221,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec) return NGX_ERROR; } step = st_last; - max = NGX_MAX_INT32_VALUE; + max = NGX_MAX_INT_T_VALUE; scale = 1; break; @@ -223,27 +234,40 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec) max /= 1000; } - if ((ngx_uint_t) value > max) { + if (value > max) { return NGX_ERROR; } - total += value * scale; + value *= scale; - if ((ngx_uint_t) total > NGX_MAX_INT32_VALUE) { + if (total > NGX_MAX_INT_T_VALUE - value) { return NGX_ERROR; } + total += value; + value = 0; - scale = is_sec ? 1 : 1000; while (p < last && *p == ' ') { p++; } } - if (valid) { - return total + value * scale; + if (!valid) { + return NGX_ERROR; } - return NGX_ERROR; + if (!is_sec) { + if (value > NGX_MAX_INT_T_VALUE / 1000) { + return NGX_ERROR; + } + + value *= 1000; + } + + if (total > NGX_MAX_INT_T_VALUE - value) { + return NGX_ERROR; + } + + return total + value; } diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index 5a944fc..b45001e 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -1568,8 +1568,6 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, ngx_rbtree_delete(&r->name_rbtree, &rn->node); - ngx_resolver_free_node(r, rn); - /* unlock name mutex */ while (next) { @@ -1580,6 +1578,8 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, ctx->handler(ctx); } + ngx_resolver_free_node(r, rn); + return; } @@ -2143,8 +2143,6 @@ valid: ngx_rbtree_delete(tree, &rn->node); - ngx_resolver_free_node(r, rn); - /* unlock addr mutex */ while (next) { @@ -2155,6 +2153,8 @@ valid: ctx->handler(ctx); } + ngx_resolver_free_node(r, rn); + return; } diff --git a/src/core/ngx_shmtx.c b/src/core/ngx_shmtx.c index a62999f..6230dc0 100644 --- a/src/core/ngx_shmtx.c +++ b/src/core/ngx_shmtx.c @@ -101,6 +101,7 @@ ngx_shmtx_lock(ngx_shmtx_t *mtx) (void) ngx_atomic_fetch_add(mtx->wait, 1); if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) { + (void) ngx_atomic_fetch_add(mtx->wait, -1); return; } @@ -174,7 +175,7 @@ ngx_shmtx_wakeup(ngx_shmtx_t *mtx) wait = *mtx->wait; - if (wait == 0) { + if ((ngx_atomic_int_t) wait <= 0) { return; } diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index 4e27917..503502a 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -897,26 +897,28 @@ ngx_filename_cmp(u_char *s1, u_char *s2, size_t n) ngx_int_t ngx_atoi(u_char *line, size_t n) { - ngx_int_t value; + ngx_int_t value, cutoff, cutlim; if (n == 0) { return NGX_ERROR; } + cutoff = NGX_MAX_INT_T_VALUE / 10; + cutlim = NGX_MAX_INT_T_VALUE % 10; + for (value = 0; n--; line++) { if (*line < '0' || *line > '9') { return NGX_ERROR; } + if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) { + return NGX_ERROR; + } + value = value * 10 + (*line - '0'); } - if (value < 0) { - return NGX_ERROR; - - } else { - return value; - } + return value; } @@ -925,13 +927,16 @@ ngx_atoi(u_char *line, size_t n) ngx_int_t ngx_atofp(u_char *line, size_t n, size_t point) { - ngx_int_t value; + ngx_int_t value, cutoff, cutlim; ngx_uint_t dot; if (n == 0) { return NGX_ERROR; } + cutoff = NGX_MAX_INT_T_VALUE / 10; + cutlim = NGX_MAX_INT_T_VALUE % 10; + dot = 0; for (value = 0; n--; line++) { @@ -953,98 +958,107 @@ ngx_atofp(u_char *line, size_t n, size_t point) return NGX_ERROR; } + if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) { + return NGX_ERROR; + } + value = value * 10 + (*line - '0'); point -= dot; } while (point--) { + if (value > cutoff) { + return NGX_ERROR; + } + value = value * 10; } - if (value < 0) { - return NGX_ERROR; - - } else { - return value; - } + return value; } ssize_t ngx_atosz(u_char *line, size_t n) { - ssize_t value; + ssize_t value, cutoff, cutlim; if (n == 0) { return NGX_ERROR; } + cutoff = NGX_MAX_SIZE_T_VALUE / 10; + cutlim = NGX_MAX_SIZE_T_VALUE % 10; + for (value = 0; n--; line++) { if (*line < '0' || *line > '9') { return NGX_ERROR; } + if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) { + return NGX_ERROR; + } + value = value * 10 + (*line - '0'); } - if (value < 0) { - return NGX_ERROR; - - } else { - return value; - } + return value; } off_t ngx_atoof(u_char *line, size_t n) { - off_t value; + off_t value, cutoff, cutlim; if (n == 0) { return NGX_ERROR; } + cutoff = NGX_MAX_OFF_T_VALUE / 10; + cutlim = NGX_MAX_OFF_T_VALUE % 10; + for (value = 0; n--; line++) { if (*line < '0' || *line > '9') { return NGX_ERROR; } + if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) { + return NGX_ERROR; + } + value = value * 10 + (*line - '0'); } - if (value < 0) { - return NGX_ERROR; - - } else { - return value; - } + return value; } time_t ngx_atotm(u_char *line, size_t n) { - time_t value; + time_t value, cutoff, cutlim; if (n == 0) { return NGX_ERROR; } + cutoff = NGX_MAX_TIME_T_VALUE / 10; + cutlim = NGX_MAX_TIME_T_VALUE % 10; + for (value = 0; n--; line++) { if (*line < '0' || *line > '9') { return NGX_ERROR; } + if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) { + return NGX_ERROR; + } + value = value * 10 + (*line - '0'); } - if (value < 0) { - return NGX_ERROR; - - } else { - return value; - } + return value; } @@ -1052,13 +1066,19 @@ ngx_int_t ngx_hextoi(u_char *line, size_t n) { u_char c, ch; - ngx_int_t value; + ngx_int_t value, cutoff; if (n == 0) { return NGX_ERROR; } + cutoff = NGX_MAX_INT_T_VALUE / 16; + for (value = 0; n--; line++) { + if (value > cutoff) { + return NGX_ERROR; + } + ch = *line; if (ch >= '0' && ch <= '9') { @@ -1076,12 +1096,7 @@ ngx_hextoi(u_char *line, size_t n) return NGX_ERROR; } - if (value < 0) { - return NGX_ERROR; - - } else { - return value; - } + return value; } diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 72c2559..4b33b67 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -1613,6 +1613,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #endif #ifdef SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING || n == SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING /* 345 */ +#endif +#ifdef SSL_R_INAPPROPRIATE_FALLBACK + || n == SSL_R_INAPPROPRIATE_FALLBACK /* 373 */ #endif || n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */ || n == SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE /* 1010 */ diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index 6a65e48..bb9a42c 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -274,7 +274,7 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, ngx_uint_t ranges) { u_char *p; - off_t start, end, size, content_length; + off_t start, end, size, content_length, cutoff, cutlim; ngx_uint_t suffix; ngx_http_range_t *range; @@ -282,6 +282,9 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, size = 0; content_length = r->headers_out.content_length_n; + cutoff = NGX_MAX_OFF_T_VALUE / 10; + cutlim = NGX_MAX_OFF_T_VALUE % 10; + for ( ;; ) { start = 0; end = 0; @@ -295,6 +298,10 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, } while (*p >= '0' && *p <= '9') { + if (start >= cutoff && (start > cutoff || *p - '0' > cutlim)) { + return NGX_HTTP_RANGE_NOT_SATISFIABLE; + } + start = start * 10 + *p++ - '0'; } @@ -321,6 +328,10 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, } while (*p >= '0' && *p <= '9') { + if (end >= cutoff && (end > cutoff || *p - '0' > cutlim)) { + return NGX_HTTP_RANGE_NOT_SATISFIABLE; + } + end = end * 10 + *p++ - '0'; } diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 4484a5e..1bcd104 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -1935,6 +1935,10 @@ ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status, ngx_int_t ngx_http_send_header(ngx_http_request_t *r) { + if (r->post_action) { + return NGX_OK; + } + if (r->header_sent) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "header already sent"); diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index 02b4a0f..8d38a19 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -2104,6 +2104,10 @@ ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b, goto invalid; case sw_chunk_size: + if (ctx->size > NGX_MAX_OFF_T_VALUE / 16) { + goto invalid; + } + if (ch >= '0' && ch <= '9') { ctx->size = ctx->size * 16 + (ch - '0'); break; @@ -2253,6 +2257,10 @@ data: ctx->state = state; b->pos = pos; + if (ctx->size > NGX_MAX_OFF_T_VALUE - 5) { + goto invalid; + } + switch (state) { case sw_chunk_start: @@ -2289,10 +2297,6 @@ data: } - if (ctx->size < 0 || ctx->length < 0) { - goto invalid; - } - return rc; done: diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 845ada3..560c5f5 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1227,12 +1227,11 @@ ngx_http_process_request_headers(ngx_event_t *rev) if (len > NGX_MAX_ERROR_STR - 300) { len = NGX_MAX_ERROR_STR - 300; - p[len++] = '.'; p[len++] = '.'; p[len++] = '.'; } ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent too long header line: \"%*s\"", - len, r->header_name_start); + "client sent too long header line: \"%*s...\"", + len, r->header_name_start); ngx_http_finalize_request(r, NGX_HTTP_REQUEST_HEADER_TOO_LARGE); diff --git a/src/http/ngx_http_spdy.c b/src/http/ngx_http_spdy.c index 9bd624c..bd6d73d 100644 --- a/src/http/ngx_http_spdy.c +++ b/src/http/ngx_http_spdy.c @@ -3156,8 +3156,10 @@ ngx_http_spdy_close_stream_handler(ngx_event_t *ev) void ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc) { + int tcp_nodelay; ngx_event_t *ev; - ngx_connection_t *fc; + ngx_connection_t *c, *fc; + ngx_http_core_loc_conf_t *clcf; ngx_http_spdy_stream_t **index, *s; ngx_http_spdy_srv_conf_t *sscf; ngx_http_spdy_connection_t *sc; @@ -3183,6 +3185,54 @@ ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc) { sc->connection->error = 1; } + + } else { + c = sc->connection; + + if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) { + if (ngx_tcp_push(c->fd) == -1) { + ngx_connection_error(c, ngx_socket_errno, + ngx_tcp_push_n " failed"); + c->error = 1; + tcp_nodelay = 0; + + } else { + c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; + tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0; + } + + } else { + tcp_nodelay = 1; + } + + clcf = ngx_http_get_module_loc_conf(stream->request, + ngx_http_core_module); + + if (tcp_nodelay + && clcf->tcp_nodelay + && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) + { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); + + if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, + (const void *) &tcp_nodelay, sizeof(int)) + == -1) + { +#if (NGX_SOLARIS) + /* Solaris returns EINVAL if a socket has been shut down */ + c->log_error = NGX_ERROR_IGNORE_EINVAL; +#endif + + ngx_connection_error(c, ngx_socket_errno, + "setsockopt(TCP_NODELAY) failed"); + + c->log_error = NGX_ERROR_INFO; + c->error = 1; + + } else { + c->tcp_nodelay = NGX_TCP_NODELAY_SET; + } + } } if (sc->stream == stream) { From 0b951e301d02dd5b20d593bba7003c752dc1da7a Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Thu, 9 Apr 2015 17:58:12 -0500 Subject: [PATCH 023/651] Fix Python 3 compatibility in ngx-conf --- debian/ngx-conf/ngx-conf | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/debian/ngx-conf/ngx-conf b/debian/ngx-conf/ngx-conf index 16e95a8..de24fcc 100755 --- a/debian/ngx-conf/ngx-conf +++ b/debian/ngx-conf/ngx-conf @@ -27,7 +27,10 @@ ## import argparse -import ConfigParser +try: + import configparser as ConfigParser +except: + import ConfigParser import glob import os import subprocess @@ -87,7 +90,7 @@ def main(): args = parse_arguments() if args.FILES == [] and not args.list: print('No files specified. These are required.') - return False + return False if args.enable: enable_configs(args.FILES, args.verbose, args.force) elif args.disable: From 2eadfe8382f819ae9c7dbf4ce5ef9375d91bddd1 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Tue, 9 Jun 2015 09:19:37 -0500 Subject: [PATCH 024/651] Switching to Nginx maintained version of index.html. Resolves unreported bugs. --- debian/changelog | 3 +++ debian/index.html | 32 -------------------------------- debian/nginx-common.install | 2 +- 3 files changed, 4 insertions(+), 33 deletions(-) delete mode 100644 debian/index.html diff --git a/debian/changelog b/debian/changelog index cc131dd..487be1a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -33,6 +33,9 @@ nginx (1.6.3-2) UNRELEASED; urgency=medium + Added configuration utility. (Closes: #652108) * debian/nginx-common.manpages: + Replaced man page with upstream maintained version. (Closes: #781345) + * debian/nginx-common.install: + + Changed debian/index.html -> html/index.html. This installs the package + maintained version of this file as opposed to our out of date version. -- Michael Lustfield Tue, 07 Apr 2015 18:57:45 -0500 diff --git a/debian/index.html b/debian/index.html deleted file mode 100644 index 118c9d6..0000000 --- a/debian/index.html +++ /dev/null @@ -1,32 +0,0 @@ - - - -Welcome to nginx on Debian! - - - -

Welcome to nginx on Debian!

-

If you see this page, the nginx web server is successfully installed and -working on Debian. Further configuration is required.

- -

For online documentation and support please refer to -nginx.org

- -

- Please use the reportbug tool to report bugs in the - nginx package with Debian. However, check existing - bug reports before reporting a new bug. -

- -

Thank you for using debian and nginx.

- - - - diff --git a/debian/nginx-common.install b/debian/nginx-common.install index a320780..eea0c94 100644 --- a/debian/nginx-common.install +++ b/debian/nginx-common.install @@ -1,6 +1,6 @@ debian/conf/* etc/nginx debian/ufw/nginx etc/ufw/applications.d -debian/index.html usr/share/nginx/html/ +html/index.html usr/share/nginx/html/ debian/vim/nginx.yaml usr/share/vim/registry contrib/vim/* usr/share/vim/addons debian/ngx-conf/ngx-conf usr/sbin/ngx-conf From 242d723c68d4075236819cda4157e3ffc80b3af7 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 11 Jun 2015 14:17:21 +0300 Subject: [PATCH 025/651] Fix version number --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 487be1a..4a35984 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.6.3-2) UNRELEASED; urgency=medium +nginx (1.6.2-6) UNRELEASED; urgency=medium [ Michael Lustfield ] * debian/conf/nginx.conf: From 604af3efb5abd9de4c138fa09fd50c9c8d8fcc9b Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 11 Jun 2015 14:42:02 +0300 Subject: [PATCH 026/651] Imported Upstream version 1.9.1 --- CHANGES | 410 +++++- CHANGES.ru | 431 +++++- LICENSE | 4 +- auto/cc/clang | 5 + auto/cc/gcc | 5 + auto/lib/google-perftools/conf | 2 +- auto/lib/openssl/make | 5 - auto/lib/perl/conf | 10 +- auto/lib/zlib/patch.zlib.h | 10 - auto/make | 61 +- auto/modules | 60 +- auto/options | 67 +- auto/os/conf | 9 + auto/os/darwin | 1 - auto/os/freebsd | 49 +- auto/os/linux | 12 - auto/os/win32 | 1 - auto/sources | 81 +- auto/summary | 27 +- auto/threads | 20 + auto/types/sizeof | 14 +- auto/unix | 68 +- configure | 5 + contrib/vim/syntax/nginx.vim | 233 ++- src/core/nginx.c | 63 +- src/core/nginx.h | 10 +- src/core/ngx_buf.c | 88 ++ src/core/ngx_buf.h | 16 +- src/core/ngx_conf_file.c | 5 +- src/core/ngx_connection.c | 208 ++- src/core/ngx_connection.h | 22 +- src/core/ngx_core.h | 15 +- src/core/ngx_crypt.c | 2 +- src/core/ngx_cycle.c | 48 +- src/core/ngx_cycle.h | 16 +- src/core/ngx_file.c | 18 +- src/core/ngx_file.h | 6 + src/core/ngx_inet.c | 10 +- src/core/ngx_log.c | 238 ++- src/core/ngx_log.h | 13 +- src/core/ngx_output_chain.c | 121 +- src/core/ngx_palloc.c | 10 +- src/core/ngx_rbtree.c | 6 +- src/core/ngx_rbtree.h | 6 +- src/core/ngx_regex.c | 51 +- src/core/ngx_resolver.c | 63 +- src/core/ngx_resolver.h | 15 +- src/core/ngx_rwlock.c | 120 ++ src/core/ngx_rwlock.h | 21 + src/core/ngx_shmtx.c | 2 +- src/core/ngx_slab.c | 91 +- src/core/ngx_slab.h | 3 + src/core/ngx_string.c | 60 +- src/core/ngx_string.h | 1 + src/core/ngx_syslog.c | 374 +++++ src/core/ngx_syslog.h | 30 + src/core/ngx_thread_pool.c | 630 ++++++++ src/core/ngx_thread_pool.h | 36 + src/core/ngx_times.c | 21 +- src/core/ngx_times.h | 1 + src/event/modules/ngx_aio_module.c | 171 --- src/event/modules/ngx_devpoll_module.c | 33 +- src/event/modules/ngx_epoll_module.c | 180 ++- src/event/modules/ngx_eventport_module.c | 68 +- src/event/modules/ngx_kqueue_module.c | 242 ++-- src/event/modules/ngx_poll_module.c | 66 +- src/event/modules/ngx_rtsig_module.c | 747 ---------- src/event/modules/ngx_select_module.c | 30 +- src/event/modules/ngx_win32_select_module.c | 16 +- src/event/ngx_event.c | 126 +- src/event/ngx_event.h | 100 +- src/event/ngx_event_accept.c | 90 +- src/event/ngx_event_busy_lock.c | 286 ---- src/event/ngx_event_busy_lock.h | 65 - src/event/ngx_event_connect.c | 15 +- src/event/ngx_event_connect.h | 5 +- src/event/ngx_event_mutex.c | 70 - src/event/ngx_event_openssl.c | 664 ++++++++- src/event/ngx_event_openssl.h | 22 +- src/event/ngx_event_openssl_stapling.c | 6 +- src/event/ngx_event_pipe.c | 64 +- src/event/ngx_event_pipe.h | 3 + src/event/ngx_event_posted.c | 152 +- src/event/ngx_event_posted.h | 51 +- src/event/ngx_event_timer.c | 152 +- src/event/ngx_event_timer.h | 16 +- .../modules/ngx_http_addition_filter_module.c | 2 +- src/http/modules/ngx_http_autoindex_module.c | 487 ++++++- .../modules/ngx_http_charset_filter_module.c | 34 +- src/http/modules/ngx_http_dav_module.c | 20 +- src/http/modules/ngx_http_fastcgi_module.c | 739 ++++++++-- src/http/modules/ngx_http_geo_module.c | 2 +- src/http/modules/ngx_http_geoip_module.c | 12 +- .../modules/ngx_http_gunzip_filter_module.c | 12 +- .../modules/ngx_http_gzip_filter_module.c | 12 +- .../modules/ngx_http_gzip_static_module.c | 2 - .../modules/ngx_http_headers_filter_module.c | 292 ++-- .../modules/ngx_http_image_filter_module.c | 1 + src/http/modules/ngx_http_limit_conn_module.c | 229 +-- src/http/modules/ngx_http_limit_req_module.c | 129 +- src/http/modules/ngx_http_log_module.c | 151 +- src/http/modules/ngx_http_memcached_module.c | 32 +- src/http/modules/ngx_http_mp4_module.c | 2 +- .../ngx_http_not_modified_filter_module.c | 52 +- src/http/modules/ngx_http_proxy_module.c | 847 +++++++++-- src/http/modules/ngx_http_rewrite_module.c | 6 +- src/http/modules/ngx_http_scgi_module.c | 413 ++++-- src/http/modules/ngx_http_ssi_filter_module.c | 5 +- src/http/modules/ngx_http_ssl_module.c | 47 +- src/http/modules/ngx_http_ssl_module.h | 2 + .../modules/ngx_http_stub_status_module.c | 18 +- src/http/modules/ngx_http_sub_filter_module.c | 21 +- .../modules/ngx_http_upstream_hash_module.c | 667 +++++++++ .../ngx_http_upstream_ip_hash_module.c | 48 +- .../ngx_http_upstream_keepalive_module.c | 24 +- .../ngx_http_upstream_least_conn_module.c | 170 +-- .../modules/ngx_http_upstream_zone_module.c | 227 +++ src/http/modules/ngx_http_uwsgi_module.c | 585 ++++++-- .../modules/ngx_http_xslt_filter_module.c | 6 +- src/http/modules/perl/ngx_http_perl_module.c | 3 +- src/http/ngx_http.c | 36 +- src/http/ngx_http.h | 8 +- src/http/ngx_http_busy_lock.c | 307 ---- src/http/ngx_http_busy_lock.h | 54 - src/http/ngx_http_cache.h | 27 +- src/http/ngx_http_copy_filter_module.c | 179 ++- src/http/ngx_http_core_module.c | 285 +++- src/http/ngx_http_core_module.h | 23 +- src/http/ngx_http_file_cache.c | 655 ++++++++- src/http/ngx_http_parse.c | 59 +- src/http/ngx_http_request.c | 28 +- src/http/ngx_http_request.h | 19 +- src/http/ngx_http_request_body.c | 142 +- src/http/ngx_http_spdy.c | 614 +++++--- src/http/ngx_http_spdy.h | 13 +- src/http/ngx_http_spdy_filter_module.c | 16 +- src/http/ngx_http_special_response.c | 4 +- src/http/ngx_http_upstream.c | 975 +++++++++++-- src/http/ngx_http_upstream.h | 43 +- src/http/ngx_http_upstream_round_robin.c | 388 +++-- src/http/ngx_http_upstream_round_robin.h | 71 +- src/http/ngx_http_variables.c | 50 +- src/http/ngx_http_write_filter_module.c | 21 +- src/mail/ngx_mail.c | 42 +- src/mail/ngx_mail.h | 5 +- src/mail/ngx_mail_auth_http_module.c | 151 +- src/mail/ngx_mail_core_module.c | 49 +- src/mail/ngx_mail_handler.c | 106 +- src/mail/ngx_mail_imap_module.c | 4 +- src/mail/ngx_mail_pop3_module.c | 4 +- src/mail/ngx_mail_proxy_module.c | 13 - src/mail/ngx_mail_smtp_module.c | 4 +- src/mail/ngx_mail_ssl_module.c | 128 +- src/mail/ngx_mail_ssl_module.h | 8 + src/misc/ngx_cpp_test_module.cpp | 2 +- src/os/unix/ngx_aio_read.c | 109 -- src/os/unix/ngx_aio_read_chain.c | 78 - src/os/unix/ngx_aio_write.c | 109 -- src/os/unix/ngx_aio_write_chain.c | 100 -- src/os/unix/ngx_channel.c | 7 - src/os/unix/ngx_darwin_config.h | 3 - src/os/unix/ngx_darwin_sendfile_chain.c | 254 +--- src/os/unix/ngx_file_aio_read.c | 42 +- src/os/unix/ngx_files.c | 109 ++ src/os/unix/ngx_files.h | 6 + src/os/unix/ngx_freebsd_config.h | 8 +- src/os/unix/ngx_freebsd_rfork_thread.c | 756 ---------- src/os/unix/ngx_freebsd_rfork_thread.h | 122 -- src/os/unix/ngx_freebsd_sendfile_chain.c | 308 ++-- src/os/unix/ngx_linux.h | 2 - src/os/unix/ngx_linux_aio_read.c | 39 +- src/os/unix/ngx_linux_config.h | 11 +- src/os/unix/ngx_linux_init.c | 33 - src/os/unix/ngx_linux_sendfile_chain.c | 455 +++--- src/os/unix/ngx_os.h | 30 +- src/os/unix/ngx_posix_config.h | 8 + src/os/unix/ngx_posix_init.c | 6 +- src/os/unix/ngx_process_cycle.c | 223 +-- src/os/unix/ngx_process_cycle.h | 2 +- src/os/unix/ngx_pthread_thread.c | 278 ---- src/os/unix/ngx_readv_chain.c | 135 +- src/os/unix/ngx_setproctitle.h | 4 +- src/os/unix/ngx_solaris_sendfilev_chain.c | 79 +- src/os/unix/ngx_thread.h | 129 +- src/os/unix/ngx_thread_cond.c | 87 ++ src/os/unix/ngx_thread_id.c | 70 + src/os/unix/ngx_thread_mutex.c | 174 +++ src/os/unix/ngx_user.c | 22 +- src/os/unix/ngx_writev_chain.c | 251 ++-- src/os/unix/rfork_thread.S | 73 - src/stream/ngx_stream.c | 555 +++++++ src/stream/ngx_stream.h | 208 +++ src/stream/ngx_stream_core_module.c | 507 +++++++ src/stream/ngx_stream_handler.c | 296 ++++ src/stream/ngx_stream_proxy_module.c | 1290 +++++++++++++++++ src/stream/ngx_stream_ssl_module.c | 456 ++++++ src/stream/ngx_stream_ssl_module.h | 49 + src/stream/ngx_stream_upstream.c | 462 ++++++ src/stream/ngx_stream_upstream.h | 103 ++ src/stream/ngx_stream_upstream_hash_module.c | 654 +++++++++ .../ngx_stream_upstream_least_conn_module.c | 305 ++++ src/stream/ngx_stream_upstream_round_robin.c | 702 +++++++++ src/stream/ngx_stream_upstream_round_robin.h | 138 ++ src/stream/ngx_stream_upstream_zone_module.c | 221 +++ 204 files changed, 19114 insertions(+), 8256 deletions(-) delete mode 100644 auto/lib/zlib/patch.zlib.h create mode 100644 auto/threads create mode 100644 src/core/ngx_rwlock.c create mode 100644 src/core/ngx_rwlock.h create mode 100644 src/core/ngx_syslog.c create mode 100644 src/core/ngx_syslog.h create mode 100644 src/core/ngx_thread_pool.c create mode 100644 src/core/ngx_thread_pool.h delete mode 100644 src/event/modules/ngx_aio_module.c delete mode 100644 src/event/modules/ngx_rtsig_module.c delete mode 100644 src/event/ngx_event_busy_lock.c delete mode 100644 src/event/ngx_event_busy_lock.h delete mode 100644 src/event/ngx_event_mutex.c create mode 100644 src/http/modules/ngx_http_upstream_hash_module.c create mode 100644 src/http/modules/ngx_http_upstream_zone_module.c delete mode 100644 src/http/ngx_http_busy_lock.c delete mode 100644 src/http/ngx_http_busy_lock.h delete mode 100644 src/os/unix/ngx_aio_read.c delete mode 100644 src/os/unix/ngx_aio_read_chain.c delete mode 100644 src/os/unix/ngx_aio_write.c delete mode 100644 src/os/unix/ngx_aio_write_chain.c delete mode 100644 src/os/unix/ngx_freebsd_rfork_thread.c delete mode 100644 src/os/unix/ngx_freebsd_rfork_thread.h delete mode 100644 src/os/unix/ngx_pthread_thread.c create mode 100644 src/os/unix/ngx_thread_cond.c create mode 100644 src/os/unix/ngx_thread_id.c create mode 100644 src/os/unix/ngx_thread_mutex.c delete mode 100644 src/os/unix/rfork_thread.S create mode 100644 src/stream/ngx_stream.c create mode 100644 src/stream/ngx_stream.h create mode 100644 src/stream/ngx_stream_core_module.c create mode 100644 src/stream/ngx_stream_handler.c create mode 100644 src/stream/ngx_stream_proxy_module.c create mode 100644 src/stream/ngx_stream_ssl_module.c create mode 100644 src/stream/ngx_stream_ssl_module.h create mode 100644 src/stream/ngx_stream_upstream.c create mode 100644 src/stream/ngx_stream_upstream.h create mode 100644 src/stream/ngx_stream_upstream_hash_module.c create mode 100644 src/stream/ngx_stream_upstream_least_conn_module.c create mode 100644 src/stream/ngx_stream_upstream_round_robin.c create mode 100644 src/stream/ngx_stream_upstream_round_robin.h create mode 100644 src/stream/ngx_stream_upstream_zone_module.c diff --git a/CHANGES b/CHANGES index f329f24..abb5e29 100644 --- a/CHANGES +++ b/CHANGES @@ -1,55 +1,437 @@ -Changes with nginx 1.6.3 07 Apr 2015 +Changes with nginx 1.9.1 26 May 2015 - *) Feature: now the "tcp_nodelay" directive works with SPDY connections. + *) Change: now SSLv3 protocol is disabled by default. - *) Bugfix: in error handling. - Thanks to Yichun Zhang and Daniil Bondarev. + *) Change: some long deprecated directives are not supported anymore. - *) Bugfix: alerts "header already sent" appeared in logs if the - "post_action" directive was used; the bug had appeared in 1.5.4. + *) Feature: the "reuseport" parameter of the "listen" directive. + Thanks to Sepherosa Ziehau and Yingqi Lu. - *) Bugfix: alerts "sem_post() failed" might appear in logs. + *) Feature: the $upstream_connect_time variable. + + *) Bugfix: in the "hash" directive on big-endian platforms. + + *) Bugfix: nginx might fail to start on some old Linux variants; the bug + had appeared in 1.7.11. + + *) Bugfix: in IP address parsing. + Thanks to Sergey Polovko. + + +Changes with nginx 1.9.0 28 Apr 2015 + + *) Change: obsolete aio and rtsig event methods have been removed. + + *) Feature: the "zone" directive inside the "upstream" block. + + *) Feature: the stream module. + + *) Feature: byte ranges support in the ngx_http_memcached_module. + Thanks to Martin Mlynář. + + *) Feature: shared memory can now be used on Windows versions with + address space layout randomization. + Thanks to Sergey Brester. + + *) Feature: the "error_log" directive can now be used on mail and server + levels in mail proxy. + + *) Bugfix: the "proxy_protocol" parameter of the "listen" directive did + not work if not specified in the first "listen" directive for a + listen socket. + + +Changes with nginx 1.7.12 07 Apr 2015 + + *) Feature: now the "tcp_nodelay" directive works with backend SSL + connections. + + *) Feature: now thread pools can be used to read cache file headers. + + *) Bugfix: in the "proxy_request_buffering" directive. + + *) Bugfix: a segmentation fault might occur in a worker process when + using thread pools on Linux. + + *) Bugfix: in error handling when using the "ssl_stapling" directive. + Thanks to Filipe da Silva. + + *) Bugfix: in the ngx_http_spdy_module. + + +Changes with nginx 1.7.11 24 Mar 2015 + + *) Change: the "sendfile" parameter of the "aio" directive is + deprecated; now nginx automatically uses AIO to pre-load data for + sendfile if both "aio" and "sendfile" directives are used. + + *) Feature: experimental thread pools support. + + *) Feature: the "proxy_request_buffering", "fastcgi_request_buffering", + "scgi_request_buffering", and "uwsgi_request_buffering" directives. + + *) Feature: request body filters experimental API. + + *) Feature: client SSL certificates support in mail proxy. + Thanks to Sven Peter, Franck Levionnois, and Filipe Da Silva. + + *) Feature: startup speedup when using the "hash ... consistent" + directive in the upstream block. + Thanks to Wai Keen Woon. + + *) Feature: debug logging into a cyclic memory buffer. *) Bugfix: in hash table handling. Thanks to Chris West. + *) Bugfix: in the "proxy_cache_revalidate" directive. + + *) Bugfix: SSL connections might hang if deferred accept or the + "proxy_protocol" parameter of the "listen" directive were used. + Thanks to James Hamlin. + + *) Bugfix: the $upstream_response_time variable might contain a wrong + value if the "image_filter" directive was used. + *) Bugfix: in integer overflow handling. Thanks to Régis Leroy. + *) Bugfix: it was not possible to enable SSLv3 with LibreSSL. -Changes with nginx 1.6.2 16 Sep 2014 + *) Bugfix: the "ignoring stale global SSL error ... called a function + you should not call" alerts appeared in logs when using LibreSSL. + + *) Bugfix: certificates specified by the "ssl_client_certificate" and + "ssl_trusted_certificate" directives were inadvertently used to + automatically construct certificate chains. + + +Changes with nginx 1.7.10 10 Feb 2015 + + *) Feature: the "use_temp_path" parameter of the "proxy_cache_path", + "fastcgi_cache_path", "scgi_cache_path", and "uwsgi_cache_path" + directives. + + *) Feature: the $upstream_header_time variable. + + *) Workaround: now on disk overflow nginx tries to write error logs once + a second only. + + *) Bugfix: the "try_files" directive did not ignore normal files while + testing directories. + Thanks to Damien Tournoud. + + *) Bugfix: alerts "sendfile() failed" if the "sendfile" directive was + used on OS X; the bug had appeared in 1.7.8. + + *) Bugfix: alerts "sem_post() failed" might appear in logs. + + *) Bugfix: nginx could not be built with musl libc. + Thanks to James Taylor. + + *) Bugfix: nginx could not be built on Tru64 UNIX. + Thanks to Goetz T. Fischer. + + +Changes with nginx 1.7.9 23 Dec 2014 + + *) Feature: variables support in the "proxy_cache", "fastcgi_cache", + "scgi_cache", and "uwsgi_cache" directives. + + *) Feature: variables support in the "expires" directive. + + *) Feature: loading of secret keys from hardware tokens with OpenSSL + engines. + Thanks to Dmitrii Pichulin. + + *) Feature: the "autoindex_format" directive. + + *) Bugfix: cache revalidation is now only used for responses with 200 + and 206 status codes. + Thanks to Piotr Sikora. + + *) Bugfix: the "TE" client request header line was passed to backends + while proxying. + + *) Bugfix: the "proxy_pass", "fastcgi_pass", "scgi_pass", and + "uwsgi_pass" directives might not work correctly inside the "if" and + "limit_except" blocks. + + *) Bugfix: the "proxy_store" directive with the "on" parameter was + ignored if the "proxy_store" directive with an explicitly specified + file path was used on a previous level. + + *) Bugfix: nginx could not be built with BoringSSL. + Thanks to Lukas Tribus. + + +Changes with nginx 1.7.8 02 Dec 2014 + + *) Change: now the "If-Modified-Since", "If-Range", etc. client request + header lines are passed to a backend while caching if nginx knows in + advance that the response will not be cached (e.g., when using + proxy_cache_min_uses). + + *) Change: now after proxy_cache_lock_timeout nginx sends a request to a + backend with caching disabled; the new directives + "proxy_cache_lock_age", "fastcgi_cache_lock_age", + "scgi_cache_lock_age", and "uwsgi_cache_lock_age" specify a time + after which the lock will be released and another attempt to cache a + response will be made. + + *) Change: the "log_format" directive can now be used only at http + level. + + *) Feature: the "proxy_ssl_certificate", "proxy_ssl_certificate_key", + "proxy_ssl_password_file", "uwsgi_ssl_certificate", + "uwsgi_ssl_certificate_key", and "uwsgi_ssl_password_file" + directives. + Thanks to Piotr Sikora. + + *) Feature: it is now possible to switch to a named location using + "X-Accel-Redirect". + Thanks to Toshikuni Fukaya. + + *) Feature: now the "tcp_nodelay" directive works with SPDY connections. + + *) Feature: new directives in vim syntax highliting scripts. + Thanks to Peter Wu. + + *) Bugfix: nginx ignored the "s-maxage" value in the "Cache-Control" + backend response header line. + Thanks to Piotr Sikora. + + *) Bugfix: in the ngx_http_spdy_module. + Thanks to Piotr Sikora. + + *) Bugfix: in the "ssl_password_file" directive when using OpenSSL + 0.9.8zc, 1.0.0o, 1.0.1j. + + *) Bugfix: alerts "header already sent" appeared in logs if the + "post_action" directive was used; the bug had appeared in 1.5.4. + + *) Bugfix: alerts "the http output chain is empty" might appear in logs + if the "postpone_output 0" directive was used with SSI includes. + + *) Bugfix: in the "proxy_cache_lock" directive with SSI subrequests. + Thanks to Yichun Zhang. + + +Changes with nginx 1.7.7 28 Oct 2014 + + *) Change: now nginx takes into account the "Vary" header line in a + backend response while caching. + + *) Feature: the "proxy_force_ranges", "fastcgi_force_ranges", + "scgi_force_ranges", and "uwsgi_force_ranges" directives. + + *) Feature: the "proxy_limit_rate", "fastcgi_limit_rate", + "scgi_limit_rate", and "uwsgi_limit_rate" directives. + + *) Feature: the "Vary" parameter of the "proxy_ignore_headers", + "fastcgi_ignore_headers", "scgi_ignore_headers", and + "uwsgi_ignore_headers" directives. + + *) Bugfix: the last part of a response received from a backend with + unbufferred proxy might not be sent to a client if "gzip" or "gunzip" + directives were used. + + *) Bugfix: in the "proxy_cache_revalidate" directive. + Thanks to Piotr Sikora. + + *) Bugfix: in error handling. + Thanks to Yichun Zhang and Daniil Bondarev. + + *) Bugfix: in the "proxy_next_upstream_tries" and + "proxy_next_upstream_timeout" directives. + Thanks to Feng Gu. + + *) Bugfix: nginx/Windows could not be built with MinGW-w64 gcc. + Thanks to Kouhei Sutou. + + +Changes with nginx 1.7.6 30 Sep 2014 + + *) Change: the deprecated "limit_zone" directive is not supported + anymore. + + *) Feature: the "limit_conn_zone" and "limit_req_zone" directives now + can be used with combinations of multiple variables. + + *) Bugfix: request body might be transmitted incorrectly when retrying a + FastCGI request to the next upstream server. + + *) Bugfix: in logging to syslog. + + +Changes with nginx 1.7.5 16 Sep 2014 *) Security: it was possible to reuse SSL sessions in unrelated contexts if a shared SSL session cache or the same TLS session ticket key was used for multiple "server" blocks (CVE-2014-3616). Thanks to Antoine Delignat-Lavaud. - *) Bugfix: requests might hang if resolver was used and a DNS server - returned a malformed response; the bug had appeared in 1.5.8. + *) Change: now the "stub_status" directive does not require a parameter. + + *) Feature: the "always" parameter of the "add_header" directive. + + *) Feature: the "proxy_next_upstream_tries", + "proxy_next_upstream_timeout", "fastcgi_next_upstream_tries", + "fastcgi_next_upstream_timeout", "memcached_next_upstream_tries", + "memcached_next_upstream_timeout", "scgi_next_upstream_tries", + "scgi_next_upstream_timeout", "uwsgi_next_upstream_tries", and + "uwsgi_next_upstream_timeout" directives. + + *) Bugfix: in the "if" parameter of the "access_log" directive. + + *) Bugfix: in the ngx_http_perl_module. + Thanks to Piotr Sikora. + + *) Bugfix: the "listen" directive of the mail proxy module did not allow + to specify more than two parameters. + + *) Bugfix: the "sub_filter" directive did not work with a string to + replace consisting of a single character. *) Bugfix: requests might hang if resolver was used and a timeout occurred during a DNS request. + *) Bugfix: in the ngx_http_spdy_module when using with AIO. -Changes with nginx 1.6.1 05 Aug 2014 + *) Bugfix: a segmentation fault might occur in a worker process if the + "set" directive was used to change the "$http_...", "$sent_http_...", + or "$upstream_http_..." variables. + + *) Bugfix: in memory allocation error handling. + Thanks to Markus Linnala and Feng Gu. + + +Changes with nginx 1.7.4 05 Aug 2014 *) Security: pipelined commands were not discarded after STARTTLS command in SMTP proxy (CVE-2014-3556); the bug had appeared in 1.5.6. Thanks to Chris Boulton. + *) Change: URI escaping now uses uppercase hexadecimal digits. + Thanks to Piotr Sikora. + + *) Feature: now nginx can be build with BoringSSL and LibreSSL. + Thanks to Piotr Sikora. + + *) Bugfix: requests might hang if resolver was used and a DNS server + returned a malformed response; the bug had appeared in 1.5.8. + + *) Bugfix: in the ngx_http_spdy_module. + Thanks to Piotr Sikora. + *) Bugfix: the $uri variable might contain garbage when returning errors with code 400. Thanks to Sergey Bobrov. + *) Bugfix: in error handling in the "proxy_store" directive and the + ngx_http_dav_module. + Thanks to Feng Gu. + + *) Bugfix: a segmentation fault might occur if logging of errors to + syslog was used; the bug had appeared in 1.7.1. + + *) Bugfix: the $geoip_latitude, $geoip_longitude, $geoip_dma_code, and + $geoip_area_code variables might not work. + Thanks to Yichun Zhang. + + *) Bugfix: in memory allocation error handling. + Thanks to Tatsuhiko Kubo and Piotr Sikora. + + +Changes with nginx 1.7.3 08 Jul 2014 + + *) Feature: weak entity tags are now preserved on response + modifications, and strong ones are changed to weak. + + *) Feature: cache revalidation now uses If-None-Match header if + possible. + + *) Feature: the "ssl_password_file" directive. + + *) Bugfix: the If-None-Match request header line was ignored if there + was no Last-Modified header in a response returned from cache. + + *) Bugfix: "peer closed connection in SSL handshake" messages were + logged at "info" level instead of "error" while connecting to + backends. + + *) Bugfix: in the ngx_http_dav_module module in nginx/Windows. + + *) Bugfix: SPDY connections might be closed prematurely if caching was + used. + + +Changes with nginx 1.7.2 17 Jun 2014 + + *) Feature: the "hash" directive inside the "upstream" block. + + *) Feature: defragmentation of free shared memory blocks. + Thanks to Wandenberg Peixoto and Yichun Zhang. + + *) Bugfix: a segmentation fault might occur in a worker process if the + default value of the "access_log" directive was used; the bug had + appeared in 1.7.0. + Thanks to Piotr Sikora. + + *) Bugfix: trailing slash was mistakenly removed from the last parameter + of the "try_files" directive. + + *) Bugfix: nginx could not be built on OS X in some cases. + + *) Bugfix: in the ngx_http_spdy_module. + + +Changes with nginx 1.7.1 27 May 2014 + + *) Feature: the "$upstream_cookie_..." variables. + + *) Feature: the $ssl_client_fingerprint variable. + + *) Feature: the "error_log" and "access_log" directives now support + logging to syslog. + + *) Feature: the mail proxy now logs client port on connect. + + *) Bugfix: memory leak if the "ssl_stapling" directive was used. + Thanks to Filipe da Silva. + + *) Bugfix: the "alias" directive used inside a location given by a + regular expression worked incorrectly if the "if" or "limit_except" + directives were used. + + *) Bugfix: the "charset" directive did not set a charset to encoded + backend responses. + + *) Bugfix: a "proxy_pass" directive without URI part might use original + request after the $args variable was set. + Thanks to Yichun Zhang. + *) Bugfix: in the "none" parameter in the "smtp_auth" directive; the bug had appeared in 1.5.6. Thanks to Svyatoslav Nikolsky. + *) Bugfix: if sub_filter and SSI were used together, then responses + might be transferred incorrectly. -Changes with nginx 1.6.0 24 Apr 2014 + *) Bugfix: nginx could not be built with the --with-file-aio option on + Linux/aarch64. - *) 1.6.x stable branch. + +Changes with nginx 1.7.0 24 Apr 2014 + + *) Feature: backend SSL certificate verification. + + *) Feature: support for SNI while working with SSL backends. + + *) Feature: the $ssl_server_name variable. + + *) Feature: the "if" parameter of the "access_log" directive. Changes with nginx 1.5.13 08 Apr 2014 @@ -3249,7 +3631,7 @@ Changes with nginx 0.7.11 18 Aug 2008 *) Feature: the "proxy_ssl_session_reuse" directive. *) Bugfix: a "proxy_pass" directive without URI part might use original - request after the "X-Accel-Redirect" redirection was used; + request after the "X-Accel-Redirect" redirection was used. *) Bugfix: if a directory has search only rights and the first index file was absent, then nginx returned the 500 status code. diff --git a/CHANGES.ru b/CHANGES.ru index 054e033..b70c132 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,25 +1,280 @@ -Изменения в nginx 1.6.3 07.04.2015 +Изменения в nginx 1.9.1 26.05.2015 - *) Добавление: теперь директива tcp_nodelay работает для - SPDY-соединений. + *) Изменение: теперь протокол SSLv3 по умолчанию запрещён. - *) Исправление: в обработке ошибок. - Спасибо Yichun Zhang и Даниилу Бондареву. + *) Изменение: некоторые давно устаревшие директивы больше не + поддерживаются. - *) Исправление: при использовании директивы post_action в лог писались - сообщения "header already sent"; ошибка появилась в nginx 1.5.4. + *) Добавление: параметр reuseport директивы listen. + Спасибо Sepherosa Ziehau и Yingqi Lu. - *) Исправление: в лог могли писаться сообщения "sem_post() failed". + *) Добавление: переменная $upstream_connect_time. + + *) Исправление: в директиве hash на big-endian платформах. + + *) Исправление: nginx мог не запускаться на некоторых старых версиях + Linux; ошибка появилась в 1.7.11. + + *) Исправление: в парсинге IP-адресов. + Спасибо Сергею Половко. + + +Изменения в nginx 1.9.0 28.04.2015 + + *) Изменение: устаревшие методы обработки соединений aio и rtsig больше + не поддерживаются. + + *) Добавление: директива zone в блоке upstream. + + *) Добавление: модуль stream. + + *) Добавление: поддержка byte ranges для ответов модуля + ngx_http_memcached_module. + Спасибо Martin Mlynář. + + *) Добавление: разделяемую память теперь можно использовать на версиях + Windows с рандомизацией адресного пространства. + Спасибо Сергею Брестеру. + + *) Добавление: директиву error_log теперь можно использовать на уровнях + mail и server в почтовом прокси-сервере. + + *) Исправление: параметр proxy_protocol директивы listen не работал, + если не был указан в первой директиве listen для данного + listen-сокета. + + +Изменения в nginx 1.7.12 07.04.2015 + + *) Добавление: теперь директива tcp_nodelay работает для SSL-соединений + с бэкендами. + + *) Добавление: теперь потоки могут использоваться для чтения заголовков + файлов в кэше. + + *) Исправление: в директиве proxy_request_buffering. + + *) Исправление: при использовании потоков на Linux в рабочем процессе + мог произойти segmentation fault. + + *) Исправление: в обработке ошибок при использовании директивы + ssl_stapling. + Спасибо Filipe da Silva. + + *) Исправление: в модуле ngx_http_spdy_module. + + +Изменения в nginx 1.7.11 24.03.2015 + + *) Изменение: параметр sendfile директивы aio более не нужен; теперь + nginx автоматически использует AIO для подгрузки данных для sendfile, + если одновременно используются директивы aio и sendfile. + + *) Добавление: экспериментальная поддержка потоков. + + *) Добавление: директивы proxy_request_buffering, + fastcgi_request_buffering, scgi_request_buffering и + uwsgi_request_buffering. + + *) Добавление: экспериментальное API для обработки тела запроса. + + *) Добавление: проверка клиентских SSL-сертификатов в почтовом + прокси-сервере. + Спасибо Sven Peter, Franck Levionnois и Filipe Da Silva. + + *) Добавление: уменьшение времени запуска при использовании дирекивы + "hash ... consistent" в блоке upstream. + Спасибо Wai Keen Woon. + + *) Добавление: отладочное логгирование в кольцевой буфер в памяти. *) Исправление: в обработке хэш-таблиц. Спасибо Chris West. + *) Исправление: в директиве proxy_cache_revalidate. + + *) Исправление: SSL-соединения могли зависать, если использовался + отложенный accept или параметр proxy_protocol директивы listen. + Спасибо James Hamlin. + + *) Исправление: переменная $upstream_response_time могла содержать + неверное значение при использовании директивы image_filter. + *) Исправление: в обработке целочисленных переполнений. Спасибо Régis Leroy. + *) Исправление: при использовании LibreSSL было невозможно включить + поддержку SSLv3. -Изменения в nginx 1.6.2 16.09.2014 + *) Исправление: при использовании LibreSSL в логах появлялись сообщения + "ignoring stale global SSL error ... called a function you should not + call". + + *) Исправление: сертификаты, указанные в директивах + ssl_client_certificate и ssl_trusted_certificate, использовались для + автоматического построения цепочек сертификатов. + + +Изменения в nginx 1.7.10 10.02.2015 + + *) Добавление: параметр use_temp_path директив proxy_cache_path, + fastcgi_cache_path, scgi_cache_path и uwsgi_cache_path. + + *) Добавление: переменная $upstream_header_time. + + *) Изменение: теперь при переполнении диска nginx пытается писать + error_log'и только раз в секунду. + + *) Исправление: директива try_files при тестировании каталогов не + игнорировала обычные файлы. + Спасибо Damien Tournoud. + + *) Исправление: при использовании директивы sendfile на OS X возникали + ошибки "sendfile() failed"; ошибка появилась в nginx 1.7.8. + + *) Исправление: в лог могли писаться сообщения "sem_post() failed". + + *) Исправление: nginx не собирался с musl libc. + Спасибо James Taylor. + + *) Исправление: nginx не собирался на Tru64 UNIX. + Спасибо Goetz T. Fischer. + + +Изменения в nginx 1.7.9 23.12.2014 + + *) Добавление: директивы proxy_cache, fastcgi_cache, scgi_cache и + uwsgi_cache поддерживают переменные. + + *) Добавление: директива expires поддерживает переменные. + + *) Добавление: возможность загрузки секретных ключей с аппаратных + устройств с помощью OpenSSL engines. + Спасибо Дмитрию Пичулину. + + *) Добавление: директива autoindex_format. + + *) Исправление: ревалидация элементов кэша теперь используется только + для ответов с кодами 200 и 206. + Спасибо Piotr Sikora. + + *) Исправление: строка "TE" заголовка запроса клиента передавалась на + бэкенд при проксировании. + + *) Исправление: директивы proxy_pass, fastcgi_pass, scgi_pass и + uwsgi_pass могли неправильно работать внутри блоков if и + limit_except. + + *) Исправление: директива proxy_store с параметром "on" игнорировалась, + если на предыдущем уровне использовалась директива proxy_store с явно + заданным путём к файлам. + + *) Исправление: nginx не собирался с BoringSSL. + Спасибо Lukas Tribus. + + +Изменения в nginx 1.7.8 02.12.2014 + + *) Изменение: теперь строки "If-Modified-Since", "If-Range" и им + подобные в заголовке запроса клиента передаются бэкенду при + включённом кэшировании, если nginx заранее знает, что не будет + кэшировать ответ (например, при использовании proxy_cache_min_uses). + + *) Изменение: теперь после истечения proxy_cache_lock_timeout nginx + отправляет запрос на бэкенд без кэширования; новые директивы + proxy_cache_lock_age, fastcgi_cache_lock_age, scgi_cache_lock_age и + uwsgi_cache_lock_age позволяют указать, через какое время блокировка + будет принудительно снята и будет сделана ещё одна попытка + закэшировать ответ. + + *) Изменение: директива log_format теперь может использоваться только на + уровне http. + + *) Добавление: директивы proxy_ssl_certificate, + proxy_ssl_certificate_key, proxy_ssl_password_file, + uwsgi_ssl_certificate, uwsgi_ssl_certificate_key и + uwsgi_ssl_password_file. + Спасибо Piotr Sikora. + + *) Добавление: теперь с помощью X-Accel-Redirect можно перейти в + именованный location. + Спасибо Toshikuni Fukaya. + + *) Добавление: теперь директива tcp_nodelay работает для + SPDY-соединений. + + *) Добавление: новые директивы в скриптах подсветки синтаксиса для vim. + Спасибо Peter Wu. + + *) Исправление: nginx игнорировал значение "s-maxage" в строке + "Cache-Control" в заголовке ответа бэкенда. + Спасибо Piotr Sikora. + + *) Исправление: в модуле ngx_http_spdy_module. + Спасибо Piotr Sikora. + + *) Исправление: в директиве ssl_password_file при использовании OpenSSL + 0.9.8zc, 1.0.0o, 1.0.1j. + + *) Исправление: при использовании директивы post_action в лог писались + сообщения "header already sent"; ошибка появилась в nginx 1.5.4. + + *) Исправление: при использовании директивы "postpone_output 0" с + SSI-подзапросами в лог могли писаться сообщения "the http output + chain is empty". + + *) Исправление: в директиве proxy_cache_lock при использовании + SSI-подзапросов. + Спасибо Yichun Zhang. + + +Изменения в nginx 1.7.7 28.10.2014 + + *) Изменение: теперь nginx учитывает при кэшировании строку "Vary" в + заголовке ответа бэкенда. + + *) Добавление: директивы proxy_force_ranges, fastcgi_force_ranges, + scgi_force_ranges и uwsgi_force_ranges. + + *) Добавление: директивы proxy_limit_rate, fastcgi_limit_rate, + scgi_limit_rate и uwsgi_limit_rate. + + *) Добавление: параметр Vary директив proxy_ignore_headers, + fastcgi_ignore_headers, scgi_ignore_headers и uwsgi_ignore_headers. + + *) Исправление: последняя часть ответа, полученного от бэкенда при + небуферизированном проксировании, могла не отправляться клиенту, если + использовались директивы gzip или gunzip. + + *) Исправление: в директиве proxy_cache_revalidate. + Спасибо Piotr Sikora. + + *) Исправление: в обработке ошибок. + Спасибо Yichun Zhang и Даниилу Бондареву. + + *) Исправление: в директивах proxy_next_upstream_tries и + proxy_next_upstream_timeout. + Спасибо Feng Gu. + + *) Исправление: nginx/Windows не собирался с MinGW-w64 gcc. + Спасибо Kouhei Sutou. + + +Изменения в nginx 1.7.6 30.09.2014 + + *) Изменение: устаревшая директива limit_zone больше не поддерживается. + + *) Добавление: в директивах limit_conn_zone и limit_req_zone теперь + можно использовать комбинации нескольких переменных. + + *) Исправление: при повторной отправке FastCGI-запроса на бэкенд тело + запроса могло передаваться неправильно. + + *) Исправление: в логгировании в syslog. + + +Изменения в nginx 1.7.5 16.09.2014 *) Безопасность: при использовании общего для нескольких блоков server разделяемого кэша SSL-сессий или общего ключа для шифрования TLS @@ -27,32 +282,172 @@ контексте другого блока server (CVE-2014-3616). Спасибо Antoine Delignat-Lavaud. - *) Исправление: запросы могли зависать, если использовался resolver и - DNS-сервер возвращал некорректный ответ; ошибка появилась в 1.5.8. + *) Изменение: директиву stub_status теперь можно указывать без + параметров. + + *) Добавление: параметр always директивы add_header. + + *) Добавление: директивы proxy_next_upstream_tries, + proxy_next_upstream_timeout, fastcgi_next_upstream_tries, + fastcgi_next_upstream_timeout, memcached_next_upstream_tries, + memcached_next_upstream_timeout, scgi_next_upstream_tries, + scgi_next_upstream_timeout, uwsgi_next_upstream_tries и + uwsgi_next_upstream_timeout. + + *) Исправление: в параметре if директивы access_log. + + *) Исправление: в модуле ngx_http_perl_module. + Спасибо Piotr Sikora. + + *) Исправление: директива listen почтового прокси-сервера не позволяла + указать более двух параметров. + + *) Исправление: директива sub_filter не работала с заменяемой строкой из + одного символа. *) Исправление: запросы могли зависать, если использовался resolver и в процессе обращения к DNS-серверу происходил таймаут. + *) Исправление: в модуле ngx_http_spdy_module при использовании + совместно с AIO. -Изменения в nginx 1.6.1 05.08.2014 + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если с помощью директивы set изменялись переменные "$http_...", + "$sent_http_..." или "$upstream_http_...". + + *) Исправление: в обработке ошибок выделения памяти. + Спасибо Markus Linnala и Feng Gu. + + +Изменения в nginx 1.7.4 05.08.2014 *) Безопасность: pipelined-команды не отбрасывались после команды STARTTLS в SMTP прокси-сервере (CVE-2014-3556); ошибка появилась в 1.5.6. Спасибо Chris Boulton. + *) Изменение: экранирование символов в URI теперь использует + шестнадцатеричные цифры в верхнем регистре. + Спасибо Piotr Sikora. + + *) Добавление: теперь nginx можно собрать с BoringSSL и LibreSSL. + Спасибо Piotr Sikora. + + *) Исправление: запросы могли зависать, если использовался resolver и + DNS-сервер возвращал некорректный ответ; ошибка появилась в 1.5.8. + + *) Исправление: в модуле ngx_http_spdy_module. + Спасибо Piotr Sikora. + *) Исправление: переменная $uri могла содержать мусор при возврате ошибок с кодом 400. Спасибо Сергею Боброву. + *) Исправление: в обработке ошибок в директиве proxy_store и в модуле + ngx_http_dav_module. + Спасибо Feng Gu. + + *) Исправление: при логгировании ошибок в syslog мог происходить + segmentation fault; ошибка появилась в 1.7.1. + + *) Исправление: переменные $geoip_latitude, $geoip_longitude, + $geoip_dma_code и $geoip_area_code могли не работать. + Спасибо Yichun Zhang. + + *) Исправление: в обработке ошибок выделения памяти. + Спасибо Tatsuhiko Kubo и Piotr Sikora. + + +Изменения в nginx 1.7.3 08.07.2014 + + *) Добавление: weak entity tags теперь не удаляются при изменениях + ответа, а strong entity tags преобразуются в weak. + + *) Добавление: ревалидация элементов кэша теперь, если это возможно, + использует заголовок If-None-Match. + + *) Добавление: директива ssl_password_file. + + *) Исправление: при возврате ответа из кэша заголовок запроса + If-None-Match игнорировался, если в ответе не было заголовка + Last-Modified. + + *) Исправление: сообщения "peer closed connection in SSL handshake" при + соединении с бэкендами логгировались на уровне info вместо error. + + *) Исправление: в модуле ngx_http_dav_module в nginx/Windows. + + *) Исправление: SPDY-соединения могли неожиданно закрываться, если + использовалось кэширование. + + +Изменения в nginx 1.7.2 17.06.2014 + + *) Добавление: директива hash в блоке upstream. + + *) Добавление: дефрагментация свободных блоков разделяемой памяти. + Спасибо Wandenberg Peixoto и Yichun Zhang. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если использовалось значение access_log по умолчанию; ошибка + появилась в 1.7.0. + Спасибо Piotr Sikora. + + *) Исправление: завершающий слэш ошибочно удалялся из последнего + параметра директивы try_files. + + *) Исправление: nginx мог не собираться на OS X. + + *) Исправление: в модуле ngx_http_spdy_module. + + +Изменения в nginx 1.7.1 27.05.2014 + + *) Добавление: переменные "$upstream_cookie_...". + + *) Добавление: переменная $ssl_client_fingerprint. + + *) Добавление: директивы error_log и access_log теперь поддерживают + логгирование в syslog. + + *) Добавление: почтовый прокси-сервер теперь логгирует порт клиента при + соединении. + + *) Исправление: утечки памяти при использовании директивы + "ssl_stapling". + Спасибо Filipe da Silva. + + *) Исправление: директива alias внутри location'а, заданного регулярным + выражением, работала неправильно, если использовались директивы if + или limit_except. + + *) Исправление: директива charset не ставила кодировку для сжатых + ответов бэкендов. + + *) Исправление: директива proxy_pass без URI могла использовать + оригинальный запрос после установки переменной $args. + Спасибо Yichun Zhang. + *) Исправление: в работе параметра none директивы smtp_auth; ошибка появилась в 1.5.6. Спасибо Святославу Никольскому. + *) Исправление: при совместном использовании sub_filter и SSI ответы + могли передаваться неверно. -Изменения в nginx 1.6.0 24.04.2014 + *) Исправление: nginx не собирался с параметром --with-file-aio на + Linux/aarch64. - *) Стабильная ветка 1.6.x. + +Изменения в nginx 1.7.0 24.04.2014 + + *) Добавление: проверка SSL-сертификатов бэкендов. + + *) Добавление: поддержка SNI при работе с бэкендами по SSL. + + *) Добавление: переменная $ssl_server_name. + + *) Добавление: параметр if директивы access_log. Изменения в nginx 1.5.13 08.04.2014 @@ -1578,7 +1973,7 @@ Изменения в nginx 0.9.2 06.12.2010 *) Добавление: поддержка строки "If-Unmodified-Since" в заголовке - запросе клиента. + запроса клиента. *) Изменение: использование accept(), если accept4() не реализован; ошибка появилась в 0.9.0. @@ -3526,7 +3921,7 @@ Изменения в nginx 0.6.31 12.05.2008 *) Исправление: nginx не обрабатывал ответ FastCGI-сервера, если строка - заголовка ответ была в конце записи FastCGI; ошибка появилась в + заголовка ответа была в конце записи FastCGI; ошибка появилась в 0.6.2. Спасибо Сергею Серову. @@ -4602,7 +4997,7 @@ *) Добавление: директива ip_hash в блоке upstream. - *) Добавление: статус WAIT в строке "Auth-Status" в заголовка ответа + *) Добавление: статус WAIT в строке "Auth-Status" в заголовке ответа сервера аутентификации IMAP/POP3 прокси. *) Исправление: nginx не собирался на 64-битных платформах; ошибка @@ -6087,7 +6482,7 @@ Изменения в nginx 0.1.36 15.06.2005 - *) Изменение: если в заголовке запросе есть дублирующиеся строки "Host", + *) Изменение: если в заголовке запроса есть дублирующиеся строки "Host", "Connection", "Content-Length" и "Authorization", то nginx теперь выдаёт ошибку 400. diff --git a/LICENSE b/LICENSE index 4ed7a6f..f752308 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ /* - * Copyright (C) 2002-2014 Igor Sysoev - * Copyright (C) 2011-2014 Nginx, Inc. + * Copyright (C) 2002-2015 Igor Sysoev + * Copyright (C) 2011-2015 Nginx, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/auto/cc/clang b/auto/cc/clang index baaf4ba..25707b4 100644 --- a/auto/cc/clang +++ b/auto/cc/clang @@ -88,6 +88,11 @@ CFLAGS="$CFLAGS -Wconditional-uninitialized" # we have a lot of unused function arguments CFLAGS="$CFLAGS -Wno-unused-parameter" +# deprecated system OpenSSL library on OS X +if [ "$NGX_SYSTEM" = "Darwin" ]; then + CFLAGS="$CFLAGS -Wno-deprecated-declarations" +fi + # stop on warning CFLAGS="$CFLAGS -Werror" diff --git a/auto/cc/gcc b/auto/cc/gcc index c27d857..727f11e 100644 --- a/auto/cc/gcc +++ b/auto/cc/gcc @@ -158,6 +158,11 @@ case "$NGX_GCC_VER" in CFLAGS="$CFLAGS -Wno-unused-parameter" # 4.2.1 shows the warning in wrong places #CFLAGS="$CFLAGS -Wunreachable-code" + + # deprecated system OpenSSL library on OS X + if [ "$NGX_SYSTEM" = "Darwin" ]; then + CFLAGS="$CFLAGS -Wno-deprecated-declarations" + fi ;; *) diff --git a/auto/lib/google-perftools/conf b/auto/lib/google-perftools/conf index 7a9de30..5d5ddae 100644 --- a/auto/lib/google-perftools/conf +++ b/auto/lib/google-perftools/conf @@ -52,7 +52,7 @@ else cat << END -$0: error: the Google perftool module requires the Google perftools +$0: error: the Google perftools module requires the Google perftools library. You can either do not enable the module or install the library. END diff --git a/auto/lib/openssl/make b/auto/lib/openssl/make index e64acd9..765cd06 100644 --- a/auto/lib/openssl/make +++ b/auto/lib/openssl/make @@ -41,11 +41,6 @@ END ;; *) - case $USE_THREADS in - NO) OPENSSL_OPT="$OPENSSL_OPT no-threads" ;; - *) OPENSSL_OPT="$OPENSSL_OPT threads" ;; - esac - case $OPENSSL in /*) ngx_prefix="$OPENSSL/.openssl" ;; *) ngx_prefix="$PWD/$OPENSSL/.openssl" ;; diff --git a/auto/lib/perl/conf b/auto/lib/perl/conf index 2fbaa76..2a1a3fe 100644 --- a/auto/lib/perl/conf +++ b/auto/lib/perl/conf @@ -41,6 +41,8 @@ if test -n "$NGX_PERL_VER"; then ngx_perl_ldopts=`$NGX_PERL -MExtUtils::Embed -e ldopts` ngx_perl_dlext=`$NGX_PERL -MConfig -e 'print $Config{dlext}'` + ngx_perl_libdir="src/http/modules/perl/blib/arch/auto" + ngx_perl_module="$ngx_perl_libdir/nginx/nginx.$ngx_perl_dlext" if $NGX_PERL -V:usemultiplicity | grep define > /dev/null; then have=NGX_HAVE_PERL_MULTIPLICITY . auto/have @@ -52,8 +54,14 @@ if test -n "$NGX_PERL_VER"; then ngx_perl_ldopts=`echo $ngx_perl_ldopts | sed 's/ -pthread//'` fi + if [ "$NGX_SYSTEM" = "Darwin" ]; then + # OS X system perl wants to link universal binaries + ngx_perl_ldopts=`echo $ngx_perl_ldopts \ + | sed -e 's/-arch x86_64 -arch i386//'` + fi + CORE_LINK="$CORE_LINK $ngx_perl_ldopts" - LINK_DEPS="$LINK_DEPS $NGX_OBJS/src/http/modules/perl/blib/arch/auto/nginx/nginx.$ngx_perl_dlext" + LINK_DEPS="$LINK_DEPS $NGX_OBJS/$ngx_perl_module" if test -n "$NGX_PERL_MODULES"; then have=NGX_PERL_MODULES value="(u_char *) \"$NGX_PERL_MODULES\"" diff --git a/auto/lib/zlib/patch.zlib.h b/auto/lib/zlib/patch.zlib.h deleted file mode 100644 index 122f7fa..0000000 --- a/auto/lib/zlib/patch.zlib.h +++ /dev/null @@ -1,10 +0,0 @@ ---- zlib.h Thu Jul 9 20:06:56 1998 -+++ zlib-1.1.3/zlib.h Tue Mar 22 13:41:04 2005 -@@ -709,7 +709,6 @@ - (0 in case of error). - */ - --ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); - /* - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of diff --git a/auto/make b/auto/make index 05b7454..98c2e3b 100644 --- a/auto/make +++ b/auto/make @@ -8,8 +8,9 @@ echo "creating $NGX_MAKEFILE" mkdir -p $NGX_OBJS/src/core $NGX_OBJS/src/event $NGX_OBJS/src/event/modules \ $NGX_OBJS/src/os/unix $NGX_OBJS/src/os/win32 \ $NGX_OBJS/src/http $NGX_OBJS/src/http/modules \ - $NGX_OBJS/src/http/modules/perl \ + $NGX_OBJS/src/http/modules/perl \ $NGX_OBJS/src/mail \ + $NGX_OBJS/src/stream \ $NGX_OBJS/src/misc @@ -35,7 +36,7 @@ fi # ALL_INCS, required by the addons and by OpenWatcom C precompiled headers -ngx_incs=`echo $CORE_INCS $NGX_OBJS $HTTP_INCS $MAIL_INCS\ +ngx_incs=`echo $CORE_INCS $NGX_OBJS $HTTP_INCS $MAIL_INCS $STREAM_INCS\ | sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont$ngx_include_opt\1/g" \ -e "s/\//$ngx_regex_dirsep/g"` @@ -121,6 +122,32 @@ END fi +# the stream dependences and include paths + +if [ $STREAM = YES ]; then + + ngx_all_srcs="$ngx_all_srcs $STREAM_SRCS" + + ngx_deps=`echo $STREAM_DEPS \ + | sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont\1/g" \ + -e "s/\//$ngx_regex_dirsep/g"` + + ngx_incs=`echo $STREAM_INCS \ + | sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont$ngx_include_opt\1/g" \ + -e "s/\//$ngx_regex_dirsep/g"` + + cat << END >> $NGX_MAKEFILE + +STREAM_DEPS = $ngx_deps + + +STREAM_INCS = $ngx_include_opt$ngx_incs + +END + +fi + + ngx_all_srcs="$ngx_all_srcs $NGX_MISC_SRCS" @@ -306,6 +333,36 @@ END fi +# the stream sources + +if [ $STREAM = YES ]; then + + if test -n "$NGX_PCH"; then + ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)" + else + ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) \$(CORE_INCS) \$(STREAM_INCS)" + fi + + for ngx_src in $STREAM_SRCS + do + ngx_src=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"` + ngx_obj=`echo $ngx_src \ + | sed -e "s#^\(.*\.\)cpp\\$#$ngx_objs_dir\1$ngx_objext#g" \ + -e "s#^\(.*\.\)cc\\$#$ngx_objs_dir\1$ngx_objext#g" \ + -e "s#^\(.*\.\)c\\$#$ngx_objs_dir\1$ngx_objext#g" \ + -e "s#^\(.*\.\)S\\$#$ngx_objs_dir\1$ngx_objext#g"` + + cat << END >> $NGX_MAKEFILE + +$ngx_obj: \$(CORE_DEPS) \$(STREAM_DEPS)$ngx_cont$ngx_src + $ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX + +END + done + +fi + + # the misc sources if test -n "$NGX_MISC_SRCS"; then diff --git a/auto/modules b/auto/modules index e1eda94..de3dc4a 100644 --- a/auto/modules +++ b/auto/modules @@ -49,13 +49,6 @@ if [ $NGX_TEST_BUILD_EPOLL = YES ]; then CORE_SRCS="$CORE_SRCS $EPOLL_SRCS" fi -if [ $NGX_TEST_BUILD_RTSIG = YES ]; then - have=NGX_HAVE_RTSIG . auto/have - have=NGX_TEST_BUILD_RTSIG . auto/have - EVENT_MODULES="$EVENT_MODULES $RTSIG_MODULE" - CORE_SRCS="$CORE_SRCS $RTSIG_SRCS" -fi - if [ $NGX_TEST_BUILD_SOLARIS_SENDFILEV = YES ]; then have=NGX_TEST_BUILD_SOLARIS_SENDFILEV . auto/have CORE_SRCS="$CORE_SRCS $SOLARIS_SENDFILEV_SRCS" @@ -371,6 +364,11 @@ if [ $HTTP_MP4 = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_MP4_SRCS" fi +if [ $HTTP_UPSTREAM_HASH = YES ]; then + HTTP_MODULES="$HTTP_MODULES $HTTP_UPSTREAM_HASH_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_HASH_SRCS" +fi + if [ $HTTP_UPSTREAM_IP_HASH = YES ]; then HTTP_MODULES="$HTTP_MODULES $HTTP_UPSTREAM_IP_HASH_MODULE" HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_IP_HASH_SRCS" @@ -386,6 +384,12 @@ if [ $HTTP_UPSTREAM_KEEPALIVE = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_KEEPALIVE_SRCS" fi +if [ $HTTP_UPSTREAM_ZONE = YES ]; then + have=NGX_HTTP_UPSTREAM_ZONE . auto/have + HTTP_MODULES="$HTTP_MODULES $HTTP_UPSTREAM_ZONE_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_ZONE_SRCS" +fi + if [ $HTTP_STUB_STATUS = YES ]; then have=NGX_STAT_STUB . auto/have HTTP_MODULES="$HTTP_MODULES ngx_http_stub_status_module" @@ -424,9 +428,21 @@ if [ $MAIL_SSL = YES ]; then fi +if [ $STREAM_SSL = YES ]; then + have=NGX_STREAM_SSL . auto/have + USE_OPENSSL=YES +fi + + modules="$CORE_MODULES $EVENT_MODULES" +# thread pool module should be initialized after events +if [ $USE_THREADS = YES ]; then + modules="$modules $THREAD_POOL_MODULE" +fi + + if [ $USE_OPENSSL = YES ]; then modules="$modules $OPENSSL_MODULE" CORE_DEPS="$CORE_DEPS $OPENSSL_DEPS" @@ -488,6 +504,36 @@ if [ $MAIL = YES ]; then fi +if [ $STREAM = YES ]; then + have=NGX_STREAM . auto/have + modules="$modules $STREAM_MODULES" + + if [ $STREAM_SSL = YES ]; then + modules="$modules $STREAM_SSL_MODULE" + STREAM_DEPS="$STREAM_DEPS $STREAM_SSL_DEPS" + STREAM_SRCS="$STREAM_SRCS $STREAM_SSL_SRCS" + fi + + if [ $STREAM_UPSTREAM_HASH = YES ]; then + modules="$modules $STREAM_UPSTREAM_HASH_MODULE" + STREAM_SRCS="$STREAM_SRCS $STREAM_UPSTREAM_HASH_SRCS" + fi + + if [ $STREAM_UPSTREAM_LEAST_CONN = YES ]; then + modules="$modules $STREAM_UPSTREAM_LEAST_CONN_MODULE" + STREAM_SRCS="$STREAM_SRCS $STREAM_UPSTREAM_LEAST_CONN_SRCS" + fi + + if [ $STREAM_UPSTREAM_ZONE = YES ]; then + have=NGX_STREAM_UPSTREAM_ZONE . auto/have + modules="$modules $STREAM_UPSTREAM_ZONE_MODULE" + STREAM_SRCS="$STREAM_SRCS $STREAM_UPSTREAM_ZONE_SRCS" + fi + + NGX_ADDON_DEPS="$NGX_ADDON_DEPS \$(STREAM_DEPS)" +fi + + if [ $NGX_GOOGLE_PERFTOOLS = YES ]; then modules="$modules $NGX_GOOGLE_PERFTOOLS_MODULE" NGX_MISC_SRCS="$NGX_MISC_SRCS $NGX_GOOGLE_PERFTOOLS_SRCS" diff --git a/auto/options b/auto/options index 6cea8c7..e3a7ede 100644 --- a/auto/options +++ b/auto/options @@ -14,6 +14,7 @@ NGX_PID_PATH= NGX_LOCK_PATH= NGX_USER= NGX_GROUP= +NGX_BUILD= CC=${CC:-cc} CPP= @@ -29,7 +30,6 @@ NGX_RPATH=NO NGX_TEST_BUILD_DEVPOLL=NO NGX_TEST_BUILD_EVENTPORT=NO NGX_TEST_BUILD_EPOLL=NO -NGX_TEST_BUILD_RTSIG=NO NGX_TEST_BUILD_SOLARIS_SENDFILEV=NO NGX_PLATFORM= @@ -37,10 +37,8 @@ NGX_WINE= EVENT_FOUND=NO -EVENT_RTSIG=NO EVENT_SELECT=NO EVENT_POLL=NO -EVENT_AIO=NO USE_THREADS=NO @@ -98,9 +96,11 @@ HTTP_FLV=NO HTTP_MP4=NO HTTP_GUNZIP=NO HTTP_GZIP_STATIC=NO +HTTP_UPSTREAM_HASH=YES HTTP_UPSTREAM_IP_HASH=YES HTTP_UPSTREAM_LEAST_CONN=YES HTTP_UPSTREAM_KEEPALIVE=YES +HTTP_UPSTREAM_ZONE=YES # STUB HTTP_STUB_STATUS=NO @@ -111,6 +111,12 @@ MAIL_POP3=YES MAIL_IMAP=YES MAIL_SMTP=YES +STREAM=NO +STREAM_SSL=NO +STREAM_UPSTREAM_HASH=YES +STREAM_UPSTREAM_LEAST_CONN=YES +STREAM_UPSTREAM_ZONE=YES + NGX_ADDONS= USE_PCRE=NO @@ -178,17 +184,15 @@ do --crossbuild=*) NGX_PLATFORM="$value" ;; + --build=*) NGX_BUILD="$value" ;; --builddir=*) NGX_OBJS="$value" ;; - --with-rtsig_module) EVENT_RTSIG=YES ;; --with-select_module) EVENT_SELECT=YES ;; --without-select_module) EVENT_SELECT=NONE ;; --with-poll_module) EVENT_POLL=YES ;; --without-poll_module) EVENT_POLL=NONE ;; - --with-aio_module) EVENT_AIO=YES ;; - #--with-threads=*) USE_THREADS="$value" ;; - #--with-threads) USE_THREADS="pthreads" ;; + --with-threads) USE_THREADS=YES ;; --with-file-aio) NGX_FILE_AIO=YES ;; --with-ipv6) NGX_IPV6=YES ;; @@ -239,20 +243,16 @@ 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_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_hash_module) HTTP_UPSTREAM_HASH=NO ;; --without-http_upstream_ip_hash_module) HTTP_UPSTREAM_IP_HASH=NO ;; --without-http_upstream_least_conn_module) HTTP_UPSTREAM_LEAST_CONN=NO ;; --without-http_upstream_keepalive_module) HTTP_UPSTREAM_KEEPALIVE=NO ;; + --without-http_upstream_zone_module) HTTP_UPSTREAM_ZONE=NO ;; --with-http_perl_module) HTTP_PERL=YES ;; --with-perl_modules_path=*) NGX_PERL_MODULES="$value" ;; @@ -264,12 +264,31 @@ use the \"--without-http_limit_conn_module\" option instead" --with-mail) MAIL=YES ;; --with-mail_ssl_module) MAIL_SSL=YES ;; # STUB - --with-imap) MAIL=YES ;; - --with-imap_ssl_module) MAIL_SSL=YES ;; + --with-imap) + MAIL=YES + NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG +$0: warning: the \"--with-imap\" option is deprecated, \ +use the \"--with-mail\" option instead" + ;; + --with-imap_ssl_module) + MAIL_SSL=YES + NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG +$0: warning: the \"--with-imap_ssl_module\" option is deprecated, \ +use the \"--with-mail_ssl_module\" option instead" + ;; --without-mail_pop3_module) MAIL_POP3=NO ;; --without-mail_imap_module) MAIL_IMAP=NO ;; --without-mail_smtp_module) MAIL_SMTP=NO ;; + --with-stream) STREAM=YES ;; + --with-stream_ssl_module) STREAM_SSL=YES ;; + --without-stream_upstream_hash_module) + STREAM_UPSTREAM_HASH=NO ;; + --without-stream_upstream_least_conn_module) + STREAM_UPSTREAM_LEAST_CONN=NO ;; + --without-stream_upstream_zone_module) + STREAM_UPSTREAM_ZONE=NO ;; + --with-google_perftools_module) NGX_GOOGLE_PERFTOOLS=YES ;; --with-cpp_test_module) NGX_CPP_TEST=YES ;; @@ -309,7 +328,6 @@ use the \"--without-http_limit_conn_module\" option instead" --test-build-devpoll) NGX_TEST_BUILD_DEVPOLL=YES ;; --test-build-eventport) NGX_TEST_BUILD_EVENTPORT=YES ;; --test-build-epoll) NGX_TEST_BUILD_EPOLL=YES ;; - --test-build-rtsig) NGX_TEST_BUILD_RTSIG=YES ;; --test-build-solaris-sendfilev) NGX_TEST_BUILD_SOLARIS_SENDFILEV=YES ;; *) @@ -341,14 +359,16 @@ cat << END --group=GROUP set non-privileged group for worker processes + --build=NAME set build name --builddir=DIR set build directory - --with-rtsig_module enable rtsig module --with-select_module enable select module --without-select_module disable select module --with-poll_module enable poll module --without-poll_module disable poll module + --with-threads enable thread pool support + --with-file-aio enable file AIO support --with-ipv6 enable IPv6 support @@ -392,12 +412,16 @@ cat << END --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 + --without-http_upstream_hash_module + disable ngx_http_upstream_hash_module --without-http_upstream_ip_hash_module disable ngx_http_upstream_ip_hash_module --without-http_upstream_least_conn_module disable ngx_http_upstream_least_conn_module --without-http_upstream_keepalive_module disable ngx_http_upstream_keepalive_module + --without-http_upstream_zone_module + disable ngx_http_upstream_zone_module --with-http_perl_module enable ngx_http_perl_module --with-perl_modules_path=PATH set Perl modules path @@ -424,6 +448,15 @@ cat << END --without-mail_imap_module disable ngx_mail_imap_module --without-mail_smtp_module disable ngx_mail_smtp_module + --with-stream enable TCP proxy module + --with-stream_ssl_module enable ngx_stream_ssl_module + --without-stream_upstream_hash_module + disable ngx_stream_upstream_hash_module + --without-stream_upstream_least_conn_module + disable ngx_stream_upstream_least_conn_module + --without-stream_upstream_zone_module + disable ngx_stream_upstream_zone_module + --with-google_perftools_module enable ngx_google_perftools_module --with-cpp_test_module enable ngx_cpp_test_module diff --git a/auto/os/conf b/auto/os/conf index fe72016..6ad0e74 100644 --- a/auto/os/conf +++ b/auto/os/conf @@ -60,6 +60,15 @@ case "$NGX_PLATFORM" in CORE_SRCS="$UNIX_SRCS" ;; + GNU:*) + # GNU Hurd + have=NGX_GNU_HURD . auto/have_headers + CORE_INCS="$UNIX_INCS" + CORE_DEPS="$UNIX_DEPS $POSIX_DEPS" + CORE_SRCS="$UNIX_SRCS" + CC_AUX_FLAGS="$CC_AUX_FLAGS -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64" + ;; + *) CORE_INCS="$UNIX_INCS" CORE_DEPS="$UNIX_DEPS $POSIX_DEPS" diff --git a/auto/os/darwin b/auto/os/darwin index b97518a..1d3e3d3 100644 --- a/auto/os/darwin +++ b/auto/os/darwin @@ -100,7 +100,6 @@ ngx_feature_test="int s = 0, fd = 1; . auto/feature if [ $ngx_found = yes ]; then - have=NGX_HAVE_SENDFILE . auto/have CORE_SRCS="$CORE_SRCS $DARWIN_SENDFILE_SRCS" fi diff --git a/auto/os/freebsd b/auto/os/freebsd index 6aa823f..937ca20 100644 --- a/auto/os/freebsd +++ b/auto/os/freebsd @@ -44,10 +44,12 @@ if [ $osreldate -gt 300007 ]; then CORE_SRCS="$CORE_SRCS $FREEBSD_SENDFILE_SRCS" fi -if [ $osreldate -gt 502103 ]; then - echo " + sendfile()'s SF_NODISKIO found" +if [ $NGX_FILE_AIO = YES ]; then + if [ $osreldate -gt 502103 ]; then + echo " + sendfile()'s SF_NODISKIO found" - have=NGX_HAVE_AIO_SENDFILE . auto/have + have=NGX_HAVE_AIO_SENDFILE . auto/have + fi fi # POSIX semaphores @@ -78,7 +80,7 @@ fi NGX_KQUEUE_CHECKED=YES -# kqueue's NOTE_LAWAT +# kqueue's NOTE_LOWAT if [ \( $version -lt 500000 -a $version -ge 430000 \) \ -o $version -ge 500018 ] @@ -97,45 +99,6 @@ then fi -if [ $USE_THREADS = "rfork" ]; then - - echo " + using rfork()" - -# # kqueue's EVFILT_SIGNAL is safe -# -# if [ $version -gt 460101 ]; then -# echo " + kqueue's EVFILT_SIGNAL is safe" -# have=NGX_HAVE_SAFE_EVFILT_SIGNAL . auto/have -# else -# echo "$0: error: the kqueue's EVFILT_SIGNAL is unsafe on this" -# echo "FreeBSD version, so --with-threads=rfork could not be used" -# echo -# -# exit 1 -# fi -fi - - -if [ $EVENT_AIO = YES ]; then - if [ \( $version -lt 500000 -a $version -ge 430000 \) \ - -o $version -ge 500014 ] - then - have=NGX_HAVE_AIO . auto/have - EVENT_MODULES="$EVENT_MODULES $AIO_MODULE" - CORE_SRCS="$CORE_SRCS $AIO_SRCS" - else - -cat << END - -$0: error: the kqueue does not support AIO on this FreeBSD version - -END - - exit 1 - fi -fi - - # cpuset_setaffinity() if [ $version -ge 701000 ]; then diff --git a/auto/os/linux b/auto/os/linux index 19bf832..c932267 100644 --- a/auto/os/linux +++ b/auto/os/linux @@ -26,18 +26,6 @@ version=$((`uname -r \ version=${version:-0} -# enable the rt signals on Linux between 2.2.19 and 2.6.17 - -if [ \( $version -ge 131603 -a $version -lt 132626 \) -o $EVENT_RTSIG = YES ] -then - echo " + rt signals found" - have=NGX_HAVE_RTSIG . auto/have - EVENT_MODULES="$EVENT_MODULES $RTSIG_MODULE" - CORE_SRCS="$CORE_SRCS $RTSIG_SRCS" - EVENT_FOUND=YES -fi - - # posix_fadvise64() had been implemented in 2.5.60 if [ $version -lt 132412 ]; then diff --git a/auto/os/win32 b/auto/os/win32 index 0b9b461..82fc212 100644 --- a/auto/os/win32 +++ b/auto/os/win32 @@ -36,5 +36,4 @@ if [ $NGX_IPV6 = YES ]; then have=NGX_HAVE_INET6 . auto/have fi -have=NGX_HAVE_AIO . auto/have have=NGX_HAVE_IOCP . auto/have diff --git a/auto/sources b/auto/sources index bff0eb1..156db56 100644 --- a/auto/sources +++ b/auto/sources @@ -28,6 +28,7 @@ CORE_DEPS="src/core/nginx.h \ src/core/ngx_sha1.h \ src/core/ngx_rbtree.h \ src/core/ngx_radix_tree.h \ + src/core/ngx_rwlock.h \ src/core/ngx_slab.h \ src/core/ngx_times.h \ src/core/ngx_shmtx.h \ @@ -37,7 +38,8 @@ CORE_DEPS="src/core/nginx.h \ src/core/ngx_resolver.h \ src/core/ngx_open_file_cache.h \ src/core/ngx_crypt.h \ - src/core/ngx_proxy_protocol.h" + src/core/ngx_proxy_protocol.h \ + src/core/ngx_syslog.h" CORE_SRCS="src/core/nginx.c \ @@ -64,12 +66,14 @@ CORE_SRCS="src/core/nginx.c \ src/core/ngx_connection.c \ src/core/ngx_cycle.c \ src/core/ngx_spinlock.c \ + src/core/ngx_rwlock.c \ src/core/ngx_cpuinfo.c \ src/core/ngx_conf_file.c \ src/core/ngx_resolver.c \ src/core/ngx_open_file_cache.c \ src/core/ngx_crypt.c \ - src/core/ngx_proxy_protocol.c" + src/core/ngx_proxy_protocol.c \ + src/core/ngx_syslog.c" REGEX_MODULE=ngx_regex_module @@ -90,14 +94,12 @@ EVENT_INCS="src/event src/event/modules" EVENT_DEPS="src/event/ngx_event.h \ src/event/ngx_event_timer.h \ src/event/ngx_event_posted.h \ - src/event/ngx_event_busy_lock.h \ src/event/ngx_event_connect.h \ src/event/ngx_event_pipe.h" EVENT_SRCS="src/event/ngx_event.c \ src/event/ngx_event_timer.c \ src/event/ngx_event_posted.c \ - src/event/ngx_event_busy_lock.c \ src/event/ngx_event_accept.c \ src/event/ngx_event_connect.c \ src/event/ngx_event_pipe.c" @@ -122,19 +124,9 @@ EVENTPORT_SRCS=src/event/modules/ngx_eventport_module.c EPOLL_MODULE=ngx_epoll_module EPOLL_SRCS=src/event/modules/ngx_epoll_module.c -RTSIG_MODULE=ngx_rtsig_module -RTSIG_SRCS=src/event/modules/ngx_rtsig_module.c - IOCP_MODULE=ngx_iocp_module IOCP_SRCS=src/event/modules/ngx_iocp_module.c -AIO_MODULE=ngx_aio_module -AIO_SRCS="src/event/modules/ngx_aio_module.c \ - src/os/unix/ngx_aio_read.c \ - src/os/unix/ngx_aio_write.c \ - src/os/unix/ngx_aio_read_chain.c \ - src/os/unix/ngx_aio_write_chain.c" - FILE_AIO_SRCS="src/os/unix/ngx_file_aio_read.c" LINUX_AIO_SRCS="src/os/unix/ngx_linux_aio_read.c" @@ -191,14 +183,16 @@ UNIX_SRCS="$CORE_SRCS $EVENT_SRCS \ POSIX_DEPS=src/os/unix/ngx_posix_config.h +THREAD_POOL_MODULE=ngx_thread_pool_module +THREAD_POOL_DEPS=src/core/ngx_thread_pool.h +THREAD_POOL_SRCS="src/core/ngx_thread_pool.c + src/os/unix/ngx_thread_cond.c + src/os/unix/ngx_thread_mutex.c + src/os/unix/ngx_thread_id.c" + FREEBSD_DEPS="src/os/unix/ngx_freebsd_config.h src/os/unix/ngx_freebsd.h" FREEBSD_SRCS=src/os/unix/ngx_freebsd_init.c FREEBSD_SENDFILE_SRCS=src/os/unix/ngx_freebsd_sendfile_chain.c -FREEBSD_RFORK_DEPS="src/os/unix/ngx_freebsd_rfork_thread.h" -FREEBSD_RFORK_SRCS="src/os/unix/ngx_freebsd_rfork_thread.c" -FREEBSD_RFORK_THREAD_SRCS="src/os/unix/rfork_thread.S" - -PTHREAD_SRCS="src/os/unix/ngx_pthread_thread.c" LINUX_DEPS="src/os/unix/ngx_linux_config.h src/os/unix/ngx_linux.h" LINUX_SRCS=src/os/unix/ngx_linux_init.c @@ -293,8 +287,7 @@ HTTP_DEPS="src/http/ngx_http.h \ src/http/ngx_http_variables.h \ src/http/ngx_http_script.h \ src/http/ngx_http_upstream.h \ - src/http/ngx_http_upstream_round_robin.h \ - src/http/ngx_http_busy_lock.h" + src/http/ngx_http_upstream_round_robin.h" HTTP_SRCS="src/http/ngx_http.c \ src/http/ngx_http_core_module.c \ @@ -318,9 +311,6 @@ HTTP_SRCS="src/http/ngx_http.c \ src/http/modules/ngx_http_headers_filter_module.c \ src/http/modules/ngx_http_not_modified_filter_module.c" -# STUB -HTTP_SRCS="$HTTP_SRCS src/http/ngx_http_busy_lock.c" - HTTP_POSTPONE_FILTER_SRCS=src/http/ngx_http_postpone_filter_module.c HTTP_FILE_CACHE_SRCS=src/http/ngx_http_file_cache.c @@ -495,6 +485,10 @@ HTTP_GZIP_STATIC_MODULE=ngx_http_gzip_static_module HTTP_GZIP_STATIC_SRCS=src/http/modules/ngx_http_gzip_static_module.c +HTTP_UPSTREAM_HASH_MODULE=ngx_http_upstream_hash_module +HTTP_UPSTREAM_HASH_SRCS=src/http/modules/ngx_http_upstream_hash_module.c + + 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 @@ -509,6 +503,11 @@ HTTP_UPSTREAM_KEEPALIVE_SRCS=" \ src/http/modules/ngx_http_upstream_keepalive_module.c" +HTTP_UPSTREAM_ZONE_MODULE=ngx_http_upstream_zone_module +HTTP_UPSTREAM_ZONE_SRCS=" \ + src/http/modules/ngx_http_upstream_zone_module.c" + + MAIL_INCS="src/mail" MAIL_DEPS="src/mail/ngx_mail.h" @@ -545,6 +544,40 @@ MAIL_AUTH_HTTP_SRCS="src/mail/ngx_mail_auth_http_module.c" MAIL_PROXY_MODULE="ngx_mail_proxy_module" MAIL_PROXY_SRCS="src/mail/ngx_mail_proxy_module.c" + +STREAM_INCS="src/stream" + +STREAM_DEPS="src/stream/ngx_stream.h \ + src/stream/ngx_stream_upstream.h \ + src/stream/ngx_stream_upstream_round_robin.h" + +STREAM_MODULES="ngx_stream_module \ + ngx_stream_core_module \ + ngx_stream_proxy_module \ + ngx_stream_upstream_module" + +STREAM_SRCS="src/stream/ngx_stream.c \ + src/stream/ngx_stream_handler.c \ + src/stream/ngx_stream_core_module.c \ + src/stream/ngx_stream_proxy_module.c \ + src/stream/ngx_stream_upstream.c \ + src/stream/ngx_stream_upstream_round_robin.c" + +STREAM_SSL_MODULE="ngx_stream_ssl_module" +STREAM_SSL_DEPS="src/stream/ngx_stream_ssl_module.h" +STREAM_SSL_SRCS="src/stream/ngx_stream_ssl_module.c" + +STREAM_UPSTREAM_HASH_MODULE=ngx_stream_upstream_hash_module +STREAM_UPSTREAM_HASH_SRCS=src/stream/ngx_stream_upstream_hash_module.c + +STREAM_UPSTREAM_LEAST_CONN_MODULE=ngx_stream_upstream_least_conn_module +STREAM_UPSTREAM_LEAST_CONN_SRCS=" \ + src/stream/ngx_stream_upstream_least_conn_module.c" + +STREAM_UPSTREAM_ZONE_MODULE=ngx_stream_upstream_zone_module +STREAM_UPSTREAM_ZONE_SRCS=src/stream/ngx_stream_upstream_zone_module.c + + NGX_GOOGLE_PERFTOOLS_MODULE=ngx_google_perftools_module NGX_GOOGLE_PERFTOOLS_SRCS=src/misc/ngx_google_perftools_module.c diff --git a/auto/summary b/auto/summary index dcebec9..1be975d 100644 --- a/auto/summary +++ b/auto/summary @@ -3,34 +3,13 @@ # Copyright (C) Nginx, Inc. -### STUB - -if [ $USE_THREADS != NO ]; then - -cat << END - -$0: error: the threads support is broken now. - -END - exit 1 - fi - -### - - echo echo "Configuration summary" -#case $USE_THREADS in -# rfork) echo " + using rfork()ed threads" ;; -# pthreads) echo " + using libpthread threads library" ;; -# libthr) echo " + using FreeBSD libthr threads library" ;; -# libc_r) echo " + using FreeBSD libc_r threads library" ;; -# linuxthreads) echo " + using FreeBSD LinuxThreads port library" ;; -# NO) echo " + threads are not used" ;; -# *) echo " + using lib$USE_THREADS threads library" ;; -#esac +if [ $USE_THREADS = YES ]; then + echo " + using threads" +fi if [ $USE_PCRE = DISABLED ]; then echo " + PCRE library is disabled" diff --git a/auto/threads b/auto/threads new file mode 100644 index 0000000..381f07a --- /dev/null +++ b/auto/threads @@ -0,0 +1,20 @@ + +# Copyright (C) Nginx, Inc. + + +if [ $USE_THREADS = YES ]; then + + if [ "$NGX_PLATFORM" = win32 ]; then + cat << END + +$0: --with-threads is not supported on Windows + +END + exit 1 + fi + + have=NGX_THREADS . auto/have + CORE_DEPS="$CORE_DEPS $THREAD_POOL_DEPS" + CORE_SRCS="$CORE_SRCS $THREAD_POOL_SRCS" + CORE_LIBS="$CORE_LIBS -lpthread" +fi diff --git a/auto/types/sizeof b/auto/types/sizeof index 9215a54..a5f66bb 100644 --- a/auto/types/sizeof +++ b/auto/types/sizeof @@ -50,22 +50,12 @@ rm -rf $NGX_AUTOTEST* case $ngx_size in 4) - if [ "$ngx_type"="long" ]; then - ngx_max_value=2147483647L - else - ngx_max_value=2147483647 - fi - + ngx_max_value=2147483647 ngx_max_len='(sizeof("-2147483648") - 1)' ;; 8) - if [ "$ngx_type"="long long" ]; then - ngx_max_value=9223372036854775807LL - else - ngx_max_value=9223372036854775807L - fi - + ngx_max_value=9223372036854775807LL ngx_max_len='(sizeof("-9223372036854775808") - 1)' ;; diff --git a/auto/unix b/auto/unix index dfeb848..595f905 100755 --- a/auto/unix +++ b/auto/unix @@ -304,7 +304,17 @@ ngx_feature_run=no ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs= -ngx_feature_test="setsockopt(0, SOL_SOCKET, SO_SETFIB, NULL, 4)" +ngx_feature_test="setsockopt(0, SOL_SOCKET, SO_SETFIB, NULL, 0)" +. auto/feature + + +ngx_feature="SO_REUSEPORT" +ngx_feature_name="NGX_HAVE_REUSEPORT" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="setsockopt(0, SOL_SOCKET, SO_REUSEPORT, NULL, 0)" . auto/feature @@ -398,16 +408,36 @@ if [ $NGX_FILE_AIO = YES ]; then if [ $ngx_found = yes ]; then CORE_SRCS="$CORE_SRCS $FILE_AIO_SRCS" + fi - elif [ $ngx_found = no ]; then + if [ $ngx_found = no ]; then ngx_feature="Linux AIO support" ngx_feature_name="NGX_HAVE_FILE_AIO" ngx_feature_run=no ngx_feature_incs="#include - #include " + #include " ngx_feature_path= ngx_feature_libs= + ngx_feature_test="struct iocb iocb; + iocb.aio_lio_opcode = IOCB_CMD_PREAD; + iocb.aio_flags = IOCB_FLAG_RESFD; + iocb.aio_resfd = -1; + (void) eventfd(0, 0)" + . auto/feature + + if [ $ngx_found = yes ]; then + have=NGX_HAVE_EVENTFD . auto/have + have=NGX_HAVE_SYS_EVENTFD_H . auto/have + CORE_SRCS="$CORE_SRCS $LINUX_AIO_SRCS" + fi + fi + + if [ $ngx_found = no ]; then + + ngx_feature="Linux AIO support (SYS_eventfd)" + ngx_feature_incs="#include + #include " ngx_feature_test="int n = SYS_eventfd; struct iocb iocb; iocb.aio_lio_opcode = IOCB_CMD_PREAD; @@ -418,16 +448,40 @@ if [ $NGX_FILE_AIO = YES ]; then if [ $ngx_found = yes ]; then have=NGX_HAVE_EVENTFD . auto/have CORE_SRCS="$CORE_SRCS $LINUX_AIO_SRCS" + fi + fi - else - cat << END + if [ $ngx_found = no ]; then + cat << END $0: no supported file AIO was found Currently file AIO is supported on FreeBSD 4.3+ and Linux 2.6.22+ only END - exit 1 - fi + exit 1 + fi + +else + + ngx_feature="eventfd()" + ngx_feature_name="NGX_HAVE_EVENTFD" + ngx_feature_run=no + ngx_feature_incs="#include " + ngx_feature_path= + ngx_feature_libs= + ngx_feature_test="(void) eventfd(0, 0)" + . auto/feature + + if [ $ngx_found = yes ]; then + have=NGX_HAVE_SYS_EVENTFD_H . auto/have + fi + + if [ $ngx_found = no ]; then + + ngx_feature="eventfd() (SYS_eventfd)" + ngx_feature_incs="#include " + ngx_feature_test="int n = SYS_eventfd" + . auto/feature fi fi diff --git a/configure b/configure index d7d8189..617d992 100755 --- a/configure +++ b/configure @@ -58,6 +58,7 @@ if [ "$NGX_PLATFORM" != win32 ]; then . auto/unix fi +. auto/threads . auto/modules . auto/lib/conf @@ -108,4 +109,8 @@ have=NGX_HTTP_SCGI_TEMP_PATH value="\"$NGX_HTTP_SCGI_TEMP_PATH\"" have=NGX_USER value="\"$NGX_USER\"" . auto/define have=NGX_GROUP value="\"$NGX_GROUP\"" . auto/define +if [ ".$NGX_BUILD" != "." ]; then + have=NGX_BUILD value="\"$NGX_BUILD\"" . auto/define +fi + . auto/summary diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim index 50d809b..444d96e 100644 --- a/contrib/vim/syntax/nginx.vim +++ b/contrib/vim/syntax/nginx.vim @@ -31,6 +31,7 @@ syn keyword ngxDirectiveBlock limit_except contained syn keyword ngxDirectiveBlock if contained syn keyword ngxDirectiveBlock geo contained syn keyword ngxDirectiveBlock map contained +syn keyword ngxDirectiveBlock split_clients contained syn keyword ngxDirectiveImportant include syn keyword ngxDirectiveImportant root @@ -41,6 +42,8 @@ syn keyword ngxDirectiveImportant internal syn keyword ngxDirectiveImportant proxy_pass syn keyword ngxDirectiveImportant memcached_pass syn keyword ngxDirectiveImportant fastcgi_pass +syn keyword ngxDirectiveImportant scgi_pass +syn keyword ngxDirectiveImportant uwsgi_pass syn keyword ngxDirectiveImportant try_files syn keyword ngxDirectiveControl break @@ -53,12 +56,15 @@ syn keyword ngxDirectiveError post_action syn keyword ngxDirectiveDeprecated connections syn keyword ngxDirectiveDeprecated imap +syn keyword ngxDirectiveDeprecated limit_zone syn keyword ngxDirectiveDeprecated open_file_cache_retest syn keyword ngxDirectiveDeprecated optimize_server_names syn keyword ngxDirectiveDeprecated satisfy_any +syn keyword ngxDirectiveDeprecated so_keepalive syn keyword ngxDirective accept_mutex syn keyword ngxDirective accept_mutex_delay +syn keyword ngxDirective acceptex_read syn keyword ngxDirective access_log syn keyword ngxDirective add_after_body syn keyword ngxDirective add_before_body @@ -74,11 +80,14 @@ syn keyword ngxDirective auth_basic_user_file syn keyword ngxDirective auth_http syn keyword ngxDirective auth_http_header syn keyword ngxDirective auth_http_timeout +syn keyword ngxDirective auth_request +syn keyword ngxDirective auth_request_set syn keyword ngxDirective autoindex syn keyword ngxDirective autoindex_exact_size syn keyword ngxDirective autoindex_localtime syn keyword ngxDirective charset syn keyword ngxDirective charset_types +syn keyword ngxDirective chunked_transfer_encoding syn keyword ngxDirective client_body_buffer_size syn keyword ngxDirective client_body_in_file_only syn keyword ngxDirective client_body_in_single_buffer @@ -102,32 +111,44 @@ syn keyword ngxDirective devpoll_changes syn keyword ngxDirective devpoll_events syn keyword ngxDirective directio syn keyword ngxDirective directio_alignment +syn keyword ngxDirective disable_symlinks syn keyword ngxDirective empty_gif syn keyword ngxDirective env syn keyword ngxDirective epoll_events syn keyword ngxDirective error_log +syn keyword ngxDirective etag syn keyword ngxDirective eventport_events syn keyword ngxDirective expires syn keyword ngxDirective fastcgi_bind syn keyword ngxDirective fastcgi_buffer_size +syn keyword ngxDirective fastcgi_buffering syn keyword ngxDirective fastcgi_buffers syn keyword ngxDirective fastcgi_busy_buffers_size syn keyword ngxDirective fastcgi_cache +syn keyword ngxDirective fastcgi_cache_bypass syn keyword ngxDirective fastcgi_cache_key +syn keyword ngxDirective fastcgi_cache_lock +syn keyword ngxDirective fastcgi_cache_lock_timeout syn keyword ngxDirective fastcgi_cache_methods syn keyword ngxDirective fastcgi_cache_min_uses syn keyword ngxDirective fastcgi_cache_path +syn keyword ngxDirective fastcgi_cache_revalidate syn keyword ngxDirective fastcgi_cache_use_stale syn keyword ngxDirective fastcgi_cache_valid syn keyword ngxDirective fastcgi_catch_stderr syn keyword ngxDirective fastcgi_connect_timeout +syn keyword ngxDirective fastcgi_force_ranges syn keyword ngxDirective fastcgi_hide_header syn keyword ngxDirective fastcgi_ignore_client_abort syn keyword ngxDirective fastcgi_ignore_headers syn keyword ngxDirective fastcgi_index syn keyword ngxDirective fastcgi_intercept_errors +syn keyword ngxDirective fastcgi_keep_conn syn keyword ngxDirective fastcgi_max_temp_file_size syn keyword ngxDirective fastcgi_next_upstream +syn keyword ngxDirective fastcgi_next_upstream_timeout +syn keyword ngxDirective fastcgi_next_upstream_tries +syn keyword ngxDirective fastcgi_no_cache syn keyword ngxDirective fastcgi_param syn keyword ngxDirective fastcgi_pass_header syn keyword ngxDirective fastcgi_pass_request_body @@ -140,12 +161,15 @@ syn keyword ngxDirective fastcgi_store syn keyword ngxDirective fastcgi_store_access syn keyword ngxDirective fastcgi_temp_file_write_size syn keyword ngxDirective fastcgi_temp_path -syn keyword ngxDirective fastcgi_upstream_fail_timeout -syn keyword ngxDirective fastcgi_upstream_max_fails syn keyword ngxDirective flv syn keyword ngxDirective geoip_city syn keyword ngxDirective geoip_country +syn keyword ngxDirective geoip_org +syn keyword ngxDirective geoip_proxy +syn keyword ngxDirective geoip_proxy_recursive syn keyword ngxDirective google_perftools_profiles +syn keyword ngxDirective gunzip +syn keyword ngxDirective gunzip_buffers syn keyword ngxDirective gzip syn keyword ngxDirective gzip_buffers syn keyword ngxDirective gzip_comp_level @@ -159,30 +183,40 @@ syn keyword ngxDirective gzip_static syn keyword ngxDirective gzip_types syn keyword ngxDirective gzip_vary syn keyword ngxDirective gzip_window +syn keyword ngxDirective hash syn keyword ngxDirective if_modified_since syn keyword ngxDirective ignore_invalid_headers syn keyword ngxDirective image_filter syn keyword ngxDirective image_filter_buffer +syn keyword ngxDirective image_filter_interlace syn keyword ngxDirective image_filter_jpeg_quality +syn keyword ngxDirective image_filter_sharpen syn keyword ngxDirective image_filter_transparency syn keyword ngxDirective imap_auth syn keyword ngxDirective imap_capabilities syn keyword ngxDirective imap_client_buffer syn keyword ngxDirective index +syn keyword ngxDirective iocp_threads syn keyword ngxDirective ip_hash +syn keyword ngxDirective keepalive +syn keyword ngxDirective keepalive_disable syn keyword ngxDirective keepalive_requests syn keyword ngxDirective keepalive_timeout syn keyword ngxDirective kqueue_changes syn keyword ngxDirective kqueue_events syn keyword ngxDirective large_client_header_buffers +syn keyword ngxDirective least_conn syn keyword ngxDirective limit_conn syn keyword ngxDirective limit_conn_log_level +syn keyword ngxDirective limit_conn_status +syn keyword ngxDirective limit_conn_zone syn keyword ngxDirective limit_rate syn keyword ngxDirective limit_rate_after syn keyword ngxDirective limit_req syn keyword ngxDirective limit_req_log_level +syn keyword ngxDirective limit_req_status syn keyword ngxDirective limit_req_zone -syn keyword ngxDirective limit_zone +syn keyword ngxDirective lingering_close syn keyword ngxDirective lingering_time syn keyword ngxDirective lingering_timeout syn keyword ngxDirective lock_file @@ -192,21 +226,27 @@ syn keyword ngxDirective log_subrequest syn keyword ngxDirective map_hash_bucket_size syn keyword ngxDirective map_hash_max_size syn keyword ngxDirective master_process +syn keyword ngxDirective max_ranges syn keyword ngxDirective memcached_bind syn keyword ngxDirective memcached_buffer_size syn keyword ngxDirective memcached_connect_timeout +syn keyword ngxDirective memcached_gzip_flag syn keyword ngxDirective memcached_next_upstream +syn keyword ngxDirective memcached_next_upstream_timeout +syn keyword ngxDirective memcached_next_upstream_tries syn keyword ngxDirective memcached_read_timeout syn keyword ngxDirective memcached_send_timeout -syn keyword ngxDirective memcached_upstream_fail_timeout -syn keyword ngxDirective memcached_upstream_max_fails syn keyword ngxDirective merge_slashes syn keyword ngxDirective min_delete_depth syn keyword ngxDirective modern_browser syn keyword ngxDirective modern_browser_value +syn keyword ngxDirective mp4 +syn keyword ngxDirective mp4_buffer_size +syn keyword ngxDirective mp4_max_buffer_size syn keyword ngxDirective msie_padding syn keyword ngxDirective msie_refresh syn keyword ngxDirective multi_accept +syn keyword ngxDirective mysql_test syn keyword ngxDirective open_file_cache syn keyword ngxDirective open_file_cache_errors syn keyword ngxDirective open_file_cache_events @@ -215,6 +255,7 @@ syn keyword ngxDirective open_file_cache_valid syn keyword ngxDirective open_log_file_cache syn keyword ngxDirective output_buffers syn keyword ngxDirective override_charset +syn keyword ngxDirective pcre_jit syn keyword ngxDirective perl syn keyword ngxDirective perl_modules syn keyword ngxDirective perl_require @@ -223,6 +264,7 @@ syn keyword ngxDirective pid syn keyword ngxDirective pop3_auth syn keyword ngxDirective pop3_capabilities syn keyword ngxDirective port_in_redirect +syn keyword ngxDirective post_acceptex syn keyword ngxDirective postpone_gzipping syn keyword ngxDirective postpone_output syn keyword ngxDirective protocol @@ -234,22 +276,33 @@ syn keyword ngxDirective proxy_buffering syn keyword ngxDirective proxy_buffers syn keyword ngxDirective proxy_busy_buffers_size syn keyword ngxDirective proxy_cache +syn keyword ngxDirective proxy_cache_bypass syn keyword ngxDirective proxy_cache_key +syn keyword ngxDirective proxy_cache_lock +syn keyword ngxDirective proxy_cache_lock_timeout syn keyword ngxDirective proxy_cache_methods syn keyword ngxDirective proxy_cache_min_uses syn keyword ngxDirective proxy_cache_path +syn keyword ngxDirective proxy_cache_revalidate syn keyword ngxDirective proxy_cache_use_stale syn keyword ngxDirective proxy_cache_valid syn keyword ngxDirective proxy_connect_timeout +syn keyword ngxDirective proxy_cookie_domain +syn keyword ngxDirective proxy_cookie_path +syn keyword ngxDirective proxy_force_ranges syn keyword ngxDirective proxy_headers_hash_bucket_size syn keyword ngxDirective proxy_headers_hash_max_size syn keyword ngxDirective proxy_hide_header +syn keyword ngxDirective proxy_http_version syn keyword ngxDirective proxy_ignore_client_abort syn keyword ngxDirective proxy_ignore_headers syn keyword ngxDirective proxy_intercept_errors syn keyword ngxDirective proxy_max_temp_file_size syn keyword ngxDirective proxy_method syn keyword ngxDirective proxy_next_upstream +syn keyword ngxDirective proxy_next_upstream_timeout +syn keyword ngxDirective proxy_next_upstream_tries +syn keyword ngxDirective proxy_no_cache syn keyword ngxDirective proxy_pass_error_message syn keyword ngxDirective proxy_pass_header syn keyword ngxDirective proxy_pass_request_body @@ -260,18 +313,27 @@ syn keyword ngxDirective proxy_send_lowat syn keyword ngxDirective proxy_send_timeout syn keyword ngxDirective proxy_set_body syn keyword ngxDirective proxy_set_header +syn keyword ngxDirective proxy_ssl_ciphers +syn keyword ngxDirective proxy_ssl_crl +syn keyword ngxDirective proxy_ssl_name +syn keyword ngxDirective proxy_ssl_protocols +syn keyword ngxDirective proxy_ssl_server_name syn keyword ngxDirective proxy_ssl_session_reuse +syn keyword ngxDirective proxy_ssl_trusted_certificate +syn keyword ngxDirective proxy_ssl_verify +syn keyword ngxDirective proxy_ssl_verify_depth syn keyword ngxDirective proxy_store syn keyword ngxDirective proxy_store_access syn keyword ngxDirective proxy_temp_file_write_size syn keyword ngxDirective proxy_temp_path syn keyword ngxDirective proxy_timeout -syn keyword ngxDirective proxy_upstream_fail_timeout -syn keyword ngxDirective proxy_upstream_max_fails syn keyword ngxDirective random_index syn keyword ngxDirective read_ahead syn keyword ngxDirective real_ip_header +syn keyword ngxDirective real_ip_recursive syn keyword ngxDirective recursive_error_pages +syn keyword ngxDirective referer_hash_bucket_size +syn keyword ngxDirective referer_hash_max_size syn keyword ngxDirective request_pool_size syn keyword ngxDirective reset_timedout_connection syn keyword ngxDirective resolver @@ -282,6 +344,45 @@ syn keyword ngxDirective rtsig_overflow_test syn keyword ngxDirective rtsig_overflow_threshold syn keyword ngxDirective rtsig_signo syn keyword ngxDirective satisfy +syn keyword ngxDirective scgi_bind +syn keyword ngxDirective scgi_buffer_size +syn keyword ngxDirective scgi_buffering +syn keyword ngxDirective scgi_buffers +syn keyword ngxDirective scgi_busy_buffers_size +syn keyword ngxDirective scgi_cache +syn keyword ngxDirective scgi_cache_bypass +syn keyword ngxDirective scgi_cache_key +syn keyword ngxDirective scgi_cache_lock +syn keyword ngxDirective scgi_cache_lock_timeout +syn keyword ngxDirective scgi_cache_methods +syn keyword ngxDirective scgi_cache_min_uses +syn keyword ngxDirective scgi_cache_path +syn keyword ngxDirective scgi_cache_revalidate +syn keyword ngxDirective scgi_cache_use_stale +syn keyword ngxDirective scgi_cache_valid +syn keyword ngxDirective scgi_connect_timeout +syn keyword ngxDirective scgi_force_ranges +syn keyword ngxDirective scgi_hide_header +syn keyword ngxDirective scgi_ignore_client_abort +syn keyword ngxDirective scgi_ignore_headers +syn keyword ngxDirective scgi_intercept_errors +syn keyword ngxDirective scgi_max_temp_file_size +syn keyword ngxDirective scgi_next_upstream +syn keyword ngxDirective scgi_next_upstream_timeout +syn keyword ngxDirective scgi_next_upstream_tries +syn keyword ngxDirective scgi_no_cache +syn keyword ngxDirective scgi_param +syn keyword ngxDirective scgi_pass_header +syn keyword ngxDirective scgi_pass_request_body +syn keyword ngxDirective scgi_pass_request_headers +syn keyword ngxDirective scgi_read_timeout +syn keyword ngxDirective scgi_send_timeout +syn keyword ngxDirective scgi_store +syn keyword ngxDirective scgi_store_access +syn keyword ngxDirective scgi_temp_file_write_size +syn keyword ngxDirective scgi_temp_path +syn keyword ngxDirective secure_link +syn keyword ngxDirective secure_link_md5 syn keyword ngxDirective secure_link_secret syn keyword ngxDirective send_lowat syn keyword ngxDirective send_timeout @@ -296,31 +397,50 @@ syn keyword ngxDirective smtp_auth syn keyword ngxDirective smtp_capabilities syn keyword ngxDirective smtp_client_buffer syn keyword ngxDirective smtp_greeting_delay -syn keyword ngxDirective so_keepalive syn keyword ngxDirective source_charset +syn keyword ngxDirective spdy_chunk_size +syn keyword ngxDirective spdy_headers_comp +syn keyword ngxDirective spdy_keepalive_timeout +syn keyword ngxDirective spdy_max_concurrent_streams +syn keyword ngxDirective spdy_pool_size +syn keyword ngxDirective spdy_recv_buffer_size +syn keyword ngxDirective spdy_recv_timeout +syn keyword ngxDirective spdy_streams_index_size syn keyword ngxDirective ssi syn keyword ngxDirective ssi_ignore_recycled_buffers +syn keyword ngxDirective ssi_last_modified syn keyword ngxDirective ssi_min_file_chunk syn keyword ngxDirective ssi_silent_errors syn keyword ngxDirective ssi_types syn keyword ngxDirective ssi_value_length syn keyword ngxDirective ssl +syn keyword ngxDirective ssl_buffer_size syn keyword ngxDirective ssl_certificate syn keyword ngxDirective ssl_certificate_key syn keyword ngxDirective ssl_ciphers syn keyword ngxDirective ssl_client_certificate syn keyword ngxDirective ssl_crl syn keyword ngxDirective ssl_dhparam +syn keyword ngxDirective ssl_ecdh_curve syn keyword ngxDirective ssl_engine +syn keyword ngxDirective ssl_password_file syn keyword ngxDirective ssl_prefer_server_ciphers syn keyword ngxDirective ssl_protocols syn keyword ngxDirective ssl_session_cache +syn keyword ngxDirective ssl_session_ticket_key +syn keyword ngxDirective ssl_session_tickets syn keyword ngxDirective ssl_session_timeout +syn keyword ngxDirective ssl_stapling +syn keyword ngxDirective ssl_stapling_file +syn keyword ngxDirective ssl_stapling_responder +syn keyword ngxDirective ssl_stapling_verify +syn keyword ngxDirective ssl_trusted_certificate syn keyword ngxDirective ssl_verify_client syn keyword ngxDirective ssl_verify_depth syn keyword ngxDirective starttls syn keyword ngxDirective stub_status syn keyword ngxDirective sub_filter +syn keyword ngxDirective sub_filter_last_modified syn keyword ngxDirective sub_filter_once syn keyword ngxDirective sub_filter_types syn keyword ngxDirective tcp_nodelay @@ -342,9 +462,59 @@ syn keyword ngxDirective userid_name syn keyword ngxDirective userid_p3p syn keyword ngxDirective userid_path syn keyword ngxDirective userid_service +syn keyword ngxDirective uwsgi_bind +syn keyword ngxDirective uwsgi_buffer_size +syn keyword ngxDirective uwsgi_buffering +syn keyword ngxDirective uwsgi_buffers +syn keyword ngxDirective uwsgi_busy_buffers_size +syn keyword ngxDirective uwsgi_cache +syn keyword ngxDirective uwsgi_cache_bypass +syn keyword ngxDirective uwsgi_cache_key +syn keyword ngxDirective uwsgi_cache_lock +syn keyword ngxDirective uwsgi_cache_lock_timeout +syn keyword ngxDirective uwsgi_cache_methods +syn keyword ngxDirective uwsgi_cache_min_uses +syn keyword ngxDirective uwsgi_cache_path +syn keyword ngxDirective uwsgi_cache_revalidate +syn keyword ngxDirective uwsgi_cache_use_stale +syn keyword ngxDirective uwsgi_cache_valid +syn keyword ngxDirective uwsgi_connect_timeout +syn keyword ngxDirective uwsgi_force_ranges +syn keyword ngxDirective uwsgi_hide_header +syn keyword ngxDirective uwsgi_ignore_client_abort +syn keyword ngxDirective uwsgi_ignore_headers +syn keyword ngxDirective uwsgi_intercept_errors +syn keyword ngxDirective uwsgi_max_temp_file_size +syn keyword ngxDirective uwsgi_modifier1 +syn keyword ngxDirective uwsgi_modifier2 +syn keyword ngxDirective uwsgi_next_upstream +syn keyword ngxDirective uwsgi_next_upstream_timeout +syn keyword ngxDirective uwsgi_next_upstream_tries +syn keyword ngxDirective uwsgi_no_cache +syn keyword ngxDirective uwsgi_param +syn keyword ngxDirective uwsgi_pass_header +syn keyword ngxDirective uwsgi_pass_request_body +syn keyword ngxDirective uwsgi_pass_request_headers +syn keyword ngxDirective uwsgi_read_timeout +syn keyword ngxDirective uwsgi_send_timeout +syn keyword ngxDirective uwsgi_ssl_ciphers +syn keyword ngxDirective uwsgi_ssl_crl +syn keyword ngxDirective uwsgi_ssl_name +syn keyword ngxDirective uwsgi_ssl_protocols +syn keyword ngxDirective uwsgi_ssl_server_name +syn keyword ngxDirective uwsgi_ssl_session_reuse +syn keyword ngxDirective uwsgi_ssl_trusted_certificate +syn keyword ngxDirective uwsgi_ssl_verify +syn keyword ngxDirective uwsgi_ssl_verify_depth +syn keyword ngxDirective uwsgi_store +syn keyword ngxDirective uwsgi_store_access +syn keyword ngxDirective uwsgi_string +syn keyword ngxDirective uwsgi_temp_file_write_size +syn keyword ngxDirective uwsgi_temp_path syn keyword ngxDirective valid_referers syn keyword ngxDirective variables_hash_bucket_size syn keyword ngxDirective variables_hash_max_size +syn keyword ngxDirective worker_aio_requests syn keyword ngxDirective worker_connections syn keyword ngxDirective worker_cpu_affinity syn keyword ngxDirective worker_priority @@ -356,6 +526,9 @@ syn keyword ngxDirective worker_threads syn keyword ngxDirective working_directory syn keyword ngxDirective xclient syn keyword ngxDirective xml_entities +syn keyword ngxDirective xslt_last_modified +syn keyword ngxDirective xslt_param +syn keyword ngxDirective xslt_string_param syn keyword ngxDirective xslt_stylesheet syn keyword ngxDirective xslt_types @@ -367,7 +540,7 @@ syn keyword ngxDirective xslt_types syn keyword ngxDirectiveThirdParty set_from_accept_language " Access Key Module -" Denies access unless the request URL contains an access key. +" Denies access unless the request URL contains an access key. syn keyword ngxDirectiveThirdParty accesskey syn keyword ngxDirectiveThirdParty accesskey_arg syn keyword ngxDirectiveThirdParty accesskey_hashmethod @@ -521,7 +694,7 @@ syn keyword ngxDirectiveThirdParty mogilefs_send_timeout syn keyword ngxDirectiveThirdParty mogilefs_tracker " MP4 Streaming Lite Module -" Will seek to a certain time within H.264/MP4 files when provided with a 'start' parameter in the URL. +" Will seek to a certain time within H.264/MP4 files when provided with a 'start' parameter in the URL. syn keyword ngxDirectiveThirdParty mp4 " Nginx Notice Module @@ -642,46 +815,6 @@ syn keyword ngxDirectiveThirdParty xss_get syn keyword ngxDirectiveThirdParty xss_input_types syn keyword ngxDirectiveThirdParty xss_output_type -" uWSGI Module -" Allows Nginx to interact with uWSGI processes and control what parameters are passed to the process. -syn keyword ngxDirectiveThirdParty uwsgi_bind -syn keyword ngxDirectiveThirdParty uwsgi_buffer_size -syn keyword ngxDirectiveThirdParty uwsgi_buffering -syn keyword ngxDirectiveThirdParty uwsgi_buffers -syn keyword ngxDirectiveThirdParty uwsgi_busy_buffers_size -syn keyword ngxDirectiveThirdParty uwsgi_cache -syn keyword ngxDirectiveThirdParty uwsgi_cache_bypass -syn keyword ngxDirectiveThirdParty uwsgi_cache_key -syn keyword ngxDirectiveThirdParty uwsgi_cache_lock -syn keyword ngxDirectiveThirdParty uwsgi_cache_lock_timeout -syn keyword ngxDirectiveThirdParty uwsgi_cache_methods -syn keyword ngxDirectiveThirdParty uwsgi_cache_min_uses -syn keyword ngxDirectiveThirdParty uwsgi_cache_path -syn keyword ngxDirectiveThirdParty uwsgi_cache_use_stale -syn keyword ngxDirectiveThirdParty uwsgi_cache_valid -syn keyword ngxDirectiveThirdParty uwsgi_connect_timeout -syn keyword ngxDirectiveThirdParty uwsgi_hide_header -syn keyword ngxDirectiveThirdParty uwsgi_ignore_client_abort -syn keyword ngxDirectiveThirdParty uwsgi_ignore_headers -syn keyword ngxDirectiveThirdParty uwsgi_intercept_errors -syn keyword ngxDirectiveThirdParty uwsgi_max_temp_file_size -syn keyword ngxDirectiveThirdParty uwsgi_modifier1 -syn keyword ngxDirectiveThirdParty uwsgi_modifier2 -syn keyword ngxDirectiveThirdParty uwsgi_next_upstream -syn keyword ngxDirectiveThirdParty uwsgi_no_cache -syn keyword ngxDirectiveThirdParty uwsgi_param -syn keyword ngxDirectiveThirdParty uwsgi_pass -syn keyword ngxDirectiveThirdParty uwsgi_pass_header -syn keyword ngxDirectiveThirdParty uwsgi_pass_request_body -syn keyword ngxDirectiveThirdParty uwsgi_pass_request_headers -syn keyword ngxDirectiveThirdParty uwsgi_read_timeout -syn keyword ngxDirectiveThirdParty uwsgi_send_timeout -syn keyword ngxDirectiveThirdParty uwsgi_store -syn keyword ngxDirectiveThirdParty uwsgi_store_access -syn keyword ngxDirectiveThirdParty uwsgi_string -syn keyword ngxDirectiveThirdParty uwsgi_temp_file_write_size -syn keyword ngxDirectiveThirdParty uwsgi_temp_path - " highlight hi link ngxComment Comment diff --git a/src/core/nginx.c b/src/core/nginx.c index 4cc8082..231a3da 100644 --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -118,13 +118,6 @@ static ngx_command_t ngx_core_commands[] = { offsetof(ngx_core_conf_t, rlimit_core), NULL }, - { ngx_string("worker_rlimit_sigpending"), - NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - 0, - offsetof(ngx_core_conf_t, rlimit_sigpending), - NULL }, - { ngx_string("working_directory"), NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, @@ -139,24 +132,6 @@ static ngx_command_t ngx_core_commands[] = { 0, NULL }, -#if (NGX_THREADS) - - { ngx_string("worker_threads"), - NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - 0, - offsetof(ngx_core_conf_t, worker_threads), - NULL }, - - { ngx_string("thread_stack_size"), - NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - 0, - offsetof(ngx_core_conf_t, thread_stack_size), - NULL }, - -#endif - ngx_null_command }; @@ -217,7 +192,7 @@ main(int argc, char *const *argv) } if (ngx_show_version) { - ngx_write_stderr("nginx version: " NGINX_VER NGX_LINEFEED); + ngx_write_stderr("nginx version: " NGINX_VER_BUILD NGX_LINEFEED); if (ngx_show_help) { ngx_write_stderr( @@ -248,18 +223,30 @@ main(int argc, char *const *argv) } if (ngx_show_configure) { - ngx_write_stderr( + #ifdef NGX_COMPILER - "built by " NGX_COMPILER NGX_LINEFEED + ngx_write_stderr("built by " NGX_COMPILER NGX_LINEFEED); #endif + #if (NGX_SSL) + if (SSLeay() == SSLEAY_VERSION_NUMBER) { + ngx_write_stderr("built with " OPENSSL_VERSION_TEXT + NGX_LINEFEED); + } else { + ngx_write_stderr("built with " OPENSSL_VERSION_TEXT + " (running with "); + ngx_write_stderr((char *) (uintptr_t) + SSLeay_version(SSLEAY_VERSION)); + ngx_write_stderr(")" NGX_LINEFEED); + } #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - "TLS SNI support enabled" NGX_LINEFEED + ngx_write_stderr("TLS SNI support enabled" NGX_LINEFEED); #else - "TLS SNI support disabled" NGX_LINEFEED + ngx_write_stderr("TLS SNI support disabled" NGX_LINEFEED); #endif #endif - "configure arguments:" NGX_CONFIGURE NGX_LINEFEED); + + ngx_write_stderr("configure arguments:" NGX_CONFIGURE NGX_LINEFEED); } if (!ngx_test_config) { @@ -954,16 +941,10 @@ ngx_core_module_create_conf(ngx_cycle_t *cycle) ccf->rlimit_nofile = NGX_CONF_UNSET; ccf->rlimit_core = NGX_CONF_UNSET; - ccf->rlimit_sigpending = NGX_CONF_UNSET; ccf->user = (ngx_uid_t) NGX_CONF_UNSET_UINT; ccf->group = (ngx_gid_t) NGX_CONF_UNSET_UINT; -#if (NGX_THREADS) - ccf->worker_threads = NGX_CONF_UNSET; - ccf->thread_stack_size = NGX_CONF_UNSET_SIZE; -#endif - if (ngx_array_init(&ccf->env, cycle->pool, 1, sizeof(ngx_str_t)) != NGX_OK) { @@ -998,14 +979,6 @@ ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf) "using last mask for remaining worker processes"); } -#endif - -#if (NGX_THREADS) - - ngx_conf_init_value(ccf->worker_threads, 0); - ngx_threads_n = ccf->worker_threads; - ngx_conf_init_size_value(ccf->thread_stack_size, 2 * 1024 * 1024); - #endif diff --git a/src/core/nginx.h b/src/core/nginx.h index e56e541..ec818e0 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,10 +9,16 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1006003 -#define NGINX_VERSION "1.6.3" +#define nginx_version 1009001 +#define NGINX_VERSION "1.9.1" #define NGINX_VER "nginx/" NGINX_VERSION +#ifdef NGX_BUILD +#define NGINX_VER_BUILD NGINX_VER " (" NGX_BUILD ")" +#else +#define NGINX_VER_BUILD NGINX_VER +#endif + #define NGINX_VAR "NGINX" #define NGX_OLDPID_EXT ".oldbin" diff --git a/src/core/ngx_buf.c b/src/core/ngx_buf.c index 835c76c..00b6644 100644 --- a/src/core/ngx_buf.c +++ b/src/core/ngx_buf.c @@ -218,3 +218,91 @@ ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy, *free = cl; } } + + +off_t +ngx_chain_coalesce_file(ngx_chain_t **in, off_t limit) +{ + off_t total, size, aligned, fprev; + ngx_fd_t fd; + ngx_chain_t *cl; + + total = 0; + + cl = *in; + fd = cl->buf->file->fd; + + do { + size = cl->buf->file_last - cl->buf->file_pos; + + if (size > limit - total) { + size = limit - total; + + aligned = (cl->buf->file_pos + size + ngx_pagesize - 1) + & ~((off_t) ngx_pagesize - 1); + + if (aligned <= cl->buf->file_last) { + size = aligned - cl->buf->file_pos; + } + } + + total += size; + fprev = cl->buf->file_pos + size; + cl = cl->next; + + } while (cl + && cl->buf->in_file + && total < limit + && fd == cl->buf->file->fd + && fprev == cl->buf->file_pos); + + *in = cl; + + return total; +} + + +ngx_chain_t * +ngx_chain_update_sent(ngx_chain_t *in, off_t sent) +{ + off_t size; + + for ( /* void */ ; in; in = in->next) { + + if (ngx_buf_special(in->buf)) { + continue; + } + + if (sent == 0) { + break; + } + + size = ngx_buf_size(in->buf); + + if (sent >= size) { + sent -= size; + + if (ngx_buf_in_memory(in->buf)) { + in->buf->pos = in->buf->last; + } + + if (in->buf->in_file) { + in->buf->file_pos = in->buf->file_last; + } + + continue; + } + + if (ngx_buf_in_memory(in->buf)) { + in->buf->pos += (size_t) sent; + } + + if (in->buf->in_file) { + in->buf->file_pos += sent; + } + + break; + } + + return in; +} diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h index ffc5310..f652b20 100644 --- a/src/core/ngx_buf.h +++ b/src/core/ngx_buf.h @@ -90,10 +90,21 @@ struct ngx_output_chain_ctx_s { #endif unsigned need_in_memory:1; unsigned need_in_temp:1; -#if (NGX_HAVE_FILE_AIO) +#if (NGX_HAVE_FILE_AIO || NGX_THREADS) unsigned aio:1; +#endif +#if (NGX_HAVE_FILE_AIO) ngx_output_chain_aio_pt aio_handler; +#if (NGX_HAVE_AIO_SENDFILE) + ssize_t (*aio_preload)(ngx_buf_t *file); +#endif +#endif + +#if (NGX_THREADS) + ngx_int_t (*thread_handler)(ngx_thread_task_t *task, + ngx_file_t *file); + ngx_thread_task_t *thread_task; #endif off_t alignment; @@ -158,5 +169,8 @@ ngx_chain_t *ngx_chain_get_free_buf(ngx_pool_t *p, ngx_chain_t **free); 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); +off_t ngx_chain_coalesce_file(ngx_chain_t **in, off_t limit); + +ngx_chain_t *ngx_chain_update_sent(ngx_chain_t *in, off_t sent); #endif /* _NGX_BUF_H_INCLUDED_ */ diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c index f61bfca..ec3c1fa 100644 --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -266,7 +266,7 @@ done: ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_close_file_n " %s failed", filename->data); - return NGX_CONF_ERROR; + rc = NGX_ERROR; } cf->conf_file = prev; @@ -781,6 +781,9 @@ ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) file.len = name.len++; file.data = ngx_pstrdup(cf->pool, &name); + if (file.data == NULL) { + return NGX_CONF_ERROR; + } ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 6b6e3b3..04a365a 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -90,6 +90,43 @@ ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen) } +ngx_int_t +ngx_clone_listening(ngx_conf_t *cf, ngx_listening_t *ls) +{ +#if (NGX_HAVE_REUSEPORT) + + ngx_int_t n; + ngx_core_conf_t *ccf; + ngx_listening_t ols; + + if (!ls->reuseport) { + return NGX_OK; + } + + ols = *ls; + + ccf = (ngx_core_conf_t *) ngx_get_conf(cf->cycle->conf_ctx, + ngx_core_module); + + for (n = 1; n < ccf->worker_processes; n++) { + + /* create a socket for each worker process */ + + ls = ngx_array_push(&cf->cycle->listening); + if (ls == NULL) { + return NGX_ERROR; + } + + *ls = ols; + ls->worker = n; + } + +#endif + + return NGX_OK; +} + + ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle) { @@ -106,6 +143,9 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) int timeout; #endif +#if (NGX_HAVE_REUSEPORT) + int reuseport; +#endif ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { @@ -215,6 +255,25 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) #endif #endif +#if (NGX_HAVE_REUSEPORT) + + reuseport = 0; + olen = sizeof(int); + + if (getsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT, + (void *) &reuseport, &olen) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "getsockopt(SO_REUSEPORT) %V failed, ignored", + &ls[i].addr_text); + + } else { + ls[i].reuseport = reuseport ? 1 : 0; + } + +#endif + #if (NGX_HAVE_TCP_FASTOPEN) olen = sizeof(int); @@ -332,6 +391,31 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) continue; } +#if (NGX_HAVE_REUSEPORT) + + if (ls[i].add_reuseport) { + + /* + * to allow transition from a socket without SO_REUSEPORT + * to multiple sockets with SO_REUSEPORT, we have to set + * SO_REUSEPORT on the old socket before opening new ones + */ + + int reuseport = 1; + + if (setsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT, + (const void *) &reuseport, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(SO_REUSEPORT) %V failed, ignored", + &ls[i].addr_text); + } + + ls[i].add_reuseport = 0; + } +#endif + if (ls[i].fd != (ngx_socket_t) -1) { continue; } @@ -370,6 +454,32 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) return NGX_ERROR; } +#if (NGX_HAVE_REUSEPORT) + + if (ls[i].reuseport) { + int reuseport; + + reuseport = 1; + + if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, + (const void *) &reuseport, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "setsockopt(SO_REUSEPORT) %V failed, ignored", + &ls[i].addr_text); + + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_close_socket_n " %V failed", + &ls[i].addr_text); + } + + return NGX_ERROR; + } + } +#endif + #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) if (ls[i].sockaddr->sa_family == AF_INET6) { @@ -389,7 +499,7 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) #endif /* TODO: close on exit */ - if (!(ngx_event_flags & NGX_USE_AIO_EVENT)) { + if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) { if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_nonblocking_n " %V failed", @@ -411,13 +521,11 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) { err = ngx_socket_errno; - if (err == NGX_EADDRINUSE && ngx_test_config) { - continue; + if (err != NGX_EADDRINUSE || !ngx_test_config) { + ngx_log_error(NGX_LOG_EMERG, log, err, + "bind() to %V failed", &ls[i].addr_text); } - ngx_log_error(NGX_LOG_EMERG, log, err, - "bind() to %V failed", &ls[i].addr_text); - if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", @@ -428,7 +536,9 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) return NGX_ERROR; } - failed = 1; + if (!ngx_test_config) { + failed = 1; + } continue; } @@ -764,10 +874,7 @@ ngx_close_listening_sockets(ngx_cycle_t *cycle) if (c) { if (c->read->active) { - if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { - ngx_del_conn(c, NGX_CLOSE_EVENT); - - } else if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { + if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { /* * it seems that Linux-2.6.x OpenVZ sends events @@ -835,8 +942,6 @@ ngx_get_connection(ngx_socket_t s, ngx_log_t *log) return NULL; } - /* ngx_mutex_lock */ - c = ngx_cycle->free_connections; if (c == NULL) { @@ -849,16 +954,12 @@ ngx_get_connection(ngx_socket_t s, ngx_log_t *log) "%ui worker_connections are not enough", ngx_cycle->connection_n); - /* ngx_mutex_unlock */ - return NULL; } ngx_cycle->free_connections = c->data; ngx_cycle->free_connection_n--; - /* ngx_mutex_unlock */ - if (ngx_cycle->files) { ngx_cycle->files[s] = c; } @@ -896,14 +997,10 @@ ngx_get_connection(ngx_socket_t s, ngx_log_t *log) void ngx_free_connection(ngx_connection_t *c) { - /* ngx_mutex_lock */ - c->data = ngx_cycle->free_connections; ngx_cycle->free_connections = c; ngx_cycle->free_connection_n++; - /* ngx_mutex_unlock */ - if (ngx_cycle->files) { ngx_cycle->files[c->fd] = NULL; } @@ -943,48 +1040,17 @@ ngx_close_connection(ngx_connection_t *c) } } -#if (NGX_THREADS) - - /* - * we have to clean the connection information before the closing - * because another thread may reopen the same file descriptor - * before we clean the connection - */ - - ngx_mutex_lock(ngx_posted_events_mutex); - - if (c->read->prev) { + if (c->read->posted) { ngx_delete_posted_event(c->read); } - if (c->write->prev) { + if (c->write->posted) { ngx_delete_posted_event(c->write); } c->read->closed = 1; c->write->closed = 1; - ngx_unlock(&c->lock); - c->read->locked = 0; - c->write->locked = 0; - - ngx_mutex_unlock(ngx_posted_events_mutex); - -#else - - if (c->read->prev) { - ngx_delete_posted_event(c->read); - } - - if (c->write->prev) { - ngx_delete_posted_event(c->write); - } - - c->read->closed = 1; - c->write->closed = 1; - -#endif - ngx_reusable_connection(c, 0); log_error = c->log_error; @@ -1092,33 +1158,33 @@ ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s, struct sockaddr_in6 *sin6; #endif - if (c->local_socklen == 0) { - return NGX_ERROR; - } + addr = 0; - switch (c->local_sockaddr->sa_family) { + if (c->local_socklen) { + switch (c->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) c->local_sockaddr; + case AF_INET6: + sin6 = (struct sockaddr_in6 *) c->local_sockaddr; - for (addr = 0, i = 0; addr == 0 && i < 16; i++) { - addr |= sin6->sin6_addr.s6_addr[i]; - } + for (i = 0; addr == 0 && i < 16; i++) { + addr |= sin6->sin6_addr.s6_addr[i]; + } - break; + break; #endif #if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - addr = 1; - break; + case AF_UNIX: + addr = 1; + break; #endif - default: /* AF_INET */ - sin = (struct sockaddr_in *) c->local_sockaddr; - addr = sin->sin_addr.s_addr; - break; + default: /* AF_INET */ + sin = (struct sockaddr_in *) c->local_sockaddr; + addr = sin->sin_addr.s_addr; + break; + } } if (addr == 0) { diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index ed14e60..a49aa95 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -51,6 +51,8 @@ struct ngx_listening_s { ngx_listening_t *previous; ngx_connection_t *connection; + ngx_uint_t worker; + unsigned open:1; unsigned remain:1; unsigned ignore:1; @@ -65,6 +67,10 @@ struct ngx_listening_s { #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) unsigned ipv6only:1; +#endif +#if (NGX_HAVE_REUSEPORT) + unsigned reuseport:1; + unsigned add_reuseport:1; #endif unsigned keepalive:2; @@ -181,19 +187,29 @@ struct ngx_connection_s { #endif #if (NGX_HAVE_AIO_SENDFILE) - unsigned aio_sendfile:1; unsigned busy_count:2; - ngx_buf_t *busy_sendfile; #endif #if (NGX_THREADS) - ngx_atomic_t lock; + ngx_thread_task_t *sendfile_task; #endif }; +#define ngx_set_connection_log(c, l) \ + \ + c->log->file = l->file; \ + c->log->next = l->next; \ + c->log->writer = l->writer; \ + c->log->wdata = l->wdata; \ + if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { \ + c->log->log_level = l->log_level; \ + } + + ngx_listening_t *ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen); +ngx_int_t ngx_clone_listening(ngx_conf_t *cf, ngx_listening_t *ls); ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle); ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle); void ngx_configure_listening_sockets(ngx_cycle_t *cycle); diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h index a2d417e..a279c81 100644 --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -9,6 +9,9 @@ #define _NGX_CORE_H_INCLUDED_ +#include + + typedef struct ngx_module_s ngx_module_t; typedef struct ngx_conf_s ngx_conf_t; typedef struct ngx_cycle_s ngx_cycle_t; @@ -22,6 +25,10 @@ typedef struct ngx_event_s ngx_event_t; typedef struct ngx_event_aio_s ngx_event_aio_t; typedef struct ngx_connection_s ngx_connection_t; +#if (NGX_THREADS) +typedef struct ngx_thread_task_s ngx_thread_task_t; +#endif + typedef void (*ngx_event_handler_pt)(ngx_event_t *ev); typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c); @@ -64,6 +71,7 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c); #endif #include #include +#include #include #include #include @@ -77,12 +85,13 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c); #include #include #include +#include #include -#define LF (u_char) 10 -#define CR (u_char) 13 -#define CRLF "\x0d\x0a" +#define LF (u_char) '\n' +#define CR (u_char) '\r' +#define CRLF "\r\n" #define ngx_abs(value) (((value) >= 0) ? (value) : - (value)) diff --git a/src/core/ngx_crypt.c b/src/core/ngx_crypt.c index e2376c6..d7d068c 100644 --- a/src/core/ngx_crypt.c +++ b/src/core/ngx_crypt.c @@ -66,7 +66,7 @@ ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) size_t saltlen, keylen; ngx_md5_t md5, ctx1; - /* Apache's apr1 crypt is Paul-Henning Kamp's md5 crypt with $apr1$ magic */ + /* Apache's apr1 crypt is Poul-Henning Kamp's md5 crypt with $apr1$ magic */ keylen = ngx_strlen(key); diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c index d1a89ae..b358f3d 100644 --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -26,10 +26,6 @@ static ngx_event_t ngx_cleaner_event; ngx_uint_t ngx_test_config; ngx_uint_t ngx_quiet_mode; -#if (NGX_THREADS) -ngx_tls_key_t ngx_core_tls_key; -#endif - /* STUB NAME */ static ngx_connection_t dumb; @@ -441,9 +437,13 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) } if (shm_zone[i].tag == oshm_zone[n].tag - && shm_zone[i].shm.size == oshm_zone[n].shm.size) + && shm_zone[i].shm.size == oshm_zone[n].shm.size + && !shm_zone[i].noreuse) { shm_zone[i].shm.addr = oshm_zone[n].shm.addr; +#if (NGX_WIN32) + shm_zone[i].shm.handle = oshm_zone[n].shm.handle; +#endif if (shm_zone[i].init(&shm_zone[i], oshm_zone[n].data) != NGX_OK) @@ -493,6 +493,10 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) continue; } + if (ls[i].remain) { + continue; + } + if (ngx_cmp_sockaddr(nls[n].sockaddr, nls[n].socklen, ls[i].sockaddr, ls[i].socklen, 1) == NGX_OK) @@ -540,6 +544,13 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) nls[n].add_deferred = 1; } #endif + +#if (NGX_HAVE_REUSEPORT) + if (nls[n].reuseport && !ls[i].reuseport) { + nls[n].add_reuseport = 1; + } +#endif + break; } } @@ -863,6 +874,22 @@ ngx_init_zone_pool(ngx_cycle_t *cycle, ngx_shm_zone_t *zn) return NGX_OK; } +#if (NGX_WIN32) + + /* remap at the required address */ + + if (ngx_shm_remap(&zn->shm, sp->addr) != NGX_OK) { + return NGX_ERROR; + } + + sp = (ngx_slab_pool_t *) zn->shm.addr; + + if (sp == sp->addr) { + return NGX_OK; + } + +#endif + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "shared zone \"%V\" has no equal addresses: %p vs %p", &zn->shm.name, sp->addr, sp); @@ -1104,6 +1131,8 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user) ngx_close_file_n " \"%s\" failed", file[i].name.data); } + + continue; } if (fi.st_uid != user) { @@ -1117,6 +1146,8 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user) ngx_close_file_n " \"%s\" failed", file[i].name.data); } + + continue; } } @@ -1133,6 +1164,8 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user) ngx_close_file_n " \"%s\" failed", file[i].name.data); } + + continue; } } } @@ -1204,6 +1237,10 @@ ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag) return NULL; } + if (shm_zone[i].shm.size == 0) { + shm_zone[i].shm.size = size; + } + if (size && size != shm_zone[i].shm.size) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the size %uz of shared memory zone \"%V\" " @@ -1228,6 +1265,7 @@ ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag) shm_zone->shm.exists = 0; shm_zone->init = NULL; shm_zone->tag = tag; + shm_zone->noreuse = 0; return shm_zone; } diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h index 21bf5ca..c601ea1 100644 --- a/src/core/ngx_cycle.h +++ b/src/core/ngx_cycle.h @@ -31,6 +31,7 @@ struct ngx_shm_zone_s { ngx_shm_t shm; ngx_shm_zone_init_pt init; void *tag; + ngx_uint_t noreuse; /* unsigned noreuse:1; */ }; @@ -82,7 +83,6 @@ typedef struct { ngx_int_t debug_points; ngx_int_t rlimit_nofile; - ngx_int_t rlimit_sigpending; off_t rlimit_core; int priority; @@ -102,20 +102,9 @@ typedef struct { ngx_array_t env; char **environment; - -#if (NGX_THREADS) - ngx_int_t worker_threads; - size_t thread_stack_size; -#endif - } ngx_core_conf_t; -typedef struct { - ngx_pool_t *pool; /* pcre's malloc() pool */ -} ngx_core_tls_t; - - #define ngx_is_init_cycle(cycle) (cycle->conf_ctx == NULL) @@ -136,9 +125,6 @@ extern ngx_array_t ngx_old_cycles; extern ngx_module_t ngx_core_module; extern ngx_uint_t ngx_test_config; extern ngx_uint_t ngx_quiet_mode; -#if (NGX_THREADS) -extern ngx_tls_key_t ngx_core_tls_key; -#endif #endif /* _NGX_CYCLE_H_INCLUDED_ */ diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c index 7e6e921..3ebd73d 100644 --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -114,7 +114,7 @@ ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain) rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool, tf->persistent, tf->clean, tf->access); - if (rc == NGX_ERROR || rc == NGX_AGAIN) { + if (rc != NGX_OK) { return rc; } @@ -356,7 +356,7 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } if (ngx_conf_full_name(cf->cycle, &path->name, 0) != NGX_OK) { - return NULL; + return NGX_CONF_ERROR; } path->conf_file = cf->conf_file->file.name.data; @@ -372,8 +372,8 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) path->len += level + 1; } - while (i < 3) { - path->level[i++] = 0; + if (path->len > 10 + i) { + return "invalid value"; } *slot = path; @@ -1035,10 +1035,18 @@ ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree) ctx->access = ngx_de_access(&dir); ctx->mtime = ngx_de_mtime(&dir); - if (ctx->pre_tree_handler(ctx, &file) == NGX_ABORT) { + rc = ctx->pre_tree_handler(ctx, &file); + + if (rc == NGX_ABORT) { goto failed; } + if (rc == NGX_DECLINED) { + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "tree skip dir \"%s\"", file.data); + continue; + } + if (ngx_walk_tree(ctx, &file) == NGX_ABORT) { goto failed; } diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h index 3ea6c28..301b191 100644 --- a/src/core/ngx_file.h +++ b/src/core/ngx_file.h @@ -23,6 +23,12 @@ struct ngx_file_s { ngx_log_t *log; +#if (NGX_THREADS) + ngx_int_t (*thread_handler)(ngx_thread_task_t *task, + ngx_file_t *file); + void *thread_ctx; +#endif + #if (NGX_HAVE_FILE_AIO) ngx_event_aio_t *aio; #endif diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c index 2c84daf..96a04fd 100644 --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -26,15 +26,15 @@ ngx_inet_addr(u_char *text, size_t len) n = 0; for (p = text; p < text + len; p++) { - - if (octet > 255) { - return INADDR_NONE; - } - c = *p; if (c >= '0' && c <= '9') { octet = octet * 10 + (c - '0'); + + if (octet > 255) { + return INADDR_NONE; + } + continue; } diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c index edf3004..0893871 100644 --- a/src/core/ngx_log.c +++ b/src/core/ngx_log.c @@ -14,6 +14,23 @@ static char *ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log); static void ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log); +#if (NGX_DEBUG) + +static void ngx_log_memory_writer(ngx_log_t *log, ngx_uint_t level, + u_char *buf, size_t len); +static void ngx_log_memory_cleanup(void *data); + + +typedef struct { + u_char *start; + u_char *end; + u_char *pos; + ngx_atomic_t written; +} ngx_log_memory_buf_t; + +#endif + + static ngx_command_t ngx_errlog_commands[] = { {ngx_string("error_log"), @@ -69,7 +86,7 @@ static ngx_str_t err_levels[] = { static const char *debug_levels[] = { "debug_core", "debug_alloc", "debug_mutex", "debug_event", - "debug_http", "debug_mail", "debug_mysql" + "debug_http", "debug_mail", "debug_mysql", "debug_stream" }; @@ -91,15 +108,14 @@ ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, va_list args; #endif u_char *p, *last, *msg; - u_char errstr[NGX_MAX_ERROR_STR]; + ssize_t n; ngx_uint_t wrote_stderr, debug_connection; + u_char errstr[NGX_MAX_ERROR_STR]; last = errstr + NGX_MAX_ERROR_STR; - ngx_memcpy(errstr, ngx_cached_err_log_time.data, - ngx_cached_err_log_time.len); - - p = errstr + ngx_cached_err_log_time.len; + p = ngx_cpymem(errstr, ngx_cached_err_log_time.data, + ngx_cached_err_log_time.len); p = ngx_slprintf(p, last, " [%V] ", &err_levels[level]); @@ -148,12 +164,34 @@ ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, break; } - (void) ngx_write_fd(log->file->fd, errstr, p - errstr); + if (log->writer) { + log->writer(log, level, errstr, p - errstr); + goto next; + } + + if (ngx_time() == log->disk_full_time) { + + /* + * on FreeBSD writing to a full filesystem with enabled softupdates + * may block process for much longer time than writing to non-full + * filesystem, so we skip writing to a log for one second + */ + + goto next; + } + + n = ngx_write_fd(log->file->fd, errstr, p - errstr); + + if (n == -1 && ngx_errno == NGX_ENOSPC) { + log->disk_full_time = ngx_time(); + } if (log->file->fd == ngx_stderr) { wrote_stderr = 1; } + next: + log = log->next; } @@ -225,9 +263,8 @@ ngx_log_stderr(ngx_err_t err, const char *fmt, ...) u_char errstr[NGX_MAX_ERROR_STR]; last = errstr + NGX_MAX_ERROR_STR; - p = errstr + 7; - ngx_memcpy(errstr, "nginx: ", 7); + p = ngx_cpymem(errstr, "nginx: ", 7); va_start(args, fmt); p = ngx_vslprintf(p, last, fmt, args); @@ -366,15 +403,35 @@ ngx_log_init(u_char *prefix) ngx_int_t ngx_log_open_default(ngx_cycle_t *cycle) { - static ngx_str_t error_log = ngx_string(NGX_ERROR_LOG_PATH); + ngx_log_t *log; + static ngx_str_t error_log = ngx_string(NGX_ERROR_LOG_PATH); - if (cycle->new_log.file == NULL) { - cycle->new_log.file = ngx_conf_open_file(cycle, &error_log); - if (cycle->new_log.file == NULL) { + if (ngx_log_get_file_log(&cycle->new_log) != NULL) { + return NGX_OK; + } + + if (cycle->new_log.log_level != 0) { + /* there are some error logs, but no files */ + + log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t)); + if (log == NULL) { return NGX_ERROR; } - cycle->new_log.log_level = NGX_LOG_ERR; + } else { + /* no error logs at all */ + log = &cycle->new_log; + } + + log->log_level = NGX_LOG_ERR; + + log->file = ngx_conf_open_file(cycle, &error_log); + if (log->file == NULL) { + return NGX_ERROR; + } + + if (log != &cycle->new_log) { + ngx_log_insert(&cycle->new_log, log); } return NGX_OK; @@ -390,7 +447,8 @@ ngx_log_redirect_stderr(ngx_cycle_t *cycle) return NGX_OK; } - fd = cycle->log->file->fd; + /* file log always exists when we are called */ + fd = ngx_log_get_file_log(cycle->log)->file->fd; if (fd != ngx_stderr) { if (ngx_set_stderr(fd) == NGX_FILE_ERROR) { @@ -405,6 +463,21 @@ ngx_log_redirect_stderr(ngx_cycle_t *cycle) } +ngx_log_t * +ngx_log_get_file_log(ngx_log_t *head) +{ + ngx_log_t *log; + + for (log = head; log; log = log->next) { + if (log->file != NULL) { + return log; + } + } + + return NULL; +} + + static char * ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log) { @@ -482,8 +555,9 @@ ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) char * ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head) { - ngx_log_t *new_log; - ngx_str_t *value, name; + ngx_log_t *new_log; + ngx_str_t *value, name; + ngx_syslog_peer_t *peer; if (*head != NULL && (*head)->log_level == 0) { new_log = *head; @@ -506,13 +580,88 @@ ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head) ngx_str_null(&name); cf->cycle->log_use_stderr = 1; - } else { - name = value[1]; - } + new_log->file = ngx_conf_open_file(cf->cycle, &name); + if (new_log->file == NULL) { + return NGX_CONF_ERROR; + } - new_log->file = ngx_conf_open_file(cf->cycle, &name); - if (new_log->file == NULL) { + } else if (ngx_strncmp(value[1].data, "memory:", 7) == 0) { + +#if (NGX_DEBUG) + size_t size, needed; + ngx_pool_cleanup_t *cln; + ngx_log_memory_buf_t *buf; + + value[1].len -= 7; + value[1].data += 7; + + needed = sizeof("MEMLOG :" NGX_LINEFEED) + + cf->conf_file->file.name.len + + NGX_SIZE_T_LEN + + NGX_INT_T_LEN + + NGX_MAX_ERROR_STR; + + size = ngx_parse_size(&value[1]); + + if (size == (size_t) NGX_ERROR || size < needed) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid buffer size \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + buf = ngx_pcalloc(cf->pool, sizeof(ngx_log_memory_buf_t)); + if (buf == NULL) { + return NGX_CONF_ERROR; + } + + buf->start = ngx_pnalloc(cf->pool, size); + if (buf->start == NULL) { + return NGX_CONF_ERROR; + } + + buf->end = buf->start + size; + + buf->pos = ngx_slprintf(buf->start, buf->end, "MEMLOG %uz %V:%ui%N", + size, &cf->conf_file->file.name, + cf->conf_file->line); + + ngx_memset(buf->pos, ' ', buf->end - buf->pos); + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_CONF_ERROR; + } + + cln->data = new_log; + cln->handler = ngx_log_memory_cleanup; + + new_log->writer = ngx_log_memory_writer; + new_log->wdata = buf; + +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "nginx was built without debug support"); return NGX_CONF_ERROR; +#endif + + } else if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) { + peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t)); + if (peer == NULL) { + return NGX_CONF_ERROR; + } + + if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) { + return NGX_CONF_ERROR; + } + + new_log->writer = ngx_syslog_writer; + new_log->wdata = peer; + + } else { + new_log->file = ngx_conf_open_file(cf->cycle, &value[1]); + if (new_log->file == NULL) { + return NGX_CONF_ERROR; + } } if (ngx_log_set_levels(cf, new_log) != NGX_CONF_OK) { @@ -559,3 +708,48 @@ ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log) log->next = new_log; } + + +#if (NGX_DEBUG) + +static void +ngx_log_memory_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf, + size_t len) +{ + u_char *p; + size_t avail, written; + ngx_log_memory_buf_t *mem; + + mem = log->wdata; + + if (mem == NULL) { + return; + } + + written = ngx_atomic_fetch_add(&mem->written, len); + + p = mem->pos + written % (mem->end - mem->pos); + + avail = mem->end - p; + + if (avail >= len) { + ngx_memcpy(p, buf, len); + + } else { + ngx_memcpy(p, buf, avail); + ngx_memcpy(mem->pos, buf + avail, len - avail); + } +} + + +static void +ngx_log_memory_cleanup(void *data) +{ + ngx_log_t *log = data; + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "destroy memory log buffer"); + + log->wdata = NULL; +} + +#endif diff --git a/src/core/ngx_log.h b/src/core/ngx_log.h index 878fb0a..cb80b5f 100644 --- a/src/core/ngx_log.h +++ b/src/core/ngx_log.h @@ -30,6 +30,7 @@ #define NGX_LOG_DEBUG_HTTP 0x100 #define NGX_LOG_DEBUG_MAIL 0x200 #define NGX_LOG_DEBUG_MYSQL 0x400 +#define NGX_LOG_DEBUG_STREAM 0x800 /* * do not forget to update debug_levels[] in src/core/ngx_log.c @@ -37,12 +38,14 @@ */ #define NGX_LOG_DEBUG_FIRST NGX_LOG_DEBUG_CORE -#define NGX_LOG_DEBUG_LAST NGX_LOG_DEBUG_MYSQL +#define NGX_LOG_DEBUG_LAST NGX_LOG_DEBUG_STREAM #define NGX_LOG_DEBUG_CONNECTION 0x80000000 #define NGX_LOG_DEBUG_ALL 0x7ffffff0 typedef u_char *(*ngx_log_handler_pt) (ngx_log_t *log, u_char *buf, size_t len); +typedef void (*ngx_log_writer_pt) (ngx_log_t *log, ngx_uint_t level, + u_char *buf, size_t len); struct ngx_log_s { @@ -51,9 +54,14 @@ struct ngx_log_s { ngx_atomic_uint_t connection; + time_t disk_full_time; + ngx_log_handler_pt handler; void *data; + ngx_log_writer_pt writer; + void *wdata; + /* * we declare "action" as "char *" because the actions are usually * the static strings and in the "u_char *" case we have to override @@ -227,6 +235,7 @@ void ngx_cdecl ngx_log_stderr(ngx_err_t err, const char *fmt, ...); u_char *ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err); ngx_int_t ngx_log_open_default(ngx_cycle_t *cycle); ngx_int_t ngx_log_redirect_stderr(ngx_cycle_t *cycle); +ngx_log_t *ngx_log_get_file_log(ngx_log_t *head); char *ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head); @@ -242,7 +251,7 @@ char *ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head); static ngx_inline void ngx_write_stderr(char *text) { - (void) ngx_write_fd(ngx_stderr, text, strlen(text)); + (void) ngx_write_fd(ngx_stderr, text, ngx_strlen(text)); } diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c index 3cb60ea..252359a 100644 --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -29,6 +29,10 @@ static ngx_inline ngx_int_t ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf); +#if (NGX_HAVE_AIO_SENDFILE) +static ngx_int_t ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx, + ngx_file_t *file); +#endif static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in); static ngx_int_t ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, @@ -45,8 +49,12 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in) ngx_int_t rc, last; ngx_chain_t *cl, *out, **last_out; - if (ctx->in == NULL && ctx->busy == NULL) { - + if (ctx->in == NULL && ctx->busy == NULL +#if (NGX_HAVE_FILE_AIO || NGX_THREADS) + && !ctx->aio +#endif + ) + { /* * the short path for the case when the ctx->in and ctx->busy chains * are empty, the incoming chain is empty too or has the single buf @@ -81,7 +89,7 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in) for ( ;; ) { -#if (NGX_HAVE_FILE_AIO) +#if (NGX_HAVE_FILE_AIO || NGX_THREADS) if (ctx->aio) { return NGX_AGAIN; } @@ -225,6 +233,13 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) return 1; } +#if (NGX_THREADS) + if (buf->in_file) { + buf->file->thread_handler = ctx->thread_handler; + buf->file->thread_ctx = ctx->filter_ctx; + } +#endif + if (buf->in_file && buf->file->directio) { return 0; } @@ -248,6 +263,12 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) buf->in_file = 0; } +#if (NGX_HAVE_AIO_SENDFILE) + if (ctx->aio_preload && buf->in_file) { + (void) ngx_output_chain_aio_setup(ctx, buf->file); + } +#endif + if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) { return 0; } @@ -260,6 +281,28 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) } +#if (NGX_HAVE_AIO_SENDFILE) + +static ngx_int_t +ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx, ngx_file_t *file) +{ + ngx_event_aio_t *aio; + + if (file->aio == NULL && ngx_file_aio_init(file, ctx->pool) != NGX_OK) { + return NGX_ERROR; + } + + aio = file->aio; + + aio->data = ctx->filter_ctx; + aio->preload_handler = ctx->aio_preload; + + return NGX_OK; +} + +#endif + + static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in) @@ -523,7 +566,6 @@ ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx) #endif #if (NGX_HAVE_FILE_AIO) - if (ctx->aio_handler) { n = ngx_file_aio_read(src->file, dst->pos, (size_t) size, src->file_pos, ctx->pool); @@ -532,15 +574,23 @@ ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx) return NGX_AGAIN; } - } else { + } else +#endif +#if (NGX_THREADS) + if (src->file->thread_handler) { + n = ngx_thread_read(&ctx->thread_task, src->file, dst->pos, + (size_t) size, src->file_pos, ctx->pool); + if (n == NGX_AGAIN) { + ctx->aio = 1; + return NGX_AGAIN; + } + + } else +#endif + { n = ngx_read_file(src->file, dst->pos, (size_t) size, src->file_pos); } -#else - - n = ngx_read_file(src->file, dst->pos, (size_t) size, src->file_pos); - -#endif #if (NGX_HAVE_ALIGNED_DIRECTIO) @@ -604,7 +654,7 @@ ngx_chain_writer(void *data, ngx_chain_t *in) ngx_chain_writer_ctx_t *ctx = data; off_t size; - ngx_chain_t *cl; + ngx_chain_t *cl, *ln, *chain; ngx_connection_t *c; c = ctx->connection; @@ -613,7 +663,23 @@ ngx_chain_writer(void *data, ngx_chain_t *in) #if 1 if (ngx_buf_size(in->buf) == 0 && !ngx_buf_special(in->buf)) { + + ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, + "zero size buf in chain writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + in->buf->temporary, + in->buf->recycled, + in->buf->in_file, + in->buf->start, + in->buf->pos, + in->buf->last, + in->buf->file, + in->buf->file_pos, + in->buf->file_last); + ngx_debug_point(); + + continue; } #endif @@ -641,9 +707,24 @@ ngx_chain_writer(void *data, ngx_chain_t *in) #if 1 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { - ngx_debug_point(); - } + ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, + "zero size buf in chain writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); + + ngx_debug_point(); + + continue; + } #endif size += ngx_buf_size(cl->buf); @@ -653,15 +734,23 @@ ngx_chain_writer(void *data, ngx_chain_t *in) return NGX_OK; } - ctx->out = c->send_chain(c, ctx->out, ctx->limit); + chain = c->send_chain(c, ctx->out, ctx->limit); ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, - "chain writer out: %p", ctx->out); + "chain writer out: %p", chain); - if (ctx->out == NGX_CHAIN_ERROR) { + if (chain == NGX_CHAIN_ERROR) { return NGX_ERROR; } + for (cl = ctx->out; cl && cl != chain; /* void */) { + ln = cl; + cl = cl->next; + ngx_free_chain(ctx->pool, ln); + } + + ctx->out = chain; + if (ctx->out == NULL) { ctx->last = &ctx->out; diff --git a/src/core/ngx_palloc.c b/src/core/ngx_palloc.c index 1f70f9e..ef4a647 100644 --- a/src/core/ngx_palloc.c +++ b/src/core/ngx_palloc.c @@ -181,7 +181,7 @@ ngx_palloc_block(ngx_pool_t *pool, size_t size) { u_char *m; size_t psize; - ngx_pool_t *p, *new, *current; + ngx_pool_t *p, *new; psize = (size_t) (pool->d.end - (u_char *) pool); @@ -200,18 +200,14 @@ ngx_palloc_block(ngx_pool_t *pool, size_t size) m = ngx_align_ptr(m, NGX_ALIGNMENT); new->d.last = m + size; - current = pool->current; - - for (p = current; p->d.next; p = p->d.next) { + for (p = pool->current; p->d.next; p = p->d.next) { if (p->d.failed++ > 4) { - current = p->d.next; + pool->current = p->d.next; } } p->d.next = new; - pool->current = current ? current : new; - return m; } diff --git a/src/core/ngx_rbtree.c b/src/core/ngx_rbtree.c index 914ca7e..6c66f40 100644 --- a/src/core/ngx_rbtree.c +++ b/src/core/ngx_rbtree.c @@ -22,8 +22,7 @@ static ngx_inline void ngx_rbtree_right_rotate(ngx_rbtree_node_t **root, void -ngx_rbtree_insert(ngx_thread_volatile ngx_rbtree_t *tree, - ngx_rbtree_node_t *node) +ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node) { ngx_rbtree_node_t **root, *temp, *sentinel; @@ -155,8 +154,7 @@ ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, void -ngx_rbtree_delete(ngx_thread_volatile ngx_rbtree_t *tree, - ngx_rbtree_node_t *node) +ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node) { ngx_uint_t red; ngx_rbtree_node_t **root, *sentinel, *subst, *temp, *w; diff --git a/src/core/ngx_rbtree.h b/src/core/ngx_rbtree.h index 6e47a5b..1d33e3f 100644 --- a/src/core/ngx_rbtree.h +++ b/src/core/ngx_rbtree.h @@ -48,10 +48,8 @@ struct ngx_rbtree_s { (tree)->insert = i -void ngx_rbtree_insert(ngx_thread_volatile ngx_rbtree_t *tree, - ngx_rbtree_node_t *node); -void ngx_rbtree_delete(ngx_thread_volatile ngx_rbtree_t *tree, - ngx_rbtree_node_t *node); +void ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node); +void ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node); void ngx_rbtree_insert_value(ngx_rbtree_node_t *root, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); void ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *root, diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c index 3771aab..416622d 100644 --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -80,17 +80,6 @@ ngx_regex_init(void) static ngx_inline void ngx_regex_malloc_init(ngx_pool_t *pool) { -#if (NGX_THREADS) - ngx_core_tls_t *tls; - - if (ngx_threaded) { - tls = ngx_thread_get_tls(ngx_core_tls_key); - tls->pool = pool; - return; - } - -#endif - ngx_pcre_pool = pool; } @@ -98,17 +87,6 @@ ngx_regex_malloc_init(ngx_pool_t *pool) static ngx_inline void ngx_regex_malloc_done(void) { -#if (NGX_THREADS) - ngx_core_tls_t *tls; - - if (ngx_threaded) { - tls = ngx_thread_get_tls(ngx_core_tls_key); - tls->pool = NULL; - return; - } - -#endif - ngx_pcre_pool = NULL; } @@ -149,7 +127,7 @@ ngx_regex_compile(ngx_regex_compile_t *rc) rc->regex = ngx_pcalloc(rc->pool, sizeof(ngx_regex_t)); if (rc->regex == NULL) { - return NGX_ERROR; + goto nomem; } rc->regex->code = re; @@ -159,7 +137,7 @@ ngx_regex_compile(ngx_regex_compile_t *rc) if (ngx_pcre_studies != NULL) { elt = ngx_list_push(ngx_pcre_studies); if (elt == NULL) { - return NGX_ERROR; + goto nomem; } elt->regex = rc->regex; @@ -204,7 +182,15 @@ failed: rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n) - rc->err.data; - return NGX_OK; + return NGX_ERROR; + +nomem: + + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "regex \"%V\" compilation failed: no memory", + &rc->pattern) + - rc->err.data; + return NGX_ERROR; } @@ -245,23 +231,8 @@ static void * ngx_libc_cdecl ngx_regex_malloc(size_t size) { ngx_pool_t *pool; -#if (NGX_THREADS) - ngx_core_tls_t *tls; - - if (ngx_threaded) { - tls = ngx_thread_get_tls(ngx_core_tls_key); - pool = tls->pool; - - } else { - pool = ngx_pcre_pool; - } - -#else - pool = ngx_pcre_pool; -#endif - if (pool) { return ngx_palloc(pool, size); } diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index b45001e..caa2b51 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -48,6 +48,11 @@ typedef struct { } ngx_resolver_an_t; +#define ngx_resolver_node(n) \ + (ngx_resolver_node_t *) \ + ((u_char *) (n) - offsetof(ngx_resolver_node_t, node)) + + ngx_int_t ngx_udp_connect(ngx_udp_connection_t *uc); @@ -288,7 +293,7 @@ ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree) while (tree->root != tree->sentinel) { - rn = (ngx_resolver_node_t *) ngx_rbtree_min(tree->root, tree->sentinel); + rn = ngx_resolver_node(ngx_rbtree_min(tree->root, tree->sentinel)); ngx_queue_remove(&rn->queue); @@ -666,7 +671,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) ctx->event->handler = ngx_resolver_timeout_handler; ctx->event->data = rn; ctx->event->log = r->log; - ctx->ident = -1; + rn->ident = -1; ngx_add_timer(ctx->event, ctx->timeout); } @@ -859,7 +864,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) ctx->event->handler = ngx_resolver_timeout_handler; ctx->event->data = rn; ctx->event->log = r->log; - ctx->ident = -1; + rn->ident = -1; ngx_add_timer(ctx->event, ctx->timeout); @@ -2290,7 +2295,7 @@ ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash) /* hash == node->key */ - rn = (ngx_resolver_node_t *) node; + rn = ngx_resolver_node(node); rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen); @@ -2329,7 +2334,7 @@ ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr) /* addr == node->key */ - return (ngx_resolver_node_t *) node; + return ngx_resolver_node(node); } /* not found */ @@ -2365,7 +2370,7 @@ ngx_resolver_lookup_addr6(ngx_resolver_t *r, struct in6_addr *addr, /* hash == node->key */ - rn = (ngx_resolver_node_t *) node; + rn = ngx_resolver_node(node); rc = ngx_memcmp(addr, &rn->addr6, 16); @@ -2403,8 +2408,8 @@ ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp, } else { /* node->key == temp->key */ - rn = (ngx_resolver_node_t *) node; - rn_temp = (ngx_resolver_node_t *) temp; + rn = ngx_resolver_node(node); + rn_temp = ngx_resolver_node(temp); p = (ngx_memn2cmp(rn->name, rn_temp->name, rn->nlen, rn_temp->nlen) < 0) ? &temp->left : &temp->right; @@ -2446,8 +2451,8 @@ ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp, } else { /* node->key == temp->key */ - rn = (ngx_resolver_node_t *) node; - rn_temp = (ngx_resolver_node_t *) temp; + rn = ngx_resolver_node(node); + rn_temp = ngx_resolver_node(temp); p = (ngx_memcmp(&rn->addr6, &rn_temp->addr6, 16) < 0) ? &temp->left : &temp->right; @@ -2747,8 +2752,7 @@ done: } if (len == -1) { - name->len = 0; - name->data = NULL; + ngx_str_null(name); return NGX_OK; } @@ -3083,23 +3087,12 @@ ngx_udp_connect(ngx_udp_connection_t *uc) c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); -#if (NGX_THREADS) - - /* TODO: lock event when call completion handler */ - - rev->lock = &c->lock; - wev->lock = &c->lock; - rev->own_lock = &c->lock; - wev->own_lock = &c->lock; - -#endif - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "connect to %V, fd:%d #%uA", &uc->server, s, c->number); rc = connect(s, uc->sockaddr, uc->socklen); - /* TODO: aio, iocp */ + /* TODO: iocp */ if (rc == -1) { ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno, @@ -3111,23 +3104,13 @@ ngx_udp_connect(ngx_udp_connection_t *uc) /* UDP sockets are always ready to write */ wev->ready = 1; - if (ngx_add_event) { + event = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ? + /* kqueue, epoll */ NGX_CLEAR_EVENT: + /* select, poll, /dev/poll */ NGX_LEVEL_EVENT; + /* eventport event type has no meaning: oneshot only */ - event = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ? - /* kqueue, epoll */ NGX_CLEAR_EVENT: - /* select, poll, /dev/poll */ NGX_LEVEL_EVENT; - /* eventport event type has no meaning: oneshot only */ - - if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { - goto failed; - } - - } else { - /* rtsig */ - - if (ngx_add_conn(c) == NGX_ERROR) { - goto failed; - } + if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { + goto failed; } return NGX_OK; diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h index 264c8c4..d3519fb 100644 --- a/src/core/ngx_resolver.h +++ b/src/core/ngx_resolver.h @@ -51,12 +51,16 @@ typedef void (*ngx_resolver_handler_pt)(ngx_resolver_ctx_t *ctx); typedef struct { - ngx_rbtree_node_t node; - ngx_queue_t queue; - /* PTR: resolved name, A: name to resolve */ u_char *name; + ngx_queue_t queue; + + /* event ident must be after 3 pointers as in ngx_connection_t */ + ngx_int_t ident; + + ngx_rbtree_node_t node; + #if (NGX_HAVE_INET6) /* PTR: IPv6 address to resolve (IPv4 address is in rbtree node key) */ struct in6_addr addr6; @@ -103,7 +107,7 @@ typedef struct { void *dummy; ngx_log_t *log; - /* ident must be after 3 pointers */ + /* event ident must be after 3 pointers as in ngx_connection_t */ ngx_int_t ident; /* simple round robin DNS peers balancer */ @@ -143,9 +147,6 @@ struct ngx_resolver_ctx_s { ngx_resolver_t *resolver; ngx_udp_connection_t *udp_connection; - /* ident must be after 3 pointers */ - ngx_int_t ident; - ngx_int_t state; ngx_str_t name; diff --git a/src/core/ngx_rwlock.c b/src/core/ngx_rwlock.c new file mode 100644 index 0000000..1404c6e --- /dev/null +++ b/src/core/ngx_rwlock.c @@ -0,0 +1,120 @@ + +/* + * Copyright (C) Ruslan Ermilov + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +#if (NGX_HAVE_ATOMIC_OPS) + + +#define NGX_RWLOCK_SPIN 2048 +#define NGX_RWLOCK_WLOCK ((ngx_atomic_uint_t) -1) + + +void +ngx_rwlock_wlock(ngx_atomic_t *lock) +{ + ngx_uint_t i, n; + + for ( ;; ) { + + if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK)) { + return; + } + + if (ngx_ncpu > 1) { + + for (n = 1; n < NGX_RWLOCK_SPIN; n <<= 1) { + + for (i = 0; i < n; i++) { + ngx_cpu_pause(); + } + + if (*lock == 0 + && ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK)) + { + return; + } + } + } + + ngx_sched_yield(); + } +} + + +void +ngx_rwlock_rlock(ngx_atomic_t *lock) +{ + ngx_uint_t i, n; + ngx_atomic_uint_t readers; + + for ( ;; ) { + readers = *lock; + + if (readers != NGX_RWLOCK_WLOCK + && ngx_atomic_cmp_set(lock, readers, readers + 1)) + { + return; + } + + if (ngx_ncpu > 1) { + + for (n = 1; n < NGX_RWLOCK_SPIN; n <<= 1) { + + for (i = 0; i < n; i++) { + ngx_cpu_pause(); + } + + readers = *lock; + + if (readers != NGX_RWLOCK_WLOCK + && ngx_atomic_cmp_set(lock, readers, readers + 1)) + { + return; + } + } + } + + ngx_sched_yield(); + } +} + + +void +ngx_rwlock_unlock(ngx_atomic_t *lock) +{ + ngx_atomic_uint_t readers; + + readers = *lock; + + if (readers == NGX_RWLOCK_WLOCK) { + *lock = 0; + return; + } + + for ( ;; ) { + + if (ngx_atomic_cmp_set(lock, readers, readers - 1)) { + return; + } + + readers = *lock; + } +} + + +#else + +#if (NGX_HTTP_UPSTREAM_ZONE) + +#error ngx_atomic_cmp_set() is not defined! + +#endif + +#endif diff --git a/src/core/ngx_rwlock.h b/src/core/ngx_rwlock.h new file mode 100644 index 0000000..8b16eca --- /dev/null +++ b/src/core/ngx_rwlock.h @@ -0,0 +1,21 @@ + +/* + * Copyright (C) Ruslan Ermilov + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_RWLOCK_H_INCLUDED_ +#define _NGX_RWLOCK_H_INCLUDED_ + + +#include +#include + + +void ngx_rwlock_wlock(ngx_atomic_t *lock); +void ngx_rwlock_rlock(ngx_atomic_t *lock); +void ngx_rwlock_unlock(ngx_atomic_t *lock); + + +#endif /* _NGX_RWLOCK_H_INCLUDED_ */ diff --git a/src/core/ngx_shmtx.c b/src/core/ngx_shmtx.c index 6230dc0..a255903 100644 --- a/src/core/ngx_shmtx.c +++ b/src/core/ngx_shmtx.c @@ -259,7 +259,7 @@ ngx_shmtx_trylock(ngx_shmtx_t *mtx) #if __osf__ /* Tru64 UNIX */ - if (err == NGX_EACCESS) { + if (err == NGX_EACCES) { return 0; } diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c index be7927c..c112506 100644 --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -129,6 +129,8 @@ ngx_slab_init(ngx_slab_pool_t *pool) pool->pages->slab = pages; } + pool->last = pool->pages + pages; + pool->log_nomem = 1; pool->log_ctx = &pool->zero; pool->zero = '\0'; @@ -158,7 +160,7 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) ngx_uint_t i, slot, shift, map; ngx_slab_page_t *page, *prev, *slots; - if (size >= ngx_slab_max_size) { + if (size > ngx_slab_max_size) { ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab alloc: %uz", size); @@ -396,6 +398,35 @@ done: } +void * +ngx_slab_calloc(ngx_slab_pool_t *pool, size_t size) +{ + void *p; + + ngx_shmtx_lock(&pool->mutex); + + p = ngx_slab_calloc_locked(pool, size); + + ngx_shmtx_unlock(&pool->mutex); + + return p; +} + + +void * +ngx_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size) +{ + void *p; + + p = ngx_slab_alloc_locked(pool, size); + if (p) { + ngx_memzero(p, size); + } + + return p; +} + + void ngx_slab_free(ngx_slab_pool_t *pool, void *p) { @@ -626,6 +657,8 @@ ngx_slab_alloc_pages(ngx_slab_pool_t *pool, ngx_uint_t pages) if (page->slab >= pages) { if (page->slab > pages) { + page[page->slab - 1].prev = (uintptr_t) &page[pages]; + page[pages].slab = page->slab - pages; page[pages].next = page->next; page[pages].prev = page->prev; @@ -672,7 +705,8 @@ static void ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page, ngx_uint_t pages) { - ngx_slab_page_t *prev; + ngx_uint_t type; + ngx_slab_page_t *prev, *join; page->slab = pages--; @@ -686,6 +720,59 @@ ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page, page->next->prev = page->prev; } + join = page + page->slab; + + if (join < pool->last) { + type = join->prev & NGX_SLAB_PAGE_MASK; + + if (type == NGX_SLAB_PAGE) { + + if (join->next != NULL) { + pages += join->slab; + page->slab += join->slab; + + prev = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK); + prev->next = join->next; + join->next->prev = join->prev; + + join->slab = NGX_SLAB_PAGE_FREE; + join->next = NULL; + join->prev = NGX_SLAB_PAGE; + } + } + } + + if (page > pool->pages) { + join = page - 1; + type = join->prev & NGX_SLAB_PAGE_MASK; + + if (type == NGX_SLAB_PAGE) { + + if (join->slab == NGX_SLAB_PAGE_FREE) { + join = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK); + } + + if (join->next != NULL) { + pages += join->slab; + join->slab += page->slab; + + prev = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK); + prev->next = join->next; + join->next->prev = join->prev; + + page->slab = NGX_SLAB_PAGE_FREE; + page->next = NULL; + page->prev = NGX_SLAB_PAGE; + + page = join; + } + } + } + + if (pages) { + page[pages].prev = (uintptr_t) page; + } + page->prev = (uintptr_t) &pool->free; page->next = pool->free.next; diff --git a/src/core/ngx_slab.h b/src/core/ngx_slab.h index 5735e3b..2922a80 100644 --- a/src/core/ngx_slab.h +++ b/src/core/ngx_slab.h @@ -29,6 +29,7 @@ typedef struct { size_t min_shift; ngx_slab_page_t *pages; + ngx_slab_page_t *last; ngx_slab_page_t free; u_char *start; @@ -49,6 +50,8 @@ typedef struct { void ngx_slab_init(ngx_slab_pool_t *pool); void *ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size); void *ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size); +void *ngx_slab_calloc(ngx_slab_pool_t *pool, size_t size); +void *ngx_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size); void ngx_slab_free(ngx_slab_pool_t *pool, void *p); void ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p); diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index 503502a..d2a8d01 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -429,8 +429,12 @@ ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args) case 'N': #if (NGX_WIN32) *buf++ = CR; -#endif + if (buf < last) { + *buf++ = LF; + } +#else *buf++ = LF; +#endif fmt++; continue; @@ -1422,7 +1426,7 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) { ngx_uint_t n; uint32_t *escape; - static u_char hex[] = "0123456789abcdef"; + static u_char hex[] = "0123456789ABCDEF"; /* " ", "#", "%", "?", %00-%1F, %7F-%FF */ @@ -1788,6 +1792,58 @@ ngx_escape_html(u_char *dst, u_char *src, size_t size) } +uintptr_t +ngx_escape_json(u_char *dst, u_char *src, size_t size) +{ + u_char ch; + ngx_uint_t len; + + if (dst == NULL) { + len = 0; + + while (size) { + ch = *src++; + + if (ch == '\\' || ch == '"') { + len++; + + } else if (ch <= 0x1f) { + len += sizeof("\\u001F") - 2; + } + + size--; + } + + return (uintptr_t) len; + } + + while (size) { + ch = *src++; + + if (ch > 0x1f) { + + if (ch == '\\' || ch == '"') { + *dst++ = '\\'; + } + + *dst++ = ch; + + } else { + *dst++ = '\\'; *dst++ = 'u'; *dst++ = '0'; *dst++ = '0'; + *dst++ = '0' + (ch >> 4); + + ch &= 0xf; + + *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10); + } + + size--; + } + + return (uintptr_t) dst; +} + + void ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h index 712e7d0..7363bd2 100644 --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -207,6 +207,7 @@ uintptr_t ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type); void ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type); uintptr_t ngx_escape_html(u_char *dst, u_char *src, size_t size); +uintptr_t ngx_escape_json(u_char *dst, u_char *src, size_t size); typedef struct { diff --git a/src/core/ngx_syslog.c b/src/core/ngx_syslog.c new file mode 100644 index 0000000..d4e79f6 --- /dev/null +++ b/src/core/ngx_syslog.c @@ -0,0 +1,374 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +#define NGX_SYSLOG_MAX_STR \ + NGX_MAX_ERROR_STR + sizeof("<255>Jan 01 00:00:00 ") - 1 \ + + (NGX_MAXHOSTNAMELEN - 1) + 1 /* space */ \ + + 32 /* tag */ + 2 /* colon, space */ + + +static char *ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer); +static ngx_int_t ngx_syslog_init_peer(ngx_syslog_peer_t *peer); +static void ngx_syslog_cleanup(void *data); + + +static char *facilities[] = { + "kern", "user", "mail", "daemon", "auth", "intern", "lpr", "news", "uucp", + "clock", "authpriv", "ftp", "ntp", "audit", "alert", "cron", "local0", + "local1", "local2", "local3", "local4", "local5", "local6", "local7", + NULL +}; + +/* note 'error/warn' like in nginx.conf, not 'err/warning' */ +static char *severities[] = { + "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug", NULL +}; + +static ngx_log_t ngx_syslog_dummy_log; +static ngx_event_t ngx_syslog_dummy_event; + + +char * +ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer) +{ + peer->pool = cf->pool; + peer->facility = NGX_CONF_UNSET_UINT; + peer->severity = NGX_CONF_UNSET_UINT; + + if (ngx_syslog_parse_args(cf, peer) != NGX_CONF_OK) { + return NGX_CONF_ERROR; + } + + if (peer->server.sockaddr == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "no syslog server specified"); + return NGX_CONF_ERROR; + } + + if (peer->facility == NGX_CONF_UNSET_UINT) { + peer->facility = 23; /* local7 */ + } + + if (peer->severity == NGX_CONF_UNSET_UINT) { + peer->severity = 6; /* info */ + } + + if (peer->tag.data == NULL) { + ngx_str_set(&peer->tag, "nginx"); + } + + peer->conn.fd = (ngx_socket_t) -1; + + return NGX_CONF_OK; +} + + +static char * +ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer) +{ + u_char *p, *comma, c; + size_t len; + ngx_str_t *value; + ngx_url_t u; + ngx_uint_t i; + + value = cf->args->elts; + + p = value[1].data + sizeof("syslog:") - 1; + + for ( ;; ) { + comma = (u_char *) ngx_strchr(p, ','); + + if (comma != NULL) { + len = comma - p; + *comma = '\0'; + + } else { + len = value[1].data + value[1].len - p; + } + + if (ngx_strncmp(p, "server=", 7) == 0) { + + if (peer->server.sockaddr != NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate syslog \"server\""); + return NGX_CONF_ERROR; + } + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url.data = p + 7; + u.url.len = len - 7; + u.default_port = 514; + + if (ngx_parse_url(cf->pool, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in syslog server \"%V\"", + u.err, &u.url); + } + + return NGX_CONF_ERROR; + } + + peer->server = u.addrs[0]; + + } else if (ngx_strncmp(p, "facility=", 9) == 0) { + + if (peer->facility != NGX_CONF_UNSET_UINT) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate syslog \"facility\""); + return NGX_CONF_ERROR; + } + + for (i = 0; facilities[i] != NULL; i++) { + + if (ngx_strcmp(p + 9, facilities[i]) == 0) { + peer->facility = i; + goto next; + } + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unknown syslog facility \"%s\"", p + 9); + return NGX_CONF_ERROR; + + } else if (ngx_strncmp(p, "severity=", 9) == 0) { + + if (peer->severity != NGX_CONF_UNSET_UINT) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate syslog \"severity\""); + return NGX_CONF_ERROR; + } + + for (i = 0; severities[i] != NULL; i++) { + + if (ngx_strcmp(p + 9, severities[i]) == 0) { + peer->severity = i; + goto next; + } + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unknown syslog severity \"%s\"", p + 9); + return NGX_CONF_ERROR; + + } else if (ngx_strncmp(p, "tag=", 4) == 0) { + + if (peer->tag.data != NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate syslog \"tag\""); + return NGX_CONF_ERROR; + } + + /* + * RFC 3164: the TAG is a string of ABNF alphanumeric characters + * that MUST NOT exceed 32 characters. + */ + if (len - 4 > 32) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "syslog tag length exceeds 32"); + return NGX_CONF_ERROR; + } + + for (i = 4; i < len; i++) { + c = ngx_tolower(p[i]); + + if (c < '0' || (c > '9' && c < 'a' && c != '_') || c > 'z') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "syslog \"tag\" only allows " + "alphanumeric characters " + "and underscore"); + return NGX_CONF_ERROR; + } + } + + peer->tag.data = p + 4; + peer->tag.len = len - 4; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unknown syslog parameter \"%s\"", p); + return NGX_CONF_ERROR; + } + + next: + + if (comma == NULL) { + break; + } + + p = comma + 1; + } + + return NGX_CONF_OK; +} + + +u_char * +ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf) +{ + ngx_uint_t pri; + + pri = peer->facility * 8 + peer->severity; + + return ngx_sprintf(buf, "<%ui>%V %V %V: ", pri, &ngx_cached_syslog_time, + &ngx_cycle->hostname, &peer->tag); +} + + +void +ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf, + size_t len) +{ + u_char *p, msg[NGX_SYSLOG_MAX_STR]; + ngx_uint_t head_len; + ngx_syslog_peer_t *peer; + + peer = log->wdata; + + if (peer->busy) { + return; + } + + peer->busy = 1; + peer->severity = level - 1; + + p = ngx_syslog_add_header(peer, msg); + head_len = p - msg; + + len -= NGX_LINEFEED_SIZE; + + if (len > NGX_SYSLOG_MAX_STR - head_len) { + len = NGX_SYSLOG_MAX_STR - head_len; + } + + p = ngx_snprintf(p, len, "%s", buf); + + (void) ngx_syslog_send(peer, msg, p - msg); + + peer->busy = 0; +} + + +ssize_t +ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len) +{ + ssize_t n; + + if (peer->conn.fd == (ngx_socket_t) -1) { + if (ngx_syslog_init_peer(peer) != NGX_OK) { + return NGX_ERROR; + } + } + + /* log syslog socket events with valid log */ + peer->conn.log = ngx_cycle->log; + + if (ngx_send) { + n = ngx_send(&peer->conn, buf, len); + + } else { + /* event module has not yet set ngx_io */ + n = ngx_os_io.send(&peer->conn, buf, len); + } + +#if (NGX_HAVE_UNIX_DOMAIN) + + if (n == NGX_ERROR && peer->server.sockaddr->sa_family == AF_UNIX) { + + if (ngx_close_socket(peer->conn.fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } + + peer->conn.fd = (ngx_socket_t) -1; + } + +#endif + + return n; +} + + +static ngx_int_t +ngx_syslog_init_peer(ngx_syslog_peer_t *peer) +{ + ngx_socket_t fd; + ngx_pool_cleanup_t *cln; + + peer->conn.read = &ngx_syslog_dummy_event; + peer->conn.write = &ngx_syslog_dummy_event; + + ngx_syslog_dummy_event.log = &ngx_syslog_dummy_log; + + fd = ngx_socket(peer->server.sockaddr->sa_family, SOCK_DGRAM, 0); + if (fd == (ngx_socket_t) -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_socket_n " failed"); + return NGX_ERROR; + } + + if (ngx_nonblocking(fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_nonblocking_n " failed"); + goto failed; + } + + if (connect(fd, peer->server.sockaddr, peer->server.socklen) == -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + "connect() failed"); + goto failed; + } + + cln = ngx_pool_cleanup_add(peer->pool, 0); + if (cln == NULL) { + goto failed; + } + + cln->data = peer; + cln->handler = ngx_syslog_cleanup; + + peer->conn.fd = fd; + + /* UDP sockets are always ready to write */ + peer->conn.write->ready = 1; + + return NGX_OK; + +failed: + + if (ngx_close_socket(fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } + + return NGX_ERROR; +} + + +static void +ngx_syslog_cleanup(void *data) +{ + ngx_syslog_peer_t *peer = data; + + /* prevents further use of this peer */ + peer->busy = 1; + + if (peer->conn.fd == (ngx_socket_t) -1) { + return; + } + + if (ngx_close_socket(peer->conn.fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } +} diff --git a/src/core/ngx_syslog.h b/src/core/ngx_syslog.h new file mode 100644 index 0000000..a915051 --- /dev/null +++ b/src/core/ngx_syslog.h @@ -0,0 +1,30 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_SYSLOG_H_INCLUDED_ +#define _NGX_SYSLOG_H_INCLUDED_ + + +typedef struct { + ngx_pool_t *pool; + ngx_uint_t facility; + ngx_uint_t severity; + ngx_str_t tag; + + ngx_addr_t server; + ngx_connection_t conn; + ngx_uint_t busy; /* unsigned busy:1; */ +} ngx_syslog_peer_t; + + +char *ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer); +u_char *ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf); +void ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf, + size_t len); +ssize_t ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len); + + +#endif /* _NGX_SYSLOG_H_INCLUDED_ */ diff --git a/src/core/ngx_thread_pool.c b/src/core/ngx_thread_pool.c new file mode 100644 index 0000000..0353085 --- /dev/null +++ b/src/core/ngx_thread_pool.c @@ -0,0 +1,630 @@ + +/* + * Copyright (C) Nginx, Inc. + * Copyright (C) Valentin V. Bartenev + * Copyright (C) Ruslan Ermilov + */ + + +#include +#include +#include + + +typedef struct { + ngx_array_t pools; +} ngx_thread_pool_conf_t; + + +typedef struct { + ngx_thread_task_t *first; + ngx_thread_task_t **last; +} ngx_thread_pool_queue_t; + +#define ngx_thread_pool_queue_init(q) \ + (q)->first = NULL; \ + (q)->last = &(q)->first + + +struct ngx_thread_pool_s { + ngx_thread_mutex_t mtx; + ngx_thread_pool_queue_t queue; + ngx_int_t waiting; + ngx_thread_cond_t cond; + + ngx_log_t *log; + + ngx_str_t name; + ngx_uint_t threads; + ngx_int_t max_queue; + + u_char *file; + ngx_uint_t line; +}; + + +static ngx_int_t ngx_thread_pool_init(ngx_thread_pool_t *tp, ngx_log_t *log, + ngx_pool_t *pool); +static void ngx_thread_pool_destroy(ngx_thread_pool_t *tp); +static void ngx_thread_pool_exit_handler(void *data, ngx_log_t *log); + +static void *ngx_thread_pool_cycle(void *data); +static void ngx_thread_pool_handler(ngx_event_t *ev); + +static char *ngx_thread_pool(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + +static void *ngx_thread_pool_create_conf(ngx_cycle_t *cycle); +static char *ngx_thread_pool_init_conf(ngx_cycle_t *cycle, void *conf); + +static ngx_int_t ngx_thread_pool_init_worker(ngx_cycle_t *cycle); +static void ngx_thread_pool_exit_worker(ngx_cycle_t *cycle); + + +static ngx_command_t ngx_thread_pool_commands[] = { + + { ngx_string("thread_pool"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE23, + ngx_thread_pool, + 0, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_core_module_t ngx_thread_pool_module_ctx = { + ngx_string("thread_pool"), + ngx_thread_pool_create_conf, + ngx_thread_pool_init_conf +}; + + +ngx_module_t ngx_thread_pool_module = { + NGX_MODULE_V1, + &ngx_thread_pool_module_ctx, /* module context */ + ngx_thread_pool_commands, /* module directives */ + NGX_CORE_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + ngx_thread_pool_init_worker, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + ngx_thread_pool_exit_worker, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_str_t ngx_thread_pool_default = ngx_string("default"); + +static ngx_uint_t ngx_thread_pool_task_id; +static ngx_atomic_t ngx_thread_pool_done_lock; +static ngx_thread_pool_queue_t ngx_thread_pool_done; + + +static ngx_int_t +ngx_thread_pool_init(ngx_thread_pool_t *tp, ngx_log_t *log, ngx_pool_t *pool) +{ + int err; + pthread_t tid; + ngx_uint_t n; + pthread_attr_t attr; + + if (ngx_notify == NULL) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "the configured event method cannot be used with thread pools"); + return NGX_ERROR; + } + + ngx_thread_pool_queue_init(&tp->queue); + + if (ngx_thread_mutex_create(&tp->mtx, log) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_thread_cond_create(&tp->cond, log) != NGX_OK) { + (void) ngx_thread_mutex_destroy(&tp->mtx, log); + return NGX_ERROR; + } + + tp->log = log; + + err = pthread_attr_init(&attr); + if (err) { + ngx_log_error(NGX_LOG_ALERT, log, err, + "pthread_attr_init() failed"); + return NGX_ERROR; + } + +#if 0 + err = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); + if (err) { + ngx_log_error(NGX_LOG_ALERT, log, err, + "pthread_attr_setstacksize() failed"); + return NGX_ERROR; + } +#endif + + for (n = 0; n < tp->threads; n++) { + err = pthread_create(&tid, &attr, ngx_thread_pool_cycle, tp); + if (err) { + ngx_log_error(NGX_LOG_ALERT, log, err, + "pthread_create() failed"); + return NGX_ERROR; + } + } + + (void) pthread_attr_destroy(&attr); + + return NGX_OK; +} + + +static void +ngx_thread_pool_destroy(ngx_thread_pool_t *tp) +{ + ngx_uint_t n; + ngx_thread_task_t task; + volatile ngx_uint_t lock; + + ngx_memzero(&task, sizeof(ngx_thread_task_t)); + + task.handler = ngx_thread_pool_exit_handler; + task.ctx = (void *) &lock; + + for (n = 0; n < tp->threads; n++) { + lock = 1; + + if (ngx_thread_task_post(tp, &task) != NGX_OK) { + return; + } + + while (lock) { + ngx_sched_yield(); + } + + task.event.active = 0; + } + + (void) ngx_thread_cond_destroy(&tp->cond, tp->log); + + (void) ngx_thread_mutex_destroy(&tp->mtx, tp->log); +} + + +static void +ngx_thread_pool_exit_handler(void *data, ngx_log_t *log) +{ + ngx_uint_t *lock = data; + + *lock = 0; + + pthread_exit(0); +} + + +ngx_thread_task_t * +ngx_thread_task_alloc(ngx_pool_t *pool, size_t size) +{ + ngx_thread_task_t *task; + + task = ngx_pcalloc(pool, sizeof(ngx_thread_task_t) + size); + if (task == NULL) { + return NULL; + } + + task->ctx = task + 1; + + return task; +} + + +ngx_int_t +ngx_thread_task_post(ngx_thread_pool_t *tp, ngx_thread_task_t *task) +{ + if (task->event.active) { + ngx_log_error(NGX_LOG_ALERT, tp->log, 0, + "task #%ui already active", task->id); + return NGX_ERROR; + } + + if (ngx_thread_mutex_lock(&tp->mtx, tp->log) != NGX_OK) { + return NGX_ERROR; + } + + if (tp->waiting >= tp->max_queue) { + (void) ngx_thread_mutex_unlock(&tp->mtx, tp->log); + + ngx_log_error(NGX_LOG_ERR, tp->log, 0, + "thread pool \"%V\" queue overflow: %i tasks waiting", + &tp->name, tp->waiting); + return NGX_ERROR; + } + + task->event.active = 1; + + task->id = ngx_thread_pool_task_id++; + task->next = NULL; + + if (ngx_thread_cond_signal(&tp->cond, tp->log) != NGX_OK) { + (void) ngx_thread_mutex_unlock(&tp->mtx, tp->log); + return NGX_ERROR; + } + + *tp->queue.last = task; + tp->queue.last = &task->next; + + tp->waiting++; + + (void) ngx_thread_mutex_unlock(&tp->mtx, tp->log); + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, tp->log, 0, + "task #%ui added to thread pool \"%V\"", + task->id, &tp->name); + + return NGX_OK; +} + + +static void * +ngx_thread_pool_cycle(void *data) +{ + ngx_thread_pool_t *tp = data; + + int err; + sigset_t set; + ngx_thread_task_t *task; + +#if 0 + ngx_time_update(); +#endif + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, tp->log, 0, + "thread in pool \"%V\" started", &tp->name); + + sigfillset(&set); + + sigdelset(&set, SIGILL); + sigdelset(&set, SIGFPE); + sigdelset(&set, SIGSEGV); + sigdelset(&set, SIGBUS); + + err = pthread_sigmask(SIG_BLOCK, &set, NULL); + if (err) { + ngx_log_error(NGX_LOG_ALERT, tp->log, err, "pthread_sigmask() failed"); + return NULL; + } + + for ( ;; ) { + if (ngx_thread_mutex_lock(&tp->mtx, tp->log) != NGX_OK) { + return NULL; + } + + /* the number may become negative */ + tp->waiting--; + + while (tp->queue.first == NULL) { + if (ngx_thread_cond_wait(&tp->cond, &tp->mtx, tp->log) + != NGX_OK) + { + (void) ngx_thread_mutex_unlock(&tp->mtx, tp->log); + return NULL; + } + } + + task = tp->queue.first; + tp->queue.first = task->next; + + if (tp->queue.first == NULL) { + tp->queue.last = &tp->queue.first; + } + + if (ngx_thread_mutex_unlock(&tp->mtx, tp->log) != NGX_OK) { + return NULL; + } + +#if 0 + ngx_time_update(); +#endif + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, tp->log, 0, + "run task #%ui in thread pool \"%V\"", + task->id, &tp->name); + + task->handler(task->ctx, tp->log); + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, tp->log, 0, + "complete task #%ui in thread pool \"%V\"", + task->id, &tp->name); + + task->next = NULL; + + ngx_spinlock(&ngx_thread_pool_done_lock, 1, 2048); + + *ngx_thread_pool_done.last = task; + ngx_thread_pool_done.last = &task->next; + + ngx_unlock(&ngx_thread_pool_done_lock); + + (void) ngx_notify(ngx_thread_pool_handler); + } +} + + +static void +ngx_thread_pool_handler(ngx_event_t *ev) +{ + ngx_event_t *event; + ngx_thread_task_t *task; + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "thread pool handler"); + + ngx_spinlock(&ngx_thread_pool_done_lock, 1, 2048); + + task = ngx_thread_pool_done.first; + ngx_thread_pool_done.first = NULL; + ngx_thread_pool_done.last = &ngx_thread_pool_done.first; + + ngx_unlock(&ngx_thread_pool_done_lock); + + while (task) { + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, + "run completion handler for task #%ui", task->id); + + event = &task->event; + task = task->next; + + event->complete = 1; + event->active = 0; + + event->handler(event); + } +} + + +static void * +ngx_thread_pool_create_conf(ngx_cycle_t *cycle) +{ + ngx_thread_pool_conf_t *tcf; + + tcf = ngx_pcalloc(cycle->pool, sizeof(ngx_thread_pool_conf_t)); + if (tcf == NULL) { + return NULL; + } + + if (ngx_array_init(&tcf->pools, cycle->pool, 4, + sizeof(ngx_thread_pool_t *)) + != NGX_OK) + { + return NULL; + } + + return tcf; +} + + +static char * +ngx_thread_pool_init_conf(ngx_cycle_t *cycle, void *conf) +{ + ngx_thread_pool_conf_t *tcf = conf; + + ngx_uint_t i; + ngx_thread_pool_t **tpp; + + tpp = tcf->pools.elts; + + for (i = 0; i < tcf->pools.nelts; i++) { + + if (tpp[i]->threads) { + continue; + } + + if (tpp[i]->name.len == ngx_thread_pool_default.len + && ngx_strncmp(tpp[i]->name.data, ngx_thread_pool_default.data, + ngx_thread_pool_default.len) + == 0) + { + tpp[i]->threads = 32; + tpp[i]->max_queue = 65536; + continue; + } + + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "unknown thread pool \"%V\" in %s:%ui", + &tpp[i]->name, tpp[i]->file, tpp[i]->line); + + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_thread_pool(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t *value; + ngx_uint_t i; + ngx_thread_pool_t *tp; + + value = cf->args->elts; + + tp = ngx_thread_pool_add(cf, &value[1]); + + if (tp == NULL) { + return NGX_CONF_ERROR; + } + + if (tp->threads) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate thread pool \"%V\"", &tp->name); + return NGX_CONF_ERROR; + } + + tp->max_queue = 65536; + + for (i = 2; i < cf->args->nelts; i++) { + + if (ngx_strncmp(value[i].data, "threads=", 8) == 0) { + + tp->threads = ngx_atoi(value[i].data + 8, value[i].len - 8); + + if (tp->threads == (ngx_uint_t) NGX_ERROR || tp->threads == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid threads value \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "max_queue=", 10) == 0) { + + tp->max_queue = ngx_atoi(value[i].data + 10, value[i].len - 10); + + if (tp->max_queue == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid max_queue value \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + continue; + } + } + + if (tp->threads == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"%V\" must have \"threads\" parameter", + &cmd->name); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +ngx_thread_pool_t * +ngx_thread_pool_add(ngx_conf_t *cf, ngx_str_t *name) +{ + ngx_thread_pool_t *tp, **tpp; + ngx_thread_pool_conf_t *tcf; + + if (name == NULL) { + name = &ngx_thread_pool_default; + } + + tp = ngx_thread_pool_get(cf->cycle, name); + + if (tp) { + return tp; + } + + tp = ngx_pcalloc(cf->pool, sizeof(ngx_thread_pool_t)); + if (tp == NULL) { + return NULL; + } + + tp->name = *name; + tp->file = cf->conf_file->file.name.data; + tp->line = cf->conf_file->line; + + tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cf->cycle->conf_ctx, + ngx_thread_pool_module); + + tpp = ngx_array_push(&tcf->pools); + if (tpp == NULL) { + return NULL; + } + + *tpp = tp; + + return tp; +} + + +ngx_thread_pool_t * +ngx_thread_pool_get(ngx_cycle_t *cycle, ngx_str_t *name) +{ + ngx_uint_t i; + ngx_thread_pool_t **tpp; + ngx_thread_pool_conf_t *tcf; + + tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cycle->conf_ctx, + ngx_thread_pool_module); + + tpp = tcf->pools.elts; + + for (i = 0; i < tcf->pools.nelts; i++) { + + if (tpp[i]->name.len == name->len + && ngx_strncmp(tpp[i]->name.data, name->data, name->len) == 0) + { + return tpp[i]; + } + } + + return NULL; +} + + +static ngx_int_t +ngx_thread_pool_init_worker(ngx_cycle_t *cycle) +{ + ngx_uint_t i; + ngx_thread_pool_t **tpp; + ngx_thread_pool_conf_t *tcf; + + if (ngx_process != NGX_PROCESS_WORKER + && ngx_process != NGX_PROCESS_SINGLE) + { + return NGX_OK; + } + + tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cycle->conf_ctx, + ngx_thread_pool_module); + + if (tcf == NULL) { + return NGX_OK; + } + + ngx_thread_pool_queue_init(&ngx_thread_pool_done); + + tpp = tcf->pools.elts; + + for (i = 0; i < tcf->pools.nelts; i++) { + if (ngx_thread_pool_init(tpp[i], cycle->log, cycle->pool) != NGX_OK) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static void +ngx_thread_pool_exit_worker(ngx_cycle_t *cycle) +{ + ngx_uint_t i; + ngx_thread_pool_t **tpp; + ngx_thread_pool_conf_t *tcf; + + if (ngx_process != NGX_PROCESS_WORKER + && ngx_process != NGX_PROCESS_SINGLE) + { + return; + } + + tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cycle->conf_ctx, + ngx_thread_pool_module); + + if (tcf == NULL) { + return; + } + + tpp = tcf->pools.elts; + + for (i = 0; i < tcf->pools.nelts; i++) { + ngx_thread_pool_destroy(tpp[i]); + } +} diff --git a/src/core/ngx_thread_pool.h b/src/core/ngx_thread_pool.h new file mode 100644 index 0000000..5e5adf6 --- /dev/null +++ b/src/core/ngx_thread_pool.h @@ -0,0 +1,36 @@ + +/* + * Copyright (C) Nginx, Inc. + * Copyright (C) Valentin V. Bartenev + */ + + +#ifndef _NGX_THREAD_POOL_H_INCLUDED_ +#define _NGX_THREAD_POOL_H_INCLUDED_ + + +#include +#include +#include + + +struct ngx_thread_task_s { + ngx_thread_task_t *next; + ngx_uint_t id; + void *ctx; + void (*handler)(void *data, ngx_log_t *log); + ngx_event_t event; +}; + + +typedef struct ngx_thread_pool_s ngx_thread_pool_t; + + +ngx_thread_pool_t *ngx_thread_pool_add(ngx_conf_t *cf, ngx_str_t *name); +ngx_thread_pool_t *ngx_thread_pool_get(ngx_cycle_t *cycle, ngx_str_t *name); + +ngx_thread_task_t *ngx_thread_task_alloc(ngx_pool_t *pool, size_t size); +ngx_int_t ngx_thread_task_post(ngx_thread_pool_t *tp, ngx_thread_task_t *task); + + +#endif /* _NGX_THREAD_POOL_H_INCLUDED_ */ diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c index 77490fa..595c122 100644 --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -29,6 +29,7 @@ volatile ngx_str_t ngx_cached_err_log_time; volatile ngx_str_t ngx_cached_http_time; volatile ngx_str_t ngx_cached_http_log_time; volatile ngx_str_t ngx_cached_http_log_iso8601; +volatile ngx_str_t ngx_cached_syslog_time; #if !(NGX_WIN32) @@ -50,6 +51,8 @@ static u_char cached_http_log_time[NGX_TIME_SLOTS] [sizeof("28/Sep/1970:12:00:00 +0600")]; static u_char cached_http_log_iso8601[NGX_TIME_SLOTS] [sizeof("1970-09-28T12:00:00+06:00")]; +static u_char cached_syslog_time[NGX_TIME_SLOTS] + [sizeof("Sep 28 12:00:00")]; static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; @@ -63,6 +66,7 @@ ngx_time_init(void) ngx_cached_http_time.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1; ngx_cached_http_log_time.len = sizeof("28/Sep/1970:12:00:00 +0600") - 1; ngx_cached_http_log_iso8601.len = sizeof("1970-09-28T12:00:00+06:00") - 1; + ngx_cached_syslog_time.len = sizeof("Sep 28 12:00:00") - 1; ngx_cached_time = &cached_time[0]; @@ -73,7 +77,7 @@ ngx_time_init(void) void ngx_time_update(void) { - u_char *p0, *p1, *p2, *p3; + u_char *p0, *p1, *p2, *p3, *p4; ngx_tm_t tm, gmt; time_t sec; ngx_uint_t msec; @@ -166,6 +170,11 @@ ngx_time_update(void) tp->gmtoff < 0 ? '-' : '+', ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60)); + p4 = &cached_syslog_time[slot][0]; + + (void) ngx_sprintf(p4, "%s %2d %02d:%02d:%02d", + months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday, + tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec); ngx_memory_barrier(); @@ -174,6 +183,7 @@ ngx_time_update(void) ngx_cached_err_log_time.data = p1; ngx_cached_http_log_time.data = p2; ngx_cached_http_log_iso8601.data = p3; + ngx_cached_syslog_time.data = p4; ngx_unlock(&ngx_time_lock); } @@ -184,7 +194,7 @@ ngx_time_update(void) void ngx_time_sigsafe_update(void) { - u_char *p; + u_char *p, *p2; ngx_tm_t tm; time_t sec; ngx_time_t *tp; @@ -224,9 +234,16 @@ ngx_time_sigsafe_update(void) tm.ngx_tm_mday, tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec); + p2 = &cached_syslog_time[slot][0]; + + (void) ngx_sprintf(p2, "%s %2d %02d:%02d:%02d", + months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday, + tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec); + ngx_memory_barrier(); ngx_cached_err_log_time.data = p; + ngx_cached_syslog_time.data = p2; ngx_unlock(&ngx_time_lock); } diff --git a/src/core/ngx_times.h b/src/core/ngx_times.h index c4b26a2..94aedcd 100644 --- a/src/core/ngx_times.h +++ b/src/core/ngx_times.h @@ -40,6 +40,7 @@ extern volatile ngx_str_t ngx_cached_err_log_time; extern volatile ngx_str_t ngx_cached_http_time; extern volatile ngx_str_t ngx_cached_http_log_time; extern volatile ngx_str_t ngx_cached_http_log_iso8601; +extern volatile ngx_str_t ngx_cached_syslog_time; /* * milliseconds elapsed since epoch and truncated to ngx_msec_t, diff --git a/src/event/modules/ngx_aio_module.c b/src/event/modules/ngx_aio_module.c deleted file mode 100644 index c881319..0000000 --- a/src/event/modules/ngx_aio_module.c +++ /dev/null @@ -1,171 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - */ - - -#include -#include -#include - - -extern ngx_event_module_t ngx_kqueue_module_ctx; - - -static ngx_int_t ngx_aio_init(ngx_cycle_t *cycle, ngx_msec_t timer); -static void ngx_aio_done(ngx_cycle_t *cycle); -static ngx_int_t ngx_aio_add_event(ngx_event_t *ev, ngx_int_t event, - ngx_uint_t flags); -static ngx_int_t ngx_aio_del_event(ngx_event_t *ev, ngx_int_t event, - ngx_uint_t flags); -static ngx_int_t ngx_aio_del_connection(ngx_connection_t *c, ngx_uint_t flags); -static ngx_int_t ngx_aio_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, - ngx_uint_t flags); - - -ngx_os_io_t ngx_os_aio = { - ngx_aio_read, - ngx_aio_read_chain, - NULL, - ngx_aio_write, - ngx_aio_write_chain, - 0 -}; - - -static ngx_str_t aio_name = ngx_string("aio"); - -ngx_event_module_t ngx_aio_module_ctx = { - &aio_name, - NULL, /* create configuration */ - NULL, /* init configuration */ - - { - ngx_aio_add_event, /* add an event */ - ngx_aio_del_event, /* delete an event */ - NULL, /* enable an event */ - NULL, /* disable an event */ - NULL, /* add an connection */ - ngx_aio_del_connection, /* delete an connection */ - NULL, /* process the changes */ - ngx_aio_process_events, /* process the events */ - ngx_aio_init, /* init the events */ - ngx_aio_done /* done the events */ - } - -}; - -ngx_module_t ngx_aio_module = { - NGX_MODULE_V1, - &ngx_aio_module_ctx, /* module context */ - NULL, /* module directives */ - NGX_EVENT_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 -}; - - -#if (NGX_HAVE_KQUEUE) - -static ngx_int_t -ngx_aio_init(ngx_cycle_t *cycle, ngx_msec_t timer) -{ - if (ngx_kqueue_module_ctx.actions.init(cycle, timer) == NGX_ERROR) { - return NGX_ERROR; - } - - ngx_io = ngx_os_aio; - - ngx_event_flags = NGX_USE_AIO_EVENT; - ngx_event_actions = ngx_aio_module_ctx.actions; - - - return NGX_OK; -} - - -static void -ngx_aio_done(ngx_cycle_t *cycle) -{ - ngx_kqueue_module_ctx.actions.done(cycle); -} - - -/* the event adding and deleting are needed for the listening sockets */ - -static ngx_int_t -ngx_aio_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) -{ - return ngx_kqueue_module_ctx.actions.add(ev, event, flags); -} - - -static ngx_int_t -ngx_aio_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) -{ - return ngx_kqueue_module_ctx.actions.del(ev, event, flags); -} - - -static ngx_int_t -ngx_aio_del_connection(ngx_connection_t *c, ngx_uint_t flags) -{ - int rc; - - if (c->read->active == 0 && c->write->active == 0) { - return NGX_OK; - } - - if (flags & NGX_CLOSE_EVENT) { - return NGX_OK; - } - - rc = aio_cancel(c->fd, NULL); - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "aio_cancel: %d", rc); - - if (rc == AIO_CANCELED) { - c->read->active = 0; - c->write->active = 0; - return NGX_OK; - } - - if (rc == AIO_ALLDONE) { - c->read->active = 0; - c->write->active = 0; - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "aio_cancel() returned AIO_ALLDONE"); - return NGX_OK; - } - - if (rc == -1) { - ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, - "aio_cancel() failed"); - return NGX_ERROR; - } - - if (rc == AIO_NOTCANCELED) { - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "aio_cancel() returned AIO_NOTCANCELED"); - - return NGX_ERROR; - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_aio_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) -{ - return ngx_kqueue_module_ctx.actions.process_events(cycle, timer, flags); -} - -#endif /* NGX_HAVE_KQUEUE */ diff --git a/src/event/modules/ngx_devpoll_module.c b/src/event/modules/ngx_devpoll_module.c index 0506103..fa8aebd 100644 --- a/src/event/modules/ngx_devpoll_module.c +++ b/src/event/modules/ngx_devpoll_module.c @@ -88,7 +88,7 @@ ngx_event_module_t ngx_devpoll_module_ctx = { ngx_devpoll_del_event, /* disable an event */ NULL, /* add an connection */ NULL, /* delete an connection */ - NULL, /* process the changes */ + NULL, /* trigger a notify */ ngx_devpoll_process_events, /* process the events */ ngx_devpoll_init, /* init the events */ ngx_devpoll_done, /* done the events */ @@ -344,7 +344,8 @@ ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_err_t err; ngx_int_t i; ngx_uint_t level, instance; - ngx_event_t *rev, *wev, **queue; + ngx_event_t *rev, *wev; + ngx_queue_t *queue; ngx_connection_t *c; struct pollfd pfd; struct dvpoll dvp; @@ -404,8 +405,6 @@ ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, return NGX_ERROR; } - ngx_mutex_lock(ngx_posted_events_mutex); - for (i = 0; i < events; i++) { fd = event_list[i].fd; @@ -495,19 +494,13 @@ ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, rev = c->read; if ((revents & POLLIN) && rev->active) { - - if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) { - rev->posted_ready = 1; - - } else { - rev->ready = 1; - } + rev->ready = 1; if (flags & NGX_POST_EVENTS) { - queue = (ngx_event_t **) (rev->accept ? - &ngx_posted_accept_events : &ngx_posted_events); + queue = rev->accept ? &ngx_posted_accept_events + : &ngx_posted_events; - ngx_locked_post_event(rev, queue); + ngx_post_event(rev, queue); } else { instance = rev->instance; @@ -523,16 +516,10 @@ ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, wev = c->write; if ((revents & POLLOUT) && wev->active) { - - if (flags & NGX_POST_THREAD_EVENTS) { - wev->posted_ready = 1; - - } else { - wev->ready = 1; - } + wev->ready = 1; if (flags & NGX_POST_EVENTS) { - ngx_locked_post_event(wev, &ngx_posted_events); + ngx_post_event(wev, &ngx_posted_events); } else { wev->handler(wev); @@ -540,8 +527,6 @@ ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, } } - ngx_mutex_unlock(ngx_posted_events_mutex); - return NGX_OK; } diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c index f5f6631..d7f915d 100644 --- a/src/event/modules/ngx_epoll_module.c +++ b/src/event/modules/ngx_epoll_module.c @@ -70,12 +70,15 @@ int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout) return -1; } +#if (NGX_HAVE_EVENTFD) +#define SYS_eventfd 323 +#endif + #if (NGX_HAVE_FILE_AIO) #define SYS_io_setup 245 #define SYS_io_destroy 246 #define SYS_io_getevents 247 -#define SYS_eventfd 323 typedef u_int aio_context_t; @@ -88,7 +91,7 @@ struct io_event { #endif -#endif +#endif /* NGX_TEST_BUILD_EPOLL */ typedef struct { @@ -98,6 +101,10 @@ typedef struct { static ngx_int_t ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer); +#if (NGX_HAVE_EVENTFD) +static ngx_int_t ngx_epoll_notify_init(ngx_log_t *log); +static void ngx_epoll_notify_handler(ngx_event_t *ev); +#endif static void ngx_epoll_done(ngx_cycle_t *cycle); static ngx_int_t ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); @@ -106,6 +113,9 @@ static ngx_int_t ngx_epoll_del_event(ngx_event_t *ev, ngx_int_t event, static ngx_int_t ngx_epoll_add_connection(ngx_connection_t *c); static ngx_int_t ngx_epoll_del_connection(ngx_connection_t *c, ngx_uint_t flags); +#if (NGX_HAVE_EVENTFD) +static ngx_int_t ngx_epoll_notify(ngx_event_handler_pt handler); +#endif static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags); @@ -120,6 +130,12 @@ static int ep = -1; static struct epoll_event *event_list; static ngx_uint_t nevents; +#if (NGX_HAVE_EVENTFD) +static int notify_fd = -1; +static ngx_event_t notify_event; +static ngx_connection_t notify_conn; +#endif + #if (NGX_HAVE_FILE_AIO) int ngx_eventfd = -1; @@ -164,7 +180,11 @@ ngx_event_module_t ngx_epoll_module_ctx = { ngx_epoll_del_event, /* disable an event */ ngx_epoll_add_connection, /* add an connection */ ngx_epoll_del_connection, /* delete an connection */ - NULL, /* process the changes */ +#if (NGX_HAVE_EVENTFD) + ngx_epoll_notify, /* trigger a notify */ +#else + NULL, /* trigger a notify */ +#endif ngx_epoll_process_events, /* process the events */ ngx_epoll_init, /* init the events */ ngx_epoll_done, /* done the events */ @@ -193,10 +213,6 @@ ngx_module_t ngx_epoll_module = { * We call io_setup(), io_destroy() io_submit(), and io_getevents() directly * as syscalls instead of libaio usage, because the library header file * supports eventfd() since 0.3.107 version only. - * - * Also we do not use eventfd() in glibc, because glibc supports it - * since 2.8 version and glibc maps two syscalls eventfd() and eventfd2() - * into single eventfd() function with different number of parameters. */ static int @@ -227,7 +243,11 @@ ngx_epoll_aio_init(ngx_cycle_t *cycle, ngx_epoll_conf_t *epcf) int n; struct epoll_event ee; +#if (NGX_HAVE_SYS_EVENTFD_H) + ngx_eventfd = eventfd(0, 0); +#else ngx_eventfd = syscall(SYS_eventfd, 0); +#endif if (ngx_eventfd == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, @@ -307,6 +327,12 @@ ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer) return NGX_ERROR; } +#if (NGX_HAVE_EVENTFD) + if (ngx_epoll_notify_init(cycle->log) != NGX_OK) { + ngx_epoll_module_ctx.actions.notify = NULL; + } +#endif + #if (NGX_HAVE_FILE_AIO) ngx_epoll_aio_init(cycle, epcf); @@ -344,6 +370,85 @@ ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer) } +#if (NGX_HAVE_EVENTFD) + +static ngx_int_t +ngx_epoll_notify_init(ngx_log_t *log) +{ + struct epoll_event ee; + +#if (NGX_HAVE_SYS_EVENTFD_H) + notify_fd = eventfd(0, 0); +#else + notify_fd = syscall(SYS_eventfd, 0); +#endif + + if (notify_fd == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "eventfd() failed"); + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, + "notify eventfd: %d", notify_fd); + + notify_event.handler = ngx_epoll_notify_handler; + notify_event.log = log; + notify_event.active = 1; + + notify_conn.fd = notify_fd; + notify_conn.read = ¬ify_event; + notify_conn.log = log; + + ee.events = EPOLLIN|EPOLLET; + ee.data.ptr = ¬ify_conn; + + if (epoll_ctl(ep, EPOLL_CTL_ADD, notify_fd, &ee) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "epoll_ctl(EPOLL_CTL_ADD, eventfd) failed"); + + if (close(notify_fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "eventfd close() failed"); + } + + return NGX_ERROR; + } + + return NGX_OK; +} + + +static void +ngx_epoll_notify_handler(ngx_event_t *ev) +{ + ssize_t n; + uint64_t count; + ngx_err_t err; + ngx_event_handler_pt handler; + + if (++ev->index == NGX_MAX_UINT32_VALUE) { + ev->index = 0; + + n = read(notify_fd, &count, sizeof(uint64_t)); + + err = ngx_errno; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "read() eventfd %d: %z count:%uL", notify_fd, n, count); + + if ((size_t) n != sizeof(uint64_t)) { + ngx_log_error(NGX_LOG_ALERT, ev->log, err, + "read() eventfd %d failed", notify_fd); + } + } + + handler = ev->data; + handler(ev); +} + +#endif + + static void ngx_epoll_done(ngx_cycle_t *cycle) { @@ -354,6 +459,17 @@ ngx_epoll_done(ngx_cycle_t *cycle) ep = -1; +#if (NGX_HAVE_EVENTFD) + + if (close(notify_fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "eventfd close() failed"); + } + + notify_fd = -1; + +#endif + #if (NGX_HAVE_FILE_AIO) if (ngx_eventfd != -1) { @@ -560,6 +676,27 @@ ngx_epoll_del_connection(ngx_connection_t *c, ngx_uint_t flags) } +#if (NGX_HAVE_EVENTFD) + +static ngx_int_t +ngx_epoll_notify(ngx_event_handler_pt handler) +{ + static uint64_t inc = 1; + + notify_event.data = handler; + + if ((size_t) write(notify_fd, &inc, sizeof(uint64_t)) != sizeof(uint64_t)) { + ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno, + "write() to eventfd %d failed", notify_fd); + return NGX_ERROR; + } + + return NGX_OK; +} + +#endif + + static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) { @@ -568,7 +705,8 @@ ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) ngx_int_t instance, i; ngx_uint_t level; ngx_err_t err; - ngx_event_t *rev, *wev, **queue; + ngx_event_t *rev, *wev; + ngx_queue_t *queue; ngx_connection_t *c; /* NGX_TIMER_INFINITE == INFTIM */ @@ -612,8 +750,6 @@ ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) return NGX_ERROR; } - ngx_mutex_lock(ngx_posted_events_mutex); - for (i = 0; i < events; i++) { c = event_list[i].data.ptr; @@ -674,18 +810,13 @@ ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) } #endif - if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) { - rev->posted_ready = 1; - - } else { - rev->ready = 1; - } + rev->ready = 1; if (flags & NGX_POST_EVENTS) { - queue = (ngx_event_t **) (rev->accept ? - &ngx_posted_accept_events : &ngx_posted_events); + queue = rev->accept ? &ngx_posted_accept_events + : &ngx_posted_events; - ngx_locked_post_event(rev, queue); + ngx_post_event(rev, queue); } else { rev->handler(rev); @@ -708,15 +839,10 @@ ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) continue; } - if (flags & NGX_POST_THREAD_EVENTS) { - wev->posted_ready = 1; - - } else { - wev->ready = 1; - } + wev->ready = 1; if (flags & NGX_POST_EVENTS) { - ngx_locked_post_event(wev, &ngx_posted_events); + ngx_post_event(wev, &ngx_posted_events); } else { wev->handler(wev); @@ -724,8 +850,6 @@ ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) } } - ngx_mutex_unlock(ngx_posted_events_mutex); - return NGX_OK; } diff --git a/src/event/modules/ngx_eventport_module.c b/src/event/modules/ngx_eventport_module.c index 5f9cf4e..bacbb05 100644 --- a/src/event/modules/ngx_eventport_module.c +++ b/src/event/modules/ngx_eventport_module.c @@ -93,6 +93,13 @@ int port_getn(int port, port_event_t list[], uint_t max, uint_t *nget, return -1; } +int port_send(int port, int events, void *user); + +int port_send(int port, int events, void *user) +{ + return -1; +} + int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid); @@ -133,6 +140,7 @@ static ngx_int_t ngx_eventport_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); static ngx_int_t ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); +static ngx_int_t ngx_eventport_notify(ngx_event_handler_pt handler); static ngx_int_t ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags); @@ -143,6 +151,7 @@ static int ep = -1; static port_event_t *event_list; static ngx_uint_t nevents; static timer_t event_timer = (timer_t) -1; +static ngx_event_t notify_event; static ngx_str_t eventport_name = ngx_string("eventport"); @@ -172,7 +181,7 @@ ngx_event_module_t ngx_eventport_module_ctx = { ngx_eventport_del_event, /* disable an event */ NULL, /* add an connection */ NULL, /* delete an connection */ - NULL, /* process the changes */ + ngx_eventport_notify, /* trigger a notify */ ngx_eventport_process_events, /* process the events */ ngx_eventport_init, /* init the events */ ngx_eventport_done, /* done the events */ @@ -214,6 +223,9 @@ ngx_eventport_init(ngx_cycle_t *cycle, ngx_msec_t timer) "port_create() failed"); return NGX_ERROR; } + + notify_event.active = 1; + notify_event.log = cycle->log; } if (nevents < epcf->events) { @@ -405,6 +417,21 @@ ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) } +static ngx_int_t +ngx_eventport_notify(ngx_event_handler_pt handler) +{ + notify_event.handler = handler; + + if (port_send(ep, 0, ¬ify_event) != 0) { + ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno, + "port_send() failed"); + return NGX_ERROR; + } + + return NGX_OK; +} + + ngx_int_t ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) @@ -414,7 +441,8 @@ ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_err_t err; ngx_int_t instance; ngx_uint_t i, level; - ngx_event_t *ev, *rev, *wev, **queue; + ngx_event_t *ev, *rev, *wev; + ngx_queue_t *queue; ngx_connection_t *c; struct timespec ts, *tp; @@ -466,8 +494,6 @@ ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, return NGX_ERROR; } - ngx_mutex_lock(ngx_posted_events_mutex); - for (i = 0; i < events; i++) { if (event_list[i].portev_source == PORT_SOURCE_TIMER) { @@ -534,19 +560,13 @@ ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, wev->active = 0; if (revents & POLLIN) { - - if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) { - rev->posted_ready = 1; - - } else { - rev->ready = 1; - } + rev->ready = 1; if (flags & NGX_POST_EVENTS) { - queue = (ngx_event_t **) (rev->accept ? - &ngx_posted_accept_events : &ngx_posted_events); + queue = rev->accept ? &ngx_posted_accept_events + : &ngx_posted_events; - ngx_locked_post_event(rev, queue); + ngx_post_event(rev, queue); } else { rev->handler(rev); @@ -574,16 +594,10 @@ ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, } if (revents & POLLOUT) { - - if (flags & NGX_POST_THREAD_EVENTS) { - wev->posted_ready = 1; - - } else { - wev->ready = 1; - } + wev->ready = 1; if (flags & NGX_POST_EVENTS) { - ngx_locked_post_event(wev, &ngx_posted_events); + ngx_post_event(wev, &ngx_posted_events); } else { wev->handler(wev); @@ -592,16 +606,20 @@ ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, continue; + case PORT_SOURCE_USER: + + ev->handler(ev); + + continue; + default: ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - "unexpected even_port object %d", + "unexpected eventport object %d", event_list[i].portev_object); continue; } } - ngx_mutex_unlock(ngx_posted_events_mutex); - return NGX_OK; } diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c index 30e456c..5573cb2 100644 --- a/src/event/modules/ngx_kqueue_module.c +++ b/src/event/modules/ngx_kqueue_module.c @@ -17,6 +17,9 @@ typedef struct { static ngx_int_t ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer); +#ifdef EVFILT_USER +static ngx_int_t ngx_kqueue_notify_init(ngx_log_t *log); +#endif static void ngx_kqueue_done(ngx_cycle_t *cycle); static ngx_int_t ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); @@ -24,7 +27,9 @@ static ngx_int_t ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); static ngx_int_t ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter, ngx_uint_t flags); -static ngx_int_t ngx_kqueue_process_changes(ngx_cycle_t *cycle, ngx_uint_t try); +#ifdef EVFILT_USER +static ngx_int_t ngx_kqueue_notify(ngx_event_handler_pt handler); +#endif static ngx_int_t ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags); static ngx_inline void ngx_kqueue_dump_event(ngx_log_t *log, @@ -36,25 +41,16 @@ static char *ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf); int ngx_kqueue = -1; -/* - * The "change_list" should be declared as ngx_thread_volatile. - * However, the use of the change_list is localized in kqueue functions and - * is protected by the mutex so even the "icc -ipo" should not build the code - * with the race condition. Thus we avoid the declaration to make a more - * readable code. - */ - -static struct kevent *change_list, *change_list0, *change_list1; +static struct kevent *change_list; static struct kevent *event_list; static ngx_uint_t max_changes, nchanges, nevents; -#if (NGX_THREADS) -static ngx_mutex_t *list_mutex; -static ngx_mutex_t *kevent_mutex; +#ifdef EVFILT_USER +static ngx_event_t notify_event; +static struct kevent notify_kev; #endif - static ngx_str_t kqueue_name = ngx_string("kqueue"); static ngx_command_t ngx_kqueue_commands[] = { @@ -89,7 +85,11 @@ ngx_event_module_t ngx_kqueue_module_ctx = { ngx_kqueue_del_event, /* disable an event */ NULL, /* add an connection */ NULL, /* delete an connection */ - ngx_kqueue_process_changes, /* process the changes */ +#ifdef EVFILT_USER + ngx_kqueue_notify, /* trigger a notify */ +#else + NULL, /* trigger a notify */ +#endif ngx_kqueue_process_events, /* process the events */ ngx_kqueue_init, /* init the events */ ngx_kqueue_done /* done the events */ @@ -133,18 +133,10 @@ ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer) return NGX_ERROR; } -#if (NGX_THREADS) - - list_mutex = ngx_mutex_init(cycle->log, 0); - if (list_mutex == NULL) { +#ifdef EVFILT_USER + if (ngx_kqueue_notify_init(cycle->log) != NGX_OK) { return NGX_ERROR; } - - kevent_mutex = ngx_mutex_init(cycle->log, 0); - if (kevent_mutex == NULL) { - return NGX_ERROR; - } - #endif } @@ -163,27 +155,15 @@ ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer) nchanges = 0; } - if (change_list0) { - ngx_free(change_list0); + if (change_list) { + ngx_free(change_list); } - change_list0 = ngx_alloc(kcf->changes * sizeof(struct kevent), - cycle->log); - if (change_list0 == NULL) { + change_list = ngx_alloc(kcf->changes * sizeof(struct kevent), + cycle->log); + if (change_list == NULL) { return NGX_ERROR; } - - if (change_list1) { - ngx_free(change_list1); - } - - change_list1 = ngx_alloc(kcf->changes * sizeof(struct kevent), - cycle->log); - if (change_list1 == NULL) { - return NGX_ERROR; - } - - change_list = change_list0; } max_changes = kcf->changes; @@ -247,6 +227,37 @@ ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer) } +#ifdef EVFILT_USER + +static ngx_int_t +ngx_kqueue_notify_init(ngx_log_t *log) +{ + notify_kev.ident = 0; + notify_kev.filter = EVFILT_USER; + notify_kev.data = 0; + notify_kev.flags = EV_ADD|EV_CLEAR; + notify_kev.fflags = 0; + notify_kev.udata = 0; + + if (kevent(ngx_kqueue, ¬ify_kev, 1, NULL, 0, NULL) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "kevent(EVFILT_USER, EV_ADD) failed"); + return NGX_ERROR; + } + + notify_event.active = 1; + notify_event.log = log; + + notify_kev.flags = 0; + notify_kev.fflags = NOTE_TRIGGER; + notify_kev.udata = NGX_KQUEUE_UDATA_T ((uintptr_t) ¬ify_event); + + return NGX_OK; +} + +#endif + + static void ngx_kqueue_done(ngx_cycle_t *cycle) { @@ -257,17 +268,9 @@ ngx_kqueue_done(ngx_cycle_t *cycle) ngx_kqueue = -1; -#if (NGX_THREADS) - ngx_mutex_destroy(kevent_mutex); - ngx_mutex_destroy(list_mutex); -#endif - - ngx_free(change_list1); - ngx_free(change_list0); + ngx_free(change_list); ngx_free(event_list); - change_list1 = NULL; - change_list0 = NULL; change_list = NULL; event_list = NULL; max_changes = 0; @@ -289,8 +292,6 @@ ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) ev->disabled = 0; ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0; - ngx_mutex_lock(list_mutex); - #if 0 if (ev->index < nchanges @@ -315,8 +316,6 @@ ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) e->index = ev->index; } - ngx_mutex_unlock(list_mutex); - return NGX_OK; } @@ -325,8 +324,6 @@ ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) ngx_log_error(NGX_LOG_ALERT, ev->log, 0, "previous event on #%d were not passed in kernel", c->fd); - ngx_mutex_unlock(list_mutex); - return NGX_ERROR; } @@ -334,8 +331,6 @@ ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) rc = ngx_kqueue_set_event(ev, event, EV_ADD|EV_ENABLE|flags); - ngx_mutex_unlock(list_mutex); - return rc; } @@ -349,8 +344,6 @@ ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) ev->active = 0; ev->disabled = 0; - ngx_mutex_lock(list_mutex); - if (ev->index < nchanges && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1) == (uintptr_t) ev) @@ -370,8 +363,6 @@ ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) e->index = ev->index; } - ngx_mutex_unlock(list_mutex); - return NGX_OK; } @@ -382,7 +373,6 @@ ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) */ if (flags & NGX_CLOSE_EVENT) { - ngx_mutex_unlock(list_mutex); return NGX_OK; } @@ -395,8 +385,6 @@ ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) rc = ngx_kqueue_set_event(ev, event, flags); - ngx_mutex_unlock(list_mutex); - return rc; } @@ -487,6 +475,25 @@ ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter, ngx_uint_t flags) } +#ifdef EVFILT_USER + +static ngx_int_t +ngx_kqueue_notify(ngx_event_handler_pt handler) +{ + notify_event.handler = handler; + + if (kevent(ngx_kqueue, ¬ify_kev, 1, NULL, 0, NULL) == -1) { + ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno, + "kevent(EVFILT_USER, NOTE_TRIGGER) failed"); + return NGX_ERROR; + } + + return NGX_OK; +} + +#endif + + static ngx_int_t ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) @@ -495,20 +502,12 @@ ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_int_t i, instance; ngx_uint_t level; ngx_err_t err; - ngx_event_t *ev, **queue; + ngx_event_t *ev; + ngx_queue_t *queue; struct timespec ts, *tp; - if (ngx_threaded) { - if (ngx_kqueue_process_changes(cycle, 0) == NGX_ERROR) { - return NGX_ERROR; - } - - n = 0; - - } else { - n = (int) nchanges; - nchanges = 0; - } + n = (int) nchanges; + nchanges = 0; if (timer == NGX_TIMER_INFINITE) { tp = NULL; @@ -573,8 +572,6 @@ ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, return NGX_ERROR; } - ngx_mutex_lock(ngx_posted_events_mutex); - for (i = 0; i < events; i++) { ngx_kqueue_dump_event(cycle->log, &event_list[i]); @@ -626,24 +623,6 @@ ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ev->active = 0; } -#if (NGX_THREADS) - - if ((flags & NGX_POST_THREAD_EVENTS) && !ev->accept) { - ev->posted_ready = 1; - ev->posted_available = event_list[i].data; - - if (event_list[i].flags & EV_EOF) { - ev->posted_eof = 1; - ev->posted_errno = event_list[i].fflags; - } - - ngx_locked_post_event(ev, &ngx_posted_events); - - continue; - } - -#endif - ev->available = event_list[i].data; if (event_list[i].flags & EV_EOF) { @@ -666,6 +645,11 @@ ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, break; +#ifdef EVFILT_USER + case EVFILT_USER: + break; +#endif + default: ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unexpected kevent() filter %d", @@ -674,9 +658,10 @@ ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, } if (flags & NGX_POST_EVENTS) { - queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events: - &ngx_posted_events); - ngx_locked_post_event(ev, queue); + queue = ev->accept ? &ngx_posted_accept_events + : &ngx_posted_events; + + ngx_post_event(ev, queue); continue; } @@ -684,65 +669,10 @@ ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ev->handler(ev); } - ngx_mutex_unlock(ngx_posted_events_mutex); - return NGX_OK; } -static ngx_int_t -ngx_kqueue_process_changes(ngx_cycle_t *cycle, ngx_uint_t try) -{ - int n; - ngx_int_t rc; - ngx_err_t err; - struct timespec ts; - struct kevent *changes; - - ngx_mutex_lock(kevent_mutex); - - ngx_mutex_lock(list_mutex); - - if (nchanges == 0) { - ngx_mutex_unlock(list_mutex); - ngx_mutex_unlock(kevent_mutex); - return NGX_OK; - } - - changes = change_list; - if (change_list == change_list0) { - change_list = change_list1; - } else { - change_list = change_list0; - } - - n = (int) nchanges; - nchanges = 0; - - ngx_mutex_unlock(list_mutex); - - ts.tv_sec = 0; - ts.tv_nsec = 0; - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "kevent changes: %d", n); - - if (kevent(ngx_kqueue, changes, n, NULL, 0, &ts) == -1) { - err = ngx_errno; - ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT, - cycle->log, err, "kevent() failed"); - rc = NGX_ERROR; - - } else { - rc = NGX_OK; - } - - ngx_mutex_unlock(kevent_mutex); - - return rc; -} - - static ngx_inline void ngx_kqueue_dump_event(ngx_log_t *log, struct kevent *kev) { diff --git a/src/event/modules/ngx_poll_module.c b/src/event/modules/ngx_poll_module.c index 4d45218..4370950 100644 --- a/src/event/modules/ngx_poll_module.c +++ b/src/event/modules/ngx_poll_module.c @@ -22,7 +22,7 @@ static char *ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf); static struct pollfd *event_list; -static ngx_int_t nevents; +static ngx_uint_t nevents; static ngx_str_t poll_name = ngx_string("poll"); @@ -39,7 +39,7 @@ ngx_event_module_t ngx_poll_module_ctx = { ngx_poll_del_event, /* disable an event */ NULL, /* add an connection */ NULL, /* delete an connection */ - NULL, /* process the changes */ + NULL, /* trigger a notify */ ngx_poll_process_events, /* process the events */ ngx_poll_init, /* init the events */ ngx_poll_done /* done the events */ @@ -198,7 +198,7 @@ ngx_poll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) if (e == NULL || e->index == NGX_INVALID_INDEX) { nevents--; - if (ev->index < (ngx_uint_t) nevents) { + if (ev->index < nevents) { ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, "index: copy event %ui to %i", nevents, ev->index); @@ -212,11 +212,11 @@ ngx_poll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) "unexpected last event"); } else { - if (c->read->index == (ngx_uint_t) nevents) { + if (c->read->index == nevents) { c->read->index = ev->index; } - if (c->write->index == (ngx_uint_t) nevents) { + if (c->write->index == nevents) { c->write->index = ev->index; } } @@ -240,9 +240,9 @@ ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) { int ready, revents; ngx_err_t err; - ngx_int_t i, nready; - ngx_uint_t found, level; - ngx_event_t *ev, **queue; + ngx_uint_t i, found, level; + ngx_event_t *ev; + ngx_queue_t *queue; ngx_connection_t *c; /* NGX_TIMER_INFINITE == INFTIM */ @@ -251,7 +251,7 @@ ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) { for (i = 0; i < nevents; i++) { ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "poll: %d: fd:%d ev:%04Xd", + "poll: %ui: fd:%d ev:%04Xd", i, event_list[i].fd, event_list[i].events); } } @@ -268,7 +268,7 @@ ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "poll ready %d of %d", ready, nevents); + "poll ready %d of %ui", ready, nevents); if (err) { if (err == NGX_EINTR) { @@ -298,22 +298,18 @@ ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) return NGX_ERROR; } - ngx_mutex_lock(ngx_posted_events_mutex); - - nready = 0; - for (i = 0; i < nevents && ready; i++) { revents = event_list[i].revents; #if 1 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "poll: %d: fd:%d ev:%04Xd rev:%04Xd", + "poll: %ui: fd:%d ev:%04Xd rev:%04Xd", i, event_list[i].fd, event_list[i].events, revents); #else if (revents) { ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "poll: %d: fd:%d ev:%04Xd rev:%04Xd", + "poll: %ui: fd:%d ev:%04Xd rev:%04Xd", i, event_list[i].fd, event_list[i].events, revents); } #endif @@ -375,31 +371,21 @@ ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) found = 1; ev = c->read; + ev->ready = 1; - if ((flags & NGX_POST_THREAD_EVENTS) && !ev->accept) { - ev->posted_ready = 1; + queue = ev->accept ? &ngx_posted_accept_events + : &ngx_posted_events; - } else { - ev->ready = 1; - } - - queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events: - &ngx_posted_events); - ngx_locked_post_event(ev, queue); + ngx_post_event(ev, queue); } if ((revents & POLLOUT) && c->write->active) { found = 1; + ev = c->write; + ev->ready = 1; - if (flags & NGX_POST_THREAD_EVENTS) { - ev->posted_ready = 1; - - } else { - ev->ready = 1; - } - - ngx_locked_post_event(ev, &ngx_posted_events); + ngx_post_event(ev, &ngx_posted_events); } if (found) { @@ -408,13 +394,11 @@ ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) } } - ngx_mutex_unlock(ngx_posted_events_mutex); - if (ready != 0) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "poll ready != events"); } - return nready; + return NGX_OK; } @@ -429,15 +413,5 @@ ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf) return NGX_CONF_OK; } -#if (NGX_THREADS) - - ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, - "poll() is not supported in the threaded mode"); - return NGX_CONF_ERROR; - -#else - return NGX_CONF_OK; - -#endif } diff --git a/src/event/modules/ngx_rtsig_module.c b/src/event/modules/ngx_rtsig_module.c deleted file mode 100644 index b36230c..0000000 --- a/src/event/modules/ngx_rtsig_module.c +++ /dev/null @@ -1,747 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - */ - - -#include -#include -#include - - -#if (NGX_TEST_BUILD_RTSIG) - -#if (NGX_DARWIN) - -#define SIGRTMIN 33 -#define si_fd __pad[0] - -#else - -#ifdef SIGRTMIN -#define si_fd _reason.__spare__.__spare2__[0] -#else -#define SIGRTMIN 33 -#define si_fd __spare__[0] -#endif - -#endif - -#define F_SETSIG 10 -#define KERN_RTSIGNR 30 -#define KERN_RTSIGMAX 31 - -int sigtimedwait(const sigset_t *set, siginfo_t *info, - const struct timespec *timeout); - -int sigtimedwait(const sigset_t *set, siginfo_t *info, - const struct timespec *timeout) -{ - return -1; -} - -int ngx_linux_rtsig_max; - -#endif - - -typedef struct { - ngx_uint_t signo; - ngx_uint_t overflow_events; - ngx_uint_t overflow_test; - ngx_uint_t overflow_threshold; -} ngx_rtsig_conf_t; - - -extern ngx_event_module_t ngx_poll_module_ctx; - -static ngx_int_t ngx_rtsig_init(ngx_cycle_t *cycle, ngx_msec_t timer); -static void ngx_rtsig_done(ngx_cycle_t *cycle); -static ngx_int_t ngx_rtsig_add_connection(ngx_connection_t *c); -static ngx_int_t ngx_rtsig_del_connection(ngx_connection_t *c, - ngx_uint_t flags); -static ngx_int_t ngx_rtsig_process_events(ngx_cycle_t *cycle, - ngx_msec_t timer, ngx_uint_t flags); -static ngx_int_t ngx_rtsig_process_overflow(ngx_cycle_t *cycle, - ngx_msec_t timer, ngx_uint_t flags); - -static void *ngx_rtsig_create_conf(ngx_cycle_t *cycle); -static char *ngx_rtsig_init_conf(ngx_cycle_t *cycle, void *conf); -static char *ngx_check_ngx_overflow_threshold_bounds(ngx_conf_t *cf, - void *post, void *data); - - -static sigset_t set; -static ngx_uint_t overflow, overflow_current; -static struct pollfd *overflow_list; - - -static ngx_str_t rtsig_name = ngx_string("rtsig"); - -static ngx_conf_num_bounds_t ngx_overflow_threshold_bounds = { - ngx_check_ngx_overflow_threshold_bounds, 2, 10 -}; - - -static ngx_command_t ngx_rtsig_commands[] = { - - { ngx_string("rtsig_signo"), - NGX_EVENT_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - 0, - offsetof(ngx_rtsig_conf_t, signo), - NULL }, - - { ngx_string("rtsig_overflow_events"), - NGX_EVENT_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - 0, - offsetof(ngx_rtsig_conf_t, overflow_events), - NULL }, - - { ngx_string("rtsig_overflow_test"), - NGX_EVENT_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - 0, - offsetof(ngx_rtsig_conf_t, overflow_test), - NULL }, - - { ngx_string("rtsig_overflow_threshold"), - NGX_EVENT_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - 0, - offsetof(ngx_rtsig_conf_t, overflow_threshold), - &ngx_overflow_threshold_bounds }, - - ngx_null_command -}; - - -ngx_event_module_t ngx_rtsig_module_ctx = { - &rtsig_name, - ngx_rtsig_create_conf, /* create configuration */ - ngx_rtsig_init_conf, /* init configuration */ - - { - NULL, /* add an event */ - NULL, /* delete an event */ - NULL, /* enable an event */ - NULL, /* disable an event */ - ngx_rtsig_add_connection, /* add an connection */ - ngx_rtsig_del_connection, /* delete an connection */ - NULL, /* process the changes */ - ngx_rtsig_process_events, /* process the events */ - ngx_rtsig_init, /* init the events */ - ngx_rtsig_done, /* done the events */ - } - -}; - -ngx_module_t ngx_rtsig_module = { - NGX_MODULE_V1, - &ngx_rtsig_module_ctx, /* module context */ - ngx_rtsig_commands, /* module directives */ - NGX_EVENT_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_rtsig_init(ngx_cycle_t *cycle, ngx_msec_t timer) -{ - ngx_rtsig_conf_t *rtscf; - - rtscf = ngx_event_get_conf(cycle->conf_ctx, ngx_rtsig_module); - - sigemptyset(&set); - sigaddset(&set, (int) rtscf->signo); - sigaddset(&set, (int) rtscf->signo + 1); - sigaddset(&set, SIGIO); - sigaddset(&set, SIGALRM); - - if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "sigprocmask() failed"); - return NGX_ERROR; - } - - if (overflow_list) { - ngx_free(overflow_list); - } - - overflow_list = ngx_alloc(sizeof(struct pollfd) * rtscf->overflow_events, - cycle->log); - if (overflow_list == NULL) { - return NGX_ERROR; - } - - ngx_io = ngx_os_io; - - ngx_event_actions = ngx_rtsig_module_ctx.actions; - - ngx_event_flags = NGX_USE_RTSIG_EVENT - |NGX_USE_GREEDY_EVENT - |NGX_USE_FD_EVENT; - - return NGX_OK; -} - - -static void -ngx_rtsig_done(ngx_cycle_t *cycle) -{ - ngx_free(overflow_list); - - overflow_list = NULL; -} - - -static ngx_int_t -ngx_rtsig_add_connection(ngx_connection_t *c) -{ - ngx_uint_t signo; - ngx_rtsig_conf_t *rtscf; - - if (c->read->accept && c->read->disabled) { - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "rtsig enable connection: fd:%d", c->fd); - - if (fcntl(c->fd, F_SETOWN, ngx_pid) == -1) { - ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, - "fcntl(F_SETOWN) failed"); - return NGX_ERROR; - } - - c->read->active = 1; - c->read->disabled = 0; - } - - rtscf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_rtsig_module); - - signo = rtscf->signo + c->read->instance; - - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "rtsig add connection: fd:%d signo:%ui", c->fd, signo); - - if (fcntl(c->fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC) == -1) { - ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, - "fcntl(O_RDWR|O_NONBLOCK|O_ASYNC) failed"); - return NGX_ERROR; - } - - if (fcntl(c->fd, F_SETSIG, (int) signo) == -1) { - ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, - "fcntl(F_SETSIG) failed"); - return NGX_ERROR; - } - - if (fcntl(c->fd, F_SETOWN, ngx_pid) == -1) { - ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, - "fcntl(F_SETOWN) failed"); - return NGX_ERROR; - } - -#if (NGX_HAVE_ONESIGFD) - if (fcntl(c->fd, F_SETAUXFL, O_ONESIGFD) == -1) { - ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, - "fcntl(F_SETAUXFL) failed"); - return NGX_ERROR; - } -#endif - - c->read->active = 1; - c->write->active = 1; - - return NGX_OK; -} - - -static ngx_int_t -ngx_rtsig_del_connection(ngx_connection_t *c, ngx_uint_t flags) -{ - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "rtsig del connection: fd:%d", c->fd); - - if ((flags & NGX_DISABLE_EVENT) && c->read->accept) { - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "rtsig disable connection: fd:%d", c->fd); - - c->read->active = 0; - c->read->disabled = 1; - return NGX_OK; - } - - if (flags & NGX_CLOSE_EVENT) { - c->read->active = 0; - c->write->active = 0; - return NGX_OK; - } - - if (fcntl(c->fd, F_SETFL, O_RDWR|O_NONBLOCK) == -1) { - ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, - "fcntl(O_RDWR|O_NONBLOCK) failed"); - return NGX_ERROR; - } - - c->read->active = 0; - c->write->active = 0; - - return NGX_OK; -} - - -static ngx_int_t -ngx_rtsig_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) -{ - int signo; - ngx_int_t instance; - ngx_err_t err; - siginfo_t si; - ngx_event_t *rev, *wev, **queue; - struct timespec ts, *tp; - struct sigaction sa; - ngx_connection_t *c; - ngx_rtsig_conf_t *rtscf; - - if (timer == NGX_TIMER_INFINITE) { - tp = NULL; - - } else { - ts.tv_sec = timer / 1000; - ts.tv_nsec = (timer % 1000) * 1000000; - tp = &ts; - } - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "rtsig timer: %M", timer); - - /* Linux's sigwaitinfo() is sigtimedwait() with the NULL timeout pointer */ - - signo = sigtimedwait(&set, &si, tp); - - if (signo == -1) { - err = ngx_errno; - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, err, - "rtsig signo:%d", signo); - - if (flags & NGX_UPDATE_TIME) { - ngx_time_update(); - } - - if (err == NGX_EAGAIN) { - - /* timeout */ - - if (timer != NGX_TIMER_INFINITE) { - return NGX_AGAIN; - } - - ngx_log_error(NGX_LOG_ALERT, cycle->log, err, - "sigtimedwait() returned EAGAIN without timeout"); - return NGX_ERROR; - } - - ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT, - cycle->log, err, "sigtimedwait() failed"); - return NGX_ERROR; - } - - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "rtsig signo:%d fd:%d band:%04Xd", - signo, si.si_fd, si.si_band); - - if (flags & NGX_UPDATE_TIME) { - ngx_time_update(); - } - - rtscf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_rtsig_module); - - if (signo == (int) rtscf->signo || signo == (int) rtscf->signo + 1) { - - if (overflow && (ngx_uint_t) si.si_fd > overflow_current) { - return NGX_OK; - } - - c = ngx_cycle->files[si.si_fd]; - - if (c == NULL) { - - /* the stale event */ - - return NGX_OK; - } - - instance = signo - (int) rtscf->signo; - - rev = c->read; - - if (rev->instance != instance) { - - /* - * the stale event from a file descriptor - * that was just closed in this iteration - */ - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "rtsig: stale event %p", c); - - return NGX_OK; - } - - if ((si.si_band & (POLLIN|POLLHUP|POLLERR)) && rev->active) { - - rev->ready = 1; - - if (flags & NGX_POST_EVENTS) { - queue = (ngx_event_t **) (rev->accept ? - &ngx_posted_accept_events : &ngx_posted_events); - - ngx_locked_post_event(rev, queue); - - } else { - rev->handler(rev); - } - } - - wev = c->write; - - if ((si.si_band & (POLLOUT|POLLHUP|POLLERR)) && wev->active) { - - wev->ready = 1; - - if (flags & NGX_POST_EVENTS) { - ngx_locked_post_event(wev, &ngx_posted_events); - - } else { - wev->handler(wev); - } - } - - return NGX_OK; - - } else if (signo == SIGALRM) { - - ngx_time_update(); - - return NGX_OK; - - } else if (signo == SIGIO) { - - ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - "rt signal queue overflowed"); - - /* flush the RT signal queue */ - - ngx_memzero(&sa, sizeof(struct sigaction)); - sa.sa_handler = SIG_DFL; - sigemptyset(&sa.sa_mask); - - if (sigaction(rtscf->signo, &sa, NULL) == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, - "sigaction(%d, SIG_DFL) failed", rtscf->signo); - } - - if (sigaction(rtscf->signo + 1, &sa, NULL) == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, - "sigaction(%d, SIG_DFL) failed", rtscf->signo + 1); - } - - overflow = 1; - overflow_current = 0; - ngx_event_actions.process_events = ngx_rtsig_process_overflow; - - return NGX_ERROR; - - } - - ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - "sigtimedwait() returned unexpected signal: %d", signo); - - return NGX_ERROR; -} - - -static ngx_int_t -ngx_rtsig_process_overflow(ngx_cycle_t *cycle, ngx_msec_t timer, - ngx_uint_t flags) -{ - int name[2], rtsig_max, rtsig_nr, events, ready; - size_t len; - ngx_err_t err; - ngx_uint_t tested, n, i; - ngx_event_t *rev, *wev, **queue; - ngx_connection_t *c; - ngx_rtsig_conf_t *rtscf; - - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "rtsig process overflow"); - - rtscf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_rtsig_module); - - tested = 0; - - for ( ;; ) { - - n = 0; - while (n < rtscf->overflow_events) { - - if (overflow_current == cycle->connection_n) { - break; - } - - c = cycle->files[overflow_current++]; - - if (c == NULL || c->fd == -1) { - continue; - } - - events = 0; - - if (c->read->active && c->read->handler) { - events |= POLLIN; - } - - if (c->write->active && c->write->handler) { - events |= POLLOUT; - } - - if (events == 0) { - continue; - } - - overflow_list[n].fd = c->fd; - overflow_list[n].events = events; - overflow_list[n].revents = 0; - n++; - } - - if (n == 0) { - break; - } - - for ( ;; ) { - ready = poll(overflow_list, n, 0); - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "rtsig overflow poll:%d", ready); - - if (ready == -1) { - err = ngx_errno; - ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT, - cycle->log, 0, - "poll() failed while the overflow recover"); - - if (err == NGX_EINTR) { - continue; - } - } - - break; - } - - if (ready <= 0) { - continue; - } - - ngx_mutex_lock(ngx_posted_events_mutex); - - for (i = 0; i < n; i++) { - c = cycle->files[overflow_list[i].fd]; - - if (c == NULL) { - continue; - } - - rev = c->read; - - if (rev->active - && !rev->closed - && rev->handler - && (overflow_list[i].revents - & (POLLIN|POLLERR|POLLHUP|POLLNVAL))) - { - tested++; - - if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) { - rev->posted_ready = 1; - - } else { - rev->ready = 1; - } - - if (flags & NGX_POST_EVENTS) { - queue = (ngx_event_t **) (rev->accept ? - &ngx_posted_accept_events : &ngx_posted_events); - - ngx_locked_post_event(rev, queue); - - } else { - rev->handler(rev); - } - } - - wev = c->write; - - if (wev->active - && !wev->closed - && wev->handler - && (overflow_list[i].revents - & (POLLOUT|POLLERR|POLLHUP|POLLNVAL))) - { - tested++; - - if (flags & NGX_POST_THREAD_EVENTS) { - wev->posted_ready = 1; - - } else { - wev->ready = 1; - } - - if (flags & NGX_POST_EVENTS) { - ngx_locked_post_event(wev, &ngx_posted_events); - - } else { - wev->handler(wev); - } - } - } - - ngx_mutex_unlock(ngx_posted_events_mutex); - - if (tested >= rtscf->overflow_test) { - - if (ngx_linux_rtsig_max) { - - /* - * Check the current rt queue length to prevent - * the new overflow. - * - * learn the "/proc/sys/kernel/rtsig-max" value because - * it can be changed since the last checking - */ - - name[0] = CTL_KERN; - name[1] = KERN_RTSIGMAX; - len = sizeof(rtsig_max); - - if (sysctl(name, 2, &rtsig_max, &len, NULL, 0) == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, errno, - "sysctl(KERN_RTSIGMAX) failed"); - return NGX_ERROR; - } - - /* name[0] = CTL_KERN; */ - name[1] = KERN_RTSIGNR; - len = sizeof(rtsig_nr); - - if (sysctl(name, 2, &rtsig_nr, &len, NULL, 0) == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, errno, - "sysctl(KERN_RTSIGNR) failed"); - return NGX_ERROR; - } - - /* - * drain the rt signal queue if the /"proc/sys/kernel/rtsig-nr" - * is bigger than - * "/proc/sys/kernel/rtsig-max" / "rtsig_overflow_threshold" - */ - - if (rtsig_max / (int) rtscf->overflow_threshold < rtsig_nr) { - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "rtsig queue state: %d/%d", - rtsig_nr, rtsig_max); - while (ngx_rtsig_process_events(cycle, 0, flags) == NGX_OK) - { - /* void */ - } - } - - } else { - - /* - * Linux has not KERN_RTSIGMAX since 2.6.6-mm2 - * so drain the rt signal queue unconditionally - */ - - while (ngx_rtsig_process_events(cycle, 0, flags) == NGX_OK) { - /* void */ - } - } - - tested = 0; - } - } - - if (flags & NGX_UPDATE_TIME) { - ngx_time_update(); - } - - ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - "rt signal queue overflow recovered"); - - overflow = 0; - ngx_event_actions.process_events = ngx_rtsig_process_events; - - return NGX_OK; -} - - -static void * -ngx_rtsig_create_conf(ngx_cycle_t *cycle) -{ - ngx_rtsig_conf_t *rtscf; - - rtscf = ngx_palloc(cycle->pool, sizeof(ngx_rtsig_conf_t)); - if (rtscf == NULL) { - return NULL; - } - - rtscf->signo = NGX_CONF_UNSET; - rtscf->overflow_events = NGX_CONF_UNSET; - rtscf->overflow_test = NGX_CONF_UNSET; - rtscf->overflow_threshold = NGX_CONF_UNSET; - - return rtscf; -} - - -static char * -ngx_rtsig_init_conf(ngx_cycle_t *cycle, void *conf) -{ - ngx_rtsig_conf_t *rtscf = conf; - - /* LinuxThreads use the first 3 RT signals */ - ngx_conf_init_uint_value(rtscf->signo, SIGRTMIN + 10); - - ngx_conf_init_uint_value(rtscf->overflow_events, 16); - ngx_conf_init_uint_value(rtscf->overflow_test, 32); - ngx_conf_init_uint_value(rtscf->overflow_threshold, 10); - - return NGX_CONF_OK; -} - - -static char * -ngx_check_ngx_overflow_threshold_bounds(ngx_conf_t *cf, void *post, void *data) -{ - if (ngx_linux_rtsig_max) { - return ngx_conf_check_num_bounds(cf, post, data); - } - - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "\"rtsig_overflow_threshold\" is not supported " - "since Linux 2.6.6-mm2, ignored"); - - return NGX_CONF_OK; -} diff --git a/src/event/modules/ngx_select_module.c b/src/event/modules/ngx_select_module.c index 5169055..5a976bd 100644 --- a/src/event/modules/ngx_select_module.c +++ b/src/event/modules/ngx_select_module.c @@ -47,7 +47,7 @@ ngx_event_module_t ngx_select_module_ctx = { ngx_select_del_event, /* disable an event */ NULL, /* add an connection */ NULL, /* delete an connection */ - NULL, /* process the changes */ + NULL, /* trigger a notify */ ngx_select_process_events, /* process the events */ ngx_select_init, /* init the events */ ngx_select_done /* done the events */ @@ -214,7 +214,8 @@ ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, int ready, nready; ngx_err_t err; ngx_uint_t i, found; - ngx_event_t *ev, **queue; + ngx_event_t *ev; + ngx_queue_t *queue; struct timeval tv, *tp; ngx_connection_t *c; @@ -227,7 +228,7 @@ ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "change max_fd: %d", max_fd); + "change max_fd: %i", max_fd); } #if (NGX_DEBUG) @@ -240,7 +241,7 @@ ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "max_fd: %d", max_fd); + "max_fd: %i", max_fd); } #endif @@ -305,8 +306,6 @@ ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, return NGX_ERROR; } - ngx_mutex_lock(ngx_posted_events_mutex); - nready = 0; for (i = 0; i < nevents; i++) { @@ -332,16 +331,15 @@ ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, if (found) { ev->ready = 1; - queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events: - &ngx_posted_events); - ngx_locked_post_event(ev, queue); + queue = ev->accept ? &ngx_posted_accept_events + : &ngx_posted_events; + + ngx_post_event(ev, queue); nready++; } } - ngx_mutex_unlock(ngx_posted_events_mutex); - if (ready != nready) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "select ready != events: %d:%d", ready, nready); @@ -421,15 +419,5 @@ ngx_select_init_conf(ngx_cycle_t *cycle, void *conf) return NGX_CONF_ERROR; } -#if (NGX_THREADS) - - ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, - "select() is not supported in the threaded mode"); - return NGX_CONF_ERROR; - -#else - return NGX_CONF_OK; - -#endif } diff --git a/src/event/modules/ngx_win32_select_module.c b/src/event/modules/ngx_win32_select_module.c index eb5382d..c671f83 100644 --- a/src/event/modules/ngx_win32_select_module.c +++ b/src/event/modules/ngx_win32_select_module.c @@ -48,7 +48,7 @@ ngx_event_module_t ngx_select_module_ctx = { ngx_select_del_event, /* disable an event */ NULL, /* add an connection */ NULL, /* delete an connection */ - NULL, /* process the changes */ + NULL, /* trigger a notify */ ngx_select_process_events, /* process the events */ ngx_select_init, /* init the events */ ngx_select_done /* done the events */ @@ -221,7 +221,8 @@ ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, int ready, nready; ngx_err_t err; ngx_uint_t i, found; - ngx_event_t *ev, **queue; + ngx_event_t *ev; + ngx_queue_t *queue; struct timeval tv, *tp; ngx_connection_t *c; @@ -296,8 +297,6 @@ ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, return NGX_ERROR; } - ngx_mutex_lock(ngx_posted_events_mutex); - nready = 0; for (i = 0; i < nevents; i++) { @@ -323,16 +322,15 @@ ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, if (found) { ev->ready = 1; - queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events: - &ngx_posted_events); - ngx_locked_post_event(ev, queue); + queue = ev->accept ? &ngx_posted_accept_events + : &ngx_posted_events; + + ngx_post_event(ev, queue); nready++; } } - ngx_mutex_unlock(ngx_posted_events_mutex); - if (ready != nready) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "select ready != events: %d:%d", ready, nready); diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index e2857f0..34a07e4 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -17,7 +17,6 @@ extern ngx_module_t ngx_kqueue_module; extern ngx_module_t ngx_eventport_module; extern ngx_module_t ngx_devpoll_module; extern ngx_module_t ngx_epoll_module; -extern ngx_module_t ngx_rtsig_module; extern ngx_module_t ngx_select_module; @@ -127,13 +126,6 @@ static ngx_command_t ngx_event_core_commands[] = { 0, NULL }, - { ngx_string("connections"), - NGX_EVENT_CONF|NGX_CONF_TAKE1, - ngx_event_connections, - 0, - 0, - NULL }, - { ngx_string("use"), NGX_EVENT_CONF|NGX_CONF_TAKE1, ngx_event_use, @@ -212,7 +204,9 @@ ngx_process_events_and_timers(ngx_cycle_t *cycle) timer = ngx_event_find_timer(); flags = NGX_UPDATE_TIME; -#if (NGX_THREADS) +#if (NGX_WIN32) + + /* handle signals from master in case of network inactivity */ if (timer == NGX_TIMER_INFINITE || timer > 500) { timer = 500; @@ -252,9 +246,7 @@ ngx_process_events_and_timers(ngx_cycle_t *cycle) ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "timer delta: %M", delta); - if (ngx_posted_accept_events) { - ngx_event_process_posted(cycle, &ngx_posted_accept_events); - } + ngx_event_process_posted(cycle, &ngx_posted_accept_events); if (ngx_accept_mutex_held) { ngx_shmtx_unlock(&ngx_accept_mutex); @@ -264,17 +256,7 @@ ngx_process_events_and_timers(ngx_cycle_t *cycle) ngx_event_expire_timers(); } - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "posted events %p", ngx_posted_events); - - if (ngx_posted_events) { - if (ngx_threaded) { - ngx_wakeup_worker_thread(cycle); - - } else { - ngx_event_process_posted(cycle, &ngx_posted_events); - } - } + ngx_event_process_posted(cycle, &ngx_posted_events); } @@ -340,7 +322,7 @@ ngx_handle_read_event(ngx_event_t *rev, ngx_uint_t flags) } } - /* aio, iocp, rtsig */ + /* iocp */ return NGX_OK; } @@ -419,7 +401,7 @@ ngx_handle_write_event(ngx_event_t *wev, size_t lowat) } } - /* aio, iocp, rtsig */ + /* iocp */ return NGX_OK; } @@ -518,7 +500,7 @@ ngx_event_module_init(ngx_cycle_t *cycle) #endif shm.size = size; - shm.name.len = sizeof("nginx_shared_zone"); + shm.name.len = sizeof("nginx_shared_zone") - 1; shm.name.data = (u_char *) "nginx_shared_zone"; shm.log = cycle->log; @@ -617,12 +599,8 @@ ngx_event_process_init(ngx_cycle_t *cycle) #endif -#if (NGX_THREADS) - ngx_posted_events_mutex = ngx_mutex_init(cycle->log, 0); - if (ngx_posted_events_mutex == NULL) { - return NGX_ERROR; - } -#endif + ngx_queue_init(&ngx_posted_accept_events); + ngx_queue_init(&ngx_posted_events); if (ngx_event_timer_init(cycle->log) == NGX_ERROR) { return NGX_ERROR; @@ -712,10 +690,6 @@ ngx_event_process_init(ngx_cycle_t *cycle) for (i = 0; i < cycle->connection_n; i++) { rev[i].closed = 1; rev[i].instance = 1; -#if (NGX_THREADS) - rev[i].lock = &c[i].lock; - rev[i].own_lock = &c[i].lock; -#endif } cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, @@ -727,10 +701,6 @@ ngx_event_process_init(ngx_cycle_t *cycle) wev = cycle->write_events; for (i = 0; i < cycle->connection_n; i++) { wev[i].closed = 1; -#if (NGX_THREADS) - wev[i].lock = &c[i].lock; - wev[i].own_lock = &c[i].lock; -#endif } i = cycle->connection_n; @@ -745,10 +715,6 @@ ngx_event_process_init(ngx_cycle_t *cycle) c[i].fd = (ngx_socket_t) -1; next = &c[i]; - -#if (NGX_THREADS) - c[i].lock = 0; -#endif } while (i); cycle->free_connections = next; @@ -759,6 +725,12 @@ ngx_event_process_init(ngx_cycle_t *cycle) ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { +#if (NGX_HAVE_REUSEPORT) + if (ls[i].reuseport && ls[i].worker != ngx_worker) { + continue; + } +#endif + c = ngx_get_connection(ls[i].fd, cycle->log); if (c == NULL) { @@ -839,19 +811,17 @@ ngx_event_process_init(ngx_cycle_t *cycle) rev->handler = ngx_event_accept; - if (ngx_use_accept_mutex) { + if (ngx_use_accept_mutex +#if (NGX_HAVE_REUSEPORT) + && !ls[i].reuseport +#endif + ) + { continue; } - if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { - if (ngx_add_conn(c) == NGX_ERROR) { - return NGX_ERROR; - } - - } else { - if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { - return NGX_ERROR; - } + if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { + return NGX_ERROR; } #endif @@ -990,12 +960,6 @@ ngx_event_connections(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return "is duplicate"; } - if (ngx_strcmp(cmd->name.data, "connections") == 0) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "the \"connections\" directive is deprecated, " - "use the \"worker_connections\" directive instead"); - } - value = cf->args->elts; ecf->connections = ngx_atoi(value[1].data, value[1].len); if (ecf->connections == (ngx_uint_t) NGX_ERROR) { @@ -1216,10 +1180,6 @@ ngx_event_core_init_conf(ngx_cycle_t *cycle, void *conf) #if (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL) int fd; -#endif -#if (NGX_HAVE_RTSIG) - ngx_uint_t rtsig; - ngx_core_conf_t *ccf; #endif ngx_int_t i; ngx_module_t *module; @@ -1241,18 +1201,6 @@ ngx_event_core_init_conf(ngx_cycle_t *cycle, void *conf) #endif -#if (NGX_HAVE_RTSIG) - - if (module == NULL) { - module = &ngx_rtsig_module; - rtsig = 1; - - } else { - rtsig = 0; - } - -#endif - #if (NGX_HAVE_DEVPOLL) module = &ngx_devpoll_module; @@ -1309,31 +1257,5 @@ ngx_event_core_init_conf(ngx_cycle_t *cycle, void *conf) ngx_conf_init_value(ecf->accept_mutex, 1); ngx_conf_init_msec_value(ecf->accept_mutex_delay, 500); - -#if (NGX_HAVE_RTSIG) - - if (!rtsig) { - return NGX_CONF_OK; - } - - if (ecf->accept_mutex) { - return NGX_CONF_OK; - } - - ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); - - if (ccf->worker_processes == 0) { - return NGX_CONF_OK; - } - - ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, - "the \"rtsig\" method requires \"accept_mutex\" to be on"); - - return NGX_CONF_ERROR; - -#else - return NGX_CONF_OK; - -#endif } diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index 530c948..855c58d 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -27,14 +27,6 @@ typedef struct { #endif -typedef struct { - ngx_uint_t lock; - - ngx_event_t *events; - ngx_event_t *last; -} ngx_event_mutex_t; - - struct ngx_event_s { void *data; @@ -42,7 +34,7 @@ struct ngx_event_s { unsigned accept:1; - /* used to detect the stale events in kqueue, rtsig, and epoll */ + /* used to detect the stale events in kqueue and epoll */ unsigned instance:1; /* @@ -74,9 +66,15 @@ struct ngx_event_s { /* the pending eof reported by kqueue, epoll or in aio chain operation */ unsigned pending_eof:1; -#if !(NGX_THREADS) - unsigned posted_ready:1; -#endif + unsigned posted:1; + + unsigned closed:1; + + /* to test on worker exit */ + unsigned channel:1; + unsigned resolver:1; + + unsigned cancelable:1; #if (NGX_WIN32) /* setsockopt(SO_UPDATE_ACCEPT_CONTEXT) was successful */ @@ -113,14 +111,8 @@ struct ngx_event_s { ngx_event_handler_pt handler; -#if (NGX_HAVE_AIO) - #if (NGX_HAVE_IOCP) ngx_event_ovlp_t ovlp; -#else - struct aiocb aiocb; -#endif - #endif ngx_uint_t index; @@ -129,40 +121,8 @@ struct ngx_event_s { ngx_rbtree_node_t timer; - unsigned closed:1; - - /* to test on worker exit */ - unsigned channel:1; - unsigned resolver:1; - -#if (NGX_THREADS) - - unsigned locked:1; - - unsigned posted_ready:1; - unsigned posted_timedout:1; - unsigned posted_eof:1; - -#if (NGX_HAVE_KQUEUE) - /* the pending errno reported by kqueue */ - int posted_errno; -#endif - -#if (NGX_HAVE_KQUEUE) || (NGX_HAVE_IOCP) - int posted_available; -#else - unsigned posted_available:1; -#endif - - ngx_atomic_t *lock; - ngx_atomic_t *own_lock; - -#endif - - /* the links of the posted queue */ - ngx_event_t *next; - ngx_event_t **prev; - + /* the posted queue */ + ngx_queue_t queue; #if 0 @@ -193,21 +153,19 @@ struct ngx_event_aio_s { ngx_event_handler_pt handler; ngx_file_t *file; +#if (NGX_HAVE_AIO_SENDFILE) + ssize_t (*preload_handler)(ngx_buf_t *file); +#endif + ngx_fd_t fd; #if (NGX_HAVE_EVENTFD) int64_t res; -#if (NGX_TEST_BUILD_EPOLL) - ngx_err_t err; - size_t nbytes; -#endif -#else - ngx_err_t err; - size_t nbytes; #endif -#if (NGX_HAVE_AIO_SENDFILE) - off_t last_offset; +#if !(NGX_HAVE_EVENTFD) || (NGX_TEST_BUILD_EPOLL) + ngx_err_t err; + size_t nbytes; #endif ngx_aiocb_t aiocb; @@ -227,7 +185,8 @@ typedef struct { ngx_int_t (*add_conn)(ngx_connection_t *c); ngx_int_t (*del_conn)(ngx_connection_t *c, ngx_uint_t flags); - ngx_int_t (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t nowait); + ngx_int_t (*notify)(ngx_event_handler_pt handler); + ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags); @@ -270,7 +229,7 @@ extern ngx_event_actions_t ngx_event_actions; #define NGX_USE_LOWAT_EVENT 0x00000010 /* - * The event filter requires to do i/o operation until EAGAIN: epoll, rtsig. + * The event filter requires to do i/o operation until EAGAIN: epoll. */ #define NGX_USE_GREEDY_EVENT 0x00000020 @@ -280,25 +239,23 @@ extern ngx_event_actions_t ngx_event_actions; #define NGX_USE_EPOLL_EVENT 0x00000040 /* - * No need to add or delete the event filters: rtsig. + * Obsolete. */ #define NGX_USE_RTSIG_EVENT 0x00000080 /* - * No need to add or delete the event filters: overlapped, aio_read, - * aioread, io_submit. + * Obsolete. */ #define NGX_USE_AIO_EVENT 0x00000100 /* * Need to add socket or handle only once: i/o completion port. - * It also requires NGX_HAVE_AIO and NGX_USE_AIO_EVENT to be set. */ #define NGX_USE_IOCP_EVENT 0x00000200 /* * The event filter has no opaque data and requires file descriptors table: - * poll, /dev/poll, rtsig. + * poll, /dev/poll. */ #define NGX_USE_FD_EVENT 0x00000400 @@ -323,7 +280,7 @@ extern ngx_event_actions_t ngx_event_actions; /* * The event filter is deleted just before the closing file. * Has no meaning for select and poll. - * kqueue, epoll, rtsig, eventport: allows to avoid explicit delete, + * kqueue, epoll, eventport: allows to avoid explicit delete, * because filter automatically is deleted * on file close, * @@ -440,7 +397,6 @@ extern ngx_event_actions_t ngx_event_actions; #endif -#define ngx_process_changes ngx_event_actions.process_changes #define ngx_process_events ngx_event_actions.process_events #define ngx_done_events ngx_event_actions.done @@ -449,6 +405,8 @@ extern ngx_event_actions_t ngx_event_actions; #define ngx_add_conn ngx_event_actions.add_conn #define ngx_del_conn ngx_event_actions.del_conn +#define ngx_notify ngx_event_actions.notify + #define ngx_add_timer ngx_event_add_timer #define ngx_del_timer ngx_event_del_timer @@ -519,7 +477,6 @@ extern ngx_atomic_t *ngx_stat_waiting; #define NGX_UPDATE_TIME 1 #define NGX_POST_EVENTS 2 -#define NGX_POST_THREAD_EVENTS 4 extern sig_atomic_t ngx_event_timer_alarm; @@ -559,7 +516,6 @@ ngx_int_t ngx_send_lowat(ngx_connection_t *c, size_t lowat); #include #include -#include #if (NGX_WIN32) #include diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index bf67ece..8888f5a 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -11,7 +11,7 @@ static ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle); -static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle); +static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all); static void ngx_close_accepted_connection(ngx_connection_t *c); @@ -42,10 +42,7 @@ ngx_event_accept(ngx_event_t *ev) ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module); - if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { - ev->available = 1; - - } else if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) { + if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) { ev->available = ecf->multi_accept; } @@ -112,7 +109,7 @@ ngx_event_accept(ngx_event_t *ev) } if (err == NGX_EMFILE || err == NGX_ENFILE) { - if (ngx_disable_accept_events((ngx_cycle_t *) ngx_cycle) + if (ngx_disable_accept_events((ngx_cycle_t *) ngx_cycle, 1) != NGX_OK) { return; @@ -176,10 +173,10 @@ ngx_event_accept(ngx_event_t *ev) return; } - /* set a blocking mode for aio and non-blocking mode for others */ + /* set a blocking mode for iocp and non-blocking mode for others */ if (ngx_inherited_nonblocking) { - if (ngx_event_flags & NGX_USE_AIO_EVENT) { + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { if (ngx_blocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ngx_blocking_n " failed"); @@ -189,7 +186,7 @@ ngx_event_accept(ngx_event_t *ev) } } else { - if (!(ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT))) { + if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) { if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ngx_nonblocking_n " failed"); @@ -232,8 +229,7 @@ ngx_event_accept(ngx_event_t *ev) wev->ready = 1; - if (ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT)) { - /* rtsig, aio, iocp */ + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { rev->ready = 1; } @@ -262,13 +258,6 @@ ngx_event_accept(ngx_event_t *ev) (void) ngx_atomic_fetch_add(ngx_stat_handled, 1); #endif -#if (NGX_THREADS) - rev->lock = &c->lock; - wev->lock = &c->lock; - rev->own_lock = &c->lock; - wev->own_lock = &c->lock; -#endif - if (ls->addr_ntop) { c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len); if (c->addr_text.data == NULL) { @@ -288,9 +277,11 @@ ngx_event_accept(ngx_event_t *ev) #if (NGX_DEBUG) { + ngx_str_t addr; struct sockaddr_in *sin; ngx_cidr_t *cidr; ngx_uint_t i; + u_char text[NGX_SOCKADDR_STRLEN]; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; ngx_uint_t n; @@ -340,12 +331,18 @@ ngx_event_accept(ngx_event_t *ev) continue; } + if (log->log_level & NGX_LOG_DEBUG_EVENT) { + addr.data = text; + addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text, + NGX_SOCKADDR_STRLEN, 1); + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0, + "*%uA accept: %V fd:%d", c->number, &addr, s); + } + } #endif - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0, - "*%uA accept: %V fd:%d", c->number, &c->addr_text, s); - if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) { if (ngx_add_conn(c) == NGX_ERROR) { ngx_close_accepted_connection(c); @@ -374,10 +371,7 @@ ngx_trylock_accept_mutex(ngx_cycle_t *cycle) ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "accept mutex locked"); - if (ngx_accept_mutex_held - && ngx_accept_events == 0 - && !(ngx_event_flags & NGX_USE_RTSIG_EVENT)) - { + if (ngx_accept_mutex_held && ngx_accept_events == 0) { return NGX_OK; } @@ -396,7 +390,7 @@ ngx_trylock_accept_mutex(ngx_cycle_t *cycle) "accept mutex lock failed: %ui", ngx_accept_mutex_held); if (ngx_accept_mutex_held) { - if (ngx_disable_accept_events(cycle) == NGX_ERROR) { + if (ngx_disable_accept_events(cycle, 0) == NGX_ERROR) { return NGX_ERROR; } @@ -419,20 +413,12 @@ ngx_enable_accept_events(ngx_cycle_t *cycle) c = ls[i].connection; - if (c->read->active) { + if (c == NULL || c->read->active) { continue; } - if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { - - if (ngx_add_conn(c) == NGX_ERROR) { - return NGX_ERROR; - } - - } else { - if (ngx_add_event(c->read, NGX_READ_EVENT, 0) == NGX_ERROR) { - return NGX_ERROR; - } + if (ngx_add_event(c->read, NGX_READ_EVENT, 0) == NGX_ERROR) { + return NGX_ERROR; } } @@ -441,7 +427,7 @@ ngx_enable_accept_events(ngx_cycle_t *cycle) static ngx_int_t -ngx_disable_accept_events(ngx_cycle_t *cycle) +ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all) { ngx_uint_t i; ngx_listening_t *ls; @@ -452,21 +438,27 @@ ngx_disable_accept_events(ngx_cycle_t *cycle) c = ls[i].connection; - if (!c->read->active) { + if (c == NULL || !c->read->active) { continue; } - if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { - if (ngx_del_conn(c, NGX_DISABLE_EVENT) == NGX_ERROR) { - return NGX_ERROR; - } +#if (NGX_HAVE_REUSEPORT) - } else { - if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT) - == NGX_ERROR) - { - return NGX_ERROR; - } + /* + * do not disable accept on worker's own sockets + * when disabling accept events due to accept mutex + */ + + if (ls[i].reuseport && !all) { + continue; + } + +#endif + + if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT) + == NGX_ERROR) + { + return NGX_ERROR; } } diff --git a/src/event/ngx_event_busy_lock.c b/src/event/ngx_event_busy_lock.c deleted file mode 100644 index fdac0da..0000000 --- a/src/event/ngx_event_busy_lock.c +++ /dev/null @@ -1,286 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - */ - - -#include -#include -#include - - -static ngx_int_t ngx_event_busy_lock_look_cacheable(ngx_event_busy_lock_t *bl, - ngx_event_busy_lock_ctx_t *ctx); -static void ngx_event_busy_lock_handler(ngx_event_t *ev); -static void ngx_event_busy_lock_posted_handler(ngx_event_t *ev); - - -/* - * NGX_OK: the busy lock is held - * NGX_AGAIN: the all busy locks are held but we will wait the specified time - * NGX_BUSY: ctx->timer == 0: there are many the busy locks - * ctx->timer != 0: there are many the waiting locks - */ - -ngx_int_t -ngx_event_busy_lock(ngx_event_busy_lock_t *bl, ngx_event_busy_lock_ctx_t *ctx) -{ - ngx_int_t rc; - - ngx_mutex_lock(bl->mutex); - - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->event->log, 0, - "event busy lock: b:%d mb:%d", - bl->busy, bl->max_busy); - - if (bl->busy < bl->max_busy) { - bl->busy++; - - rc = NGX_OK; - - } else if (ctx->timer && bl->waiting < bl->max_waiting) { - bl->waiting++; - ngx_add_timer(ctx->event, ctx->timer); - ctx->event->handler = ngx_event_busy_lock_handler; - - if (bl->events) { - bl->last->next = ctx; - - } else { - bl->events = ctx; - } - - bl->last = ctx; - - rc = NGX_AGAIN; - - } else { - rc = NGX_BUSY; - } - - ngx_mutex_unlock(bl->mutex); - - return rc; -} - - -ngx_int_t -ngx_event_busy_lock_cacheable(ngx_event_busy_lock_t *bl, - ngx_event_busy_lock_ctx_t *ctx) -{ - ngx_int_t rc; - - ngx_mutex_lock(bl->mutex); - - rc = ngx_event_busy_lock_look_cacheable(bl, ctx); - - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ctx->event->log, 0, - "event busy lock: %d w:%d mw:%d", - rc, bl->waiting, bl->max_waiting); - - /* - * NGX_OK: no the same request, there is free slot and we locked it - * NGX_BUSY: no the same request and there is no free slot - * NGX_AGAIN: the same request is processing - */ - - if (rc == NGX_AGAIN) { - - if (ctx->timer && bl->waiting < bl->max_waiting) { - bl->waiting++; - ngx_add_timer(ctx->event, ctx->timer); - ctx->event->handler = ngx_event_busy_lock_handler; - - if (bl->events == NULL) { - bl->events = ctx; - } else { - bl->last->next = ctx; - } - bl->last = ctx; - - } else { - rc = NGX_BUSY; - } - } - - ngx_mutex_unlock(bl->mutex); - - return rc; -} - - -void -ngx_event_busy_unlock(ngx_event_busy_lock_t *bl, - ngx_event_busy_lock_ctx_t *ctx) -{ - ngx_event_t *ev; - ngx_event_busy_lock_ctx_t *wakeup; - - ngx_mutex_lock(bl->mutex); - - if (bl->events) { - wakeup = bl->events; - bl->events = bl->events->next; - - } else { - wakeup = NULL; - bl->busy--; - } - - /* - * MP: all ctx's and their queue must be in shared memory, - * each ctx has pid to wake up - */ - - if (wakeup == NULL) { - ngx_mutex_unlock(bl->mutex); - return; - } - - if (ctx->md5) { - for (wakeup = bl->events; wakeup; wakeup = wakeup->next) { - if (wakeup->md5 == NULL || wakeup->slot != ctx->slot) { - continue; - } - - wakeup->handler = ngx_event_busy_lock_posted_handler; - wakeup->cache_updated = 1; - - ev = wakeup->event; - - ngx_post_event(ev, &ngx_posted_events); - } - - ngx_mutex_unlock(bl->mutex); - - } else { - bl->waiting--; - - ngx_mutex_unlock(bl->mutex); - - wakeup->handler = ngx_event_busy_lock_posted_handler; - wakeup->locked = 1; - - ev = wakeup->event; - - if (ev->timer_set) { - ngx_del_timer(ev); - } - - ngx_post_event(ev, &ngx_posted_events); - } -} - - -void -ngx_event_busy_lock_cancel(ngx_event_busy_lock_t *bl, - ngx_event_busy_lock_ctx_t *ctx) -{ - ngx_event_busy_lock_ctx_t *c, *p; - - ngx_mutex_lock(bl->mutex); - - bl->waiting--; - - if (ctx == bl->events) { - bl->events = ctx->next; - - } else { - p = bl->events; - for (c = bl->events->next; c; c = c->next) { - if (c == ctx) { - p->next = ctx->next; - break; - } - p = c; - } - } - - ngx_mutex_unlock(bl->mutex); -} - - -static ngx_int_t -ngx_event_busy_lock_look_cacheable(ngx_event_busy_lock_t *bl, - ngx_event_busy_lock_ctx_t *ctx) -{ - ngx_int_t free; - ngx_uint_t i, bit, cacheable, mask; - - bit = 0; - cacheable = 0; - free = -1; - -#if (NGX_SUPPRESS_WARN) - mask = 0; -#endif - - for (i = 0; i < bl->max_busy; i++) { - - if ((bit & 7) == 0) { - mask = bl->md5_mask[i / 8]; - } - - if (mask & 1) { - if (ngx_memcmp(&bl->md5[i * 16], ctx->md5, 16) == 0) { - ctx->waiting = 1; - ctx->slot = i; - return NGX_AGAIN; - } - cacheable++; - - } else if (free == -1) { - free = i; - } - - if (cacheable == bl->cacheable) { - if (free == -1 && cacheable < bl->max_busy) { - free = i + 1; - } - - break; - } - - mask >>= 1; - bit++; - } - - if (free == -1) { - return NGX_BUSY; - } - -#if 0 - if (bl->busy == bl->max_busy) { - return NGX_BUSY; - } -#endif - - ngx_memcpy(&bl->md5[free * 16], ctx->md5, 16); - bl->md5_mask[free / 8] |= 1 << (free & 7); - ctx->slot = free; - - bl->cacheable++; - bl->busy++; - - return NGX_OK; -} - - -static void -ngx_event_busy_lock_handler(ngx_event_t *ev) -{ - ev->handler = ngx_event_busy_lock_posted_handler; - - ngx_post_event(ev, &ngx_posted_events); -} - - -static void -ngx_event_busy_lock_posted_handler(ngx_event_t *ev) -{ - ngx_event_busy_lock_ctx_t *ctx; - - ctx = ev->data; - ctx->handler(ev); -} diff --git a/src/event/ngx_event_busy_lock.h b/src/event/ngx_event_busy_lock.h deleted file mode 100644 index 254c233..0000000 --- a/src/event/ngx_event_busy_lock.h +++ /dev/null @@ -1,65 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - */ - - -#ifndef _NGX_EVENT_BUSY_LOCK_H_INCLUDED_ -#define _NGX_EVENT_BUSY_LOCK_H_INCLUDED_ - - -#include -#include -#include - -typedef struct ngx_event_busy_lock_ctx_s ngx_event_busy_lock_ctx_t; - -struct ngx_event_busy_lock_ctx_s { - ngx_event_t *event; - ngx_event_handler_pt handler; - void *data; - ngx_msec_t timer; - - unsigned locked:1; - unsigned waiting:1; - unsigned cache_updated:1; - - char *md5; - ngx_int_t slot; - - ngx_event_busy_lock_ctx_t *next; -}; - - -typedef struct { - u_char *md5_mask; - char *md5; - ngx_uint_t cacheable; - - ngx_uint_t busy; - ngx_uint_t max_busy; - - ngx_uint_t waiting; - ngx_uint_t max_waiting; - - ngx_event_busy_lock_ctx_t *events; - ngx_event_busy_lock_ctx_t *last; - -#if (NGX_THREADS) - ngx_mutex_t *mutex; -#endif -} ngx_event_busy_lock_t; - - -ngx_int_t ngx_event_busy_lock(ngx_event_busy_lock_t *bl, - ngx_event_busy_lock_ctx_t *ctx); -ngx_int_t ngx_event_busy_lock_cacheable(ngx_event_busy_lock_t *bl, - ngx_event_busy_lock_ctx_t *ctx); -void ngx_event_busy_unlock(ngx_event_busy_lock_t *bl, - ngx_event_busy_lock_ctx_t *ctx); -void ngx_event_busy_lock_cancel(ngx_event_busy_lock_t *bl, - ngx_event_busy_lock_ctx_t *ctx); - - -#endif /* _NGX_EVENT_BUSY_LOCK_H_INCLUDED_ */ diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c index 5fcabcf..1186958 100644 --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -104,17 +104,6 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc) c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); -#if (NGX_THREADS) - - /* TODO: lock event when call completion handler */ - - rev->lock = pc->lock; - wev->lock = pc->lock; - rev->own_lock = &c->lock; - wev->own_lock = &c->lock; - -#endif - if (ngx_add_conn) { if (ngx_add_conn(c) == NGX_ERROR) { goto failed; @@ -182,13 +171,11 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc) return NGX_OK; } - if (ngx_event_flags & NGX_USE_AIO_EVENT) { + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, ngx_socket_errno, "connect(): %d", rc); - /* aio, iocp */ - if (ngx_blocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_blocking_n " failed"); diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h index 951c24f..ed18db7 100644 --- a/src/event/ngx_event_connect.h +++ b/src/event/ngx_event_connect.h @@ -42,6 +42,7 @@ struct ngx_peer_connection_s { ngx_str_t *name; ngx_uint_t tries; + ngx_msec_t start_time; ngx_event_get_peer_pt get; ngx_event_free_peer_pt free; @@ -52,10 +53,6 @@ struct ngx_peer_connection_s { ngx_event_save_peer_session_pt save_session; #endif -#if (NGX_THREADS) - ngx_atomic_t *lock; -#endif - ngx_addr_t *local; int rcvbuf; diff --git a/src/event/ngx_event_mutex.c b/src/event/ngx_event_mutex.c deleted file mode 100644 index 2bdfd5b..0000000 --- a/src/event/ngx_event_mutex.c +++ /dev/null @@ -1,70 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - */ - - -#include -#include -#include - - -ngx_int_t ngx_event_mutex_timedlock(ngx_event_mutex_t *m, ngx_msec_t timer, - ngx_event_t *ev) -{ - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, - "lock event mutex %p lock:%XD", m, m->lock); - - if (m->lock) { - - if (m->events == NULL) { - m->events = ev; - - } else { - m->last->next = ev; - } - - m->last = ev; - ev->next = NULL; - -#if (NGX_THREADS0) - ev->light = 1; -#endif - - ngx_add_timer(ev, timer); - - return NGX_AGAIN; - } - - m->lock = 1; - - return NGX_OK; -} - - -ngx_int_t ngx_event_mutex_unlock(ngx_event_mutex_t *m, ngx_log_t *log) -{ - ngx_event_t *ev; - - if (m->lock == 0) { - ngx_log_error(NGX_LOG_ALERT, log, 0, - "tring to unlock the free event mutex %p", m); - return NGX_ERROR; - } - - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0, - "unlock event mutex %p, next event: %p", m, m->events); - - m->lock = 0; - - if (m->events) { - ev = m->events; - m->events = ev->next; - - ev->next = (ngx_event_t *) ngx_posted_events; - ngx_posted_events = ev; - } - - return NGX_OK; -} diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 4b33b67..1b789e6 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -10,14 +10,20 @@ #include +#define NGX_SSL_PASSWORD_BUFFER_SIZE 4096 + + typedef struct { ngx_uint_t engine; /* unsigned engine:1; */ } ngx_openssl_conf_t; +static int ngx_ssl_password_callback(char *buf, int size, int rwflag, + void *userdata); static int ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store); static void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret); +static void ngx_ssl_passwords_cleanup(void *data); static void ngx_ssl_handshake_handler(ngx_event_t *ev); static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n); static void ngx_ssl_write_handler(ngx_event_t *wev); @@ -46,6 +52,10 @@ static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, HMAC_CTX *hctx, int enc); #endif +#if (OPENSSL_VERSION_NUMBER < 0x10002002L || defined LIBRESSL_VERSION_NUMBER) +static ngx_int_t ngx_ssl_check_name(ngx_str_t *name, ASN1_STRING *str); +#endif + static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void ngx_openssl_exit(ngx_cycle_t *cycle); @@ -98,7 +108,9 @@ int ngx_ssl_stapling_index; ngx_int_t ngx_ssl_init(ngx_log_t *log) { +#ifndef OPENSSL_IS_BORINGSSL OPENSSL_config(NULL); +#endif SSL_library_init(); SSL_load_error_strings(); @@ -196,27 +208,53 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) /* client side options */ +#ifdef SSL_OP_MICROSOFT_SESS_ID_BUG SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_SESS_ID_BUG); +#endif + +#ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_CHALLENGE_BUG); +#endif /* server side options */ +#ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG); +#endif + +#ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER); +#endif #ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING /* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */ SSL_CTX_set_options(ssl->ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING); #endif +#ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG); - SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG); - SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG); +#endif +#ifdef SSL_OP_TLS_D5_BUG + SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG); +#endif + +#ifdef SSL_OP_TLS_BLOCK_PADDING_BUG + SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG); +#endif + +#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); +#endif SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE); +#ifdef SSL_CTRL_CLEAR_OPTIONS + /* only in 0.9.8m+ */ + SSL_CTX_clear_options(ssl->ctx, + SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1); +#endif + if (!(protocols & NGX_SSL_SSLv2)) { SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv2); } @@ -227,11 +265,13 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1); } #ifdef SSL_OP_NO_TLSv1_1 + SSL_CTX_clear_options(ssl->ctx, SSL_OP_NO_TLSv1_1); if (!(protocols & NGX_SSL_TLSv1_1)) { SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_1); } #endif #ifdef SSL_OP_NO_TLSv1_2 + SSL_CTX_clear_options(ssl->ctx, SSL_OP_NO_TLSv1_2); if (!(protocols & NGX_SSL_TLSv1_2)) { SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_2); } @@ -245,6 +285,10 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) SSL_CTX_set_mode(ssl->ctx, SSL_MODE_RELEASE_BUFFERS); #endif +#ifdef SSL_MODE_NO_AUTO_CHAIN + SSL_CTX_set_mode(ssl->ctx, SSL_MODE_NO_AUTO_CHAIN); +#endif + SSL_CTX_set_read_ahead(ssl->ctx, 1); SSL_CTX_set_info_callback(ssl->ctx, ngx_ssl_info_callback); @@ -255,11 +299,13 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, - ngx_str_t *key) + ngx_str_t *key, ngx_array_t *passwords) { - BIO *bio; - X509 *x509; - u_long n; + BIO *bio; + X509 *x509; + u_long n; + ngx_str_t *pwd; + ngx_uint_t tries; if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) { return NGX_ERROR; @@ -342,23 +388,135 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, BIO_free(bio); + if (ngx_strncmp(key->data, "engine:", sizeof("engine:") - 1) == 0) { + +#ifndef OPENSSL_NO_ENGINE + + u_char *p, *last; + ENGINE *engine; + EVP_PKEY *pkey; + + p = key->data + sizeof("engine:") - 1; + last = (u_char *) ngx_strchr(p, ':'); + + if (last == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid syntax in \"%V\"", key); + return NGX_ERROR; + } + + *last = '\0'; + + engine = ENGINE_by_id((char *) p); + + if (engine == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "ENGINE_by_id(\"%s\") failed", p); + return NGX_ERROR; + } + + *last++ = ':'; + + pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0); + + if (pkey == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "ENGINE_load_private_key(\"%s\") failed", last); + ENGINE_free(engine); + return NGX_ERROR; + } + + ENGINE_free(engine); + + if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_use_PrivateKey(\"%s\") failed", last); + EVP_PKEY_free(pkey); + return NGX_ERROR; + } + + EVP_PKEY_free(pkey); + + return NGX_OK; + +#else + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "loading \"engine:...\" certificate keys " + "is not supported"); + return NGX_ERROR; + +#endif + } + if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) { return NGX_ERROR; } - if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data, - SSL_FILETYPE_PEM) - == 0) - { + if (passwords) { + tries = passwords->nelts; + pwd = passwords->elts; + + SSL_CTX_set_default_passwd_cb(ssl->ctx, ngx_ssl_password_callback); + SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, pwd); + + } else { + tries = 1; +#if (NGX_SUPPRESS_WARN) + pwd = NULL; +#endif + } + + for ( ;; ) { + + if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data, + SSL_FILETYPE_PEM) + != 0) + { + break; + } + + if (--tries) { + ERR_clear_error(); + SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, ++pwd); + continue; + } + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data); return NGX_ERROR; } + SSL_CTX_set_default_passwd_cb(ssl->ctx, NULL); + return NGX_OK; } +static int +ngx_ssl_password_callback(char *buf, int size, int rwflag, void *userdata) +{ + ngx_str_t *pwd = userdata; + + if (rwflag) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "ngx_ssl_password_callback() is called for encryption"); + return 0; + } + + if (pwd->len > (size_t) size) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "password is truncated to %d bytes", size); + } else { + size = pwd->len; + } + + ngx_memcpy(buf, pwd->data, size); + + return size; +} + + ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_int_t depth) @@ -521,7 +679,7 @@ ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, "verify:%d, error:%d, depth:%d, " - "subject:\"%s\",issuer: \"%s\"", + "subject:\"%s\", issuer:\"%s\"", ok, err, depth, subject, issuer); if (sname) { @@ -585,16 +743,164 @@ ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, { static RSA *key; - if (key_length == 512) { - if (key == NULL) { - key = RSA_generate_key(512, RSA_F4, NULL, NULL); - } + if (key_length != 512) { + return NULL; } +#ifndef OPENSSL_NO_DEPRECATED + + if (key == NULL) { + key = RSA_generate_key(512, RSA_F4, NULL, NULL); + } + +#endif + return key; } +ngx_array_t * +ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file) +{ + u_char *p, *last, *end; + size_t len; + ssize_t n; + ngx_fd_t fd; + ngx_str_t *pwd; + ngx_array_t *passwords; + ngx_pool_cleanup_t *cln; + u_char buf[NGX_SSL_PASSWORD_BUFFER_SIZE]; + + if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) { + return NULL; + } + + cln = ngx_pool_cleanup_add(cf->temp_pool, 0); + passwords = ngx_array_create(cf->temp_pool, 4, sizeof(ngx_str_t)); + + if (cln == NULL || passwords == NULL) { + return NULL; + } + + cln->handler = ngx_ssl_passwords_cleanup; + cln->data = passwords; + + fd = ngx_open_file(file->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (fd == NGX_INVALID_FILE) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, + ngx_open_file_n " \"%s\" failed", file->data); + return NULL; + } + + len = 0; + last = buf; + + do { + n = ngx_read_fd(fd, last, NGX_SSL_PASSWORD_BUFFER_SIZE - len); + + if (n == -1) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, + ngx_read_fd_n " \"%s\" failed", file->data); + passwords = NULL; + goto cleanup; + } + + end = last + n; + + if (len && n == 0) { + *end++ = LF; + } + + p = buf; + + for ( ;; ) { + last = ngx_strlchr(last, end, LF); + + if (last == NULL) { + break; + } + + len = last++ - p; + + if (len && p[len - 1] == CR) { + len--; + } + + if (len) { + pwd = ngx_array_push(passwords); + if (pwd == NULL) { + passwords = NULL; + goto cleanup; + } + + pwd->len = len; + pwd->data = ngx_pnalloc(cf->temp_pool, len); + + if (pwd->data == NULL) { + passwords->nelts--; + passwords = NULL; + goto cleanup; + } + + ngx_memcpy(pwd->data, p, len); + } + + p = last; + } + + len = end - p; + + if (len == NGX_SSL_PASSWORD_BUFFER_SIZE) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "too long line in \"%s\"", file->data); + passwords = NULL; + goto cleanup; + } + + ngx_memmove(buf, p, len); + last = buf + len; + + } while (n != 0); + + if (passwords->nelts == 0) { + pwd = ngx_array_push(passwords); + if (pwd == NULL) { + passwords = NULL; + goto cleanup; + } + + ngx_memzero(pwd, sizeof(ngx_str_t)); + } + +cleanup: + + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_conf_log_error(NGX_LOG_ALERT, cf, ngx_errno, + ngx_close_file_n " \"%s\" failed", file->data); + } + + ngx_memzero(buf, NGX_SSL_PASSWORD_BUFFER_SIZE); + + return passwords; +} + + +static void +ngx_ssl_passwords_cleanup(void *data) +{ + ngx_array_t *passwords = data; + + ngx_str_t *pwd; + ngx_uint_t i; + + pwd = passwords->elts; + + for (i = 0; i < passwords->nelts; i++) { + ngx_memzero(pwd[i].data, pwd[i].len); + } +} + + ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) { @@ -852,11 +1158,15 @@ ngx_ssl_handshake(ngx_connection_t *c) c->recv_chain = ngx_ssl_recv_chain; c->send_chain = ngx_ssl_send_chain; +#ifdef SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS + /* initial handshake done, disable renegotiation (CVE-2009-3555) */ if (c->ssl->connection->s3) { c->ssl->connection->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS; } +#endif + return NGX_OK; } @@ -903,8 +1213,8 @@ ngx_ssl_handshake(ngx_connection_t *c) c->read->eof = 1; if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) { - ngx_log_error(NGX_LOG_INFO, c->log, err, - "peer closed connection in SSL handshake"); + ngx_connection_error(c, err, + "peer closed connection in SSL handshake"); return NGX_ERROR; } @@ -941,10 +1251,10 @@ ngx_ssl_handshake_handler(ngx_event_t *ev) ssize_t -ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl) +ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl, off_t limit) { u_char *last; - ssize_t n, bytes; + ssize_t n, bytes, size; ngx_buf_t *b; bytes = 0; @@ -953,8 +1263,19 @@ ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl) last = b->last; for ( ;; ) { + size = b->end - last; - n = ngx_ssl_recv(c, last, b->end - last); + if (limit) { + if (bytes >= limit) { + return bytes; + } + + if (bytes + size > limit) { + size = (ssize_t) (limit - bytes); + } + } + + n = ngx_ssl_recv(c, last, size); if (n > 0) { last += n; @@ -1207,7 +1528,6 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) } in->buf->pos += n; - c->sent += n; if (in->buf->pos == in->buf->last) { in = in->next; @@ -1308,7 +1628,6 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) } buf->pos += n; - c->sent += n; if (n < size) { break; @@ -1366,6 +1685,8 @@ ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size) ngx_post_event(c->read, &ngx_posted_events); } + c->sent += n; + return n; } @@ -1958,9 +2279,10 @@ static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) { int len; - u_char *p, *id, *cached_sess; + u_char *p, *id, *cached_sess, *session_id; uint32_t hash; SSL_CTX *ssl_ctx; + unsigned int session_id_length; ngx_shm_zone_t *shm_zone; ngx_connection_t *c; ngx_slab_pool_t *shpool; @@ -2023,13 +2345,24 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) } } +#if OPENSSL_VERSION_NUMBER >= 0x0090800fL + + session_id = (u_char *) SSL_SESSION_get_id(sess, &session_id_length); + +#else + + session_id = sess->session_id; + session_id_length = sess->session_id_length; + +#endif + #if (NGX_PTR_SIZE == 8) id = sess_id->sess_id; #else - id = ngx_slab_alloc_locked(shpool, sess->session_id_length); + id = ngx_slab_alloc_locked(shpool, session_id_length); if (id == NULL) { @@ -2037,7 +2370,7 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) ngx_ssl_expire_sessions(cache, shpool, 0); - id = ngx_slab_alloc_locked(shpool, sess->session_id_length); + id = ngx_slab_alloc_locked(shpool, session_id_length); if (id == NULL) { goto failed; @@ -2048,16 +2381,16 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) ngx_memcpy(cached_sess, buf, len); - ngx_memcpy(id, sess->session_id, sess->session_id_length); + ngx_memcpy(id, session_id, session_id_length); - hash = ngx_crc32_short(sess->session_id, sess->session_id_length); + hash = ngx_crc32_short(session_id, session_id_length); ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "ssl new session: %08XD:%d:%d", - hash, sess->session_id_length, len); + "ssl new session: %08XD:%ud:%d", + hash, session_id_length, len); sess_id->node.key = hash; - sess_id->node.data = (u_char) sess->session_id_length; + sess_id->node.data = (u_char) session_id_length; sess_id->id = id; sess_id->len = len; sess_id->session = cached_sess; @@ -2205,10 +2538,10 @@ ngx_ssl_remove_cached_session(SSL_CTX *ssl, ngx_ssl_session_t *sess) static void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess) { - size_t len; u_char *id; uint32_t hash; ngx_int_t rc; + unsigned int len; ngx_shm_zone_t *shm_zone; ngx_slab_pool_t *shpool; ngx_rbtree_node_t *node, *sentinel; @@ -2223,13 +2556,21 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess) cache = shm_zone->data; +#if OPENSSL_VERSION_NUMBER >= 0x0090800fL + + id = (u_char *) SSL_SESSION_get_id(sess, &len); + +#else + id = sess->session_id; - len = (size_t) sess->session_id_length; + len = sess->session_id_length; + +#endif hash = ngx_crc32_short(id, len); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, - "ssl remove session: %08XD:%uz", hash, len); + "ssl remove session: %08XD:%ud", hash, len); shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; @@ -2515,7 +2856,7 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, if (enc == 1) { /* encrypt session ticket */ - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "ssl session ticket encrypt, key: \"%*s\" (%s session)", ngx_hex_dump(buf, key[0].name, 16) - buf, buf, SSL_session_reused(ssl_conn) ? "reused" : "new"); @@ -2524,7 +2865,7 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, EVP_EncryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, key[0].aes_key, iv); HMAC_Init_ex(hctx, key[0].hmac_key, 16, ngx_ssl_session_ticket_md(), NULL); - memcpy(name, key[0].name, 16); + ngx_memcpy(name, key[0].name, 16); return 0; @@ -2537,7 +2878,7 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, } } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "ssl session ticket decrypt, key: \"%*s\" not found", ngx_hex_dump(buf, name, 16) - buf, buf); @@ -2545,7 +2886,7 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, found: - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "ssl session ticket decrypt, key: \"%*s\"%s", ngx_hex_dump(buf, key[i].name, 16) - buf, buf, (i == 0) ? " (default)" : ""); @@ -2583,6 +2924,175 @@ ngx_ssl_cleanup_ctx(void *data) } +ngx_int_t +ngx_ssl_check_host(ngx_connection_t *c, ngx_str_t *name) +{ + X509 *cert; + + cert = SSL_get_peer_certificate(c->ssl->connection); + if (cert == NULL) { + return NGX_ERROR; + } + +#if (OPENSSL_VERSION_NUMBER >= 0x10002002L && !defined LIBRESSL_VERSION_NUMBER) + + /* X509_check_host() is only available in OpenSSL 1.0.2+ */ + + if (name->len == 0) { + goto failed; + } + + if (X509_check_host(cert, (char *) name->data, name->len, 0, NULL) != 1) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "X509_check_host(): no match"); + goto failed; + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "X509_check_host(): match"); + + goto found; + +#else + { + int n, i; + X509_NAME *sname; + ASN1_STRING *str; + X509_NAME_ENTRY *entry; + GENERAL_NAME *altname; + STACK_OF(GENERAL_NAME) *altnames; + + /* + * As per RFC6125 and RFC2818, we check subjectAltName extension, + * and if it's not present - commonName in Subject is checked. + */ + + altnames = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); + + if (altnames) { + n = sk_GENERAL_NAME_num(altnames); + + for (i = 0; i < n; i++) { + altname = sk_GENERAL_NAME_value(altnames, i); + + if (altname->type != GEN_DNS) { + continue; + } + + str = altname->d.dNSName; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL subjectAltName: \"%*s\"", + ASN1_STRING_length(str), ASN1_STRING_data(str)); + + if (ngx_ssl_check_name(name, str) == NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL subjectAltName: match"); + GENERAL_NAMES_free(altnames); + goto found; + } + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL subjectAltName: no match"); + + GENERAL_NAMES_free(altnames); + goto failed; + } + + /* + * If there is no subjectAltName extension, check commonName + * in Subject. While RFC2818 requires to only check "most specific" + * CN, both Apache and OpenSSL check all CNs, and so do we. + */ + + sname = X509_get_subject_name(cert); + + if (sname == NULL) { + goto failed; + } + + i = -1; + for ( ;; ) { + i = X509_NAME_get_index_by_NID(sname, NID_commonName, i); + + if (i < 0) { + break; + } + + entry = X509_NAME_get_entry(sname, i); + str = X509_NAME_ENTRY_get_data(entry); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL commonName: \"%*s\"", + ASN1_STRING_length(str), ASN1_STRING_data(str)); + + if (ngx_ssl_check_name(name, str) == NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL commonName: match"); + goto found; + } + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL commonName: no match"); + } +#endif + +failed: + + X509_free(cert); + return NGX_ERROR; + +found: + + X509_free(cert); + return NGX_OK; +} + + +#if (OPENSSL_VERSION_NUMBER < 0x10002002L || defined LIBRESSL_VERSION_NUMBER) + +static ngx_int_t +ngx_ssl_check_name(ngx_str_t *name, ASN1_STRING *pattern) +{ + u_char *s, *p, *end; + size_t slen, plen; + + s = name->data; + slen = name->len; + + p = ASN1_STRING_data(pattern); + plen = ASN1_STRING_length(pattern); + + if (slen == plen && ngx_strncasecmp(s, p, plen) == 0) { + return NGX_OK; + } + + if (plen > 2 && p[0] == '*' && p[1] == '.') { + plen -= 1; + p += 1; + + end = s + slen; + s = ngx_strlchr(s, end, '.'); + + if (s == NULL) { + return NGX_ERROR; + } + + slen = end - s; + + if (plen == slen && ngx_strncasecmp(s, p, plen) == 0) { + return NGX_OK; + } + } + + return NGX_ERROR; +} + +#endif + + ngx_int_t ngx_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { @@ -2602,9 +3112,9 @@ ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { - int len; - u_char *buf; - SSL_SESSION *sess; + u_char *buf; + SSL_SESSION *sess; + unsigned int len; sess = SSL_get0_session(c->ssl->connection); if (sess == NULL) { @@ -2612,9 +3122,17 @@ ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) return NGX_OK; } +#if OPENSSL_VERSION_NUMBER >= 0x0090800fL + + buf = (u_char *) SSL_SESSION_get_id(sess, &len); + +#else + buf = sess->session_id; len = sess->session_id_length; +#endif + s->len = 2 * len; s->data = ngx_pnalloc(pool, 2 * len); if (s->data == NULL) { @@ -2641,6 +3159,28 @@ ngx_ssl_get_session_reused(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } +ngx_int_t +ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + + const char *servername; + + servername = SSL_get_servername(c->ssl->connection, + TLSEXT_NAMETYPE_host_name); + if (servername) { + s->data = (u_char *) servername; + s->len = ngx_strlen(servername); + return NGX_OK; + } + +#endif + + s->len = 0; + return NGX_OK; +} + + ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { @@ -2858,6 +3398,40 @@ ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } +ngx_int_t +ngx_ssl_get_fingerprint(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + X509 *cert; + unsigned int len; + u_char buf[EVP_MAX_MD_SIZE]; + + s->len = 0; + + cert = SSL_get_peer_certificate(c->ssl->connection); + if (cert == NULL) { + return NGX_OK; + } + + if (!X509_digest(cert, EVP_sha1(), buf, &len)) { + X509_free(cert); + return NGX_ERROR; + } + + s->len = 2 * len; + s->data = ngx_pnalloc(pool, 2 * len); + if (s->data == NULL) { + X509_free(cert); + return NGX_ERROR; + } + + ngx_hex_dump(s->data, buf, len); + + X509_free(cert); + + return NGX_OK; +} + + ngx_int_t ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { @@ -2906,6 +3480,8 @@ ngx_openssl_create_conf(ngx_cycle_t *cycle) static char * ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { +#ifndef OPENSSL_NO_ENGINE + ngx_openssl_conf_t *oscf = conf; ENGINE *engine; @@ -2940,6 +3516,12 @@ ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ENGINE_free(engine); return NGX_CONF_OK; + +#else + + return "is not supported"; + +#endif } @@ -2947,5 +3529,7 @@ static void ngx_openssl_exit(ngx_cycle_t *cycle) { EVP_cleanup(); +#ifndef OPENSSL_NO_ENGINE ENGINE_cleanup(); +#endif } diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index b7f8500..08eff64 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -14,10 +14,21 @@ #include #include +#include #include +#include +#include +#ifndef OPENSSL_NO_ENGINE #include +#endif #include +#ifndef OPENSSL_NO_OCSP #include +#endif +#include +#include +#include +#include #define NGX_SSL_NAME "OpenSSL" @@ -112,7 +123,7 @@ typedef struct { ngx_int_t ngx_ssl_init(ngx_log_t *log); ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data); ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, - ngx_str_t *cert, ngx_str_t *key); + ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords); ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_int_t depth); ngx_int_t ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, @@ -124,6 +135,7 @@ ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_resolver_t *resolver, ngx_msec_t resolver_timeout); RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, int key_length); +ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file); ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file); ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name); ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, @@ -150,6 +162,8 @@ ngx_int_t ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session); || n == X509_V_ERR_CERT_UNTRUSTED \ || n == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE) +ngx_int_t ngx_ssl_check_host(ngx_connection_t *c, ngx_str_t *name); + ngx_int_t ngx_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); @@ -159,6 +173,8 @@ ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_session_reused(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, @@ -169,6 +185,8 @@ ngx_int_t ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_fingerprint(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); @@ -176,7 +194,7 @@ ngx_int_t ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_int_t ngx_ssl_handshake(ngx_connection_t *c); ssize_t ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size); ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size); -ssize_t ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl); +ssize_t ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl, off_t limit); ngx_chain_t *ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); void ngx_ssl_free_buffer(ngx_connection_t *c); diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c index 3a3cc7f..c39598f 100644 --- a/src/event/ngx_event_openssl_stapling.c +++ b/src/event/ngx_event_openssl_stapling.c @@ -11,7 +11,7 @@ #include -#ifdef SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB +#if (!defined OPENSSL_NO_OCSP && defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) typedef struct { @@ -310,6 +310,7 @@ ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl) if (X509_STORE_CTX_init(store_ctx, store, NULL, NULL) == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_STORE_CTX_init() failed"); + X509_STORE_CTX_free(store_ctx); return NGX_ERROR; } @@ -1118,6 +1119,7 @@ ngx_ssl_ocsp_create_request(ngx_ssl_ocsp_ctx_t *ctx) if (OCSP_request_add0_id(ocsp, id) == NULL) { ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0, "OCSP_request_add0_id() failed"); + OCSP_CERTID_free(id); goto failed; } @@ -1195,6 +1197,8 @@ ngx_ssl_ocsp_create_request(ngx_ssl_ocsp_ctx_t *ctx) b->last = p; ctx->request = b; + OCSP_REQUEST_free(ocsp); + return NGX_OK; failed: diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c index eed807d..8ba247f 100644 --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -66,11 +66,13 @@ ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write) return NGX_ABORT; } - if (rev->active && !rev->ready) { - ngx_add_timer(rev, p->read_timeout); + if (!rev->delayed) { + if (rev->active && !rev->ready) { + ngx_add_timer(rev, p->read_timeout); - } else if (rev->timer_set) { - ngx_del_timer(rev); + } else if (rev->timer_set) { + ngx_del_timer(rev); + } } } @@ -99,9 +101,11 @@ ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write) static ngx_int_t ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) { + off_t limit; ssize_t n, size; ngx_int_t rc; ngx_buf_t *b; + ngx_msec_t delay; ngx_chain_t *chain, *cl, *ln; if (p->upstream_eof || p->upstream_error || p->upstream_done) { @@ -169,6 +173,25 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) } #endif + if (p->limit_rate) { + if (p->upstream->read->delayed) { + break; + } + + limit = (off_t) p->limit_rate * (ngx_time() - p->start_sec + 1) + - p->read_length; + + if (limit <= 0) { + p->upstream->read->delayed = 1; + delay = (ngx_msec_t) (- limit * 1000 / p->limit_rate + 1); + ngx_add_timer(p->upstream->read, delay); + break; + } + + } else { + limit = 0; + } + if (p->free_raw_bufs) { /* use the free bufs if they exist */ @@ -270,7 +293,7 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) break; } - n = p->upstream->recv_chain(p->upstream, chain); + n = p->upstream->recv_chain(p->upstream, chain, limit); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe recv chain: %z", n); @@ -301,6 +324,8 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) } } + delay = p->limit_rate ? (ngx_msec_t) n * 1000 / p->limit_rate : 0; + p->read_length += n; cl = chain; p->free_raw_bufs = NULL; @@ -337,6 +362,12 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) ln->next = p->free_raw_bufs; p->free_raw_bufs = cl; } + + if (delay > 0) { + p->upstream->read->delayed = 1; + ngx_add_timer(p->upstream->read, delay); + break; + } } #if (NGX_DEBUG) @@ -345,7 +376,7 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) ngx_log_debug8(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe buf busy s:%d t:%d f:%d " "%p, pos %p, size: %z " - "file: %O, size: %z", + "file: %O, size: %O", (cl->buf->shadow ? 1 : 0), cl->buf->temporary, cl->buf->in_file, cl->buf->start, cl->buf->pos, @@ -358,7 +389,7 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) ngx_log_debug8(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe buf out s:%d t:%d f:%d " "%p, pos %p, size: %z " - "file: %O, size: %z", + "file: %O, size: %O", (cl->buf->shadow ? 1 : 0), cl->buf->temporary, cl->buf->in_file, cl->buf->start, cl->buf->pos, @@ -371,7 +402,7 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) ngx_log_debug8(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe buf in s:%d t:%d f:%d " "%p, pos %p, size: %z " - "file: %O, size: %z", + "file: %O, size: %O", (cl->buf->shadow ? 1 : 0), cl->buf->temporary, cl->buf->in_file, cl->buf->start, cl->buf->pos, @@ -384,7 +415,7 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) ngx_log_debug8(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe buf free s:%d t:%d f:%d " "%p, pos %p, size: %z " - "file: %O, size: %z", + "file: %O, size: %O", (cl->buf->shadow ? 1 : 0), cl->buf->temporary, cl->buf->in_file, cl->buf->start, cl->buf->pos, @@ -439,7 +470,11 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) } } - if (p->cacheable && p->in) { + if (p->cacheable && (p->in || p->buf_to_file)) { + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, + "pipe write chain"); + if (ngx_event_pipe_write_chain_to_temp_file(p) == NGX_ABORT) { return NGX_ABORT; } @@ -515,15 +550,6 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p) p->in = NULL; } - if (p->cacheable && p->buf_to_file) { - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, - "pipe write chain"); - - if (ngx_event_pipe_write_chain_to_temp_file(p) == NGX_ABORT) { - return NGX_ABORT; - } - } - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write downstream done"); diff --git a/src/event/ngx_event_pipe.h b/src/event/ngx_event_pipe.h index f24e6d1..451fc4c 100644 --- a/src/event/ngx_event_pipe.h +++ b/src/event/ngx_event_pipe.h @@ -80,6 +80,9 @@ struct ngx_event_pipe_s { size_t preread_size; ngx_buf_t *buf_to_file; + size_t limit_rate; + time_t start_sec; + ngx_temp_file_t *temp_file; /* STUB */ int num; diff --git a/src/event/ngx_event_posted.c b/src/event/ngx_event_posted.c index e548145..d851f3d 100644 --- a/src/event/ngx_event_posted.c +++ b/src/event/ngx_event_posted.c @@ -10,164 +10,26 @@ #include -ngx_thread_volatile ngx_event_t *ngx_posted_accept_events; -ngx_thread_volatile ngx_event_t *ngx_posted_events; - -#if (NGX_THREADS) -ngx_mutex_t *ngx_posted_events_mutex; -#endif +ngx_queue_t ngx_posted_accept_events; +ngx_queue_t ngx_posted_events; void -ngx_event_process_posted(ngx_cycle_t *cycle, - ngx_thread_volatile ngx_event_t **posted) +ngx_event_process_posted(ngx_cycle_t *cycle, ngx_queue_t *posted) { + ngx_queue_t *q; ngx_event_t *ev; - for ( ;; ) { + while (!ngx_queue_empty(posted)) { - ev = (ngx_event_t *) *posted; + q = ngx_queue_head(posted); + ev = ngx_queue_data(q, ngx_event_t, queue); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "posted event %p", ev); - if (ev == NULL) { - return; - } - ngx_delete_posted_event(ev); ev->handler(ev); } } - - -#if (NGX_THREADS) && !(NGX_WIN32) - -void -ngx_wakeup_worker_thread(ngx_cycle_t *cycle) -{ - ngx_int_t i; -#if 0 - ngx_uint_t busy; - ngx_event_t *ev; - - busy = 1; - - if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) { - return; - } - - for (ev = (ngx_event_t *) ngx_posted_events; ev; ev = ev->next) { - if (*(ev->lock) == 0) { - busy = 0; - break; - } - } - - ngx_mutex_unlock(ngx_posted_events_mutex); - - if (busy) { - return; - } -#endif - - for (i = 0; i < ngx_threads_n; i++) { - if (ngx_threads[i].state == NGX_THREAD_FREE) { - ngx_cond_signal(ngx_threads[i].cv); - return; - } - } -} - - -ngx_int_t -ngx_event_thread_process_posted(ngx_cycle_t *cycle) -{ - ngx_event_t *ev; - - for ( ;; ) { - - ev = (ngx_event_t *) ngx_posted_events; - - for ( ;; ) { - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "posted event %p", ev); - - if (ev == NULL) { - return NGX_OK; - } - - if (ngx_trylock(ev->lock) == 0) { - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "posted event %p is busy", ev); - - ev = ev->next; - continue; - } - - if (ev->lock != ev->own_lock) { - if (*(ev->own_lock)) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - "the own lock of the posted event %p is busy", ev); - ngx_unlock(ev->lock); - ev = ev->next; - continue; - } - *(ev->own_lock) = 1; - } - - ngx_delete_posted_event(ev); - - ev->locked = 1; - - ev->ready |= ev->posted_ready; - ev->timedout |= ev->posted_timedout; - ev->pending_eof |= ev->posted_eof; -#if (NGX_HAVE_KQUEUE) - ev->kq_errno |= ev->posted_errno; -#endif - if (ev->posted_available) { - ev->available = ev->posted_available; - } - - ev->posted_ready = 0; - ev->posted_timedout = 0; - ev->posted_eof = 0; -#if (NGX_HAVE_KQUEUE) - ev->posted_errno = 0; -#endif - ev->posted_available = 0; - - ngx_mutex_unlock(ngx_posted_events_mutex); - - ev->handler(ev); - - ngx_mutex_lock(ngx_posted_events_mutex); - - if (ev->locked) { - ngx_unlock(ev->lock); - - if (ev->lock != ev->own_lock) { - ngx_unlock(ev->own_lock); - } - } - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "posted event %p is done", ev); - - break; - } - } -} - -#else - -void -ngx_wakeup_worker_thread(ngx_cycle_t *cycle) -{ -} - -#endif diff --git a/src/event/ngx_event_posted.h b/src/event/ngx_event_posted.h index abd2e26..145d30f 100644 --- a/src/event/ngx_event_posted.h +++ b/src/event/ngx_event_posted.h @@ -14,62 +14,35 @@ #include -#if (NGX_THREADS) -extern ngx_mutex_t *ngx_posted_events_mutex; -#endif - - -#define ngx_locked_post_event(ev, queue) \ +#define ngx_post_event(ev, q) \ \ - if (ev->prev == NULL) { \ - ev->next = (ngx_event_t *) *queue; \ - ev->prev = (ngx_event_t **) queue; \ - *queue = ev; \ + if (!(ev)->posted) { \ + (ev)->posted = 1; \ + ngx_queue_insert_tail(q, &(ev)->queue); \ \ - if (ev->next) { \ - ev->next->prev = &ev->next; \ - } \ - \ - ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "post event %p", ev); \ + ngx_log_debug1(NGX_LOG_DEBUG_CORE, (ev)->log, 0, "post event %p", ev);\ \ } else { \ - ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, \ + ngx_log_debug1(NGX_LOG_DEBUG_CORE, (ev)->log, 0, \ "update posted event %p", ev); \ } -#define ngx_post_event(ev, queue) \ - \ - ngx_mutex_lock(ngx_posted_events_mutex); \ - ngx_locked_post_event(ev, queue); \ - ngx_mutex_unlock(ngx_posted_events_mutex); - - #define ngx_delete_posted_event(ev) \ \ - *(ev->prev) = ev->next; \ + (ev)->posted = 0; \ + ngx_queue_remove(&(ev)->queue); \ \ - if (ev->next) { \ - ev->next->prev = ev->prev; \ - } \ - \ - ev->prev = NULL; \ - ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, \ + ngx_log_debug1(NGX_LOG_DEBUG_CORE, (ev)->log, 0, \ "delete posted event %p", ev); -void ngx_event_process_posted(ngx_cycle_t *cycle, - ngx_thread_volatile ngx_event_t **posted); -void ngx_wakeup_worker_thread(ngx_cycle_t *cycle); - -#if (NGX_THREADS) -ngx_int_t ngx_event_thread_process_posted(ngx_cycle_t *cycle); -#endif +void ngx_event_process_posted(ngx_cycle_t *cycle, ngx_queue_t *posted); -extern ngx_thread_volatile ngx_event_t *ngx_posted_accept_events; -extern ngx_thread_volatile ngx_event_t *ngx_posted_events; +extern ngx_queue_t ngx_posted_accept_events; +extern ngx_queue_t ngx_posted_events; #endif /* _NGX_EVENT_POSTED_H_INCLUDED_ */ diff --git a/src/event/ngx_event_timer.c b/src/event/ngx_event_timer.c index 177ac1c..8f547b2 100644 --- a/src/event/ngx_event_timer.c +++ b/src/event/ngx_event_timer.c @@ -10,13 +10,8 @@ #include -#if (NGX_THREADS) -ngx_mutex_t *ngx_event_timer_mutex; -#endif - - -ngx_thread_volatile ngx_rbtree_t ngx_event_timer_rbtree; -static ngx_rbtree_node_t ngx_event_timer_sentinel; +ngx_rbtree_t ngx_event_timer_rbtree; +static ngx_rbtree_node_t ngx_event_timer_sentinel; /* * the event timer rbtree may contain the duplicate keys, however, @@ -30,20 +25,6 @@ ngx_event_timer_init(ngx_log_t *log) ngx_rbtree_init(&ngx_event_timer_rbtree, &ngx_event_timer_sentinel, ngx_rbtree_insert_timer_value); -#if (NGX_THREADS) - - if (ngx_event_timer_mutex) { - ngx_event_timer_mutex->log = log; - return NGX_OK; - } - - ngx_event_timer_mutex = ngx_mutex_init(log, 0); - if (ngx_event_timer_mutex == NULL) { - return NGX_ERROR; - } - -#endif - return NGX_OK; } @@ -58,15 +39,11 @@ ngx_event_find_timer(void) return NGX_TIMER_INFINITE; } - ngx_mutex_lock(ngx_event_timer_mutex); - root = ngx_event_timer_rbtree.root; sentinel = ngx_event_timer_rbtree.sentinel; node = ngx_rbtree_min(root, sentinel); - ngx_mutex_unlock(ngx_event_timer_mutex); - timer = (ngx_msec_int_t) (node->key - ngx_current_msec); return (ngx_msec_t) (timer > 0 ? timer : 0); @@ -82,9 +59,6 @@ ngx_event_expire_timers(void) sentinel = ngx_event_timer_rbtree.sentinel; for ( ;; ) { - - ngx_mutex_lock(ngx_event_timer_mutex); - root = ngx_event_timer_rbtree.root; if (root == sentinel) { @@ -93,66 +67,72 @@ ngx_event_expire_timers(void) node = ngx_rbtree_min(root, sentinel); - /* node->key <= ngx_current_time */ + /* node->key > ngx_current_time */ - 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) - - if (ngx_threaded && ngx_trylock(ev->lock) == 0) { - - /* - * We cannot change the timer of the event that is being - * handled by another thread. And we cannot easy walk - * the rbtree to find next expired timer so we exit the loop. - * However, it should be a rare case when the event that is - * being handled has an expired timer. - */ - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, - "event %p is busy in expire timers", ev); - break; - } -#endif - - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, - "event timer del: %d: %M", - ngx_event_ident(ev->data), ev->timer.key); - - ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer); - - ngx_mutex_unlock(ngx_event_timer_mutex); - -#if (NGX_DEBUG) - ev->timer.left = NULL; - ev->timer.right = NULL; - ev->timer.parent = NULL; -#endif - - ev->timer_set = 0; - -#if (NGX_THREADS) - if (ngx_threaded) { - ev->posted_timedout = 1; - - ngx_post_event(ev, &ngx_posted_events); - - ngx_unlock(ev->lock); - - continue; - } -#endif - - ev->timedout = 1; - - ev->handler(ev); - - continue; + if ((ngx_msec_int_t) (node->key - ngx_current_msec) > 0) { + return; } - break; - } + ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer)); - ngx_mutex_unlock(ngx_event_timer_mutex); + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "event timer del: %d: %M", + ngx_event_ident(ev->data), ev->timer.key); + + ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer); + +#if (NGX_DEBUG) + ev->timer.left = NULL; + ev->timer.right = NULL; + ev->timer.parent = NULL; +#endif + + ev->timer_set = 0; + + ev->timedout = 1; + + ev->handler(ev); + } +} + + +void +ngx_event_cancel_timers(void) +{ + ngx_event_t *ev; + ngx_rbtree_node_t *node, *root, *sentinel; + + sentinel = ngx_event_timer_rbtree.sentinel; + + for ( ;; ) { + root = ngx_event_timer_rbtree.root; + + if (root == sentinel) { + return; + } + + node = ngx_rbtree_min(root, sentinel); + + ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer)); + + if (!ev->cancelable) { + return; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "event timer cancel: %d: %M", + ngx_event_ident(ev->data), ev->timer.key); + + ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer); + +#if (NGX_DEBUG) + ev->timer.left = NULL; + ev->timer.right = NULL; + ev->timer.parent = NULL; +#endif + + ev->timer_set = 0; + + ev->handler(ev); + } } diff --git a/src/event/ngx_event_timer.h b/src/event/ngx_event_timer.h index ec9b316..99f8a48 100644 --- a/src/event/ngx_event_timer.h +++ b/src/event/ngx_event_timer.h @@ -22,14 +22,10 @@ ngx_int_t ngx_event_timer_init(ngx_log_t *log); ngx_msec_t ngx_event_find_timer(void); void ngx_event_expire_timers(void); +void ngx_event_cancel_timers(void); -#if (NGX_THREADS) -extern ngx_mutex_t *ngx_event_timer_mutex; -#endif - - -extern ngx_thread_volatile ngx_rbtree_t ngx_event_timer_rbtree; +extern ngx_rbtree_t ngx_event_timer_rbtree; static ngx_inline void @@ -39,12 +35,8 @@ ngx_event_del_timer(ngx_event_t *ev) "event timer del: %d: %M", ngx_event_ident(ev->data), ev->timer.key); - ngx_mutex_lock(ngx_event_timer_mutex); - ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer); - ngx_mutex_unlock(ngx_event_timer_mutex); - #if (NGX_DEBUG) ev->timer.left = NULL; ev->timer.right = NULL; @@ -89,12 +81,8 @@ ngx_event_add_timer(ngx_event_t *ev, ngx_msec_t timer) "event timer add: %d: %M:%M", ngx_event_ident(ev->data), timer, ev->timer.key); - ngx_mutex_lock(ngx_event_timer_mutex); - ngx_rbtree_insert(&ngx_event_timer_rbtree, &ev->timer); - ngx_mutex_unlock(ngx_event_timer_mutex); - ev->timer_set = 1; } diff --git a/src/http/modules/ngx_http_addition_filter_module.c b/src/http/modules/ngx_http_addition_filter_module.c index f598cea..db4970b 100644 --- a/src/http/modules/ngx_http_addition_filter_module.c +++ b/src/http/modules/ngx_http_addition_filter_module.c @@ -121,7 +121,7 @@ ngx_http_addition_header_filter(ngx_http_request_t *r) ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); - ngx_http_clear_etag(r); + ngx_http_weak_etag(r); return ngx_http_next_header_filter(r); } diff --git a/src/http/modules/ngx_http_autoindex_module.c b/src/http/modules/ngx_http_autoindex_module.c index f694df0..b3bf652 100644 --- a/src/http/modules/ngx_http_autoindex_module.c +++ b/src/http/modules/ngx_http_autoindex_module.c @@ -30,6 +30,7 @@ typedef struct { size_t escape_html; unsigned dir:1; + unsigned file:1; time_t mtime; off_t size; @@ -38,26 +39,51 @@ typedef struct { typedef struct { ngx_flag_t enable; + ngx_uint_t format; ngx_flag_t localtime; ngx_flag_t exact_size; } ngx_http_autoindex_loc_conf_t; +#define NGX_HTTP_AUTOINDEX_HTML 0 +#define NGX_HTTP_AUTOINDEX_JSON 1 +#define NGX_HTTP_AUTOINDEX_JSONP 2 +#define NGX_HTTP_AUTOINDEX_XML 3 + #define NGX_HTTP_AUTOINDEX_PREALLOCATE 50 #define NGX_HTTP_AUTOINDEX_NAME_LEN 50 +static ngx_buf_t *ngx_http_autoindex_html(ngx_http_request_t *r, + ngx_array_t *entries); +static ngx_buf_t *ngx_http_autoindex_json(ngx_http_request_t *r, + ngx_array_t *entries, ngx_str_t *callback); +static ngx_int_t ngx_http_autoindex_jsonp_callback(ngx_http_request_t *r, + ngx_str_t *callback); +static ngx_buf_t *ngx_http_autoindex_xml(ngx_http_request_t *r, + ngx_array_t *entries); + static int ngx_libc_cdecl ngx_http_autoindex_cmp_entries(const void *one, const void *two); static ngx_int_t ngx_http_autoindex_error(ngx_http_request_t *r, ngx_dir_t *dir, ngx_str_t *name); + static ngx_int_t ngx_http_autoindex_init(ngx_conf_t *cf); static void *ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); +static ngx_conf_enum_t ngx_http_autoindex_format[] = { + { ngx_string("html"), NGX_HTTP_AUTOINDEX_HTML }, + { ngx_string("json"), NGX_HTTP_AUTOINDEX_JSON }, + { ngx_string("jsonp"), NGX_HTTP_AUTOINDEX_JSONP }, + { ngx_string("xml"), NGX_HTTP_AUTOINDEX_XML }, + { ngx_null_string, 0 } +}; + + static ngx_command_t ngx_http_autoindex_commands[] = { { ngx_string("autoindex"), @@ -67,6 +93,13 @@ static ngx_command_t ngx_http_autoindex_commands[] = { offsetof(ngx_http_autoindex_loc_conf_t, enable), NULL }, + { ngx_string("autoindex_format"), + 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_autoindex_loc_conf_t, format), + &ngx_http_autoindex_format }, + { ngx_string("autoindex_localtime"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -116,47 +149,23 @@ ngx_module_t ngx_http_autoindex_module = { }; -static u_char title[] = -"" CRLF -"Index of " -; - - -static u_char header[] = -"" CRLF -"" CRLF -"

Index of " -; - -static u_char tail[] = -"" CRLF -"" CRLF -; - - static ngx_int_t ngx_http_autoindex_handler(ngx_http_request_t *r) { - u_char *last, *filename, scale; - off_t length; - size_t len, char_len, escape_html, allocated, root; - ngx_tm_t tm; + u_char *last, *filename; + size_t len, allocated, root; ngx_err_t err; ngx_buf_t *b; - ngx_int_t rc, size; - ngx_str_t path; + ngx_int_t rc; + ngx_str_t path, callback; ngx_dir_t dir; - ngx_uint_t i, level, utf8; + ngx_uint_t level, format; ngx_pool_t *pool; - ngx_time_t *tp; ngx_chain_t out; ngx_array_t entries; ngx_http_autoindex_entry_t *entry; ngx_http_autoindex_loc_conf_t *alcf; - static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - if (r->uri.data[r->uri.len - 1] != '/') { return NGX_DECLINED; } @@ -189,6 +198,18 @@ ngx_http_autoindex_handler(ngx_http_request_t *r) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http autoindex: \"%s\"", path.data); + format = alcf->format; + + if (format == NGX_HTTP_AUTOINDEX_JSONP) { + if (ngx_http_autoindex_jsonp_callback(r, &callback) != NGX_OK) { + return NGX_HTTP_BAD_REQUEST; + } + + if (callback.len == 0) { + format = NGX_HTTP_AUTOINDEX_JSON; + } + } + if (ngx_open_dir(&path, &dir) == NGX_ERROR) { err = ngx_errno; @@ -231,8 +252,28 @@ ngx_http_autoindex_handler(ngx_http_request_t *r) } r->headers_out.status = NGX_HTTP_OK; - r->headers_out.content_type_len = sizeof("text/html") - 1; - ngx_str_set(&r->headers_out.content_type, "text/html"); + + switch (format) { + + case NGX_HTTP_AUTOINDEX_JSON: + ngx_str_set(&r->headers_out.content_type, "application/json"); + break; + + case NGX_HTTP_AUTOINDEX_JSONP: + ngx_str_set(&r->headers_out.content_type, "application/javascript"); + break; + + case NGX_HTTP_AUTOINDEX_XML: + ngx_str_set(&r->headers_out.content_type, "text/xml"); + ngx_str_set(&r->headers_out.charset, "utf-8"); + break; + + default: /* NGX_HTTP_AUTOINDEX_HTML */ + ngx_str_set(&r->headers_out.content_type, "text/html"); + break; + } + + r->headers_out.content_type_len = r->headers_out.content_type.len; r->headers_out.content_type_lowcase = NULL; rc = ngx_http_send_header(r); @@ -249,16 +290,6 @@ ngx_http_autoindex_handler(ngx_http_request_t *r) filename = path.data; filename[path.len] = '/'; - if (r->headers_out.charset.len == 5 - && ngx_strncasecmp(r->headers_out.charset.data, (u_char *) "utf-8", 5) - == 0) - { - utf8 = 1; - - } else { - utf8 = 0; - } - for ( ;; ) { ngx_set_errno(0); @@ -339,19 +370,8 @@ ngx_http_autoindex_handler(ngx_http_request_t *r) ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1); - entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len, - NGX_ESCAPE_URI_COMPONENT); - - entry->escape_html = ngx_escape_html(NULL, entry->name.data, - entry->name.len); - - if (utf8) { - entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len); - } else { - entry->utf_len = len; - } - entry->dir = ngx_de_is_dir(&dir); + entry->file = ngx_de_is_file(&dir); entry->mtime = ngx_de_mtime(&dir); entry->size = ngx_de_size(&dir); } @@ -361,6 +381,93 @@ ngx_http_autoindex_handler(ngx_http_request_t *r) ngx_close_dir_n " \"%V\" failed", &path); } + if (entries.nelts > 1) { + ngx_qsort(entries.elts, (size_t) entries.nelts, + sizeof(ngx_http_autoindex_entry_t), + ngx_http_autoindex_cmp_entries); + } + + switch (format) { + + case NGX_HTTP_AUTOINDEX_JSON: + b = ngx_http_autoindex_json(r, &entries, NULL); + break; + + case NGX_HTTP_AUTOINDEX_JSONP: + b = ngx_http_autoindex_json(r, &entries, &callback); + break; + + case NGX_HTTP_AUTOINDEX_XML: + b = ngx_http_autoindex_xml(r, &entries); + break; + + default: /* NGX_HTTP_AUTOINDEX_HTML */ + b = ngx_http_autoindex_html(r, &entries); + break; + } + + if (b == NULL) { + return NGX_ERROR; + } + + /* TODO: free temporary pool */ + + if (r == r->main) { + b->last_buf = 1; + } + + b->last_in_chain = 1; + + out.buf = b; + out.next = NULL; + + return ngx_http_output_filter(r, &out); +} + + +static ngx_buf_t * +ngx_http_autoindex_html(ngx_http_request_t *r, ngx_array_t *entries) +{ + u_char *last, scale; + off_t length; + size_t len, char_len, escape_html; + ngx_tm_t tm; + ngx_buf_t *b; + ngx_int_t size; + ngx_uint_t i, utf8; + ngx_time_t *tp; + ngx_http_autoindex_entry_t *entry; + ngx_http_autoindex_loc_conf_t *alcf; + + static u_char title[] = + "" CRLF + "Index of " + ; + + static u_char header[] = + "" CRLF + "" CRLF + "

Index of " + ; + + static u_char tail[] = + "" CRLF + "" CRLF + ; + + static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + + if (r->headers_out.charset.len == 5 + && ngx_strncasecmp(r->headers_out.charset.data, (u_char *) "utf-8", 5) + == 0) + { + utf8 = 1; + + } else { + utf8 = 0; + } + escape_html = ngx_escape_html(NULL, r->uri.data, r->uri.len); len = sizeof(title) - 1 @@ -372,8 +479,22 @@ ngx_http_autoindex_handler(ngx_http_request_t *r) + sizeof("
") - 1 + sizeof(tail) - 1; - entry = entries.elts; - for (i = 0; i < entries.nelts; i++) { + entry = entries->elts; + for (i = 0; i < entries->nelts; i++) { + entry[i].escape = 2 * ngx_escape_uri(NULL, entry[i].name.data, + entry[i].name.len, + NGX_ESCAPE_URI_COMPONENT); + + entry[i].escape_html = ngx_escape_html(NULL, entry[i].name.data, + entry[i].name.len); + + if (utf8) { + entry[i].utf_len = ngx_utf8_length(entry[i].name.data, + entry[i].name.len); + } else { + entry[i].utf_len = entry[i].name.len; + } + len += sizeof("pool, len); if (b == NULL) { - return NGX_ERROR; - } - - if (entries.nelts > 1) { - ngx_qsort(entry, (size_t) entries.nelts, - sizeof(ngx_http_autoindex_entry_t), - ngx_http_autoindex_cmp_entries); + return NULL; } b->last = ngx_cpymem(b->last, title, sizeof(title) - 1); @@ -416,9 +531,10 @@ ngx_http_autoindex_handler(ngx_http_request_t *r) b->last = ngx_cpymem(b->last, "
../" CRLF,
                          sizeof("
../" CRLF) - 1);
 
+    alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module);
     tp = ngx_timeofday();
 
-    for (i = 0; i < entries.nelts; i++) {
+    for (i = 0; i < entries->nelts; i++) {
         b->last = ngx_cpymem(b->last, "last++ = LF;
     }
 
-    /* TODO: free temporary pool */
-
     b->last = ngx_cpymem(b->last, "

", sizeof("

") - 1); b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1); - if (r == r->main) { - b->last_buf = 1; + return b; +} + + +static ngx_buf_t * +ngx_http_autoindex_json(ngx_http_request_t *r, ngx_array_t *entries, + ngx_str_t *callback) +{ + size_t len; + ngx_buf_t *b; + ngx_uint_t i; + ngx_http_autoindex_entry_t *entry; + + len = sizeof("[" CRLF CRLF "]") - 1; + + if (callback) { + len += sizeof("/* callback */" CRLF "();") - 1 + callback->len; } - b->last_in_chain = 1; + entry = entries->elts; - out.buf = b; - out.next = NULL; + for (i = 0; i < entries->nelts; i++) { + entry[i].escape = ngx_escape_json(NULL, entry[i].name.data, + entry[i].name.len); - return ngx_http_output_filter(r, &out); + len += sizeof("{ }," CRLF) - 1 + + sizeof("\"name\":\"\"") - 1 + + entry[i].name.len + entry[i].escape + + sizeof(", \"type\":\"directory\"") - 1 + + sizeof(", \"mtime\":\"Wed, 31 Dec 1986 10:00:00 GMT\"") - 1; + + if (entry[i].file) { + len += sizeof(", \"size\":") - 1 + NGX_OFF_T_LEN; + } + } + + b = ngx_create_temp_buf(r->pool, len); + if (b == NULL) { + return NULL; + } + + if (callback) { + b->last = ngx_cpymem(b->last, "/* callback */" CRLF, + sizeof("/* callback */" CRLF) - 1); + + b->last = ngx_cpymem(b->last, callback->data, callback->len); + + *b->last++ = '('; + } + + *b->last++ = '['; + + for (i = 0; i < entries->nelts; i++) { + b->last = ngx_cpymem(b->last, CRLF "{ \"name\":\"", + sizeof(CRLF "{ \"name\":\"") - 1); + + if (entry[i].escape) { + b->last = (u_char *) ngx_escape_json(b->last, entry[i].name.data, + entry[i].name.len); + } else { + b->last = ngx_cpymem(b->last, entry[i].name.data, + entry[i].name.len); + } + + b->last = ngx_cpymem(b->last, "\", \"type\":\"", + sizeof("\", \"type\":\"") - 1); + + if (entry[i].dir) { + b->last = ngx_cpymem(b->last, "directory", sizeof("directory") - 1); + + } else if (entry[i].file) { + b->last = ngx_cpymem(b->last, "file", sizeof("file") - 1); + + } else { + b->last = ngx_cpymem(b->last, "other", sizeof("other") - 1); + } + + b->last = ngx_cpymem(b->last, "\", \"mtime\":\"", + sizeof("\", \"mtime\":\"") - 1); + + b->last = ngx_http_time(b->last, entry[i].mtime); + + if (entry[i].file) { + b->last = ngx_cpymem(b->last, "\", \"size\":", + sizeof("\", \"size\":") - 1); + b->last = ngx_sprintf(b->last, "%O", entry[i].size); + + } else { + *b->last++ = '"'; + } + + b->last = ngx_cpymem(b->last, " },", sizeof(" },") - 1); + } + + if (i > 0) { + b->last--; /* strip last comma */ + } + + b->last = ngx_cpymem(b->last, CRLF "]", sizeof(CRLF "]") - 1); + + if (callback) { + *b->last++ = ')'; *b->last++ = ';'; + } + + return b; +} + + +static ngx_int_t +ngx_http_autoindex_jsonp_callback(ngx_http_request_t *r, ngx_str_t *callback) +{ + u_char *p, c, ch; + ngx_uint_t i; + + if (ngx_http_arg(r, (u_char *) "callback", 8, callback) != NGX_OK) { + callback->len = 0; + return NGX_OK; + } + + if (callback->len > 128) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent too long callback name: \"%V\"", callback); + return NGX_DECLINED; + } + + p = callback->data; + + for (i = 0; i < callback->len; i++) { + ch = p[i]; + + c = (u_char) (ch | 0x20); + if (c >= 'a' && c <= 'z') { + continue; + } + + if ((ch >= '0' && ch <= '9') || ch == '_' || ch == '.') { + continue; + } + + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid callback name: \"%V\"", callback); + + return NGX_DECLINED; + } + + return NGX_OK; +} + + +static ngx_buf_t * +ngx_http_autoindex_xml(ngx_http_request_t *r, ngx_array_t *entries) +{ + size_t len; + ngx_tm_t tm; + ngx_buf_t *b; + ngx_str_t type; + ngx_uint_t i; + ngx_http_autoindex_entry_t *entry; + + static u_char head[] = "" CRLF "" CRLF; + static u_char tail[] = "" CRLF; + + len = sizeof(head) - 1 + sizeof(tail) - 1; + + entry = entries->elts; + + for (i = 0; i < entries->nelts; i++) { + entry[i].escape = ngx_escape_html(NULL, entry[i].name.data, + entry[i].name.len); + + len += sizeof("" CRLF) - 1 + + entry[i].name.len + entry[i].escape + + sizeof(" mtime=\"1986-12-31T10:00:00Z\"") - 1; + + if (entry[i].file) { + len += sizeof(" size=\"\"") - 1 + NGX_OFF_T_LEN; + } + } + + b = ngx_create_temp_buf(r->pool, len); + if (b == NULL) { + return NULL; + } + + b->last = ngx_cpymem(b->last, head, sizeof(head) - 1); + + for (i = 0; i < entries->nelts; i++) { + *b->last++ = '<'; + + if (entry[i].dir) { + ngx_str_set(&type, "directory"); + + } else if (entry[i].file) { + ngx_str_set(&type, "file"); + + } else { + ngx_str_set(&type, "other"); + } + + b->last = ngx_cpymem(b->last, type.data, type.len); + + b->last = ngx_cpymem(b->last, " mtime=\"", sizeof(" mtime=\"") - 1); + + ngx_gmtime(entry[i].mtime, &tm); + + b->last = ngx_sprintf(b->last, "%4d-%02d-%02dT%02d:%02d:%02dZ", + tm.ngx_tm_year, tm.ngx_tm_mon, + tm.ngx_tm_mday, tm.ngx_tm_hour, + tm.ngx_tm_min, tm.ngx_tm_sec); + + if (entry[i].file) { + b->last = ngx_cpymem(b->last, "\" size=\"", + sizeof("\" size=\"") - 1); + b->last = ngx_sprintf(b->last, "%O", entry[i].size); + } + + *b->last++ = '"'; *b->last++ = '>'; + + if (entry[i].escape) { + b->last = (u_char *) ngx_escape_html(b->last, entry[i].name.data, + entry[i].name.len); + } else { + b->last = ngx_cpymem(b->last, entry[i].name.data, + entry[i].name.len); + } + + *b->last++ = '<'; *b->last++ = '/'; + + b->last = ngx_cpymem(b->last, type.data, type.len); + + *b->last++ = '>'; + + *b->last++ = CR; *b->last++ = LF; + } + + b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1); + + return b; } @@ -665,6 +1007,7 @@ ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf) } conf->enable = NGX_CONF_UNSET; + conf->format = NGX_CONF_UNSET_UINT; conf->localtime = NGX_CONF_UNSET; conf->exact_size = NGX_CONF_UNSET; @@ -679,6 +1022,8 @@ ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_autoindex_loc_conf_t *conf = child; ngx_conf_merge_value(conf->enable, prev->enable, 0); + ngx_conf_merge_uint_value(conf->format, prev->format, + NGX_HTTP_AUTOINDEX_HTML); ngx_conf_merge_value(conf->localtime, prev->localtime, 0); ngx_conf_merge_value(conf->exact_size, prev->exact_size, 1); diff --git a/src/http/modules/ngx_http_charset_filter_module.c b/src/http/modules/ngx_http_charset_filter_module.c index c9b7e9e..4ea9818 100644 --- a/src/http/modules/ngx_http_charset_filter_module.c +++ b/src/http/modules/ngx_http_charset_filter_module.c @@ -272,12 +272,27 @@ ngx_http_charset_header_filter(ngx_http_request_t *r) return ngx_http_next_header_filter(r); } + if (source_charset == charset) { + r->headers_out.content_type.len = r->headers_out.content_type_len; + + ngx_http_set_charset(r, &dst); + + return ngx_http_next_header_filter(r); + } + + /* source_charset != charset */ + + if (r->headers_out.content_encoding + && r->headers_out.content_encoding->value.len) + { + return ngx_http_next_header_filter(r); + } + mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); charsets = mcf->charsets.elts; - if (source_charset != charset - && (charsets[source_charset].tables == NULL - || charsets[source_charset].tables[charset] == NULL)) + if (charsets[source_charset].tables == NULL + || charsets[source_charset].tables[charset] == NULL) { goto no_charset_map; } @@ -286,11 +301,7 @@ ngx_http_charset_header_filter(ngx_http_request_t *r) ngx_http_set_charset(r, &dst); - if (source_charset != charset) { - return ngx_http_charset_ctx(r, charsets, charset, source_charset); - } - - return ngx_http_next_header_filter(r); + return ngx_http_charset_ctx(r, charsets, charset, source_charset); no_charset_map: @@ -311,13 +322,6 @@ ngx_http_destination_charset(ngx_http_request_t *r, ngx_str_t *name) ngx_http_charset_loc_conf_t *mlcf; ngx_http_charset_main_conf_t *mcf; - if (!r->ignore_content_encoding - && r->headers_out.content_encoding - && r->headers_out.content_encoding->value.len) - { - return NGX_DECLINED; - } - if (r->headers_out.content_type.len == 0) { return NGX_DECLINED; } diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c index e7f9e9a..529aba5 100644 --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -212,7 +212,10 @@ ngx_http_dav_put_handler(ngx_http_request_t *r) return; } - ngx_http_map_uri_to_path(r, &path, &root, 0); + if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } path.len--; @@ -320,7 +323,9 @@ ngx_http_dav_delete_handler(ngx_http_request_t *r) ok: - ngx_http_map_uri_to_path(r, &path, &root, 0); + if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http delete filename: \"%s\"", path.data); @@ -488,6 +493,9 @@ ngx_http_dav_mkcol_handler(ngx_http_request_t *r, ngx_http_dav_loc_conf_t *dlcf) } p = ngx_http_map_uri_to_path(r, &path, &root, 0); + if (p == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } *(p - 1) = '\0'; r->uri.len--; @@ -666,7 +674,9 @@ destination_done: overwrite_done: - ngx_http_map_uri_to_path(r, &path, &root, 0); + if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http copy from: \"%s\"", path.data); @@ -674,7 +684,9 @@ overwrite_done: uri = r->uri; r->uri = duri; - ngx_http_map_uri_to_path(r, ©.path, &root, 0); + if (ngx_http_map_uri_to_path(r, ©.path, &root, 0) == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } r->uri = uri; diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 80cd1a2..f3f78e8 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -10,23 +10,36 @@ #include +typedef struct { + ngx_array_t caches; /* ngx_http_file_cache_t * */ +} ngx_http_fastcgi_main_conf_t; + + +typedef struct { + ngx_array_t *flushes; + ngx_array_t *lengths; + ngx_array_t *values; + ngx_uint_t number; + ngx_hash_t hash; +} ngx_http_fastcgi_params_t; + + typedef struct { ngx_http_upstream_conf_t upstream; ngx_str_t index; - ngx_array_t *flushes; - ngx_array_t *params_len; - ngx_array_t *params; + ngx_http_fastcgi_params_t params; +#if (NGX_HTTP_CACHE) + ngx_http_fastcgi_params_t params_cache; +#endif + ngx_array_t *params_source; ngx_array_t *catch_stderr; ngx_array_t *fastcgi_lengths; ngx_array_t *fastcgi_values; - ngx_hash_t headers_hash; - ngx_uint_t header_params; - ngx_flag_t keep_conn; #if (NGX_HTTP_CACHE) @@ -68,8 +81,12 @@ typedef struct { size_t length; size_t padding; + ngx_chain_t *free; + ngx_chain_t *busy; + unsigned fastcgi_stdout:1; unsigned large_stderr:1; + unsigned header_sent:1; ngx_array_t *split_parts; @@ -134,6 +151,8 @@ static ngx_int_t ngx_http_fastcgi_create_key(ngx_http_request_t *r); #endif 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_body_output_filter(void *data, + ngx_chain_t *in); 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, @@ -147,11 +166,13 @@ static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc); static ngx_int_t ngx_http_fastcgi_add_variables(ngx_conf_t *cf); +static void *ngx_http_fastcgi_create_main_conf(ngx_conf_t *cf); static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); -static ngx_int_t ngx_http_fastcgi_merge_params(ngx_conf_t *cf, - ngx_http_fastcgi_loc_conf_t *conf, ngx_http_fastcgi_loc_conf_t *prev); +static ngx_int_t ngx_http_fastcgi_init_params(ngx_conf_t *cf, + ngx_http_fastcgi_loc_conf_t *conf, ngx_http_fastcgi_params_t *params, + ngx_keyval_t *default_params); static ngx_int_t ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); @@ -242,6 +263,13 @@ static ngx_command_t ngx_http_fastcgi_commands[] = { offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffering), NULL }, + { ngx_string("fastcgi_request_buffering"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.request_buffering), + NULL }, + { ngx_string("fastcgi_ignore_client_abort"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -326,6 +354,20 @@ static ngx_command_t ngx_http_fastcgi_commands[] = { offsetof(ngx_http_fastcgi_loc_conf_t, upstream.busy_buffers_size_conf), NULL }, + { ngx_string("fastcgi_force_ranges"), + 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.force_ranges), + NULL }, + + { ngx_string("fastcgi_limit_rate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.limit_rate), + NULL }, + #if (NGX_HTTP_CACHE) { ngx_string("fastcgi_cache"), @@ -345,8 +387,8 @@ static ngx_command_t ngx_http_fastcgi_commands[] = { { ngx_string("fastcgi_cache_path"), NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE, ngx_http_file_cache_set_slot, - 0, - 0, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_fastcgi_main_conf_t, caches), &ngx_http_fastcgi_module }, { ngx_string("fastcgi_cache_bypass"), @@ -405,6 +447,13 @@ static ngx_command_t ngx_http_fastcgi_commands[] = { offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock_timeout), NULL }, + { ngx_string("fastcgi_cache_lock_age"), + 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_age), + NULL }, + { ngx_string("fastcgi_cache_revalidate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -442,6 +491,20 @@ static ngx_command_t ngx_http_fastcgi_commands[] = { offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream), &ngx_http_fastcgi_next_upstream_masks }, + { ngx_string("fastcgi_next_upstream_tries"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream_tries), + NULL }, + + { ngx_string("fastcgi_next_upstream_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.next_upstream_timeout), + NULL }, + { ngx_string("fastcgi_param"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23, ngx_http_upstream_param_set_slot, @@ -492,7 +555,7 @@ static ngx_http_module_t ngx_http_fastcgi_module_ctx = { ngx_http_fastcgi_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ - NULL, /* create main configuration */ + ngx_http_fastcgi_create_main_conf, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ @@ -573,7 +636,7 @@ static ngx_keyval_t ngx_http_fastcgi_cache_headers[] = { { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("$upstream_cache_last_modified") }, { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") }, - { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") }, + { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("$upstream_cache_etag") }, { ngx_string("HTTP_IF_MATCH"), ngx_string("") }, { ngx_string("HTTP_RANGE"), ngx_string("") }, { ngx_string("HTTP_IF_RANGE"), ngx_string("") }, @@ -591,10 +654,13 @@ static ngx_path_init_t ngx_http_fastcgi_temp_path = { static ngx_int_t ngx_http_fastcgi_handler(ngx_http_request_t *r) { - ngx_int_t rc; - ngx_http_upstream_t *u; - ngx_http_fastcgi_ctx_t *f; - ngx_http_fastcgi_loc_conf_t *flcf; + ngx_int_t rc; + ngx_http_upstream_t *u; + ngx_http_fastcgi_ctx_t *f; + ngx_http_fastcgi_loc_conf_t *flcf; +#if (NGX_HTTP_CACHE) + ngx_http_fastcgi_main_conf_t *fmcf; +#endif if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -623,8 +689,12 @@ ngx_http_fastcgi_handler(ngx_http_request_t *r) u->conf = &flcf->upstream; #if (NGX_HTTP_CACHE) + fmcf = ngx_http_get_module_main_conf(r, ngx_http_fastcgi_module); + + u->caches = &fmcf->caches; u->create_key = ngx_http_fastcgi_create_key; #endif + u->create_request = ngx_http_fastcgi_create_request; u->reinit_request = ngx_http_fastcgi_reinit_request; u->process_header = ngx_http_fastcgi_process_header; @@ -646,6 +716,12 @@ ngx_http_fastcgi_handler(ngx_http_request_t *r) u->input_filter = ngx_http_fastcgi_non_buffered_filter; u->input_filter_ctx = r; + if (!flcf->upstream.request_buffering + && flcf->upstream.pass_request_body) + { + r->request_body_no_buffering = 1; + } + rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { @@ -742,9 +818,11 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) ngx_chain_t *cl, *body; ngx_list_part_t *part; ngx_table_elt_t *header, **ignored; + ngx_http_upstream_t *u; ngx_http_script_code_pt code; ngx_http_script_engine_t e, le; ngx_http_fastcgi_header_t *h; + ngx_http_fastcgi_params_t *params; ngx_http_fastcgi_loc_conf_t *flcf; ngx_http_script_len_code_pt lcode; @@ -752,15 +830,23 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) header_params = 0; ignored = NULL; + u = r->upstream; + flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); - if (flcf->params_len) { +#if (NGX_HTTP_CACHE) + params = u->cacheable ? &flcf->params_cache : &flcf->params; +#else + params = &flcf->params; +#endif + + if (params->lengths) { ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); - ngx_http_script_flush_no_cacheable_variables(r, flcf->flushes); + ngx_http_script_flush_no_cacheable_variables(r, params->flushes); le.flushed = 1; - le.ip = flcf->params_len->elts; + le.ip = params->lengths->elts; le.request = r; while (*(uintptr_t *) le.ip) { @@ -789,7 +875,7 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) allocated = 0; lowcase_key = NULL; - if (flcf->header_params) { + if (params->number) { n = 0; part = &r->headers_in.headers.part; @@ -819,7 +905,7 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) i = 0; } - if (flcf->header_params) { + if (params->number) { if (allocated < header[i].key.len) { allocated = header[i].key.len + 16; lowcase_key = ngx_pnalloc(r->pool, allocated); @@ -844,7 +930,7 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) lowcase_key[n] = ch; } - if (ngx_hash_find(&flcf->headers_hash, hash, lowcase_key, n)) { + if (ngx_hash_find(¶ms->hash, hash, lowcase_key, n)) { ignored[header_params++] = &header[i]; continue; } @@ -914,15 +1000,15 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) + sizeof(ngx_http_fastcgi_header_t); - if (flcf->params_len) { + if (params->lengths) { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); - e.ip = flcf->params->elts; + e.ip = params->values->elts; e.pos = b->last; e.request = r; e.flushed = 1; - le.ip = flcf->params_len->elts; + le.ip = params->lengths->elts; while (*(uintptr_t *) le.ip) { @@ -1070,12 +1156,17 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) h->padding_length = 0; h->reserved = 0; - h = (ngx_http_fastcgi_header_t *) b->last; - b->last += sizeof(ngx_http_fastcgi_header_t); + if (r->request_body_no_buffering) { - if (flcf->upstream.pass_request_body) { - body = r->upstream->request_bufs; - r->upstream->request_bufs = cl; + u->request_bufs = cl; + + u->output.output_filter = ngx_http_fastcgi_body_output_filter; + u->output.filter_ctx = r; + + } else if (flcf->upstream.pass_request_body) { + + body = u->request_bufs; + u->request_bufs = cl; #if (NGX_SUPPRESS_WARN) file_pos = 0; @@ -1115,6 +1206,7 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) } else { b->pos = pos; + b->start = pos; pos += 32 * 1024; if (pos >= body->buf->last) { @@ -1129,6 +1221,9 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) padding = 8 - len % 8; padding = (padding == 8) ? 0 : padding; + h = (ngx_http_fastcgi_header_t *) cl->buf->last; + cl->buf->last += sizeof(ngx_http_fastcgi_header_t); + h->version = 1; h->type = NGX_HTTP_FASTCGI_STDIN; h->request_id_hi = 0; @@ -1158,9 +1253,6 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) b->last += padding; } - h = (ngx_http_fastcgi_header_t *) b->last; - b->last += sizeof(ngx_http_fastcgi_header_t); - cl->next = ngx_alloc_chain_link(r->pool); if (cl->next == NULL) { return NGX_ERROR; @@ -1175,17 +1267,22 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) } } else { - r->upstream->request_bufs = cl; + u->request_bufs = cl; } - h->version = 1; - h->type = NGX_HTTP_FASTCGI_STDIN; - h->request_id_hi = 0; - h->request_id_lo = 1; - h->content_length_hi = 0; - h->content_length_lo = 0; - h->padding_length = 0; - h->reserved = 0; + if (!r->request_body_no_buffering) { + h = (ngx_http_fastcgi_header_t *) cl->buf->last; + cl->buf->last += sizeof(ngx_http_fastcgi_header_t); + + h->version = 1; + h->type = NGX_HTTP_FASTCGI_STDIN; + h->request_id_hi = 0; + h->request_id_lo = 1; + h->content_length_hi = 0; + h->content_length_lo = 0; + h->padding_length = 0; + h->reserved = 0; + } cl->next = NULL; @@ -1218,6 +1315,294 @@ ngx_http_fastcgi_reinit_request(ngx_http_request_t *r) } +static ngx_int_t +ngx_http_fastcgi_body_output_filter(void *data, ngx_chain_t *in) +{ + ngx_http_request_t *r = data; + + off_t file_pos; + u_char *pos, *start; + size_t len, padding; + ngx_buf_t *b; + ngx_int_t rc; + ngx_uint_t next, last; + ngx_chain_t *cl, *tl, *out, **ll; + ngx_http_fastcgi_ctx_t *f; + ngx_http_fastcgi_header_t *h; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "fastcgi output filter"); + + f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); + + if (in == NULL) { + out = in; + goto out; + } + + out = NULL; + ll = &out; + + if (!f->header_sent) { + /* first buffer contains headers, pass it unmodified */ + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "fastcgi output header"); + + f->header_sent = 1; + + tl = ngx_alloc_chain_link(r->pool); + if (tl == NULL) { + return NGX_ERROR; + } + + tl->buf = in->buf; + *ll = tl; + ll = &tl->next; + + in = in->next; + + if (in == NULL) { + tl->next = NULL; + goto out; + } + } + + cl = ngx_chain_get_free_buf(r->pool, &f->free); + if (cl == NULL) { + return NGX_ERROR; + } + + b = cl->buf; + + b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter; + b->temporary = 1; + + if (b->start == NULL) { + /* reserve space for maximum possible padding, 7 bytes */ + + b->start = ngx_palloc(r->pool, + sizeof(ngx_http_fastcgi_header_t) + 7); + if (b->start == NULL) { + return NGX_ERROR; + } + + b->pos = b->start; + b->last = b->start; + + b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7; + } + + *ll = cl; + + last = 0; + padding = 0; + +#if (NGX_SUPPRESS_WARN) + file_pos = 0; + pos = NULL; +#endif + + while (in) { + + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, + "fastcgi output in l:%d f:%d %p, pos %p, size: %z " + "file: %O, size: %O", + in->buf->last_buf, + in->buf->in_file, + in->buf->start, in->buf->pos, + in->buf->last - in->buf->pos, + in->buf->file_pos, + in->buf->file_last - in->buf->file_pos); + + if (in->buf->last_buf) { + last = 1; + } + + if (ngx_buf_special(in->buf)) { + in = in->next; + continue; + } + + if (in->buf->in_file) { + file_pos = in->buf->file_pos; + + } else { + pos = in->buf->pos; + } + + next = 0; + + do { + tl = ngx_chain_get_free_buf(r->pool, &f->free); + if (tl == NULL) { + return NGX_ERROR; + } + + b = tl->buf; + start = b->start; + + ngx_memcpy(b, in->buf, sizeof(ngx_buf_t)); + + /* + * restore b->start to preserve memory allocated in the buffer, + * to reuse it later for headers and padding + */ + + b->start = start; + + if (in->buf->in_file) { + b->file_pos = file_pos; + file_pos += 32 * 1024; + + if (file_pos >= in->buf->file_last) { + file_pos = in->buf->file_last; + next = 1; + } + + b->file_last = file_pos; + len = (ngx_uint_t) (file_pos - b->file_pos); + + } else { + b->pos = pos; + pos += 32 * 1024; + + if (pos >= in->buf->last) { + pos = in->buf->last; + next = 1; + } + + b->last = pos; + len = (ngx_uint_t) (pos - b->pos); + } + + b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter; + b->shadow = in->buf; + b->last_shadow = next; + + b->last_buf = 0; + b->last_in_chain = 0; + + padding = 8 - len % 8; + padding = (padding == 8) ? 0 : padding; + + h = (ngx_http_fastcgi_header_t *) cl->buf->last; + cl->buf->last += sizeof(ngx_http_fastcgi_header_t); + + h->version = 1; + h->type = NGX_HTTP_FASTCGI_STDIN; + h->request_id_hi = 0; + h->request_id_lo = 1; + h->content_length_hi = (u_char) ((len >> 8) & 0xff); + h->content_length_lo = (u_char) (len & 0xff); + h->padding_length = (u_char) padding; + h->reserved = 0; + + cl->next = tl; + cl = tl; + + tl = ngx_chain_get_free_buf(r->pool, &f->free); + if (tl == NULL) { + return NGX_ERROR; + } + + b = tl->buf; + + b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter; + b->temporary = 1; + + if (b->start == NULL) { + /* reserve space for maximum possible padding, 7 bytes */ + + b->start = ngx_palloc(r->pool, + sizeof(ngx_http_fastcgi_header_t) + 7); + if (b->start == NULL) { + return NGX_ERROR; + } + + b->pos = b->start; + b->last = b->start; + + b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7; + } + + if (padding) { + ngx_memzero(b->last, padding); + b->last += padding; + } + + cl->next = tl; + cl = tl; + + } while (!next); + + in = in->next; + } + + if (last) { + h = (ngx_http_fastcgi_header_t *) cl->buf->last; + cl->buf->last += sizeof(ngx_http_fastcgi_header_t); + + h->version = 1; + h->type = NGX_HTTP_FASTCGI_STDIN; + h->request_id_hi = 0; + h->request_id_lo = 1; + h->content_length_hi = 0; + h->content_length_lo = 0; + h->padding_length = 0; + h->reserved = 0; + + cl->buf->last_buf = 1; + + } else if (padding == 0) { + /* TODO: do not allocate buffers instead */ + cl->buf->temporary = 0; + cl->buf->sync = 1; + } + + cl->next = NULL; + +out: + +#if (NGX_DEBUG) + + for (cl = out; cl; cl = cl->next) { + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, + "fastcgi output out l:%d f:%d %p, pos %p, size: %z " + "file: %O, size: %O", + cl->buf->last_buf, + cl->buf->in_file, + cl->buf->start, cl->buf->pos, + cl->buf->last - cl->buf->pos, + cl->buf->file_pos, + cl->buf->file_last - cl->buf->file_pos); + } + +#endif + + rc = ngx_chain_writer(&r->upstream->writer, out); + + ngx_chain_update_chains(r->pool, &f->free, &f->busy, &out, + (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter); + + for (cl = f->free; cl; cl = cl->next) { + + /* mark original buffers as sent */ + + if (cl->buf->shadow) { + if (cl->buf->last_shadow) { + b = cl->buf->shadow; + b->pos = b->last; + } + + cl->buf->shadow = NULL; + } + } + + return rc; +} + + static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r) { @@ -2284,6 +2669,29 @@ ngx_http_fastcgi_add_variables(ngx_conf_t *cf) } +static void * +ngx_http_fastcgi_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_fastcgi_main_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_main_conf_t)); + if (conf == NULL) { + return NULL; + } + +#if (NGX_HTTP_CACHE) + if (ngx_array_init(&conf->caches, cf->pool, 4, + sizeof(ngx_http_file_cache_t *)) + != NGX_OK) + { + return NULL; + } +#endif + + return conf; +} + + static void * ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf) { @@ -2300,6 +2708,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf) * conf->upstream.bufs.num = 0; * conf->upstream.ignore_headers = 0; * conf->upstream.next_upstream = 0; + * conf->upstream.cache_zone = NULL; * conf->upstream.cache_use_stale = 0; * conf->upstream.cache_methods = 0; * conf->upstream.temp_path = NULL; @@ -2314,17 +2723,22 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf) conf->upstream.store = NGX_CONF_UNSET; conf->upstream.store_access = NGX_CONF_UNSET_UINT; + conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT; conf->upstream.buffering = NGX_CONF_UNSET; + conf->upstream.request_buffering = NGX_CONF_UNSET; conf->upstream.ignore_client_abort = NGX_CONF_UNSET; + conf->upstream.force_ranges = NGX_CONF_UNSET; conf->upstream.local = NGX_CONF_UNSET_PTR; conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; + conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE; conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE; conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; @@ -2334,13 +2748,14 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf) conf->upstream.pass_request_body = NGX_CONF_UNSET; #if (NGX_HTTP_CACHE) - conf->upstream.cache = NGX_CONF_UNSET_PTR; + conf->upstream.cache = NGX_CONF_UNSET; conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT; 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; + conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC; conf->upstream.cache_revalidate = NGX_CONF_UNSET; #endif @@ -2371,28 +2786,48 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_fastcgi_loc_conf_t *conf = child; size_t size; + ngx_int_t rc; ngx_hash_init_t hash; ngx_http_core_loc_conf_t *clcf; - if (conf->upstream.store != 0) { +#if (NGX_HTTP_CACHE) + + if (conf->upstream.store > 0) { + conf->upstream.cache = 0; + } + + if (conf->upstream.cache > 0) { + conf->upstream.store = 0; + } + +#endif + + if (conf->upstream.store == NGX_CONF_UNSET) { ngx_conf_merge_value(conf->upstream.store, prev->upstream.store, 0); - if (conf->upstream.store_lengths == NULL) { - conf->upstream.store_lengths = prev->upstream.store_lengths; - conf->upstream.store_values = prev->upstream.store_values; - } + conf->upstream.store_lengths = prev->upstream.store_lengths; + conf->upstream.store_values = prev->upstream.store_values; } ngx_conf_merge_uint_value(conf->upstream.store_access, prev->upstream.store_access, 0600); + ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries, + prev->upstream.next_upstream_tries, 0); + ngx_conf_merge_value(conf->upstream.buffering, prev->upstream.buffering, 1); + ngx_conf_merge_value(conf->upstream.request_buffering, + prev->upstream.request_buffering, 1); + ngx_conf_merge_value(conf->upstream.ignore_client_abort, prev->upstream.ignore_client_abort, 0); + ngx_conf_merge_value(conf->upstream.force_ranges, + prev->upstream.force_ranges, 0); + ngx_conf_merge_ptr_value(conf->upstream.local, prev->upstream.local, NULL); @@ -2405,6 +2840,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->upstream.read_timeout, prev->upstream.read_timeout, 60000); + ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout, + prev->upstream.next_upstream_timeout, 0); + ngx_conf_merge_size_value(conf->upstream.send_lowat, prev->upstream.send_lowat, 0); @@ -2412,6 +2850,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->upstream.buffer_size, (size_t) ngx_pagesize); + ngx_conf_merge_size_value(conf->upstream.limit_rate, + prev->upstream.limit_rate, 0); + ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, 8, ngx_pagesize); @@ -2531,13 +2972,18 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #if (NGX_HTTP_CACHE) - ngx_conf_merge_ptr_value(conf->upstream.cache, - prev->upstream.cache, NULL); + if (conf->upstream.cache == NGX_CONF_UNSET) { + ngx_conf_merge_value(conf->upstream.cache, + prev->upstream.cache, 0); - if (conf->upstream.cache && conf->upstream.cache->data == NULL) { + conf->upstream.cache_zone = prev->upstream.cache_zone; + conf->upstream.cache_value = prev->upstream.cache_value; + } + + if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) { ngx_shm_zone_t *shm_zone; - shm_zone = conf->upstream.cache; + shm_zone = conf->upstream.cache_zone; ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"fastcgi_cache\" zone \"%V\" is unknown", @@ -2582,12 +3028,20 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) conf->cache_key = prev->cache_key; } + if (conf->upstream.cache && conf->cache_key.value.data == NULL) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "no \"fastcgi_cache_key\" for \"fastcgi_cache\""); + } + 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); + ngx_conf_merge_msec_value(conf->upstream.cache_lock_age, + prev->upstream.cache_lock_age, 5000); + ngx_conf_merge_value(conf->upstream.cache_revalidate, prev->upstream.cache_revalidate, 0); @@ -2619,20 +3073,20 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } - if (conf->upstream.upstream == NULL) { - conf->upstream.upstream = prev->upstream.upstream; - } + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); - if (conf->fastcgi_lengths == NULL) { + if (clcf->noname + && conf->upstream.upstream == NULL && conf->fastcgi_lengths == NULL) + { + conf->upstream.upstream = prev->upstream.upstream; conf->fastcgi_lengths = prev->fastcgi_lengths; conf->fastcgi_values = prev->fastcgi_values; } - if (conf->upstream.upstream || conf->fastcgi_lengths) { - clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); - if (clcf->handler == NULL && clcf->lmt_excpt) { - clcf->handler = ngx_http_fastcgi_handler; - } + if (clcf->lmt_excpt && clcf->handler == NULL + && (conf->upstream.upstream || conf->fastcgi_lengths)) + { + clcf->handler = ngx_http_fastcgi_handler; } #if (NGX_PCRE) @@ -2642,69 +3096,67 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) } #endif - if (ngx_http_fastcgi_merge_params(cf, conf, prev) != NGX_OK) { + if (conf->params_source == NULL) { + conf->params = prev->params; +#if (NGX_HTTP_CACHE) + conf->params_cache = prev->params_cache; +#endif + conf->params_source = prev->params_source; + } + + rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params, NULL); + if (rc != NGX_OK) { return NGX_CONF_ERROR; } +#if (NGX_HTTP_CACHE) + + if (conf->upstream.cache) { + rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params_cache, + ngx_http_fastcgi_cache_headers); + if (rc != NGX_OK) { + return NGX_CONF_ERROR; + } + } + +#endif + return NGX_CONF_OK; } static ngx_int_t -ngx_http_fastcgi_merge_params(ngx_conf_t *cf, - ngx_http_fastcgi_loc_conf_t *conf, ngx_http_fastcgi_loc_conf_t *prev) +ngx_http_fastcgi_init_params(ngx_conf_t *cf, ngx_http_fastcgi_loc_conf_t *conf, + ngx_http_fastcgi_params_t *params, ngx_keyval_t *default_params) { u_char *p; size_t size; uintptr_t *code; ngx_uint_t i, nsrc; - ngx_array_t headers_names; -#if (NGX_HTTP_CACHE) - ngx_array_t params_merged; -#endif + ngx_array_t headers_names, params_merged; + ngx_keyval_t *h; ngx_hash_key_t *hk; ngx_hash_init_t hash; - ngx_http_upstream_param_t *src; + ngx_http_upstream_param_t *src, *s; ngx_http_script_compile_t sc; ngx_http_script_copy_code_t *copy; - if (conf->params_source == NULL) { - conf->params_source = prev->params_source; - - if (prev->headers_hash.buckets -#if (NGX_HTTP_CACHE) - && ((conf->upstream.cache == NULL) - == (prev->upstream.cache == NULL)) -#endif - ) - { - conf->flushes = prev->flushes; - conf->params_len = prev->params_len; - conf->params = prev->params; - conf->headers_hash = prev->headers_hash; - conf->header_params = prev->header_params; - - return NGX_OK; - } - } - - if (conf->params_source == NULL -#if (NGX_HTTP_CACHE) - && (conf->upstream.cache == NULL) -#endif - ) - { - conf->headers_hash.buckets = (void *) 1; + if (params->hash.buckets) { return NGX_OK; } - conf->params_len = ngx_array_create(cf->pool, 64, 1); - if (conf->params_len == NULL) { + if (conf->params_source == NULL && default_params == NULL) { + params->hash.buckets = (void *) 1; + return NGX_OK; + } + + params->lengths = ngx_array_create(cf->pool, 64, 1); + if (params->lengths == NULL) { return NGX_ERROR; } - conf->params = ngx_array_create(cf->pool, 512, 1); - if (conf->params == NULL) { + params->values = ngx_array_create(cf->pool, 512, 1); + if (params->values == NULL) { return NGX_ERROR; } @@ -2723,12 +3175,7 @@ ngx_http_fastcgi_merge_params(ngx_conf_t *cf, nsrc = 0; } -#if (NGX_HTTP_CACHE) - - if (conf->upstream.cache) { - ngx_keyval_t *h; - ngx_http_upstream_param_t *s; - + if (default_params) { if (ngx_array_init(¶ms_merged, cf->temp_pool, 4, sizeof(ngx_http_upstream_param_t)) != NGX_OK) @@ -2746,7 +3193,7 @@ ngx_http_fastcgi_merge_params(ngx_conf_t *cf, *s = src[i]; } - h = ngx_http_fastcgi_cache_headers; + h = default_params; while (h->key.len) { @@ -2777,8 +3224,6 @@ ngx_http_fastcgi_merge_params(ngx_conf_t *cf, nsrc = params_merged.nelts; } -#endif - for (i = 0; i < nsrc; i++) { if (src[i].key.len > sizeof("HTTP_") - 1 @@ -2799,7 +3244,7 @@ ngx_http_fastcgi_merge_params(ngx_conf_t *cf, } } - copy = ngx_array_push_n(conf->params_len, + copy = ngx_array_push_n(params->lengths, sizeof(ngx_http_script_copy_code_t)); if (copy == NULL) { return NGX_ERROR; @@ -2808,7 +3253,7 @@ 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, + copy = ngx_array_push_n(params->lengths, sizeof(ngx_http_script_copy_code_t)); if (copy == NULL) { return NGX_ERROR; @@ -2822,7 +3267,7 @@ ngx_http_fastcgi_merge_params(ngx_conf_t *cf, + src[i].key.len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); - copy = ngx_array_push_n(conf->params, size); + copy = ngx_array_push_n(params->values, size); if (copy == NULL) { return NGX_ERROR; } @@ -2838,15 +3283,15 @@ ngx_http_fastcgi_merge_params(ngx_conf_t *cf, sc.cf = cf; sc.source = &src[i].value; - sc.flushes = &conf->flushes; - sc.lengths = &conf->params_len; - sc.values = &conf->params; + sc.flushes = ¶ms->flushes; + sc.lengths = ¶ms->lengths; + sc.values = ¶ms->values; if (ngx_http_script_compile(&sc) != NGX_OK) { return NGX_ERROR; } - code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t)); + code = ngx_array_push_n(params->lengths, sizeof(uintptr_t)); if (code == NULL) { return NGX_ERROR; } @@ -2854,7 +3299,7 @@ ngx_http_fastcgi_merge_params(ngx_conf_t *cf, *code = (uintptr_t) NULL; - code = ngx_array_push_n(conf->params, sizeof(uintptr_t)); + code = ngx_array_push_n(params->values, sizeof(uintptr_t)); if (code == NULL) { return NGX_ERROR; } @@ -2862,16 +3307,16 @@ ngx_http_fastcgi_merge_params(ngx_conf_t *cf, *code = (uintptr_t) NULL; } - code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t)); + code = ngx_array_push_n(params->lengths, sizeof(uintptr_t)); if (code == NULL) { return NGX_ERROR; } *code = (uintptr_t) NULL; - conf->header_params = headers_names.nelts; + params->number = headers_names.nelts; - hash.hash = &conf->headers_hash; + hash.hash = ¶ms->hash; hash.key = ngx_hash_key_lc; hash.max_size = 512; hash.bucket_size = 64; @@ -3137,9 +3582,7 @@ ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; ngx_http_script_compile_t sc; - if (flcf->upstream.store != NGX_CONF_UNSET - || flcf->upstream.store_lengths) - { + if (flcf->upstream.store != NGX_CONF_UNSET) { return "is duplicate"; } @@ -3151,17 +3594,14 @@ ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } #if (NGX_HTTP_CACHE) - - if (flcf->upstream.cache != NGX_CONF_UNSET_PTR - && flcf->upstream.cache != NULL) - { + if (flcf->upstream.cache > 0) { return "is incompatible with \"fastcgi_cache\""; } - #endif + flcf->upstream.store = 1; + if (ngx_strcmp(value[1].data, "on") == 0) { - flcf->upstream.store = 1; return NGX_CONF_OK; } @@ -3193,26 +3633,53 @@ ngx_http_fastcgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_fastcgi_loc_conf_t *flcf = conf; - ngx_str_t *value; + ngx_str_t *value; + ngx_http_complex_value_t cv; + ngx_http_compile_complex_value_t ccv; value = cf->args->elts; - if (flcf->upstream.cache != NGX_CONF_UNSET_PTR) { + if (flcf->upstream.cache != NGX_CONF_UNSET) { return "is duplicate"; } if (ngx_strcmp(value[1].data, "off") == 0) { - flcf->upstream.cache = NULL; + flcf->upstream.cache = 0; return NGX_CONF_OK; } - if (flcf->upstream.store > 0 || flcf->upstream.store_lengths) { + if (flcf->upstream.store > 0) { return "is incompatible with \"fastcgi_store\""; } - flcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, - &ngx_http_fastcgi_module); - if (flcf->upstream.cache == NULL) { + flcf->upstream.cache = 1; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + + flcf->upstream.cache_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (flcf->upstream.cache_value == NULL) { + return NGX_CONF_ERROR; + } + + *flcf->upstream.cache_value = cv; + + return NGX_CONF_OK; + } + + flcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_fastcgi_module); + if (flcf->upstream.cache_zone == NULL) { return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c index 34c3b19..9b3c6cb 100644 --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -1470,7 +1470,7 @@ ngx_http_geo_include_binary_base(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, vv = (ngx_http_variable_value_t *) (base + sizeof(ngx_http_geo_header_t)); - while(vv->data) { + while (vv->data) { len = ngx_align(sizeof(ngx_http_variable_value_t) + vv->len, sizeof(void *)); ngx_crc32_update(&crc32, (u_char *) vv, len); diff --git a/src/http/modules/ngx_http_geoip_module.c b/src/http/modules/ngx_http_geoip_module.c index 576fc5f..8e151aa 100644 --- a/src/http/modules/ngx_http_geoip_module.c +++ b/src/http/modules/ngx_http_geoip_module.c @@ -553,6 +553,9 @@ ngx_http_geoip_city_float_variable(ngx_http_request_t *r, val = *(float *) ((char *) gr + data); v->len = ngx_sprintf(v->data, "%.4f", val) - v->data; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; GeoIPRecord_delete(gr); @@ -582,6 +585,9 @@ ngx_http_geoip_city_int_variable(ngx_http_request_t *r, val = *(int *) ((char *) gr + data); v->len = ngx_sprintf(v->data, "%d", val) - v->data; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; GeoIPRecord_delete(gr); @@ -691,7 +697,7 @@ ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (cf->args->nelts == 3) { if (ngx_strcmp(value[2].data, "utf8") == 0) { - GeoIP_set_charset (gcf->country, GEOIP_CHARSET_UTF8); + GeoIP_set_charset(gcf->country, GEOIP_CHARSET_UTF8); } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -746,7 +752,7 @@ ngx_http_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (cf->args->nelts == 3) { if (ngx_strcmp(value[2].data, "utf8") == 0) { - GeoIP_set_charset (gcf->org, GEOIP_CHARSET_UTF8); + GeoIP_set_charset(gcf->org, GEOIP_CHARSET_UTF8); } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -807,7 +813,7 @@ ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (cf->args->nelts == 3) { if (ngx_strcmp(value[2].data, "utf8") == 0) { - GeoIP_set_charset (gcf->city, GEOIP_CHARSET_UTF8); + GeoIP_set_charset(gcf->city, GEOIP_CHARSET_UTF8); } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, diff --git a/src/http/modules/ngx_http_gunzip_filter_module.c b/src/http/modules/ngx_http_gunzip_filter_module.c index adadc9d..c1341f5 100644 --- a/src/http/modules/ngx_http_gunzip_filter_module.c +++ b/src/http/modules/ngx_http_gunzip_filter_module.c @@ -165,7 +165,7 @@ ngx_http_gunzip_header_filter(ngx_http_request_t *r) ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); - ngx_http_clear_etag(r); + ngx_http_weak_etag(r); return ngx_http_next_header_filter(r); } @@ -175,6 +175,7 @@ static ngx_int_t ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { int rc; + ngx_uint_t flush; ngx_chain_t *cl; ngx_http_gunzip_ctx_t *ctx; @@ -199,7 +200,7 @@ ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) } } - if (ctx->nomem || in == NULL) { + if (ctx->nomem) { /* flush busy buffers */ @@ -212,6 +213,10 @@ ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &cl, (ngx_buf_tag_t) &ngx_http_gunzip_filter_module); ctx->nomem = 0; + flush = 0; + + } else { + flush = ctx->busy ? 1 : 0; } for ( ;; ) { @@ -258,7 +263,7 @@ ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) /* rc == NGX_AGAIN */ } - if (ctx->out == NULL) { + if (ctx->out == NULL && !flush) { return ctx->busy ? NGX_AGAIN : NGX_OK; } @@ -276,6 +281,7 @@ ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) "gunzip out: %p", ctx->out); ctx->nomem = 0; + flush = 0; if (ctx->done) { return rc; diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index ea1f1d0..f941e63 100644 --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -306,7 +306,7 @@ ngx_http_gzip_header_filter(ngx_http_request_t *r) ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); - ngx_http_clear_etag(r); + ngx_http_weak_etag(r); return ngx_http_next_header_filter(r); } @@ -316,6 +316,7 @@ static ngx_int_t ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { int rc; + ngx_uint_t flush; ngx_chain_t *cl; ngx_http_gzip_ctx_t *ctx; @@ -372,7 +373,7 @@ ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) r->connection->buffered |= NGX_HTTP_GZIP_BUFFERED; } - if (ctx->nomem || in == NULL) { + if (ctx->nomem) { /* flush busy buffers */ @@ -385,6 +386,10 @@ ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &cl, (ngx_buf_tag_t) &ngx_http_gzip_filter_module); ctx->nomem = 0; + flush = 0; + + } else { + flush = ctx->busy ? 1 : 0; } for ( ;; ) { @@ -432,7 +437,7 @@ ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) /* rc == NGX_AGAIN */ } - if (ctx->out == NULL) { + if (ctx->out == NULL && !flush) { ngx_http_gzip_filter_free_copy_buf(r, ctx); return ctx->busy ? NGX_AGAIN : NGX_OK; @@ -457,6 +462,7 @@ ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ctx->last_out = &ctx->out; ctx->nomem = 0; + flush = 0; if (ctx->done) { return rc; diff --git a/src/http/modules/ngx_http_gzip_static_module.c b/src/http/modules/ngx_http_gzip_static_module.c index 1746e55..4d54090 100644 --- a/src/http/modules/ngx_http_gzip_static_module.c +++ b/src/http/modules/ngx_http_gzip_static_module.c @@ -246,8 +246,6 @@ ngx_http_gzip_static_handler(ngx_http_request_t *r) ngx_str_set(&h->value, "gzip"); r->headers_out.content_encoding = h; - r->ignore_content_encoding = 1; - /* we need to allocate all before the header would be sent */ b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c index e33e7ce..a356814 100644 --- a/src/http/modules/ngx_http_headers_filter_module.c +++ b/src/http/modules/ngx_http_headers_filter_module.c @@ -28,6 +28,7 @@ struct ngx_http_header_val_s { ngx_str_t key; ngx_http_set_header_pt handler; ngx_uint_t offset; + ngx_uint_t always; /* unsigned always:1 */ }; @@ -43,14 +44,17 @@ typedef enum { typedef struct { - ngx_http_expires_t expires; - time_t expires_time; - ngx_array_t *headers; + ngx_http_expires_t expires; + time_t expires_time; + ngx_http_complex_value_t *expires_value; + ngx_array_t *headers; } ngx_http_headers_conf_t; 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_parse_expires(ngx_str_t *value, + ngx_http_expires_t *expires, time_t *expires_time, char **err); 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, @@ -98,7 +102,7 @@ static ngx_command_t ngx_http_headers_filter_commands[] = { { ngx_string("add_header"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF - |NGX_CONF_TAKE2, + |NGX_CONF_TAKE23, ngx_http_headers_add, NGX_HTTP_LOC_CONF_OFFSET, 0, @@ -146,28 +150,38 @@ static ngx_int_t ngx_http_headers_filter(ngx_http_request_t *r) { ngx_str_t value; - ngx_uint_t i; + ngx_uint_t i, safe_status; ngx_http_header_val_t *h; ngx_http_headers_conf_t *conf; conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module); if ((conf->expires == NGX_HTTP_EXPIRES_OFF && conf->headers == NULL) - || r != r->main - || (r->headers_out.status != NGX_HTTP_OK - && r->headers_out.status != NGX_HTTP_CREATED - && r->headers_out.status != NGX_HTTP_NO_CONTENT - && r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT - && r->headers_out.status != NGX_HTTP_MOVED_PERMANENTLY - && r->headers_out.status != NGX_HTTP_MOVED_TEMPORARILY - && r->headers_out.status != NGX_HTTP_SEE_OTHER - && r->headers_out.status != NGX_HTTP_NOT_MODIFIED - && r->headers_out.status != NGX_HTTP_TEMPORARY_REDIRECT)) + || r != r->main) { return ngx_http_next_header_filter(r); } - if (conf->expires != NGX_HTTP_EXPIRES_OFF) { + switch (r->headers_out.status) { + + case NGX_HTTP_OK: + case NGX_HTTP_CREATED: + case NGX_HTTP_NO_CONTENT: + case NGX_HTTP_PARTIAL_CONTENT: + case NGX_HTTP_MOVED_PERMANENTLY: + case NGX_HTTP_MOVED_TEMPORARILY: + case NGX_HTTP_SEE_OTHER: + case NGX_HTTP_NOT_MODIFIED: + case NGX_HTTP_TEMPORARY_REDIRECT: + safe_status = 1; + break; + + default: + safe_status = 0; + break; + } + + if (conf->expires != NGX_HTTP_EXPIRES_OFF && safe_status) { if (ngx_http_set_expires(r, conf) != NGX_OK) { return NGX_ERROR; } @@ -177,6 +191,10 @@ ngx_http_headers_filter(ngx_http_request_t *r) h = conf->headers->elts; for (i = 0; i < conf->headers->nelts; i++) { + if (!safe_status && !h[i].always) { + continue; + } + if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) { return NGX_ERROR; } @@ -194,28 +212,52 @@ ngx_http_headers_filter(ngx_http_request_t *r) static ngx_int_t ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf) { - size_t len; - time_t now, expires_time, max_age; - ngx_uint_t i; - ngx_table_elt_t *expires, *cc, **ccp; + char *err; + size_t len; + time_t now, expires_time, max_age; + ngx_str_t value; + ngx_int_t rc; + ngx_uint_t i; + ngx_table_elt_t *e, *cc, **ccp; + ngx_http_expires_t expires; - expires = r->headers_out.expires; + expires = conf->expires; + expires_time = conf->expires_time; - if (expires == NULL) { + if (conf->expires_value != NULL) { - expires = ngx_list_push(&r->headers_out.headers); - if (expires == NULL) { + if (ngx_http_complex_value(r, conf->expires_value, &value) != NGX_OK) { return NGX_ERROR; } - r->headers_out.expires = expires; + rc = ngx_http_parse_expires(&value, &expires, &expires_time, &err); - expires->hash = 1; - ngx_str_set(&expires->key, "Expires"); + if (rc != NGX_OK) { + return NGX_OK; + } + + if (expires == NGX_HTTP_EXPIRES_OFF) { + return NGX_OK; + } + } + + e = r->headers_out.expires; + + if (e == NULL) { + + e = ngx_list_push(&r->headers_out.headers); + if (e == NULL) { + return NGX_ERROR; + } + + r->headers_out.expires = e; + + e->hash = 1; + ngx_str_set(&e->key, "Expires"); } len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT"); - expires->value.len = len - 1; + e->value.len = len - 1; ccp = r->headers_out.cache_control.elts; @@ -250,26 +292,26 @@ ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf) cc = ccp[0]; } - if (conf->expires == NGX_HTTP_EXPIRES_EPOCH) { - expires->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT"; + if (expires == NGX_HTTP_EXPIRES_EPOCH) { + e->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT"; ngx_str_set(&cc->value, "no-cache"); return NGX_OK; } - if (conf->expires == NGX_HTTP_EXPIRES_MAX) { - expires->value.data = (u_char *) "Thu, 31 Dec 2037 23:55:55 GMT"; + if (expires == NGX_HTTP_EXPIRES_MAX) { + e->value.data = (u_char *) "Thu, 31 Dec 2037 23:55:55 GMT"; /* 10 years */ ngx_str_set(&cc->value, "max-age=315360000"); return NGX_OK; } - expires->value.data = ngx_pnalloc(r->pool, len); - if (expires->value.data == NULL) { + e->value.data = ngx_pnalloc(r->pool, len); + if (e->value.data == NULL) { return NGX_ERROR; } - if (conf->expires_time == 0 && conf->expires != NGX_HTTP_EXPIRES_DAILY) { - ngx_memcpy(expires->value.data, ngx_cached_http_time.data, + if (expires_time == 0 && expires != NGX_HTTP_EXPIRES_DAILY) { + ngx_memcpy(e->value.data, ngx_cached_http_time.data, ngx_cached_http_time.len + 1); ngx_str_set(&cc->value, "max-age=0"); return NGX_OK; @@ -277,22 +319,22 @@ ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf) now = ngx_time(); - if (conf->expires == NGX_HTTP_EXPIRES_DAILY) { - expires_time = ngx_next_time(conf->expires_time); + if (expires == NGX_HTTP_EXPIRES_DAILY) { + expires_time = ngx_next_time(expires_time); max_age = expires_time - now; - } else if (conf->expires == NGX_HTTP_EXPIRES_ACCESS + } else if (expires == NGX_HTTP_EXPIRES_ACCESS || r->headers_out.last_modified_time == -1) { - expires_time = now + conf->expires_time; - max_age = conf->expires_time; + max_age = expires_time; + expires_time += now; } else { - expires_time = r->headers_out.last_modified_time + conf->expires_time; + expires_time += r->headers_out.last_modified_time; max_age = expires_time - now; } - ngx_http_time(expires->value.data, expires_time); + ngx_http_time(e->value.data, expires_time); if (conf->expires_time < 0 || max_age < 0) { ngx_str_set(&cc->value, "no-cache"); @@ -312,6 +354,78 @@ ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf) } +static ngx_int_t +ngx_http_parse_expires(ngx_str_t *value, ngx_http_expires_t *expires, + time_t *expires_time, char **err) +{ + ngx_uint_t minus; + + if (*expires != NGX_HTTP_EXPIRES_MODIFIED) { + + if (value->len == 5 && ngx_strncmp(value->data, "epoch", 5) == 0) { + *expires = NGX_HTTP_EXPIRES_EPOCH; + return NGX_OK; + } + + if (value->len == 3 && ngx_strncmp(value->data, "max", 3) == 0) { + *expires = NGX_HTTP_EXPIRES_MAX; + return NGX_OK; + } + + if (value->len == 3 && ngx_strncmp(value->data, "off", 3) == 0) { + *expires = NGX_HTTP_EXPIRES_OFF; + return NGX_OK; + } + } + + if (value->len && value->data[0] == '@') { + value->data++; + value->len--; + minus = 0; + + if (*expires == NGX_HTTP_EXPIRES_MODIFIED) { + *err = "daily time cannot be used with \"modified\" parameter"; + return NGX_ERROR; + } + + *expires = NGX_HTTP_EXPIRES_DAILY; + + } else if (value->len && value->data[0] == '+') { + value->data++; + value->len--; + minus = 0; + + } else if (value->len && value->data[0] == '-') { + value->data++; + value->len--; + minus = 1; + + } else { + minus = 0; + } + + *expires_time = ngx_parse_time(value, 1); + + if (*expires_time == (time_t) NGX_ERROR) { + *err = "invalid value"; + return NGX_ERROR; + } + + if (*expires == NGX_HTTP_EXPIRES_DAILY + && *expires_time > 24 * 60 * 60) + { + *err = "daily time value must be less than 24 hours"; + return NGX_ERROR; + } + + if (minus) { + *expires_time = - *expires_time; + } + + return NGX_OK; +} + + static ngx_int_t ngx_http_add_header(ngx_http_request_t *r, ngx_http_header_val_t *hv, ngx_str_t *value) @@ -442,6 +556,7 @@ ngx_http_headers_create_conf(ngx_conf_t *cf) * * conf->headers = NULL; * conf->expires_time = 0; + * conf->expires_value = NULL; */ conf->expires = NGX_HTTP_EXPIRES_UNSET; @@ -459,6 +574,7 @@ ngx_http_headers_merge_conf(ngx_conf_t *cf, void *parent, void *child) if (conf->expires == NGX_HTTP_EXPIRES_UNSET) { conf->expires = prev->expires; conf->expires_time = prev->expires_time; + conf->expires_value = prev->expires_value; if (conf->expires == NGX_HTTP_EXPIRES_UNSET) { conf->expires = NGX_HTTP_EXPIRES_OFF; @@ -488,8 +604,12 @@ ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_headers_conf_t *hcf = conf; - ngx_uint_t minus, n; - ngx_str_t *value; + char *err; + ngx_str_t *value; + ngx_int_t rc; + ngx_uint_t n; + ngx_http_complex_value_t cv; + ngx_http_compile_complex_value_t ccv; if (hcf->expires != NGX_HTTP_EXPIRES_UNSET) { return "is duplicate"; @@ -499,21 +619,6 @@ ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (cf->args->nelts == 2) { - if (ngx_strcmp(value[1].data, "epoch") == 0) { - hcf->expires = NGX_HTTP_EXPIRES_EPOCH; - return NGX_CONF_OK; - } - - if (ngx_strcmp(value[1].data, "max") == 0) { - hcf->expires = NGX_HTTP_EXPIRES_MAX; - return NGX_CONF_OK; - } - - if (ngx_strcmp(value[1].data, "off") == 0) { - hcf->expires = NGX_HTTP_EXPIRES_OFF; - return NGX_CONF_OK; - } - hcf->expires = NGX_HTTP_EXPIRES_ACCESS; n = 1; @@ -529,45 +634,33 @@ ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) n = 2; } - if (value[n].data[0] == '@') { - value[n].data++; - value[n].len--; - minus = 0; + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); - if (hcf->expires == NGX_HTTP_EXPIRES_MODIFIED) { - return "daily time cannot be used with \"modified\" parameter"; + ccv.cf = cf; + ccv.value = &value[n]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + + hcf->expires_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (hcf->expires_value == NULL) { + return NGX_CONF_ERROR; } - hcf->expires = NGX_HTTP_EXPIRES_DAILY; + *hcf->expires_value = cv; - } else if (value[n].data[0] == '+') { - value[n].data++; - value[n].len--; - minus = 0; - - } else if (value[n].data[0] == '-') { - value[n].data++; - value[n].len--; - minus = 1; - - } else { - minus = 0; + return NGX_CONF_OK; } - hcf->expires_time = ngx_parse_time(&value[n], 1); - - if (hcf->expires_time == (time_t) NGX_ERROR) { - return "invalid value"; - } - - if (hcf->expires == NGX_HTTP_EXPIRES_DAILY - && hcf->expires_time > 24 * 60 * 60) - { - return "daily time value must be less than 24 hours"; - } - - if (minus) { - hcf->expires_time = - hcf->expires_time; + rc = ngx_http_parse_expires(&value[n], &hcf->expires, &hcf->expires_time, + &err); + if (rc != NGX_OK) { + return err; } return NGX_CONF_OK; @@ -603,6 +696,7 @@ ngx_http_headers_add(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) hv->key = value[1]; hv->handler = ngx_http_add_header; hv->offset = 0; + hv->always = 0; set = ngx_http_set_headers; for (i = 0; set[i].name.len; i++) { @@ -631,5 +725,17 @@ ngx_http_headers_add(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } + if (cf->args->nelts == 3) { + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[3].data, "always") != 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[3]); + return NGX_CONF_ERROR; + } + + hv->always = 1; + return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_image_filter_module.c b/src/http/modules/ngx_http_image_filter_module.c index c983b97..bd7a309 100644 --- a/src/http/modules/ngx_http_image_filter_module.c +++ b/src/http/modules/ngx_http_image_filter_module.c @@ -1012,6 +1012,7 @@ transparent: b->last_buf = 1; ngx_http_image_length(r, b); + ngx_http_weak_etag(r); return b; } diff --git a/src/http/modules/ngx_http_limit_conn_module.c b/src/http/modules/ngx_http_limit_conn_module.c index 7f0eea7..4379311 100644 --- a/src/http/modules/ngx_http_limit_conn_module.c +++ b/src/http/modules/ngx_http_limit_conn_module.c @@ -11,41 +11,40 @@ typedef struct { - u_char color; - u_char len; - u_short conn; - u_char data[1]; + 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_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_rbtree_t *rbtree; + ngx_http_complex_value_t key; } ngx_http_limit_conn_ctx_t; typedef struct { - ngx_shm_zone_t *shm_zone; - ngx_uint_t conn; + 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_uint_t status_code; + ngx_array_t limits; + ngx_uint_t log_level; + ngx_uint_t status_code; } 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); + ngx_str_t *key, 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); @@ -54,18 +53,11 @@ 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 }, @@ -89,13 +81,6 @@ static ngx_command_t ngx_http_limit_conn_commands[] = { 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, @@ -155,13 +140,13 @@ ngx_module_t ngx_http_limit_conn_module = { static ngx_int_t ngx_http_limit_conn_handler(ngx_http_request_t *r) { - size_t len, n; + size_t n; uint32_t hash; + ngx_str_t key; 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; @@ -178,41 +163,37 @@ ngx_http_limit_conn_handler(ngx_http_request_t *r) for (i = 0; i < lccf->limits.nelts; i++) { ctx = limits[i].shm_zone->data; - vv = ngx_http_get_indexed_variable(r, ctx->index); + if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } - if (vv == NULL || vv->not_found) { + if (key.len == 0) { continue; } - len = vv->len; - - if (len == 0) { - continue; - } - - if (len > 255) { + if (key.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); + "the value of the \"%V\" key " + "is more than 255 bytes: \"%V\"", + &ctx->key.value, &key); continue; } r->main->limit_conn_set = 1; - hash = ngx_crc32_short(vv->data, len); + hash = ngx_crc32_short(key.data, key.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); + node = ngx_http_limit_conn_lookup(ctx->rbtree, &key, hash); if (node == NULL) { n = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_limit_conn_node_t, data) - + len; + + key.len; node = ngx_slab_alloc_locked(shpool, n); @@ -225,9 +206,9 @@ ngx_http_limit_conn_handler(ngx_http_request_t *r) lc = (ngx_http_limit_conn_node_t *) &node->color; node->key = hash; - lc->len = (u_char) len; + lc->len = (u_char) key.len; lc->conn = 1; - ngx_memcpy(lc->data, vv->data, len); + ngx_memcpy(lc->data, key.data, key.len); ngx_rbtree_insert(ctx->rbtree, node); @@ -314,8 +295,7 @@ ngx_http_limit_conn_rbtree_insert_value(ngx_rbtree_node_t *temp, static ngx_rbtree_node_t * -ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_http_variable_value_t *vv, - uint32_t hash) +ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_str_t *key, uint32_t hash) { ngx_int_t rc; ngx_rbtree_node_t *node, *sentinel; @@ -340,8 +320,8 @@ ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_http_variable_value_t *vv, lcn = (ngx_http_limit_conn_node_t *) &node->color; - rc = ngx_memn2cmp(vv->data, lcn->data, - (size_t) vv->len, (size_t) lcn->len); + rc = ngx_memn2cmp(key->data, lcn->data, key->len, (size_t) lcn->len); + if (rc == 0) { return node; } @@ -413,11 +393,16 @@ ngx_http_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data) ctx = shm_zone->data; if (octx) { - if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) { + if (ctx->key.value.len != octx->key.value.len + || ngx_strncmp(ctx->key.value.data, octx->key.value.data, + ctx->key.value.len) + != 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); + "limit_conn_zone \"%V\" uses the \"%V\" key " + "while previously it used the \"%V\" key", + &shm_zone->shm.name, &ctx->key.value, + &octx->key.value); return NGX_ERROR; } @@ -507,20 +492,35 @@ 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) { - 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; + 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; + ngx_http_compile_complex_value_t ccv; value = cf->args->elts; - ctx = NULL; + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &ctx->key; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + size = 0; name.len = 0; - for (i = 1; i < cf->args->nelts; i++) { + for (i = 2; i < cf->args->nelts; i++) { if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { @@ -556,26 +556,6 @@ ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 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; @@ -588,13 +568,6 @@ ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 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) { @@ -605,78 +578,8 @@ ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 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); + "%V \"%V\" is already bound to key \"%V\"", + &cmd->name, &name, &ctx->key.value); return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c index 74f7fda..9059ac3 100644 --- a/src/http/modules/ngx_http_limit_req_module.c +++ b/src/http/modules/ngx_http_limit_req_module.c @@ -35,8 +35,7 @@ typedef struct { ngx_slab_pool_t *shpool; /* integer value, 1 corresponds to 0.001 r/s */ ngx_uint_t rate; - ngx_int_t index; - ngx_str_t var; + ngx_http_complex_value_t key; ngx_http_limit_req_node_t *node; } ngx_http_limit_req_ctx_t; @@ -59,8 +58,7 @@ typedef struct { 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_limit_t *limit, - ngx_uint_t hash, u_char *data, size_t len, ngx_uint_t *ep, - ngx_uint_t account); + ngx_uint_t hash, ngx_str_t *key, 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, @@ -158,12 +156,11 @@ 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; uint32_t hash; + ngx_str_t key; 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; @@ -189,31 +186,27 @@ ngx_http_limit_req_handler(ngx_http_request_t *r) ctx = limit->shm_zone->data; - vv = ngx_http_get_indexed_variable(r, ctx->index); + if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } - if (vv == NULL || vv->not_found) { + if (key.len == 0) { continue; } - len = vv->len; - - if (len == 0) { - continue; - } - - if (len > 65535) { + if (key.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); + "the value of the \"%V\" key " + "is more than 65535 bytes: \"%V\"", + &ctx->key.value, &key); continue; } - hash = ngx_crc32_short(vv->data, len); + hash = ngx_crc32_short(key.data, key.len); ngx_shmtx_lock(&ctx->shpool->mutex); - rc = ngx_http_limit_req_lookup(limit, hash, vv->data, len, &excess, + rc = ngx_http_limit_req_lookup(limit, hash, &key, &excess, (n == lrcf->limits.nelts - 1)); ngx_shmtx_unlock(&ctx->shpool->mutex); @@ -365,7 +358,7 @@ 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_limit_t *limit, ngx_uint_t hash, - u_char *data, size_t len, ngx_uint_t *ep, ngx_uint_t account) + ngx_str_t *key, ngx_uint_t *ep, ngx_uint_t account) { size_t size; ngx_int_t rc, excess; @@ -400,7 +393,7 @@ ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, ngx_uint_t hash, lr = (ngx_http_limit_req_node_t *) &node->color; - rc = ngx_memn2cmp(data, lr->data, len, (size_t) lr->len); + rc = ngx_memn2cmp(key->data, lr->data, key->len, (size_t) lr->len); if (rc == 0) { ngx_queue_remove(&lr->queue); @@ -440,7 +433,7 @@ ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, ngx_uint_t hash, size = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_limit_req_node_t, data) - + len; + + key->len; ngx_http_limit_req_expire(ctx, 1); @@ -461,10 +454,10 @@ ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, ngx_uint_t hash, lr = (ngx_http_limit_req_node_t *) &node->color; - lr->len = (u_char) len; + lr->len = (u_short) key->len; lr->excess = 0; - ngx_memcpy(lr->data, data, len); + ngx_memcpy(lr->data, key->data, key->len); ngx_rbtree_insert(&ctx->sh->rbtree, node); @@ -632,11 +625,16 @@ ngx_http_limit_req_init_zone(ngx_shm_zone_t *shm_zone, void *data) ctx = shm_zone->data; if (octx) { - if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) { + if (ctx->key.value.len != octx->key.value.len + || ngx_strncmp(ctx->key.value.data, octx->key.value.data, + ctx->key.value.len) + != 0) + { ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, - "limit_req \"%V\" uses the \"%V\" variable " - "while previously it used the \"%V\" variable", - &shm_zone->shm.name, &ctx->var, &octx->var); + "limit_req \"%V\" uses the \"%V\" key " + "while previously it used the \"%V\" key", + &shm_zone->shm.name, &ctx->key.value, + &octx->key.value); return NGX_ERROR; } @@ -731,24 +729,39 @@ ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, void *child) static char * ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - u_char *p; - size_t len; - ssize_t size; - ngx_str_t *value, name, s; - ngx_int_t rate, scale; - ngx_uint_t i; - ngx_shm_zone_t *shm_zone; - ngx_http_limit_req_ctx_t *ctx; + u_char *p; + size_t len; + ssize_t size; + ngx_str_t *value, name, s; + ngx_int_t rate, scale; + ngx_uint_t i; + ngx_shm_zone_t *shm_zone; + ngx_http_limit_req_ctx_t *ctx; + ngx_http_compile_complex_value_t ccv; value = cf->args->elts; - ctx = NULL; + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &ctx->key; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + size = 0; rate = 1; scale = 1; name.len = 0; - for (i = 1; i < cf->args->nelts; i++) { + for (i = 2; i < cf->args->nelts; i++) { if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { @@ -808,26 +821,6 @@ ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } - if (value[i].data[0] == '$') { - - value[i].len--; - value[i].data++; - - ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_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; @@ -840,13 +833,6 @@ ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 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; - } - ctx->rate = rate * 1000 / scale; shm_zone = ngx_shared_memory_add(cf, &name, size, @@ -859,8 +845,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, - "%V \"%V\" is already bound to variable \"%V\"", - &cmd->name, &name, &ctx->var); + "%V \"%V\" is already bound to key \"%V\"", + &cmd->name, &name, &ctx->key.value); return NGX_CONF_ERROR; } @@ -933,13 +919,6 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - if (shm_zone->data == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "unknown limit_req_zone \"%V\"", - &shm_zone->shm.name); - return NGX_CONF_ERROR; - } - limits = lrcf->limits.elts; if (limits == NULL) { diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c index 7eb29b3..df9424f 100644 --- a/src/http/modules/ngx_http_log_module.c +++ b/src/http/modules/ngx_http_log_module.c @@ -66,7 +66,9 @@ typedef struct { ngx_http_log_script_t *script; time_t disk_full_time; time_t error_log_time; + ngx_syslog_peer_t *syslog_peer; ngx_http_log_fmt_t *format; + ngx_http_complex_value_t *filter; } ngx_http_log_t; @@ -150,7 +152,7 @@ static ngx_int_t ngx_http_log_init(ngx_conf_t *cf); static ngx_command_t ngx_http_log_commands[] = { { ngx_string("log_format"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE, + NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE, ngx_http_log_set_format, NGX_HTTP_MAIN_CONF_OFFSET, 0, @@ -239,7 +241,9 @@ static ngx_int_t ngx_http_log_handler(ngx_http_request_t *r) { u_char *line, *p; - size_t len; + size_t len, size; + ssize_t n; + ngx_str_t val; ngx_uint_t i, l; ngx_http_log_t *log; ngx_http_log_op_t *op; @@ -258,6 +262,16 @@ ngx_http_log_handler(ngx_http_request_t *r) log = lcf->logs->elts; for (l = 0; l < lcf->logs->nelts; l++) { + if (log[l].filter) { + if (ngx_http_complex_value(r, log[l].filter, &val) != NGX_OK) { + return NGX_ERROR; + } + + if (val.len == 0 || (val.len == 1 && val.data[0] == '0')) { + continue; + } + } + if (ngx_time() == log[l].disk_full_time) { /* @@ -282,6 +296,16 @@ ngx_http_log_handler(ngx_http_request_t *r) } } + if (log[l].syslog_peer) { + + /* length of syslog's PRI and HEADER message parts */ + len += sizeof("<255>Jan 01 00:00:00 ") - 1 + + ngx_cycle->hostname.len + 1 + + log[l].syslog_peer->tag.len + 2; + + goto alloc_line; + } + len += NGX_LINEFEED_SIZE; buffer = log[l].file ? log[l].file->data : NULL; @@ -320,6 +344,8 @@ ngx_http_log_handler(ngx_http_request_t *r) } } + alloc_line: + line = ngx_pnalloc(r->pool, len); if (line == NULL) { return NGX_ERROR; @@ -327,10 +353,33 @@ ngx_http_log_handler(ngx_http_request_t *r) p = line; + if (log[l].syslog_peer) { + p = ngx_syslog_add_header(log[l].syslog_peer, line); + } + for (i = 0; i < log[l].format->ops->nelts; i++) { p = op[i].run(r, p, &op[i]); } + if (log[l].syslog_peer) { + + size = p - line; + + n = ngx_syslog_send(log[l].syslog_peer, line, size); + + if (n < 0) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "send() to syslog failed"); + + } else if ((size_t) n != size) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "send() to syslog has written only %z of %uz", + n, size); + } + + continue; + } + ngx_linefeed(p); ngx_http_log_write(r, &log[l], line, p - line); @@ -695,10 +744,23 @@ ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log) static void ngx_http_log_flush_handler(ngx_event_t *ev) { + ngx_open_file_t *file; + ngx_http_log_buf_t *buffer; + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "http log buffer flush handler"); - ngx_http_log_flush(ev->data, ev->log); + if (ev->timedout) { + ngx_http_log_flush(ev->data, ev->log); + return; + } + + /* cancel the flush timer for graceful shutdown */ + + file = ev->data; + buffer = file->data; + + buffer->event = NULL; } @@ -1060,15 +1122,13 @@ ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } + ngx_memzero(log, sizeof(ngx_http_log_t)); + log->file = ngx_conf_open_file(cf->cycle, &ngx_http_access_log); if (log->file == NULL) { return NGX_CONF_ERROR; } - log->script = NULL; - log->disk_full_time = 0; - log->error_log_time = 0; - lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module); fmt = lmcf->formats.elts; @@ -1085,16 +1145,18 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_log_loc_conf_t *llcf = conf; - ssize_t size; - ngx_int_t gzip; - ngx_uint_t i, n; - ngx_msec_t flush; - ngx_str_t *value, name, s; - ngx_http_log_t *log; - ngx_http_log_buf_t *buffer; - ngx_http_log_fmt_t *fmt; - ngx_http_log_main_conf_t *lmcf; - ngx_http_script_compile_t sc; + ssize_t size; + ngx_int_t gzip; + ngx_uint_t i, n; + ngx_msec_t flush; + ngx_str_t *value, name, s; + ngx_http_log_t *log; + ngx_syslog_peer_t *peer; + ngx_http_log_buf_t *buffer; + ngx_http_log_fmt_t *fmt; + ngx_http_log_main_conf_t *lmcf; + ngx_http_script_compile_t sc; + ngx_http_compile_complex_value_t ccv; value = cf->args->elts; @@ -1125,6 +1187,23 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_memzero(log, sizeof(ngx_http_log_t)); + + if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) { + + peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t)); + if (peer == NULL) { + return NGX_CONF_ERROR; + } + + if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) { + return NGX_CONF_ERROR; + } + + log->syslog_peer = peer; + + goto process_formats; + } + n = ngx_http_script_variables_count(&value[1]); if (n == 0) { @@ -1158,6 +1237,8 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } +process_formats: + if (cf->args->nelts >= 3) { name = value[2]; @@ -1255,6 +1336,29 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } + if (ngx_strncmp(value[i].data, "if=", 3) == 0) { + s.len = value[i].len - 3; + s.data = value[i].data + 3; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &s; + 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; + } + + log->filter = ccv.complex_value; + + continue; + } + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[i]); return NGX_CONF_ERROR; @@ -1275,6 +1379,12 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } + if (log->syslog_peer) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "logs to syslog cannot be buffered"); + return NGX_CONF_ERROR; + } + if (log->file->data) { buffer = log->file->data; @@ -1314,6 +1424,7 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) buffer->event->data = log->file; buffer->event->handler = ngx_http_log_flush_handler; buffer->event->log = &cf->cycle->new_log; + buffer->event->cancelable = 1; buffer->flush = flush; } @@ -1337,12 +1448,6 @@ 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; diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c index aaa047e..8341b92 100644 --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -102,6 +102,20 @@ static ngx_command_t ngx_http_memcached_commands[] = { offsetof(ngx_http_memcached_loc_conf_t, upstream.next_upstream), &ngx_http_memcached_next_upstream_masks }, + { ngx_string("memcached_next_upstream_tries"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_memcached_loc_conf_t, upstream.next_upstream_tries), + NULL }, + + { ngx_string("memcached_next_upstream_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_memcached_loc_conf_t, upstream.next_upstream_timeout), + NULL }, + { ngx_string("memcached_gzip_flag"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, @@ -380,11 +394,8 @@ found: } h->hash = 1; - h->key.len = sizeof("Content-Encoding") - 1; - h->key.data = (u_char *) "Content-Encoding"; - h->value.len = sizeof("gzip") - 1; - h->value.data = (u_char *) "gzip"; - + ngx_str_set(&h->key, "Content-Encoding"); + ngx_str_set(&h->value, "gzip"); r->headers_out.content_encoding = h; } @@ -394,7 +405,7 @@ found: p = line.data + line.len; u->headers_in.content_length_n = ngx_atoof(start, p - start); - if (u->headers_in.content_length_n == -1) { + if (u->headers_in.content_length_n == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "memcached sent invalid length in response \"%V\" " "for key \"%V\"", @@ -586,9 +597,11 @@ ngx_http_memcached_create_loc_conf(ngx_conf_t *cf) */ conf->upstream.local = NGX_CONF_UNSET_PTR; + conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT; conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; @@ -605,6 +618,7 @@ ngx_http_memcached_create_loc_conf(ngx_conf_t *cf) conf->upstream.intercept_404 = 1; conf->upstream.pass_request_headers = 0; conf->upstream.pass_request_body = 0; + conf->upstream.force_ranges = 1; conf->index = NGX_CONF_UNSET; conf->gzip_flag = NGX_CONF_UNSET_UINT; @@ -622,6 +636,9 @@ ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->upstream.local, prev->upstream.local, NULL); + ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries, + prev->upstream.next_upstream_tries, 0); + ngx_conf_merge_msec_value(conf->upstream.connect_timeout, prev->upstream.connect_timeout, 60000); @@ -631,6 +648,9 @@ ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->upstream.read_timeout, prev->upstream.read_timeout, 60000); + ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout, + prev->upstream.next_upstream_timeout, 0); + ngx_conf_merge_size_value(conf->upstream.buffer_size, prev->upstream.buffer_size, (size_t) ngx_pagesize); diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index 8f439ba..980bf57 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -1840,7 +1840,7 @@ ngx_http_mp4_read_smhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) atom->pos = atom_header; atom->last = atom_header + atom_size; - trak->vmhd_size += atom_size; + trak->smhd_size += atom_size; trak->out[NGX_HTTP_MP4_SMHD_ATOM].buf = atom; ngx_mp4_atom_next(mp4, atom_data_size); diff --git a/src/http/modules/ngx_http_not_modified_filter_module.c b/src/http/modules/ngx_http_not_modified_filter_module.c index 7f1ab62..acc94de 100644 --- a/src/http/modules/ngx_http_not_modified_filter_module.c +++ b/src/http/modules/ngx_http_not_modified_filter_module.c @@ -13,7 +13,7 @@ static ngx_uint_t ngx_http_test_if_unmodified(ngx_http_request_t *r); static ngx_uint_t ngx_http_test_if_modified(ngx_http_request_t *r); static ngx_uint_t ngx_http_test_if_match(ngx_http_request_t *r, - ngx_table_elt_t *header); + ngx_table_elt_t *header, ngx_uint_t weak); static ngx_int_t ngx_http_not_modified_filter_init(ngx_conf_t *cf); @@ -56,7 +56,7 @@ ngx_http_not_modified_header_filter(ngx_http_request_t *r) { if (r->headers_out.status != NGX_HTTP_OK || r != r->main - || r->headers_out.last_modified_time == -1) + || r->disable_not_modified) { return ngx_http_next_header_filter(r); } @@ -69,7 +69,7 @@ ngx_http_not_modified_header_filter(ngx_http_request_t *r) } if (r->headers_in.if_match - && !ngx_http_test_if_match(r, r->headers_in.if_match)) + && !ngx_http_test_if_match(r, r->headers_in.if_match, 0)) { return ngx_http_filter_finalize_request(r, NULL, NGX_HTTP_PRECONDITION_FAILED); @@ -84,7 +84,7 @@ ngx_http_not_modified_header_filter(ngx_http_request_t *r) } if (r->headers_in.if_none_match - && !ngx_http_test_if_match(r, r->headers_in.if_none_match)) + && !ngx_http_test_if_match(r, r->headers_in.if_none_match, 1)) { return ngx_http_next_header_filter(r); } @@ -114,11 +114,15 @@ ngx_http_test_if_unmodified(ngx_http_request_t *r) { time_t iums; + if (r->headers_out.last_modified_time == (time_t) -1) { + return 0; + } + iums = ngx_http_parse_time(r->headers_in.if_unmodified_since->value.data, r->headers_in.if_unmodified_since->value.len); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http iums:%d lm:%d", iums, r->headers_out.last_modified_time); + "http iums:%T lm:%T", iums, r->headers_out.last_modified_time); if (iums >= r->headers_out.last_modified_time) { return 1; @@ -134,6 +138,10 @@ ngx_http_test_if_modified(ngx_http_request_t *r) time_t ims; ngx_http_core_loc_conf_t *clcf; + if (r->headers_out.last_modified_time == (time_t) -1) { + return 1; + } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (clcf->if_modified_since == NGX_HTTP_IMS_OFF) { @@ -144,7 +152,7 @@ ngx_http_test_if_modified(ngx_http_request_t *r) r->headers_in.if_modified_since->value.len); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http ims:%d lm:%d", ims, r->headers_out.last_modified_time); + "http ims:%T lm:%T", ims, r->headers_out.last_modified_time); if (ims == r->headers_out.last_modified_time) { return 0; @@ -161,10 +169,11 @@ ngx_http_test_if_modified(ngx_http_request_t *r) static ngx_uint_t -ngx_http_test_if_match(ngx_http_request_t *r, ngx_table_elt_t *header) +ngx_http_test_if_match(ngx_http_request_t *r, ngx_table_elt_t *header, + ngx_uint_t weak) { u_char *start, *end, ch; - ngx_str_t *etag, *list; + ngx_str_t etag, *list; list = &header->value; @@ -176,25 +185,42 @@ ngx_http_test_if_match(ngx_http_request_t *r, ngx_table_elt_t *header) return 0; } - etag = &r->headers_out.etag->value; + etag = r->headers_out.etag->value; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http im:\"%V\" etag:%V", list, etag); + "http im:\"%V\" etag:%V", list, &etag); + + if (weak + && etag.len > 2 + && etag.data[0] == 'W' + && etag.data[1] == '/') + { + etag.len -= 2; + etag.data += 2; + } start = list->data; end = list->data + list->len; while (start < end) { - if (etag->len > (size_t) (end - start)) { + if (weak + && end - start > 2 + && start[0] == 'W' + && start[1] == '/') + { + start += 2; + } + + if (etag.len > (size_t) (end - start)) { return 0; } - if (ngx_strncmp(start, etag->data, etag->len) != 0) { + if (ngx_strncmp(start, etag.data, etag.len) != 0) { goto skip; } - start += etag->len; + start += etag.len; while (start < end) { ch = *start; diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 8ee32f4..514c23b 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -10,6 +10,11 @@ #include +typedef struct { + ngx_array_t caches; /* ngx_http_file_cache_t * */ +} ngx_http_proxy_main_conf_t; + + typedef struct ngx_http_proxy_rewrite_s ngx_http_proxy_rewrite_t; typedef ngx_int_t (*ngx_http_proxy_rewrite_pt)(ngx_http_request_t *r, @@ -39,16 +44,26 @@ typedef struct { } ngx_http_proxy_vars_t; +typedef struct { + ngx_array_t *flushes; + ngx_array_t *lengths; + ngx_array_t *values; + ngx_hash_t hash; +} ngx_http_proxy_headers_t; + + typedef struct { ngx_http_upstream_conf_t upstream; - ngx_array_t *flushes; - ngx_array_t *body_set_len; - ngx_array_t *body_set; - ngx_array_t *headers_set_len; - ngx_array_t *headers_set; - ngx_hash_t headers_set_hash; + ngx_array_t *body_flushes; + ngx_array_t *body_lengths; + ngx_array_t *body_values; + ngx_str_t body_source; + ngx_http_proxy_headers_t headers; +#if (NGX_HTTP_CACHE) + ngx_http_proxy_headers_t headers_cache; +#endif ngx_array_t *headers_source; ngx_array_t *proxy_lengths; @@ -58,8 +73,6 @@ typedef struct { ngx_array_t *cookie_domains; ngx_array_t *cookie_paths; - ngx_str_t body_source; - ngx_str_t method; ngx_str_t location; ngx_str_t url; @@ -81,6 +94,12 @@ typedef struct { ngx_uint_t ssl; ngx_uint_t ssl_protocols; ngx_str_t ssl_ciphers; + ngx_uint_t ssl_verify_depth; + ngx_str_t ssl_trusted_certificate; + ngx_str_t ssl_crl; + ngx_str_t ssl_certificate; + ngx_str_t ssl_certificate_key; + ngx_array_t *ssl_passwords; #endif } ngx_http_proxy_loc_conf_t; @@ -91,7 +110,12 @@ typedef struct { ngx_http_proxy_vars_t vars; off_t internal_body_length; - ngx_uint_t head; /* unsigned head:1 */ + ngx_chain_t *free; + ngx_chain_t *busy; + + unsigned head:1; + unsigned internal_chunked:1; + unsigned header_sent:1; } ngx_http_proxy_ctx_t; @@ -102,6 +126,7 @@ static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r); #endif 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_body_output_filter(void *data, ngx_chain_t *in); 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); @@ -127,6 +152,8 @@ static ngx_int_t static ngx_int_t ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r, + 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, @@ -137,11 +164,13 @@ 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_main_conf(ngx_conf_t *cf); static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); -static ngx_int_t ngx_http_proxy_merge_headers(ngx_conf_t *cf, - ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_loc_conf_t *prev); +static ngx_int_t ngx_http_proxy_init_headers(ngx_conf_t *cf, + ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_headers_t *headers, + ngx_keyval_t *default_headers); static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -159,6 +188,10 @@ static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); #endif +#if (NGX_HTTP_SSL) +static char *ngx_http_proxy_ssl_password_file(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +#endif static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data); @@ -267,6 +300,13 @@ static ngx_command_t ngx_http_proxy_commands[] = { offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering), NULL }, + { ngx_string("proxy_request_buffering"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.request_buffering), + NULL }, + { ngx_string("proxy_ignore_client_abort"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -386,6 +426,20 @@ static ngx_command_t ngx_http_proxy_commands[] = { offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf), NULL }, + { ngx_string("proxy_force_ranges"), + 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.force_ranges), + NULL }, + + { ngx_string("proxy_limit_rate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.limit_rate), + NULL }, + #if (NGX_HTTP_CACHE) { ngx_string("proxy_cache"), @@ -405,8 +459,8 @@ static ngx_command_t ngx_http_proxy_commands[] = { { ngx_string("proxy_cache_path"), NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE, ngx_http_file_cache_set_slot, - 0, - 0, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_proxy_main_conf_t, caches), &ngx_http_proxy_module }, { ngx_string("proxy_cache_bypass"), @@ -465,6 +519,13 @@ static ngx_command_t ngx_http_proxy_commands[] = { offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout), NULL }, + { ngx_string("proxy_cache_lock_age"), + 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_age), + NULL }, + { ngx_string("proxy_cache_revalidate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -502,6 +563,20 @@ static ngx_command_t ngx_http_proxy_commands[] = { offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream), &ngx_http_proxy_next_upstream_masks }, + { ngx_string("proxy_next_upstream_tries"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_tries), + NULL }, + + { ngx_string("proxy_next_upstream_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.next_upstream_timeout), + NULL }, + { ngx_string("proxy_pass_header"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_array_slot, @@ -553,6 +628,69 @@ static ngx_command_t ngx_http_proxy_commands[] = { offsetof(ngx_http_proxy_loc_conf_t, ssl_ciphers), NULL }, + { ngx_string("proxy_ssl_name"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_set_complex_value_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_name), + NULL }, + + { ngx_string("proxy_ssl_server_name"), + 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.ssl_server_name), + NULL }, + + { ngx_string("proxy_ssl_verify"), + 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.ssl_verify), + NULL }, + + { ngx_string("proxy_ssl_verify_depth"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, ssl_verify_depth), + NULL }, + + { ngx_string("proxy_ssl_trusted_certificate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, ssl_trusted_certificate), + NULL }, + + { ngx_string("proxy_ssl_crl"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, ssl_crl), + NULL }, + + { ngx_string("proxy_ssl_certificate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate), + NULL }, + + { ngx_string("proxy_ssl_certificate_key"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate_key), + NULL }, + + { ngx_string("proxy_ssl_password_file"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_proxy_ssl_password_file, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + #endif ngx_null_command @@ -563,7 +701,7 @@ static ngx_http_module_t ngx_http_proxy_module_ctx = { ngx_http_proxy_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ - NULL, /* create main configuration */ + ngx_http_proxy_create_main_conf, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ @@ -598,7 +736,8 @@ static ngx_keyval_t ngx_http_proxy_headers[] = { { ngx_string("Host"), ngx_string("$proxy_host") }, { ngx_string("Connection"), ngx_string("close") }, { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") }, - { ngx_string("Transfer-Encoding"), ngx_string("") }, + { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") }, + { ngx_string("TE"), ngx_string("") }, { ngx_string("Keep-Alive"), ngx_string("") }, { ngx_string("Expect"), ngx_string("") }, { ngx_string("Upgrade"), ngx_string("") }, @@ -625,14 +764,15 @@ static ngx_keyval_t ngx_http_proxy_cache_headers[] = { { ngx_string("Host"), ngx_string("$proxy_host") }, { ngx_string("Connection"), ngx_string("close") }, { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") }, - { ngx_string("Transfer-Encoding"), ngx_string("") }, + { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") }, + { ngx_string("TE"), ngx_string("") }, { ngx_string("Keep-Alive"), ngx_string("") }, { ngx_string("Expect"), ngx_string("") }, { ngx_string("Upgrade"), ngx_string("") }, { ngx_string("If-Modified-Since"), ngx_string("$upstream_cache_last_modified") }, { ngx_string("If-Unmodified-Since"), ngx_string("") }, - { ngx_string("If-None-Match"), ngx_string("") }, + { ngx_string("If-None-Match"), ngx_string("$upstream_cache_etag") }, { ngx_string("If-Match"), ngx_string("") }, { ngx_string("Range"), ngx_string("") }, { ngx_string("If-Range"), ngx_string("") }, @@ -661,6 +801,10 @@ static ngx_http_variable_t ngx_http_proxy_vars[] = { ngx_http_proxy_internal_body_length_variable, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, + { ngx_string("proxy_internal_chunked"), NULL, + ngx_http_proxy_internal_chunked_variable, 0, + NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, + { ngx_null_string, NULL, NULL, 0, 0, 0 } }; @@ -673,10 +817,13 @@ static ngx_path_init_t ngx_http_proxy_temp_path = { static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r) { - ngx_int_t rc; - ngx_http_upstream_t *u; - ngx_http_proxy_ctx_t *ctx; - ngx_http_proxy_loc_conf_t *plcf; + ngx_int_t rc; + ngx_http_upstream_t *u; + ngx_http_proxy_ctx_t *ctx; + ngx_http_proxy_loc_conf_t *plcf; +#if (NGX_HTTP_CACHE) + ngx_http_proxy_main_conf_t *pmcf; +#endif if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -684,7 +831,7 @@ ngx_http_proxy_handler(ngx_http_request_t *r) ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t)); if (ctx == NULL) { - return NGX_ERROR; + return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_set_ctx(r, ctx, ngx_http_proxy_module); @@ -711,8 +858,12 @@ ngx_http_proxy_handler(ngx_http_request_t *r) u->conf = &plcf->upstream; #if (NGX_HTTP_CACHE) + pmcf = ngx_http_get_module_main_conf(r, ngx_http_proxy_module); + + u->caches = &pmcf->caches; u->create_key = ngx_http_proxy_create_key; #endif + u->create_request = ngx_http_proxy_create_request; u->reinit_request = ngx_http_proxy_reinit_request; u->process_header = ngx_http_proxy_process_status_line; @@ -744,6 +895,14 @@ ngx_http_proxy_handler(ngx_http_request_t *r) u->accel = 1; + if (!plcf->upstream.request_buffering + && plcf->body_values == NULL && plcf->upstream.pass_request_body + && (!r->headers_in.chunked + || plcf->http_version == NGX_HTTP_VERSION_11)) + { + r->request_body_no_buffering = 1; + } + rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { @@ -972,6 +1131,7 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) ngx_http_upstream_t *u; ngx_http_proxy_ctx_t *ctx; ngx_http_script_code_pt code; + ngx_http_proxy_headers_t *headers; ngx_http_script_engine_t e, le; ngx_http_proxy_loc_conf_t *plcf; ngx_http_script_len_code_pt lcode; @@ -980,6 +1140,12 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); +#if (NGX_HTTP_CACHE) + headers = u->cacheable ? &plcf->headers_cache : &plcf->headers; +#else + headers = &plcf->headers; +#endif + if (u->method.len) { /* HEAD was changed to GET to cache response */ method = u->method; @@ -1038,10 +1204,11 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); - ngx_http_script_flush_no_cacheable_variables(r, plcf->flushes); + ngx_http_script_flush_no_cacheable_variables(r, plcf->body_flushes); + ngx_http_script_flush_no_cacheable_variables(r, headers->flushes); - if (plcf->body_set_len) { - le.ip = plcf->body_set_len->elts; + if (plcf->body_lengths) { + le.ip = plcf->body_lengths->elts; le.request = r; le.flushed = 1; body_len = 0; @@ -1054,11 +1221,15 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) ctx->internal_body_length = body_len; len += body_len; + } else if (r->headers_in.chunked && r->reading_body) { + ctx->internal_body_length = -1; + ctx->internal_chunked = 1; + } else { ctx->internal_body_length = r->headers_in.content_length_n; } - le.ip = plcf->headers_set_len->elts; + le.ip = headers->lengths->elts; le.request = r; le.flushed = 1; @@ -1087,7 +1258,7 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) i = 0; } - if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash, + if (ngx_hash_find(&headers->hash, header[i].hash, header[i].lowcase_key, header[i].key.len)) { continue; @@ -1158,12 +1329,12 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); - e.ip = plcf->headers_set->elts; + e.ip = headers->values->elts; e.pos = b->last; e.request = r; e.flushed = 1; - le.ip = plcf->headers_set_len->elts; + le.ip = headers->lengths->elts; while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; @@ -1211,7 +1382,7 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) i = 0; } - if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash, + if (ngx_hash_find(&headers->hash, header[i].hash, header[i].lowcase_key, header[i].key.len)) { continue; @@ -1236,9 +1407,10 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) /* add "\r\n" at the header end */ *b->last++ = CR; *b->last++ = LF; - if (plcf->body_set) { - e.ip = plcf->body_set->elts; + if (plcf->body_values) { + e.ip = plcf->body_values->elts; e.pos = b->last; + e.skip = 0; while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; @@ -1249,10 +1421,19 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http proxy header:\n\"%*s\"", + "http proxy header:%N\"%*s\"", (size_t) (b->last - b->pos), b->pos); - if (plcf->body_set == NULL && plcf->upstream.pass_request_body) { + if (r->request_body_no_buffering) { + + u->request_bufs = cl; + + if (ctx->internal_chunked) { + u->output.output_filter = ngx_http_proxy_body_output_filter; + u->output.filter_ctx = r; + } + + } else if (plcf->body_values == NULL && plcf->upstream.pass_request_body) { body = u->request_bufs; u->request_bufs = cl; @@ -1313,6 +1494,173 @@ ngx_http_proxy_reinit_request(ngx_http_request_t *r) } +static ngx_int_t +ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in) +{ + ngx_http_request_t *r = data; + + off_t size; + u_char *chunk; + ngx_int_t rc; + ngx_buf_t *b; + ngx_chain_t *out, *cl, *tl, **ll, **fl; + ngx_http_proxy_ctx_t *ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "proxy output filter"); + + ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); + + if (in == NULL) { + out = in; + goto out; + } + + out = NULL; + ll = &out; + + if (!ctx->header_sent) { + /* first buffer contains headers, pass it unmodified */ + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "proxy output header"); + + ctx->header_sent = 1; + + tl = ngx_alloc_chain_link(r->pool); + if (tl == NULL) { + return NGX_ERROR; + } + + tl->buf = in->buf; + *ll = tl; + ll = &tl->next; + + in = in->next; + + if (in == NULL) { + tl->next = NULL; + goto out; + } + } + + size = 0; + cl = in; + fl = ll; + + for ( ;; ) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "proxy output chunk: %d", ngx_buf_size(cl->buf)); + + size += ngx_buf_size(cl->buf); + + if (cl->buf->flush + || cl->buf->sync + || ngx_buf_in_memory(cl->buf) + || cl->buf->in_file) + { + tl = ngx_alloc_chain_link(r->pool); + if (tl == NULL) { + return NGX_ERROR; + } + + tl->buf = cl->buf; + *ll = tl; + ll = &tl->next; + } + + if (cl->next == NULL) { + break; + } + + cl = cl->next; + } + + if (size) { + tl = ngx_chain_get_free_buf(r->pool, &ctx->free); + if (tl == NULL) { + return NGX_ERROR; + } + + b = tl->buf; + chunk = b->start; + + if (chunk == NULL) { + /* the "0000000000000000" is 64-bit hexadecimal string */ + + chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1); + if (chunk == NULL) { + return NGX_ERROR; + } + + b->start = chunk; + b->end = chunk + sizeof("0000000000000000" CRLF) - 1; + } + + b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter; + b->memory = 0; + b->temporary = 1; + b->pos = chunk; + b->last = ngx_sprintf(chunk, "%xO" CRLF, size); + + tl->next = *fl; + *fl = tl; + } + + if (cl->buf->last_buf) { + tl = ngx_chain_get_free_buf(r->pool, &ctx->free); + if (tl == NULL) { + return NGX_ERROR; + } + + b = tl->buf; + + b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter; + b->temporary = 0; + b->memory = 1; + b->last_buf = 1; + b->pos = (u_char *) CRLF "0" CRLF CRLF; + b->last = b->pos + 7; + + cl->buf->last_buf = 0; + + *ll = tl; + + if (size == 0) { + b->pos += 2; + } + + } else if (size > 0) { + tl = ngx_chain_get_free_buf(r->pool, &ctx->free); + if (tl == NULL) { + return NGX_ERROR; + } + + b = tl->buf; + + b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter; + b->temporary = 0; + b->memory = 1; + b->pos = (u_char *) CRLF; + b->last = b->pos + 2; + + *ll = tl; + + } else { + *ll = NULL; + } + +out: + + rc = ngx_chain_writer(&r->upstream->writer, out); + + ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out, + (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter); + + return rc; +} + + static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r) { @@ -2106,6 +2454,30 @@ ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r, } +static ngx_int_t +ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_http_proxy_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); + + if (ctx == NULL || !ctx->internal_chunked) { + v->not_found = 1; + return NGX_OK; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + v->data = (u_char *) "chunked"; + v->len = sizeof("chunked") - 1; + + return NGX_OK; +} + + static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix) @@ -2320,7 +2692,7 @@ ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix, if (replacement->len > len) { - data = ngx_pnalloc(r->pool, new_len); + data = ngx_pnalloc(r->pool, new_len + 1); if (data == NULL) { return NGX_ERROR; } @@ -2329,7 +2701,7 @@ ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix, p = ngx_copy(p, replacement->data, replacement->len); ngx_memcpy(p, h->value.data + prefix + len, - h->value.len - len - prefix); + h->value.len - len - prefix + 1); h->value.data = data; @@ -2338,7 +2710,7 @@ ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix, replacement->len); ngx_memmove(p, h->value.data + prefix + len, - h->value.len - len - prefix); + h->value.len - len - prefix + 1); } h->value.len = new_len; @@ -2366,6 +2738,29 @@ ngx_http_proxy_add_variables(ngx_conf_t *cf) } +static void * +ngx_http_proxy_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_proxy_main_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_main_conf_t)); + if (conf == NULL) { + return NULL; + } + +#if (NGX_HTTP_CACHE) + if (ngx_array_init(&conf->caches, cf->pool, 4, + sizeof(ngx_http_file_cache_t *)) + != NGX_OK) + { + return NULL; + } +#endif + + return conf; +} + + static void * ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) { @@ -2382,6 +2777,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) * conf->upstream.bufs.num = 0; * conf->upstream.ignore_headers = 0; * conf->upstream.next_upstream = 0; + * conf->upstream.cache_zone = NULL; * conf->upstream.cache_use_stale = 0; * conf->upstream.cache_methods = 0; * conf->upstream.temp_path = NULL; @@ -2390,34 +2786,47 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) * conf->upstream.location = NULL; * conf->upstream.store_lengths = NULL; * conf->upstream.store_values = NULL; + * conf->upstream.ssl_name = NULL; * * conf->method = { 0, NULL }; * conf->headers_source = NULL; - * conf->headers_set_len = NULL; - * conf->headers_set = NULL; - * conf->headers_set_hash = NULL; - * conf->body_set_len = NULL; - * conf->body_set = NULL; + * conf->headers.lengths = NULL; + * conf->headers.values = NULL; + * conf->headers.hash = { NULL, 0 }; + * conf->headers_cache.lengths = NULL; + * conf->headers_cache.values = NULL; + * conf->headers_cache.hash = { NULL, 0 }; + * conf->body_lengths = NULL; + * conf->body_values = NULL; * conf->body_source = { 0, NULL }; * conf->redirects = NULL; * conf->ssl = 0; * conf->ssl_protocols = 0; * conf->ssl_ciphers = { 0, NULL }; + * conf->ssl_trusted_certificate = { 0, NULL }; + * conf->ssl_crl = { 0, NULL }; + * conf->ssl_certificate = { 0, NULL }; + * conf->ssl_certificate_key = { 0, NULL }; */ conf->upstream.store = NGX_CONF_UNSET; conf->upstream.store_access = NGX_CONF_UNSET_UINT; + conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT; conf->upstream.buffering = NGX_CONF_UNSET; + conf->upstream.request_buffering = NGX_CONF_UNSET; conf->upstream.ignore_client_abort = NGX_CONF_UNSET; + conf->upstream.force_ranges = NGX_CONF_UNSET; conf->upstream.local = NGX_CONF_UNSET_PTR; conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; + conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE; conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE; conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; @@ -2427,13 +2836,14 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) conf->upstream.pass_request_body = NGX_CONF_UNSET; #if (NGX_HTTP_CACHE) - conf->upstream.cache = NGX_CONF_UNSET_PTR; + conf->upstream.cache = NGX_CONF_UNSET; conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT; 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; + conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC; conf->upstream.cache_revalidate = NGX_CONF_UNSET; #endif @@ -2441,8 +2851,13 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) conf->upstream.pass_headers = NGX_CONF_UNSET_PTR; conf->upstream.intercept_errors = NGX_CONF_UNSET; + #if (NGX_HTTP_SSL) conf->upstream.ssl_session_reuse = NGX_CONF_UNSET; + conf->upstream.ssl_server_name = NGX_CONF_UNSET; + conf->upstream.ssl_verify = NGX_CONF_UNSET; + conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; + conf->ssl_passwords = NGX_CONF_UNSET_PTR; #endif /* "proxy_cyclic_temp_file" is disabled */ @@ -2473,30 +2888,50 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) u_char *p; size_t size; + ngx_int_t rc; ngx_hash_init_t hash; ngx_http_core_loc_conf_t *clcf; ngx_http_proxy_rewrite_t *pr; ngx_http_script_compile_t sc; - if (conf->upstream.store != 0) { +#if (NGX_HTTP_CACHE) + + if (conf->upstream.store > 0) { + conf->upstream.cache = 0; + } + + if (conf->upstream.cache > 0) { + conf->upstream.store = 0; + } + +#endif + + if (conf->upstream.store == NGX_CONF_UNSET) { ngx_conf_merge_value(conf->upstream.store, prev->upstream.store, 0); - if (conf->upstream.store_lengths == NULL) { - conf->upstream.store_lengths = prev->upstream.store_lengths; - conf->upstream.store_values = prev->upstream.store_values; - } + conf->upstream.store_lengths = prev->upstream.store_lengths; + conf->upstream.store_values = prev->upstream.store_values; } ngx_conf_merge_uint_value(conf->upstream.store_access, prev->upstream.store_access, 0600); + ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries, + prev->upstream.next_upstream_tries, 0); + ngx_conf_merge_value(conf->upstream.buffering, prev->upstream.buffering, 1); + ngx_conf_merge_value(conf->upstream.request_buffering, + prev->upstream.request_buffering, 1); + ngx_conf_merge_value(conf->upstream.ignore_client_abort, prev->upstream.ignore_client_abort, 0); + ngx_conf_merge_value(conf->upstream.force_ranges, + prev->upstream.force_ranges, 0); + ngx_conf_merge_ptr_value(conf->upstream.local, prev->upstream.local, NULL); @@ -2509,6 +2944,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->upstream.read_timeout, prev->upstream.read_timeout, 60000); + ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout, + prev->upstream.next_upstream_timeout, 0); + ngx_conf_merge_size_value(conf->upstream.send_lowat, prev->upstream.send_lowat, 0); @@ -2516,6 +2954,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->upstream.buffer_size, (size_t) ngx_pagesize); + ngx_conf_merge_size_value(conf->upstream.limit_rate, + prev->upstream.limit_rate, 0); + ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, 8, ngx_pagesize); @@ -2634,13 +3075,18 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #if (NGX_HTTP_CACHE) - ngx_conf_merge_ptr_value(conf->upstream.cache, - prev->upstream.cache, NULL); + if (conf->upstream.cache == NGX_CONF_UNSET) { + ngx_conf_merge_value(conf->upstream.cache, + prev->upstream.cache, 0); - if (conf->upstream.cache && conf->upstream.cache->data == NULL) { + conf->upstream.cache_zone = prev->upstream.cache_zone; + conf->upstream.cache_value = prev->upstream.cache_value; + } + + if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) { ngx_shm_zone_t *shm_zone; - shm_zone = conf->upstream.cache; + shm_zone = conf->upstream.cache_zone; ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"proxy_cache\" zone \"%V\" is unknown", @@ -2691,6 +3137,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout, prev->upstream.cache_lock_timeout, 5000); + ngx_conf_merge_msec_value(conf->upstream.cache_lock_age, + prev->upstream.cache_lock_age, 5000); + ngx_conf_merge_value(conf->upstream.cache_revalidate, prev->upstream.cache_revalidate, 0); @@ -2714,20 +3163,41 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->upstream.intercept_errors, 0); #if (NGX_HTTP_SSL) + ngx_conf_merge_value(conf->upstream.ssl_session_reuse, prev->upstream.ssl_session_reuse, 1); ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3 - |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 - |NGX_SSL_TLSv1_2)); + (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 + |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); + if (conf->upstream.ssl_name == NULL) { + conf->upstream.ssl_name = prev->upstream.ssl_name; + } + + ngx_conf_merge_value(conf->upstream.ssl_server_name, + prev->upstream.ssl_server_name, 0); + ngx_conf_merge_value(conf->upstream.ssl_verify, + prev->upstream.ssl_verify, 0); + ngx_conf_merge_uint_value(conf->ssl_verify_depth, + prev->ssl_verify_depth, 1); + ngx_conf_merge_str_value(conf->ssl_trusted_certificate, + prev->ssl_trusted_certificate, ""); + ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); + + ngx_conf_merge_str_value(conf->ssl_certificate, + prev->ssl_certificate, ""); + ngx_conf_merge_str_value(conf->ssl_certificate_key, + prev->ssl_certificate_key, ""); + ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); + if (conf->ssl && ngx_http_proxy_set_ssl(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; } + #endif ngx_conf_merge_value(conf->redirect, prev->redirect, 1); @@ -2785,12 +3255,6 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) 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); @@ -2814,39 +3278,45 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } - if (conf->upstream.upstream == NULL) { - conf->upstream.upstream = prev->upstream.upstream; - conf->vars = prev->vars; - } + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + + if (clcf->noname + && conf->upstream.upstream == NULL && conf->proxy_lengths == NULL) + { + conf->upstream.upstream = prev->upstream.upstream; + conf->location = prev->location; + conf->vars = prev->vars; - if (conf->proxy_lengths == NULL) { conf->proxy_lengths = prev->proxy_lengths; conf->proxy_values = prev->proxy_values; + +#if (NGX_HTTP_SSL) + conf->upstream.ssl = prev->upstream.ssl; +#endif } - if (conf->upstream.upstream || conf->proxy_lengths) { - clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); - if (clcf->handler == NULL && clcf->lmt_excpt) { - clcf->handler = ngx_http_proxy_handler; - conf->location = prev->location; - } + if (clcf->lmt_excpt && clcf->handler == NULL + && (conf->upstream.upstream || conf->proxy_lengths)) + { + clcf->handler = ngx_http_proxy_handler; } if (conf->body_source.data == NULL) { + conf->body_flushes = prev->body_flushes; conf->body_source = prev->body_source; - conf->body_set_len = prev->body_set_len; - conf->body_set = prev->body_set; + conf->body_lengths = prev->body_lengths; + conf->body_values = prev->body_values; } - if (conf->body_source.data && conf->body_set_len == NULL) { + if (conf->body_source.data && conf->body_lengths == NULL) { ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); sc.cf = cf; sc.source = &conf->body_source; - sc.flushes = &conf->flushes; - sc.lengths = &conf->body_set_len; - sc.values = &conf->body_set; + sc.flushes = &conf->body_flushes; + sc.lengths = &conf->body_lengths; + sc.values = &conf->body_values; sc.complete_lengths = 1; sc.complete_values = 1; @@ -2855,17 +3325,39 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) } } - if (ngx_http_proxy_merge_headers(cf, conf, prev) != NGX_OK) { + if (conf->headers_source == NULL) { + conf->headers = prev->headers; +#if (NGX_HTTP_CACHE) + conf->headers_cache = prev->headers_cache; +#endif + conf->headers_source = prev->headers_source; + } + + rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers, + ngx_http_proxy_headers); + if (rc != NGX_OK) { return NGX_CONF_ERROR; } +#if (NGX_HTTP_CACHE) + + if (conf->upstream.cache) { + rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers_cache, + ngx_http_proxy_cache_headers); + if (rc != NGX_OK) { + return NGX_CONF_ERROR; + } + } + +#endif + return NGX_CONF_OK; } static ngx_int_t -ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, - ngx_http_proxy_loc_conf_t *prev) +ngx_http_proxy_init_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, + ngx_http_proxy_headers_t *headers, ngx_keyval_t *default_headers) { u_char *p; size_t size; @@ -2878,24 +3370,10 @@ ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, ngx_http_script_compile_t sc; ngx_http_script_copy_code_t *copy; - if (conf->headers_source == NULL) { - conf->flushes = prev->flushes; - conf->headers_set_len = prev->headers_set_len; - conf->headers_set = prev->headers_set; - conf->headers_set_hash = prev->headers_set_hash; - conf->headers_source = prev->headers_source; - } - - if (conf->headers_set_hash.buckets -#if (NGX_HTTP_CACHE) - && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL)) -#endif - ) - { + if (headers->hash.buckets) { return NGX_OK; } - if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t)) != NGX_OK) { @@ -2916,27 +3394,16 @@ ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, } } - conf->headers_set_len = ngx_array_create(cf->pool, 64, 1); - if (conf->headers_set_len == NULL) { + headers->lengths = ngx_array_create(cf->pool, 64, 1); + if (headers->lengths == NULL) { return NGX_ERROR; } - conf->headers_set = ngx_array_create(cf->pool, 512, 1); - if (conf->headers_set == NULL) { + headers->values = ngx_array_create(cf->pool, 512, 1); + if (headers->values == NULL) { return NGX_ERROR; } - -#if (NGX_HTTP_CACHE) - - h = conf->upstream.cache ? ngx_http_proxy_cache_headers: - ngx_http_proxy_headers; -#else - - h = ngx_http_proxy_headers; - -#endif - src = conf->headers_source->elts; for (i = 0; i < conf->headers_source->nelts; i++) { @@ -2948,6 +3415,8 @@ ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, *s = src[i]; } + h = default_headers; + while (h->key.len) { src = headers_merged.elts; @@ -2987,7 +3456,7 @@ ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, } if (ngx_http_script_variables_count(&src[i].value) == 0) { - copy = ngx_array_push_n(conf->headers_set_len, + copy = ngx_array_push_n(headers->lengths, sizeof(ngx_http_script_copy_code_t)); if (copy == NULL) { return NGX_ERROR; @@ -3005,7 +3474,7 @@ ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); - copy = ngx_array_push_n(conf->headers_set, size); + copy = ngx_array_push_n(headers->values, size); if (copy == NULL) { return NGX_ERROR; } @@ -3022,7 +3491,7 @@ ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, *p++ = CR; *p = LF; } else { - copy = ngx_array_push_n(conf->headers_set_len, + copy = ngx_array_push_n(headers->lengths, sizeof(ngx_http_script_copy_code_t)); if (copy == NULL) { return NGX_ERROR; @@ -3037,7 +3506,7 @@ ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); - copy = ngx_array_push_n(conf->headers_set, size); + copy = ngx_array_push_n(headers->values, size); if (copy == NULL) { return NGX_ERROR; } @@ -3054,16 +3523,16 @@ ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, sc.cf = cf; sc.source = &src[i].value; - sc.flushes = &conf->flushes; - sc.lengths = &conf->headers_set_len; - sc.values = &conf->headers_set; + sc.flushes = &headers->flushes; + sc.lengths = &headers->lengths; + sc.values = &headers->values; if (ngx_http_script_compile(&sc) != NGX_OK) { return NGX_ERROR; } - copy = ngx_array_push_n(conf->headers_set_len, + copy = ngx_array_push_n(headers->lengths, sizeof(ngx_http_script_copy_code_t)); if (copy == NULL) { return NGX_ERROR; @@ -3078,7 +3547,7 @@ ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); - copy = ngx_array_push_n(conf->headers_set, size); + copy = ngx_array_push_n(headers->values, size); if (copy == NULL) { return NGX_ERROR; } @@ -3090,14 +3559,14 @@ ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, *p++ = CR; *p = LF; } - code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t)); + code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t)); if (code == NULL) { return NGX_ERROR; } *code = (uintptr_t) NULL; - code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t)); + code = ngx_array_push_n(headers->values, sizeof(uintptr_t)); if (code == NULL) { return NGX_ERROR; } @@ -3105,7 +3574,7 @@ ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, *code = (uintptr_t) NULL; } - code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t)); + code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t)); if (code == NULL) { return NGX_ERROR; } @@ -3113,7 +3582,7 @@ ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, *code = (uintptr_t) NULL; - hash.hash = &conf->headers_set_hash; + hash.hash = &headers->hash; hash.key = ngx_hash_key_lc; hash.max_size = conf->headers_hash_max_size; hash.bucket_size = conf->headers_hash_bucket_size; @@ -3612,9 +4081,7 @@ ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; ngx_http_script_compile_t sc; - if (plcf->upstream.store != NGX_CONF_UNSET - || plcf->upstream.store_lengths) - { + if (plcf->upstream.store != NGX_CONF_UNSET) { return "is duplicate"; } @@ -3626,17 +4093,14 @@ ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } #if (NGX_HTTP_CACHE) - - if (plcf->upstream.cache != NGX_CONF_UNSET_PTR - && plcf->upstream.cache != NULL) - { + if (plcf->upstream.cache > 0) { return "is incompatible with \"proxy_cache\""; } - #endif + plcf->upstream.store = 1; + if (ngx_strcmp(value[1].data, "on") == 0) { - plcf->upstream.store = 1; return NGX_CONF_OK; } @@ -3668,26 +4132,53 @@ ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_proxy_loc_conf_t *plcf = conf; - ngx_str_t *value; + ngx_str_t *value; + ngx_http_complex_value_t cv; + ngx_http_compile_complex_value_t ccv; value = cf->args->elts; - if (plcf->upstream.cache != NGX_CONF_UNSET_PTR) { + if (plcf->upstream.cache != NGX_CONF_UNSET) { return "is duplicate"; } if (ngx_strcmp(value[1].data, "off") == 0) { - plcf->upstream.cache = NULL; + plcf->upstream.cache = 0; return NGX_CONF_OK; } - if (plcf->upstream.store > 0 || plcf->upstream.store_lengths) { + if (plcf->upstream.store > 0) { return "is incompatible with \"proxy_store\""; } - plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, - &ngx_http_proxy_module); - if (plcf->upstream.cache == NULL) { + plcf->upstream.cache = 1; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + + plcf->upstream.cache_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (plcf->upstream.cache_value == NULL) { + return NGX_CONF_ERROR; + } + + *plcf->upstream.cache_value = cv; + + return NGX_CONF_OK; + } + + plcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_proxy_module); + if (plcf->upstream.cache_zone == NULL) { return NGX_CONF_ERROR; } @@ -3725,6 +4216,33 @@ ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif +#if (NGX_HTTP_SSL) + +static char * +ngx_http_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_proxy_loc_conf_t *plcf = conf; + + ngx_str_t *value; + + if (plcf->ssl_passwords != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + plcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); + + if (plcf->ssl_passwords == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + +#endif + + static char * ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data) { @@ -3774,6 +4292,31 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) return NGX_ERROR; } + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_ssl_cleanup_ctx; + cln->data = plcf->upstream.ssl; + + if (plcf->ssl_certificate.len) { + + if (plcf->ssl_certificate_key.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"proxy_ssl_certificate_key\" is defined " + "for certificate \"%V\"", &plcf->ssl_certificate); + return NGX_ERROR; + } + + if (ngx_ssl_certificate(cf, plcf->upstream.ssl, &plcf->ssl_certificate, + &plcf->ssl_certificate_key, plcf->ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + } + if (SSL_CTX_set_cipher_list(plcf->upstream.ssl->ctx, (const char *) plcf->ssl_ciphers.data) == 0) @@ -3784,13 +4327,25 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) return NGX_ERROR; } - cln = ngx_pool_cleanup_add(cf->pool, 0); - if (cln == NULL) { - return NGX_ERROR; - } + if (plcf->upstream.ssl_verify) { + if (plcf->ssl_trusted_certificate.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no proxy_ssl_trusted_certificate for proxy_ssl_verify"); + return NGX_ERROR; + } - cln->handler = ngx_ssl_cleanup_ctx; - cln->data = plcf->upstream.ssl; + if (ngx_ssl_trusted_certificate(cf, plcf->upstream.ssl, + &plcf->ssl_trusted_certificate, + plcf->ssl_verify_depth) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_ssl_crl(cf, plcf->upstream.ssl, &plcf->ssl_crl) != NGX_OK) { + return NGX_ERROR; + } + } return NGX_OK; } diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c index 4081f87..f241196 100644 --- a/src/http/modules/ngx_http_rewrite_module.c +++ b/src/http/modules/ngx_http_rewrite_module.c @@ -930,7 +930,11 @@ ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (v->get_handler == NULL && ngx_strncasecmp(value[1].data, (u_char *) "http_", 5) != 0 && ngx_strncasecmp(value[1].data, (u_char *) "sent_http_", 10) != 0 - && ngx_strncasecmp(value[1].data, (u_char *) "upstream_http_", 14) != 0) + && ngx_strncasecmp(value[1].data, (u_char *) "upstream_http_", 14) != 0 + && ngx_strncasecmp(value[1].data, (u_char *) "cookie_", 7) != 0 + && ngx_strncasecmp(value[1].data, (u_char *) "upstream_cookie_", 16) + != 0 + && ngx_strncasecmp(value[1].data, (u_char *) "arg_", 4) != 0) { v->get_handler = ngx_http_rewrite_var; v->data = index; diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index 884cb50..6e5b077 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -11,17 +11,29 @@ #include +typedef struct { + ngx_array_t caches; /* ngx_http_file_cache_t * */ +} ngx_http_scgi_main_conf_t; + + +typedef struct { + ngx_array_t *flushes; + ngx_array_t *lengths; + ngx_array_t *values; + ngx_uint_t number; + ngx_hash_t hash; +} ngx_http_scgi_params_t; + + typedef struct { ngx_http_upstream_conf_t upstream; - ngx_array_t *flushes; - ngx_array_t *params_len; - ngx_array_t *params; + ngx_http_scgi_params_t params; +#if (NGX_HTTP_CACHE) + ngx_http_scgi_params_t params_cache; +#endif ngx_array_t *params_source; - ngx_hash_t headers_hash; - ngx_uint_t header_params; - ngx_array_t *scgi_lengths; ngx_array_t *scgi_values; @@ -40,11 +52,13 @@ static ngx_int_t ngx_http_scgi_process_header(ngx_http_request_t *r); static void ngx_http_scgi_abort_request(ngx_http_request_t *r); static void ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc); +static void *ngx_http_scgi_create_main_conf(ngx_conf_t *cf); static void *ngx_http_scgi_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); -static ngx_int_t ngx_http_scgi_merge_params(ngx_conf_t *cf, - ngx_http_scgi_loc_conf_t *conf, ngx_http_scgi_loc_conf_t *prev); +static ngx_int_t ngx_http_scgi_init_params(ngx_conf_t *cf, + ngx_http_scgi_loc_conf_t *conf, ngx_http_scgi_params_t *params, + ngx_keyval_t *default_params); static char *ngx_http_scgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, @@ -106,6 +120,13 @@ static ngx_command_t ngx_http_scgi_commands[] = { offsetof(ngx_http_scgi_loc_conf_t, upstream.buffering), NULL }, + { ngx_string("scgi_request_buffering"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_scgi_loc_conf_t, upstream.request_buffering), + NULL }, + { ngx_string("scgi_ignore_client_abort"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -183,6 +204,20 @@ static ngx_command_t ngx_http_scgi_commands[] = { offsetof(ngx_http_scgi_loc_conf_t, upstream.busy_buffers_size_conf), NULL }, + { ngx_string("scgi_force_ranges"), + 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.force_ranges), + NULL }, + + { ngx_string("scgi_limit_rate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_scgi_loc_conf_t, upstream.limit_rate), + NULL }, + #if (NGX_HTTP_CACHE) { ngx_string("scgi_cache"), @@ -202,8 +237,8 @@ static ngx_command_t ngx_http_scgi_commands[] = { { ngx_string("scgi_cache_path"), NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE, ngx_http_file_cache_set_slot, - 0, - 0, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_scgi_main_conf_t, caches), &ngx_http_scgi_module }, { ngx_string("scgi_cache_bypass"), @@ -262,6 +297,13 @@ static ngx_command_t ngx_http_scgi_commands[] = { offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock_timeout), NULL }, + { ngx_string("scgi_cache_lock_age"), + 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_age), + NULL }, + { ngx_string("scgi_cache_revalidate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -299,6 +341,20 @@ static ngx_command_t ngx_http_scgi_commands[] = { offsetof(ngx_http_scgi_loc_conf_t, upstream.next_upstream), &ngx_http_scgi_next_upstream_masks }, + { ngx_string("scgi_next_upstream_tries"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_scgi_loc_conf_t, upstream.next_upstream_tries), + NULL }, + + { ngx_string("scgi_next_upstream_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.next_upstream_timeout), + NULL }, + { ngx_string("scgi_param"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23, ngx_http_upstream_param_set_slot, @@ -335,7 +391,7 @@ static ngx_http_module_t ngx_http_scgi_module_ctx = { NULL, /* preconfiguration */ NULL, /* postconfiguration */ - NULL, /* create main configuration */ + ngx_http_scgi_create_main_conf, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ @@ -379,7 +435,7 @@ static ngx_keyval_t ngx_http_scgi_cache_headers[] = { { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("$upstream_cache_last_modified") }, { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") }, - { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") }, + { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("$upstream_cache_etag") }, { ngx_string("HTTP_IF_MATCH"), ngx_string("") }, { ngx_string("HTTP_RANGE"), ngx_string("") }, { ngx_string("HTTP_IF_RANGE"), ngx_string("") }, @@ -397,10 +453,13 @@ static ngx_path_init_t ngx_http_scgi_temp_path = { static ngx_int_t ngx_http_scgi_handler(ngx_http_request_t *r) { - ngx_int_t rc; - ngx_http_status_t *status; - ngx_http_upstream_t *u; - ngx_http_scgi_loc_conf_t *scf; + ngx_int_t rc; + ngx_http_status_t *status; + ngx_http_upstream_t *u; + ngx_http_scgi_loc_conf_t *scf; +#if (NGX_HTTP_CACHE) + ngx_http_scgi_main_conf_t *smcf; +#endif if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -429,8 +488,12 @@ ngx_http_scgi_handler(ngx_http_request_t *r) u->conf = &scf->upstream; #if (NGX_HTTP_CACHE) + smcf = ngx_http_get_module_main_conf(r, ngx_http_scgi_module); + + u->caches = &smcf->caches; u->create_key = ngx_http_scgi_create_key; #endif + u->create_request = ngx_http_scgi_create_request; u->reinit_request = ngx_http_scgi_reinit_request; u->process_header = ngx_http_scgi_process_status_line; @@ -448,6 +511,13 @@ ngx_http_scgi_handler(ngx_http_request_t *r) u->pipe->input_filter = ngx_event_pipe_copy_input_filter; u->pipe->input_ctx = r; + if (!scf->upstream.request_buffering + && scf->upstream.pass_request_body + && !r->headers_in.chunked) + { + r->request_body_no_buffering = 1; + } + rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { @@ -544,6 +614,7 @@ ngx_http_scgi_create_request(ngx_http_request_t *r) ngx_chain_t *cl, *body; ngx_list_part_t *part; ngx_table_elt_t *header, **ignored; + ngx_http_scgi_params_t *params; ngx_http_script_code_pt code; ngx_http_script_engine_t e, le; ngx_http_scgi_loc_conf_t *scf; @@ -568,13 +639,19 @@ ngx_http_scgi_create_request(ngx_http_request_t *r) scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module); - if (scf->params_len) { +#if (NGX_HTTP_CACHE) + params = r->upstream->cacheable ? &scf->params_cache : &scf->params; +#else + params = &scf->params; +#endif + + if (params->lengths) { ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); - ngx_http_script_flush_no_cacheable_variables(r, scf->flushes); + ngx_http_script_flush_no_cacheable_variables(r, params->flushes); le.flushed = 1; - le.ip = scf->params_len->elts; + le.ip = params->lengths->elts; le.request = r; while (*(uintptr_t *) le.ip) { @@ -603,7 +680,7 @@ ngx_http_scgi_create_request(ngx_http_request_t *r) allocated = 0; lowcase_key = NULL; - if (scf->header_params) { + if (params->number) { n = 0; part = &r->headers_in.headers.part; @@ -633,7 +710,7 @@ ngx_http_scgi_create_request(ngx_http_request_t *r) i = 0; } - if (scf->header_params) { + if (params->number) { if (allocated < header[i].key.len) { allocated = header[i].key.len + 16; lowcase_key = ngx_pnalloc(r->pool, allocated); @@ -658,7 +735,7 @@ ngx_http_scgi_create_request(ngx_http_request_t *r) lowcase_key[n] = ch; } - if (ngx_hash_find(&scf->headers_hash, hash, lowcase_key, n)) { + if (ngx_hash_find(¶ms->hash, hash, lowcase_key, n)) { ignored[header_params++] = &header[i]; continue; } @@ -686,15 +763,15 @@ ngx_http_scgi_create_request(ngx_http_request_t *r) b->last = ngx_sprintf(b->last, "%ui:CONTENT_LENGTH%Z%V%Z", len, &content_length); - if (scf->params_len) { + if (params->lengths) { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); - e.ip = scf->params->elts; + e.ip = params->values->elts; e.pos = b->last; e.request = r; e.flushed = 1; - le.ip = scf->params_len->elts; + le.ip = params->lengths->elts; while (*(uintptr_t *) le.ip) { @@ -802,7 +879,10 @@ ngx_http_scgi_create_request(ngx_http_request_t *r) *b->last++ = (u_char) ','; - if (scf->upstream.pass_request_body) { + if (r->request_body_no_buffering) { + r->upstream->request_bufs = cl; + + } else if (scf->upstream.pass_request_body) { body = r->upstream->request_bufs; r->upstream->request_bufs = cl; @@ -1062,6 +1142,29 @@ ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc) } +static void * +ngx_http_scgi_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_scgi_main_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_scgi_main_conf_t)); + if (conf == NULL) { + return NULL; + } + +#if (NGX_HTTP_CACHE) + if (ngx_array_init(&conf->caches, cf->pool, 4, + sizeof(ngx_http_file_cache_t *)) + != NGX_OK) + { + return NULL; + } +#endif + + return conf; +} + + static void * ngx_http_scgi_create_loc_conf(ngx_conf_t *cf) { @@ -1074,17 +1177,22 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t *cf) conf->upstream.store = NGX_CONF_UNSET; conf->upstream.store_access = NGX_CONF_UNSET_UINT; + conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT; conf->upstream.buffering = NGX_CONF_UNSET; + conf->upstream.request_buffering = NGX_CONF_UNSET; conf->upstream.ignore_client_abort = NGX_CONF_UNSET; + conf->upstream.force_ranges = NGX_CONF_UNSET; conf->upstream.local = NGX_CONF_UNSET_PTR; conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; + conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE; conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE; conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; @@ -1094,13 +1202,14 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t *cf) conf->upstream.pass_request_body = NGX_CONF_UNSET; #if (NGX_HTTP_CACHE) - conf->upstream.cache = NGX_CONF_UNSET_PTR; + conf->upstream.cache = NGX_CONF_UNSET; conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT; 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; + conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC; conf->upstream.cache_revalidate = NGX_CONF_UNSET; #endif @@ -1127,27 +1236,47 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_scgi_loc_conf_t *conf = child; size_t size; + ngx_int_t rc; ngx_hash_init_t hash; ngx_http_core_loc_conf_t *clcf; - if (conf->upstream.store != 0) { +#if (NGX_HTTP_CACHE) + + if (conf->upstream.store > 0) { + conf->upstream.cache = 0; + } + + if (conf->upstream.cache > 0) { + conf->upstream.store = 0; + } + +#endif + + if (conf->upstream.store == NGX_CONF_UNSET) { ngx_conf_merge_value(conf->upstream.store, prev->upstream.store, 0); - if (conf->upstream.store_lengths == NULL) { - conf->upstream.store_lengths = prev->upstream.store_lengths; - conf->upstream.store_values = prev->upstream.store_values; - } + conf->upstream.store_lengths = prev->upstream.store_lengths; + conf->upstream.store_values = prev->upstream.store_values; } ngx_conf_merge_uint_value(conf->upstream.store_access, prev->upstream.store_access, 0600); + ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries, + prev->upstream.next_upstream_tries, 0); + ngx_conf_merge_value(conf->upstream.buffering, prev->upstream.buffering, 1); + ngx_conf_merge_value(conf->upstream.request_buffering, + prev->upstream.request_buffering, 1); + ngx_conf_merge_value(conf->upstream.ignore_client_abort, prev->upstream.ignore_client_abort, 0); + ngx_conf_merge_value(conf->upstream.force_ranges, + prev->upstream.force_ranges, 0); + ngx_conf_merge_ptr_value(conf->upstream.local, prev->upstream.local, NULL); @@ -1160,6 +1289,9 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->upstream.read_timeout, prev->upstream.read_timeout, 60000); + ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout, + prev->upstream.next_upstream_timeout, 0); + ngx_conf_merge_size_value(conf->upstream.send_lowat, prev->upstream.send_lowat, 0); @@ -1167,6 +1299,9 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->upstream.buffer_size, (size_t) ngx_pagesize); + ngx_conf_merge_size_value(conf->upstream.limit_rate, + prev->upstream.limit_rate, 0); + ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, 8, ngx_pagesize); @@ -1248,7 +1383,8 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) } if (conf->upstream.max_temp_file_size != 0 - && conf->upstream.max_temp_file_size < size) { + && 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 " "temporary files usage or must be equal to or greater than " @@ -1285,13 +1421,18 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #if (NGX_HTTP_CACHE) - ngx_conf_merge_ptr_value(conf->upstream.cache, - prev->upstream.cache, NULL); + if (conf->upstream.cache == NGX_CONF_UNSET) { + ngx_conf_merge_value(conf->upstream.cache, + prev->upstream.cache, 0); - if (conf->upstream.cache && conf->upstream.cache->data == NULL) { + conf->upstream.cache_zone = prev->upstream.cache_zone; + conf->upstream.cache_value = prev->upstream.cache_value; + } + + if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) { ngx_shm_zone_t *shm_zone; - shm_zone = conf->upstream.cache; + shm_zone = conf->upstream.cache_zone; ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"scgi_cache\" zone \"%V\" is unknown", @@ -1336,12 +1477,20 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) conf->cache_key = prev->cache_key; } + if (conf->upstream.cache && conf->cache_key.value.data == NULL) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "no \"scgi_cache_key\" for \"scgi_cache\""); + } + 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); + ngx_conf_merge_msec_value(conf->upstream.cache_lock_age, + prev->upstream.cache_lock_age, 5000); + ngx_conf_merge_value(conf->upstream.cache_revalidate, prev->upstream.cache_revalidate, 0); @@ -1366,85 +1515,83 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } - if (conf->upstream.upstream == NULL) { - conf->upstream.upstream = prev->upstream.upstream; - } + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); - if (conf->scgi_lengths == NULL) { + if (clcf->noname + && conf->upstream.upstream == NULL && conf->scgi_lengths == NULL) + { + conf->upstream.upstream = prev->upstream.upstream; conf->scgi_lengths = prev->scgi_lengths; conf->scgi_values = prev->scgi_values; } - if (conf->upstream.upstream || conf->scgi_lengths) { - clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); - if (clcf->handler == NULL && clcf->lmt_excpt) { - clcf->handler = ngx_http_scgi_handler; + if (clcf->lmt_excpt && clcf->handler == NULL + && (conf->upstream.upstream || conf->scgi_lengths)) + { + clcf->handler = ngx_http_scgi_handler; + } + + if (conf->params_source == NULL) { + conf->params = prev->params; +#if (NGX_HTTP_CACHE) + conf->params_cache = prev->params_cache; +#endif + conf->params_source = prev->params_source; + } + + rc = ngx_http_scgi_init_params(cf, conf, &conf->params, NULL); + if (rc != NGX_OK) { + return NGX_CONF_ERROR; + } + +#if (NGX_HTTP_CACHE) + + if (conf->upstream.cache) { + rc = ngx_http_scgi_init_params(cf, conf, &conf->params_cache, + ngx_http_scgi_cache_headers); + if (rc != NGX_OK) { + return NGX_CONF_ERROR; } } - if (ngx_http_scgi_merge_params(cf, conf, prev) != NGX_OK) { - return NGX_CONF_ERROR; - } +#endif return NGX_CONF_OK; } static ngx_int_t -ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf, - ngx_http_scgi_loc_conf_t *prev) +ngx_http_scgi_init_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf, + ngx_http_scgi_params_t *params, ngx_keyval_t *default_params) { u_char *p; size_t size; uintptr_t *code; ngx_uint_t i, nsrc; - ngx_array_t headers_names; -#if (NGX_HTTP_CACHE) - ngx_array_t params_merged; -#endif + ngx_array_t headers_names, params_merged; + ngx_keyval_t *h; ngx_hash_key_t *hk; ngx_hash_init_t hash; - ngx_http_upstream_param_t *src; + ngx_http_upstream_param_t *src, *s; ngx_http_script_compile_t sc; ngx_http_script_copy_code_t *copy; - if (conf->params_source == NULL) { - conf->params_source = prev->params_source; - - if (prev->headers_hash.buckets -#if (NGX_HTTP_CACHE) - && ((conf->upstream.cache == NULL) - == (prev->upstream.cache == NULL)) -#endif - ) - { - conf->flushes = prev->flushes; - conf->params_len = prev->params_len; - conf->params = prev->params; - conf->headers_hash = prev->headers_hash; - conf->header_params = prev->header_params; - - return NGX_OK; - } - } - - if (conf->params_source == NULL -#if (NGX_HTTP_CACHE) - && (conf->upstream.cache == NULL) -#endif - ) - { - conf->headers_hash.buckets = (void *) 1; + if (params->hash.buckets) { return NGX_OK; } - conf->params_len = ngx_array_create(cf->pool, 64, 1); - if (conf->params_len == NULL) { + if (conf->params_source == NULL && default_params == NULL) { + params->hash.buckets = (void *) 1; + return NGX_OK; + } + + params->lengths = ngx_array_create(cf->pool, 64, 1); + if (params->lengths == NULL) { return NGX_ERROR; } - conf->params = ngx_array_create(cf->pool, 512, 1); - if (conf->params == NULL) { + params->values = ngx_array_create(cf->pool, 512, 1); + if (params->values == NULL) { return NGX_ERROR; } @@ -1463,12 +1610,7 @@ ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf, nsrc = 0; } -#if (NGX_HTTP_CACHE) - - if (conf->upstream.cache) { - ngx_keyval_t *h; - ngx_http_upstream_param_t *s; - + if (default_params) { if (ngx_array_init(¶ms_merged, cf->temp_pool, 4, sizeof(ngx_http_upstream_param_t)) != NGX_OK) @@ -1486,7 +1628,7 @@ ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf, *s = src[i]; } - h = ngx_http_scgi_cache_headers; + h = default_params; while (h->key.len) { @@ -1517,8 +1659,6 @@ ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf, nsrc = params_merged.nelts; } -#endif - for (i = 0; i < nsrc; i++) { if (src[i].key.len > sizeof("HTTP_") - 1 @@ -1539,7 +1679,7 @@ ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf, } } - copy = ngx_array_push_n(conf->params_len, + copy = ngx_array_push_n(params->lengths, sizeof(ngx_http_script_copy_code_t)); if (copy == NULL) { return NGX_ERROR; @@ -1548,7 +1688,7 @@ 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, + copy = ngx_array_push_n(params->lengths, sizeof(ngx_http_script_copy_code_t)); if (copy == NULL) { return NGX_ERROR; @@ -1562,7 +1702,7 @@ ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf, + src[i].key.len + 1 + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); - copy = ngx_array_push_n(conf->params, size); + copy = ngx_array_push_n(params->values, size); if (copy == NULL) { return NGX_ERROR; } @@ -1578,15 +1718,15 @@ ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf, sc.cf = cf; sc.source = &src[i].value; - sc.flushes = &conf->flushes; - sc.lengths = &conf->params_len; - sc.values = &conf->params; + sc.flushes = ¶ms->flushes; + sc.lengths = ¶ms->lengths; + sc.values = ¶ms->values; if (ngx_http_script_compile(&sc) != NGX_OK) { return NGX_ERROR; } - code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t)); + code = ngx_array_push_n(params->lengths, sizeof(uintptr_t)); if (code == NULL) { return NGX_ERROR; } @@ -1594,7 +1734,7 @@ ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf, *code = (uintptr_t) NULL; - code = ngx_array_push_n(conf->params, sizeof(uintptr_t)); + code = ngx_array_push_n(params->values, sizeof(uintptr_t)); if (code == NULL) { return NGX_ERROR; } @@ -1602,23 +1742,16 @@ ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf, *code = (uintptr_t) NULL; } - code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t)); + code = ngx_array_push_n(params->lengths, sizeof(uintptr_t)); if (code == NULL) { return NGX_ERROR; } *code = (uintptr_t) NULL; - code = ngx_array_push_n(conf->params, sizeof(uintptr_t)); - if (code == NULL) { - return NGX_ERROR; - } + params->number = headers_names.nelts; - *code = (uintptr_t) NULL; - - conf->header_params = headers_names.nelts; - - hash.hash = &conf->headers_hash; + hash.hash = ¶ms->hash; hash.key = ngx_hash_key_lc; hash.max_size = 512; hash.bucket_size = 64; @@ -1645,7 +1778,7 @@ ngx_http_scgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return "is duplicate"; } - clcf = ngx_http_conf_get_module_loc_conf (cf, ngx_http_core_module); + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); clcf->handler = ngx_http_scgi_handler; value = cf->args->elts; @@ -1699,7 +1832,7 @@ ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; ngx_http_script_compile_t sc; - if (scf->upstream.store != NGX_CONF_UNSET || scf->upstream.store_lengths) { + if (scf->upstream.store != NGX_CONF_UNSET) { return "is duplicate"; } @@ -1711,17 +1844,14 @@ ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } #if (NGX_HTTP_CACHE) - - if (scf->upstream.cache != NGX_CONF_UNSET_PTR - && scf->upstream.cache != NULL) - { + if (scf->upstream.cache > 0) { return "is incompatible with \"scgi_cache\""; } - #endif + scf->upstream.store = 1; + if (ngx_strcmp(value[1].data, "on") == 0) { - scf->upstream.store = 1; return NGX_CONF_OK; } @@ -1753,26 +1883,53 @@ ngx_http_scgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_scgi_loc_conf_t *scf = conf; - ngx_str_t *value; + ngx_str_t *value; + ngx_http_complex_value_t cv; + ngx_http_compile_complex_value_t ccv; value = cf->args->elts; - if (scf->upstream.cache != NGX_CONF_UNSET_PTR) { + if (scf->upstream.cache != NGX_CONF_UNSET) { return "is duplicate"; } if (ngx_strcmp(value[1].data, "off") == 0) { - scf->upstream.cache = NULL; + scf->upstream.cache = 0; return NGX_CONF_OK; } - if (scf->upstream.store > 0 || scf->upstream.store_lengths) { + if (scf->upstream.store > 0) { return "is incompatible with \"scgi_store\""; } - scf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, - &ngx_http_scgi_module); - if (scf->upstream.cache == NULL) { + scf->upstream.cache = 1; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + + scf->upstream.cache_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (scf->upstream.cache_value == NULL) { + return NGX_CONF_ERROR; + } + + *scf->upstream.cache_value = cv; + + return NGX_CONF_OK; + } + + scf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_scgi_module); + if (scf->upstream.cache_zone == NULL) { return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index aeb1376..8236320 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -369,10 +369,13 @@ ngx_http_ssi_header_filter(ngx_http_request_t *r) if (r == r->main) { ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); - ngx_http_clear_etag(r); if (!slcf->last_modified) { ngx_http_clear_last_modified(r); + ngx_http_clear_etag(r); + + } else { + ngx_http_weak_etag(r); } } diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 206f58d..d6a1794 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -43,6 +43,8 @@ static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, static char *ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -91,6 +93,13 @@ static ngx_command_t ngx_http_ssl_commands[] = { offsetof(ngx_http_ssl_srv_conf_t, certificate_key), NULL }, + { ngx_string("ssl_password_file"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_ssl_password_file, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL }, + { ngx_string("ssl_dhparam"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, @@ -273,6 +282,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_session_reused"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_session_reused, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_server_name"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_server_name, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_cert"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 }, @@ -289,6 +301,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_client_serial"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_serial_number, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_fingerprint"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_fingerprint, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_verify"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_client_verify, NGX_HTTP_VAR_CHANGEABLE, 0 }, @@ -508,6 +523,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) sscf->buffer_size = NGX_CONF_UNSET_SIZE; sscf->verify = NGX_CONF_UNSET_UINT; sscf->verify_depth = NGX_CONF_UNSET_UINT; + sscf->passwords = NGX_CONF_UNSET_PTR; sscf->builtin_session_cache = NGX_CONF_UNSET; sscf->session_timeout = NGX_CONF_UNSET; sscf->session_tickets = NGX_CONF_UNSET; @@ -545,7 +561,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) prev->prefer_server_ciphers, 0); ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3|NGX_SSL_TLSv1 + (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, @@ -557,6 +573,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->certificate, prev->certificate, ""); ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, ""); + ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL); + ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate, @@ -646,7 +664,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) cln->data = &conf->ssl; if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate, - &conf->certificate_key) + &conf->certificate_key, conf->passwords) != NGX_OK) { return NGX_CONF_ERROR; @@ -697,8 +715,10 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } +#ifndef LIBRESSL_VERSION_NUMBER /* a temporary 512-bit RSA key is required for export versions of MSIE */ SSL_CTX_set_tmp_rsa_callback(conf->ssl.ctx, ngx_ssl_rsa512_key_callback); +#endif if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { return NGX_CONF_ERROR; @@ -775,6 +795,29 @@ ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +static char * +ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_ssl_srv_conf_t *sscf = conf; + + ngx_str_t *value; + + if (sscf->passwords != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + sscf->passwords = ngx_ssl_read_password_file(cf, &value[1]); + + if (sscf->passwords == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + static char * ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h index ec2c62f..8e69e9e 100644 --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -42,6 +42,8 @@ typedef struct { ngx_str_t ciphers; + ngx_array_t *passwords; + ngx_shm_zone_t *shm_zone; ngx_flag_t session_tickets; diff --git a/src/http/modules/ngx_http_stub_status_module.c b/src/http/modules/ngx_http_stub_status_module.c index b5ecd6d..dd68358 100644 --- a/src/http/modules/ngx_http_stub_status_module.c +++ b/src/http/modules/ngx_http_stub_status_module.c @@ -10,18 +10,19 @@ #include +static ngx_int_t ngx_http_stub_status_handler(ngx_http_request_t *r); static ngx_int_t ngx_http_stub_status_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_stub_status_add_variables(ngx_conf_t *cf); +static char *ngx_http_set_stub_status(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); -static char *ngx_http_set_status(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); static ngx_command_t ngx_http_status_commands[] = { { ngx_string("stub_status"), - NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, - ngx_http_set_status, + NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1, + ngx_http_set_stub_status, 0, 0, NULL }, @@ -30,7 +31,6 @@ static ngx_command_t ngx_http_status_commands[] = { }; - static ngx_http_module_t ngx_http_stub_status_module_ctx = { ngx_http_stub_status_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ @@ -80,7 +80,8 @@ static ngx_http_variable_t ngx_http_stub_status_vars[] = { }; -static ngx_int_t ngx_http_status_handler(ngx_http_request_t *r) +static ngx_int_t +ngx_http_stub_status_handler(ngx_http_request_t *r) { size_t size; ngx_int_t rc; @@ -223,12 +224,13 @@ ngx_http_stub_status_add_variables(ngx_conf_t *cf) } -static char *ngx_http_set_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +static char * +ngx_http_set_stub_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_core_loc_conf_t *clcf; clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); - clcf->handler = ngx_http_status_handler; + clcf->handler = ngx_http_stub_status_handler; return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c index a4d666b..e6a34a7 100644 --- a/src/http/modules/ngx_http_sub_filter_module.c +++ b/src/http/modules/ngx_http_sub_filter_module.c @@ -175,10 +175,13 @@ ngx_http_sub_header_filter(ngx_http_request_t *r) if (r == r->main) { ngx_http_clear_content_length(r); - ngx_http_clear_etag(r); if (!slcf->last_modified) { ngx_http_clear_last_modified(r); + ngx_http_clear_etag(r); + + } else { + ngx_http_weak_etag(r); } } @@ -305,6 +308,7 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) b->last = ctx->copy_end; b->shadow = NULL; b->last_buf = 0; + b->last_in_chain = 0; b->recycled = 0; if (b->in_file) { @@ -374,7 +378,9 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) continue; } - if (ctx->buf->last_buf && ctx->looked.len) { + if (ctx->looked.len + && (ctx->buf->last_buf || ctx->buf->last_in_chain)) + { cl = ngx_chain_get_free_buf(r->pool, &ctx->free); if (cl == NULL) { return NGX_ERROR; @@ -394,7 +400,7 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ctx->looked.len = 0; } - if (ctx->buf->last_buf || ctx->buf->flush + if (ctx->buf->last_buf || ctx->buf->flush || ctx->buf->sync || ngx_buf_in_memory(ctx->buf)) { if (b == NULL) { @@ -414,6 +420,7 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) } b->last_buf = ctx->buf->last_buf; + b->last_in_chain = ctx->buf->last_in_chain; b->flush = ctx->buf->flush; b->shadow = ctx->buf; @@ -539,6 +546,14 @@ ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) for ( ;; ) { if (ch == match) { + + if (ctx->match.len == 1) { + ctx->pos = p + 1; + ctx->copy_end = p; + + return NGX_OK; + } + copy_end = p; ctx->looked.data[0] = *p; looked = 1; diff --git a/src/http/modules/ngx_http_upstream_hash_module.c b/src/http/modules/ngx_http_upstream_hash_module.c new file mode 100644 index 0000000..1e2e05c --- /dev/null +++ b/src/http/modules/ngx_http_upstream_hash_module.c @@ -0,0 +1,667 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + uint32_t hash; + ngx_str_t *server; +} ngx_http_upstream_chash_point_t; + + +typedef struct { + ngx_uint_t number; + ngx_http_upstream_chash_point_t point[1]; +} ngx_http_upstream_chash_points_t; + + +typedef struct { + ngx_http_complex_value_t key; + ngx_http_upstream_chash_points_t *points; +} ngx_http_upstream_hash_srv_conf_t; + + +typedef struct { + /* the round robin data must be first */ + ngx_http_upstream_rr_peer_data_t rrp; + ngx_http_upstream_hash_srv_conf_t *conf; + ngx_str_t key; + ngx_uint_t tries; + ngx_uint_t rehash; + uint32_t hash; + ngx_event_get_peer_pt get_rr_peer; +} ngx_http_upstream_hash_peer_data_t; + + +static ngx_int_t ngx_http_upstream_init_hash(ngx_conf_t *cf, + ngx_http_upstream_srv_conf_t *us); +static ngx_int_t ngx_http_upstream_init_hash_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us); +static ngx_int_t ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, + void *data); + +static ngx_int_t ngx_http_upstream_init_chash(ngx_conf_t *cf, + ngx_http_upstream_srv_conf_t *us); +static int ngx_libc_cdecl + ngx_http_upstream_chash_cmp_points(const void *one, const void *two); +static ngx_uint_t ngx_http_upstream_find_chash_point( + ngx_http_upstream_chash_points_t *points, uint32_t hash); +static ngx_int_t ngx_http_upstream_init_chash_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us); +static ngx_int_t ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, + void *data); + +static void *ngx_http_upstream_hash_create_conf(ngx_conf_t *cf); +static char *ngx_http_upstream_hash(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_command_t ngx_http_upstream_hash_commands[] = { + + { ngx_string("hash"), + NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12, + ngx_http_upstream_hash, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_upstream_hash_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_http_upstream_hash_create_conf, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_upstream_hash_module = { + NGX_MODULE_V1, + &ngx_http_upstream_hash_module_ctx, /* module context */ + ngx_http_upstream_hash_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_hash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) +{ + if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) { + return NGX_ERROR; + } + + us->peer.init = ngx_http_upstream_init_hash_peer; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_init_hash_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us) +{ + ngx_http_upstream_hash_srv_conf_t *hcf; + ngx_http_upstream_hash_peer_data_t *hp; + + hp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_hash_peer_data_t)); + if (hp == NULL) { + return NGX_ERROR; + } + + r->upstream->peer.data = &hp->rrp; + + if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) { + return NGX_ERROR; + } + + r->upstream->peer.get = ngx_http_upstream_get_hash_peer; + + hcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_hash_module); + + if (ngx_http_complex_value(r, &hcf->key, &hp->key) != NGX_OK) { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "upstream hash key:\"%V\"", &hp->key); + + hp->conf = hcf; + hp->tries = 0; + hp->rehash = 0; + hp->hash = 0; + hp->get_rr_peer = ngx_http_upstream_get_round_robin_peer; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) +{ + ngx_http_upstream_hash_peer_data_t *hp = data; + + time_t now; + u_char buf[NGX_INT_T_LEN]; + size_t size; + uint32_t hash; + ngx_int_t w; + uintptr_t m; + ngx_uint_t n, p; + ngx_http_upstream_rr_peer_t *peer; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "get hash peer, try: %ui", pc->tries); + + ngx_http_upstream_rr_peers_wlock(hp->rrp.peers); + + if (hp->tries > 20 || hp->rrp.peers->single) { + ngx_http_upstream_rr_peers_unlock(hp->rrp.peers); + return hp->get_rr_peer(pc, &hp->rrp); + } + + now = ngx_time(); + + pc->cached = 0; + pc->connection = NULL; + + for ( ;; ) { + + /* + * Hash expression is compatible with Cache::Memcached: + * ((crc32([REHASH] KEY) >> 16) & 0x7fff) + PREV_HASH + * with REHASH omitted at the first iteration. + */ + + ngx_crc32_init(hash); + + if (hp->rehash > 0) { + size = ngx_sprintf(buf, "%ui", hp->rehash) - buf; + ngx_crc32_update(&hash, buf, size); + } + + ngx_crc32_update(&hash, hp->key.data, hp->key.len); + ngx_crc32_final(hash); + + hash = (hash >> 16) & 0x7fff; + + hp->hash += hash; + hp->rehash++; + + w = hp->hash % hp->rrp.peers->total_weight; + peer = hp->rrp.peers->peer; + p = 0; + + while (w >= peer->weight) { + w -= peer->weight; + peer = peer->next; + p++; + } + + n = p / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); + + if (hp->rrp.tried[n] & m) { + goto next; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "get hash peer, value:%uD, peer:%ui", hp->hash, p); + + if (peer->down) { + goto next; + } + + if (peer->max_fails + && peer->fails >= peer->max_fails + && now - peer->checked <= peer->fail_timeout) + { + goto next; + } + + break; + + next: + + if (++hp->tries > 20) { + ngx_http_upstream_rr_peers_unlock(hp->rrp.peers); + return hp->get_rr_peer(pc, &hp->rrp); + } + } + + hp->rrp.current = peer; + + pc->sockaddr = peer->sockaddr; + pc->socklen = peer->socklen; + pc->name = &peer->name; + + peer->conns++; + + if (now - peer->checked > peer->fail_timeout) { + peer->checked = now; + } + + ngx_http_upstream_rr_peers_unlock(hp->rrp.peers); + + hp->rrp.tried[n] |= m; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_init_chash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) +{ + u_char *host, *port, c; + size_t host_len, port_len, size; + uint32_t hash, base_hash; + ngx_str_t *server; + ngx_uint_t npoints, i, j; + ngx_http_upstream_rr_peer_t *peer; + ngx_http_upstream_rr_peers_t *peers; + ngx_http_upstream_chash_points_t *points; + ngx_http_upstream_hash_srv_conf_t *hcf; + union { + uint32_t value; + u_char byte[4]; + } prev_hash; + + if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) { + return NGX_ERROR; + } + + us->peer.init = ngx_http_upstream_init_chash_peer; + + peers = us->peer.data; + npoints = peers->total_weight * 160; + + size = sizeof(ngx_http_upstream_chash_points_t) + + sizeof(ngx_http_upstream_chash_point_t) * (npoints - 1); + + points = ngx_palloc(cf->pool, size); + if (points == NULL) { + return NGX_ERROR; + } + + points->number = 0; + + for (peer = peers->peer; peer; peer = peer->next) { + server = &peer->server; + + /* + * Hash expression is compatible with Cache::Memcached::Fast: + * crc32(HOST \0 PORT PREV_HASH). + */ + + if (server->len >= 5 + && ngx_strncasecmp(server->data, (u_char *) "unix:", 5) == 0) + { + host = server->data + 5; + host_len = server->len - 5; + port = NULL; + port_len = 0; + goto done; + } + + for (j = 0; j < server->len; j++) { + c = server->data[server->len - j - 1]; + + if (c == ':') { + host = server->data; + host_len = server->len - j - 1; + port = server->data + server->len - j; + port_len = j; + goto done; + } + + if (c < '0' || c > '9') { + break; + } + } + + host = server->data; + host_len = server->len; + port = NULL; + port_len = 0; + + done: + + ngx_crc32_init(base_hash); + ngx_crc32_update(&base_hash, host, host_len); + ngx_crc32_update(&base_hash, (u_char *) "", 1); + ngx_crc32_update(&base_hash, port, port_len); + + prev_hash.value = 0; + npoints = peer->weight * 160; + + for (j = 0; j < npoints; j++) { + hash = base_hash; + + ngx_crc32_update(&hash, prev_hash.byte, 4); + ngx_crc32_final(hash); + + points->point[points->number].hash = hash; + points->point[points->number].server = server; + points->number++; + +#if (NGX_HAVE_LITTLE_ENDIAN) + prev_hash.value = hash; +#else + prev_hash.byte[0] = (u_char) (hash & 0xff); + prev_hash.byte[1] = (u_char) ((hash >> 8) & 0xff); + prev_hash.byte[2] = (u_char) ((hash >> 16) & 0xff); + prev_hash.byte[3] = (u_char) ((hash >> 24) & 0xff); +#endif + } + } + + ngx_qsort(points->point, + points->number, + sizeof(ngx_http_upstream_chash_point_t), + ngx_http_upstream_chash_cmp_points); + + for (i = 0, j = 1; j < points->number; j++) { + if (points->point[i].hash != points->point[j].hash) { + points->point[++i] = points->point[j]; + } + } + + points->number = i + 1; + + hcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_hash_module); + hcf->points = points; + + return NGX_OK; +} + + +static int ngx_libc_cdecl +ngx_http_upstream_chash_cmp_points(const void *one, const void *two) +{ + ngx_http_upstream_chash_point_t *first = + (ngx_http_upstream_chash_point_t *) one; + ngx_http_upstream_chash_point_t *second = + (ngx_http_upstream_chash_point_t *) two; + + if (first->hash < second->hash) { + return -1; + + } else if (first->hash > second->hash) { + return 1; + + } else { + return 0; + } +} + + +static ngx_uint_t +ngx_http_upstream_find_chash_point(ngx_http_upstream_chash_points_t *points, + uint32_t hash) +{ + ngx_uint_t i, j, k; + ngx_http_upstream_chash_point_t *point; + + /* find first point >= hash */ + + point = &points->point[0]; + + i = 0; + j = points->number; + + while (i < j) { + k = (i + j) / 2; + + if (hash > point[k].hash) { + i = k + 1; + + } else if (hash < point[k].hash) { + j = k; + + } else { + return k; + } + } + + return i; +} + + +static ngx_int_t +ngx_http_upstream_init_chash_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us) +{ + uint32_t hash; + ngx_http_upstream_hash_srv_conf_t *hcf; + ngx_http_upstream_hash_peer_data_t *hp; + + if (ngx_http_upstream_init_hash_peer(r, us) != NGX_OK) { + return NGX_ERROR; + } + + r->upstream->peer.get = ngx_http_upstream_get_chash_peer; + + hp = r->upstream->peer.data; + hcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_hash_module); + + hash = ngx_crc32_long(hp->key.data, hp->key.len); + + ngx_http_upstream_rr_peers_rlock(hp->rrp.peers); + + hp->hash = ngx_http_upstream_find_chash_point(hcf->points, hash); + + ngx_http_upstream_rr_peers_unlock(hp->rrp.peers); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) +{ + ngx_http_upstream_hash_peer_data_t *hp = data; + + time_t now; + intptr_t m; + ngx_str_t *server; + ngx_int_t total; + ngx_uint_t i, n, best_i; + ngx_http_upstream_rr_peer_t *peer, *best; + ngx_http_upstream_chash_point_t *point; + ngx_http_upstream_chash_points_t *points; + ngx_http_upstream_hash_srv_conf_t *hcf; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "get consistent hash peer, try: %ui", pc->tries); + + ngx_http_upstream_rr_peers_wlock(hp->rrp.peers); + + pc->cached = 0; + pc->connection = NULL; + + now = ngx_time(); + hcf = hp->conf; + + points = hcf->points; + point = &points->point[0]; + + for ( ;; ) { + server = point[hp->hash % points->number].server; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "consistent hash peer:%uD, server:\"%V\"", + hp->hash, server); + + best = NULL; + best_i = 0; + total = 0; + + for (peer = hp->rrp.peers->peer, i = 0; + peer; + peer = peer->next, i++) + { + + n = i / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); + + if (hp->rrp.tried[n] & m) { + continue; + } + + if (peer->down) { + continue; + } + + if (peer->server.len != server->len + || ngx_strncmp(peer->server.data, server->data, server->len) + != 0) + { + continue; + } + + if (peer->max_fails + && peer->fails >= peer->max_fails + && now - peer->checked <= peer->fail_timeout) + { + continue; + } + + peer->current_weight += peer->effective_weight; + total += peer->effective_weight; + + if (peer->effective_weight < peer->weight) { + peer->effective_weight++; + } + + if (best == NULL || peer->current_weight > best->current_weight) { + best = peer; + best_i = i; + } + } + + if (best) { + best->current_weight -= total; + goto found; + } + + hp->hash++; + hp->tries++; + + if (hp->tries >= points->number) { + ngx_http_upstream_rr_peers_unlock(hp->rrp.peers); + return NGX_BUSY; + } + } + +found: + + hp->rrp.current = best; + + pc->sockaddr = best->sockaddr; + pc->socklen = best->socklen; + pc->name = &best->name; + + best->conns++; + + if (now - best->checked > best->fail_timeout) { + best->checked = now; + } + + ngx_http_upstream_rr_peers_unlock(hp->rrp.peers); + + n = best_i / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << best_i % (8 * sizeof(uintptr_t)); + + hp->rrp.tried[n] |= m; + + return NGX_OK; +} + + +static void * +ngx_http_upstream_hash_create_conf(ngx_conf_t *cf) +{ + ngx_http_upstream_hash_srv_conf_t *conf; + + conf = ngx_palloc(cf->pool, sizeof(ngx_http_upstream_hash_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + conf->points = NULL; + + return conf; +} + + +static char * +ngx_http_upstream_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_upstream_hash_srv_conf_t *hcf = conf; + + ngx_str_t *value; + ngx_http_upstream_srv_conf_t *uscf; + ngx_http_compile_complex_value_t ccv; + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &hcf->key; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); + + if (uscf->peer.init_upstream) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "load balancing method redefined"); + } + + uscf->flags = NGX_HTTP_UPSTREAM_CREATE + |NGX_HTTP_UPSTREAM_WEIGHT + |NGX_HTTP_UPSTREAM_MAX_FAILS + |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT + |NGX_HTTP_UPSTREAM_DOWN; + + if (cf->args->nelts == 2) { + uscf->peer.init_upstream = ngx_http_upstream_init_hash; + + } else if (ngx_strcmp(value[2].data, "consistent") == 0) { + uscf->peer.init_upstream = ngx_http_upstream_init_chash; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c index 041883f..401b58e 100644 --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c @@ -161,7 +161,10 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) /* TODO: cached */ + ngx_http_upstream_rr_peers_wlock(iphp->rrp.peers); + if (iphp->tries > 20 || iphp->rrp.peers->single) { + ngx_http_upstream_rr_peers_unlock(iphp->rrp.peers); return iphp->get_rr_peer(pc, &iphp->rrp); } @@ -178,20 +181,14 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) hash = (hash * 113 + iphp->addr[i]) % 6271; } - if (!iphp->rrp.peers->weighted) { - p = hash % iphp->rrp.peers->number; + w = hash % iphp->rrp.peers->total_weight; + peer = iphp->rrp.peers->peer; + p = 0; - } else { - w = hash % iphp->rrp.peers->total_weight; - - for (i = 0; i < iphp->rrp.peers->number; i++) { - w -= iphp->rrp.peers->peer[i].weight; - if (w < 0) { - break; - } - } - - p = i; + while (w >= peer->weight) { + w -= peer->weight; + peer = peer->next; + p++; } n = p / (8 * sizeof(uintptr_t)); @@ -204,49 +201,40 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get ip hash peer, hash: %ui %04XA", p, m); - peer = &iphp->rrp.peers->peer[p]; - - /* ngx_lock_mutex(iphp->rrp.peers->mutex); */ - if (peer->down) { - goto next_try; + goto next; } if (peer->max_fails && peer->fails >= peer->max_fails && now - peer->checked <= peer->fail_timeout) { - goto next_try; + goto next; } break; - next_try: - - iphp->rrp.tried[n] |= m; - - /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */ - - pc->tries--; - next: - if (++iphp->tries >= 20) { + if (++iphp->tries > 20) { + ngx_http_upstream_rr_peers_unlock(iphp->rrp.peers); return iphp->get_rr_peer(pc, &iphp->rrp); } } - iphp->rrp.current = p; + iphp->rrp.current = peer; pc->sockaddr = peer->sockaddr; pc->socklen = peer->socklen; pc->name = &peer->name; + peer->conns++; + if (now - peer->checked > peer->fail_timeout) { peer->checked = now; } - /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */ + ngx_http_upstream_rr_peers_unlock(iphp->rrp.peers); iphp->rrp.tried[n] |= m; iphp->hash = hash; diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c b/src/http/modules/ngx_http_upstream_keepalive_module.c index d07ed9e..4e005fc 100644 --- a/src/http/modules/ngx_http_upstream_keepalive_module.c +++ b/src/http/modules/ngx_http_upstream_keepalive_module.c @@ -79,7 +79,7 @@ static char *ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, static ngx_command_t ngx_http_upstream_keepalive_commands[] = { { ngx_string("keepalive"), - NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12, + NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, ngx_http_upstream_keepalive, NGX_HTTP_SRV_CONF_OFFSET, 0, @@ -248,6 +248,7 @@ ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc, void *data) "get keepalive peer: using connection %p", c); c->idle = 0; + c->sent = 0; c->log = pc->log; c->read->log = pc->log; c->write->log = pc->log; @@ -386,7 +387,7 @@ ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev) n = recv(c->fd, buf, 1, MSG_PEEK); if (n == -1 && ngx_socket_errno == NGX_EAGAIN) { - /* stale event */ + ev->ready = 0; if (ngx_handle_read_event(c->read, 0) != NGX_OK) { goto close; @@ -485,7 +486,6 @@ ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 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); @@ -514,23 +514,5 @@ ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) kcf->max_cached = n; - for (i = 2; i < cf->args->nelts; i++) { - - if (ngx_strcmp(value[i].data, "single") == 0) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "the \"single\" parameter is deprecated"); - 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/src/http/modules/ngx_http_upstream_least_conn_module.c b/src/http/modules/ngx_http_upstream_least_conn_module.c index dbef95d..92951bd 100644 --- a/src/http/modules/ngx_http_upstream_least_conn_module.c +++ b/src/http/modules/ngx_http_upstream_least_conn_module.c @@ -10,29 +10,10 @@ #include -typedef struct { - ngx_uint_t *conns; -} ngx_http_upstream_least_conn_conf_t; - - -typedef struct { - /* the round robin data must be first */ - ngx_http_upstream_rr_peer_data_t rrp; - - ngx_uint_t *conns; - - ngx_event_get_peer_pt get_rr_peer; - ngx_event_free_peer_pt free_rr_peer; -} ngx_http_upstream_lc_peer_data_t; - - static ngx_int_t ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r, ngx_http_upstream_srv_conf_t *us); static ngx_int_t ngx_http_upstream_get_least_conn_peer( ngx_peer_connection_t *pc, void *data); -static void ngx_http_upstream_free_least_conn_peer(ngx_peer_connection_t *pc, - void *data, ngx_uint_t state); -static void *ngx_http_upstream_least_conn_create_conf(ngx_conf_t *cf); static char *ngx_http_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -57,7 +38,7 @@ static ngx_http_module_t ngx_http_upstream_least_conn_module_ctx = { NULL, /* create main configuration */ NULL, /* init main configuration */ - ngx_http_upstream_least_conn_create_conf, /* create server configuration */ + NULL, /* create server configuration */ NULL, /* merge server configuration */ NULL, /* create location configuration */ @@ -85,10 +66,6 @@ static ngx_int_t ngx_http_upstream_init_least_conn(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) { - ngx_uint_t n; - ngx_http_upstream_rr_peers_t *peers; - ngx_http_upstream_least_conn_conf_t *lcf; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "init least conn"); @@ -96,22 +73,6 @@ ngx_http_upstream_init_least_conn(ngx_conf_t *cf, return NGX_ERROR; } - peers = us->peer.data; - - n = peers->number; - - if (peers->next) { - n += peers->next->number; - } - - lcf = ngx_http_conf_upstream_srv_conf(us, - ngx_http_upstream_least_conn_module); - - lcf->conns = ngx_pcalloc(cf->pool, sizeof(ngx_uint_t) * n); - if (lcf->conns == NULL) { - return NGX_ERROR; - } - us->peer.init = ngx_http_upstream_init_least_conn_peer; return NGX_OK; @@ -122,33 +83,14 @@ static ngx_int_t ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r, ngx_http_upstream_srv_conf_t *us) { - ngx_http_upstream_lc_peer_data_t *lcp; - ngx_http_upstream_least_conn_conf_t *lcf; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "init least conn peer"); - lcf = ngx_http_conf_upstream_srv_conf(us, - ngx_http_upstream_least_conn_module); - - lcp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_lc_peer_data_t)); - if (lcp == NULL) { - return NGX_ERROR; - } - - lcp->conns = lcf->conns; - - r->upstream->peer.data = &lcp->rrp; - if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) { return NGX_ERROR; } r->upstream->peer.get = ngx_http_upstream_get_least_conn_peer; - r->upstream->peer.free = ngx_http_upstream_free_least_conn_peer; - - lcp->get_rr_peer = ngx_http_upstream_get_round_robin_peer; - lcp->free_rr_peer = ngx_http_upstream_free_round_robin_peer; return NGX_OK; } @@ -157,7 +99,7 @@ ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r, static ngx_int_t ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) { - ngx_http_upstream_lc_peer_data_t *lcp = data; + ngx_http_upstream_rr_peer_data_t *rrp = data; time_t now; uintptr_t m; @@ -169,8 +111,8 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get least conn peer, try: %ui", pc->tries); - if (lcp->rrp.peers->single) { - return lcp->get_rr_peer(pc, &lcp->rrp); + if (rrp->peers->single) { + return ngx_http_upstream_get_round_robin_peer(pc, rrp); } pc->cached = 0; @@ -178,7 +120,9 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) now = ngx_time(); - peers = lcp->rrp.peers; + peers = rrp->peers; + + ngx_http_upstream_rr_peers_wlock(peers); best = NULL; total = 0; @@ -188,17 +132,18 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) p = 0; #endif - for (i = 0; i < peers->number; i++) { + for (peer = peers->peer, i = 0; + peer; + peer = peer->next, i++) + { n = i / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); - if (lcp->rrp.tried[n] & m) { + if (rrp->tried[n] & m) { continue; } - peer = &peers->peer[i]; - if (peer->down) { continue; } @@ -217,15 +162,13 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) */ if (best == NULL - || lcp->conns[i] * best->weight < lcp->conns[p] * peer->weight) + || peer->conns * best->weight < best->conns * peer->weight) { best = peer; many = 0; p = i; - } else if (lcp->conns[i] * best->weight - == lcp->conns[p] * peer->weight) - { + } else if (peer->conns * best->weight == best->conns * peer->weight) { many = 1; } } @@ -241,22 +184,22 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get least conn peer, many"); - for (i = p; i < peers->number; i++) { - + for (peer = best, i = p; + peer; + peer = peer->next, i++) + { n = i / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); - if (lcp->rrp.tried[n] & m) { + if (rrp->tried[n] & m) { continue; } - peer = &peers->peer[i]; - if (peer->down) { continue; } - if (lcp->conns[i] * best->weight != lcp->conns[p] * peer->weight) { + if (peer->conns * best->weight != best->conns * peer->weight) { continue; } @@ -291,17 +234,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) pc->socklen = best->socklen; pc->name = &best->name; - lcp->rrp.current = p; + best->conns++; + + rrp->current = best; n = p / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); - lcp->rrp.tried[n] |= m; - lcp->conns[p]++; + rrp->tried[n] |= m; - if (pc->tries == 1 && peers->next) { - pc->tries += peers->next->number; - } + ngx_http_upstream_rr_peers_unlock(peers); return NGX_OK; @@ -311,78 +253,40 @@ failed: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get least conn peer, backup servers"); - lcp->conns += peers->number; + rrp->peers = peers->next; - lcp->rrp.peers = peers->next; - pc->tries = lcp->rrp.peers->number; - - n = (lcp->rrp.peers->number + (8 * sizeof(uintptr_t) - 1)) + n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t)); for (i = 0; i < n; i++) { - lcp->rrp.tried[i] = 0; + rrp->tried[i] = 0; } - rc = ngx_http_upstream_get_least_conn_peer(pc, lcp); + ngx_http_upstream_rr_peers_unlock(peers); + + rc = ngx_http_upstream_get_least_conn_peer(pc, rrp); if (rc != NGX_BUSY) { return rc; } + + ngx_http_upstream_rr_peers_wlock(peers); } /* all peers failed, mark them as live for quick recovery */ - for (i = 0; i < peers->number; i++) { - peers->peer[i].fails = 0; + for (peer = peers->peer; peer; peer = peer->next) { + peer->fails = 0; } + ngx_http_upstream_rr_peers_unlock(peers); + pc->name = peers->name; return NGX_BUSY; } -static void -ngx_http_upstream_free_least_conn_peer(ngx_peer_connection_t *pc, - void *data, ngx_uint_t state) -{ - ngx_http_upstream_lc_peer_data_t *lcp = data; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "free least conn peer %ui %ui", pc->tries, state); - - if (lcp->rrp.peers->single) { - lcp->free_rr_peer(pc, &lcp->rrp, state); - return; - } - - lcp->conns[lcp->rrp.current]--; - - lcp->free_rr_peer(pc, &lcp->rrp, state); -} - - -static void * -ngx_http_upstream_least_conn_create_conf(ngx_conf_t *cf) -{ - ngx_http_upstream_least_conn_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, - sizeof(ngx_http_upstream_least_conn_conf_t)); - if (conf == NULL) { - return NULL; - } - - /* - * set by ngx_pcalloc(): - * - * conf->conns = NULL; - */ - - return conf; -} - - static char * ngx_http_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/http/modules/ngx_http_upstream_zone_module.c b/src/http/modules/ngx_http_upstream_zone_module.c new file mode 100644 index 0000000..ea7c43b --- /dev/null +++ b/src/http/modules/ngx_http_upstream_zone_module.c @@ -0,0 +1,227 @@ + +/* + * Copyright (C) Ruslan Ermilov + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +static char *ngx_http_upstream_zone(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone, + void *data); +static ngx_int_t ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, + ngx_http_upstream_srv_conf_t *uscf); + + +static ngx_command_t ngx_http_upstream_zone_commands[] = { + + { ngx_string("zone"), + NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12, + ngx_http_upstream_zone, + 0, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_upstream_zone_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_upstream_zone_module = { + NGX_MODULE_V1, + &ngx_http_upstream_zone_module_ctx, /* module context */ + ngx_http_upstream_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 char * +ngx_http_upstream_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ssize_t size; + ngx_str_t *value; + ngx_http_upstream_srv_conf_t *uscf; + ngx_http_upstream_main_conf_t *umcf; + + uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); + umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module); + + value = cf->args->elts; + + if (!value[1].len) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid zone name \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 3) { + size = ngx_parse_size(&value[2]); + + if (size == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid zone size \"%V\"", &value[2]); + 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[1]); + return NGX_CONF_ERROR; + } + + } else { + size = 0; + } + + uscf->shm_zone = ngx_shared_memory_add(cf, &value[1], size, + &ngx_http_upstream_module); + if (uscf->shm_zone == NULL) { + return NGX_CONF_ERROR; + } + + uscf->shm_zone->init = ngx_http_upstream_init_zone; + uscf->shm_zone->data = umcf; + + uscf->shm_zone->noreuse = 1; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data) +{ + size_t len; + ngx_uint_t i; + ngx_slab_pool_t *shpool; + ngx_http_upstream_srv_conf_t *uscf, **uscfp; + ngx_http_upstream_main_conf_t *umcf; + + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + + if (shm_zone->shm.exists) { + return NGX_ERROR; + } + + len = sizeof(" in upstream 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 upstream zone \"%V\"%Z", + &shm_zone->shm.name); + + + /* copy peers to shared memory */ + + umcf = shm_zone->data; + uscfp = umcf->upstreams.elts; + + for (i = 0; i < umcf->upstreams.nelts; i++) { + uscf = uscfp[i]; + + if (uscf->shm_zone != shm_zone) { + continue; + } + + if (ngx_http_upstream_zone_copy_peers(shpool, uscf) != NGX_OK) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, + ngx_http_upstream_srv_conf_t *uscf) +{ + ngx_http_upstream_rr_peer_t *peer, **peerp; + ngx_http_upstream_rr_peers_t *peers, *backup; + + peers = ngx_slab_alloc(shpool, sizeof(ngx_http_upstream_rr_peers_t)); + if (peers == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(peers, uscf->peer.data, sizeof(ngx_http_upstream_rr_peers_t)); + + peers->shpool = shpool; + + for (peerp = &peers->peer; *peerp; peerp = &peer->next) { + /* pool is unlocked */ + peer = ngx_slab_calloc_locked(shpool, + sizeof(ngx_http_upstream_rr_peer_t)); + if (peer == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(peer, *peerp, sizeof(ngx_http_upstream_rr_peer_t)); + + *peerp = peer; + } + + if (peers->next == NULL) { + goto done; + } + + backup = ngx_slab_alloc(shpool, sizeof(ngx_http_upstream_rr_peers_t)); + if (backup == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(backup, peers->next, sizeof(ngx_http_upstream_rr_peers_t)); + + backup->shpool = shpool; + + for (peerp = &backup->peer; *peerp; peerp = &peer->next) { + /* pool is unlocked */ + peer = ngx_slab_calloc_locked(shpool, + sizeof(ngx_http_upstream_rr_peer_t)); + if (peer == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(peer, *peerp, sizeof(ngx_http_upstream_rr_peer_t)); + + *peerp = peer; + } + + peers->next = backup; + +done: + + uscf->peer.data = peers; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index 17dfc3b..a50c553 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -12,17 +12,29 @@ #include +typedef struct { + ngx_array_t caches; /* ngx_http_file_cache_t * */ +} ngx_http_uwsgi_main_conf_t; + + +typedef struct { + ngx_array_t *flushes; + ngx_array_t *lengths; + ngx_array_t *values; + ngx_uint_t number; + ngx_hash_t hash; +} ngx_http_uwsgi_params_t; + + typedef struct { ngx_http_upstream_conf_t upstream; - ngx_array_t *flushes; - ngx_array_t *params_len; - ngx_array_t *params; + ngx_http_uwsgi_params_t params; +#if (NGX_HTTP_CACHE) + ngx_http_uwsgi_params_t params_cache; +#endif ngx_array_t *params_source; - ngx_hash_t headers_hash; - ngx_uint_t header_params; - ngx_array_t *uwsgi_lengths; ngx_array_t *uwsgi_values; @@ -39,6 +51,12 @@ typedef struct { ngx_uint_t ssl; ngx_uint_t ssl_protocols; ngx_str_t ssl_ciphers; + ngx_uint_t ssl_verify_depth; + ngx_str_t ssl_trusted_certificate; + ngx_str_t ssl_crl; + ngx_str_t ssl_certificate; + ngx_str_t ssl_certificate_key; + ngx_array_t *ssl_passwords; #endif } ngx_http_uwsgi_loc_conf_t; @@ -53,11 +71,13 @@ 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); +static void *ngx_http_uwsgi_create_main_conf(ngx_conf_t *cf); static void *ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); -static ngx_int_t ngx_http_uwsgi_merge_params(ngx_conf_t *cf, - ngx_http_uwsgi_loc_conf_t *conf, ngx_http_uwsgi_loc_conf_t *prev); +static ngx_int_t ngx_http_uwsgi_init_params(ngx_conf_t *cf, + ngx_http_uwsgi_loc_conf_t *conf, ngx_http_uwsgi_params_t *params, + ngx_keyval_t *default_params); static char *ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -73,6 +93,8 @@ static char *ngx_http_uwsgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, #endif #if (NGX_HTTP_SSL) +static char *ngx_http_uwsgi_ssl_password_file(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); static ngx_int_t ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf); #endif @@ -158,6 +180,13 @@ static ngx_command_t ngx_http_uwsgi_commands[] = { offsetof(ngx_http_uwsgi_loc_conf_t, upstream.buffering), NULL }, + { ngx_string("uwsgi_request_buffering"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.request_buffering), + NULL }, + { ngx_string("uwsgi_ignore_client_abort"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -235,6 +264,20 @@ static ngx_command_t ngx_http_uwsgi_commands[] = { offsetof(ngx_http_uwsgi_loc_conf_t, upstream.busy_buffers_size_conf), NULL }, + { ngx_string("uwsgi_force_ranges"), + 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.force_ranges), + NULL }, + + { ngx_string("uwsgi_limit_rate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.limit_rate), + NULL }, + #if (NGX_HTTP_CACHE) { ngx_string("uwsgi_cache"), @@ -254,8 +297,8 @@ static ngx_command_t ngx_http_uwsgi_commands[] = { { ngx_string("uwsgi_cache_path"), NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE, ngx_http_file_cache_set_slot, - 0, - 0, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_uwsgi_main_conf_t, caches), &ngx_http_uwsgi_module }, { ngx_string("uwsgi_cache_bypass"), @@ -314,6 +357,13 @@ static ngx_command_t ngx_http_uwsgi_commands[] = { offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_lock_timeout), NULL }, + { ngx_string("uwsgi_cache_lock_age"), + 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_age), + NULL }, + { ngx_string("uwsgi_cache_revalidate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -351,6 +401,20 @@ static ngx_command_t ngx_http_uwsgi_commands[] = { offsetof(ngx_http_uwsgi_loc_conf_t, upstream.next_upstream), &ngx_http_uwsgi_next_upstream_masks }, + { ngx_string("uwsgi_next_upstream_tries"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.next_upstream_tries), + NULL }, + + { ngx_string("uwsgi_next_upstream_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.next_upstream_timeout), + NULL }, + { ngx_string("uwsgi_param"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23, ngx_http_upstream_param_set_slot, @@ -409,6 +473,69 @@ static ngx_command_t ngx_http_uwsgi_commands[] = { offsetof(ngx_http_uwsgi_loc_conf_t, ssl_ciphers), NULL }, + { ngx_string("uwsgi_ssl_name"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_set_complex_value_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_name), + NULL }, + + { ngx_string("uwsgi_ssl_server_name"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_server_name), + NULL }, + + { ngx_string("uwsgi_ssl_verify"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_verify), + NULL }, + + { ngx_string("uwsgi_ssl_verify_depth"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, ssl_verify_depth), + NULL }, + + { ngx_string("uwsgi_ssl_trusted_certificate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, ssl_trusted_certificate), + NULL }, + + { ngx_string("uwsgi_ssl_crl"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, ssl_crl), + NULL }, + + { ngx_string("uwsgi_ssl_certificate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate), + NULL }, + + { ngx_string("uwsgi_ssl_certificate_key"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate_key), + NULL }, + + { ngx_string("uwsgi_ssl_password_file"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_uwsgi_ssl_password_file, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + #endif ngx_null_command @@ -419,7 +546,7 @@ static ngx_http_module_t ngx_http_uwsgi_module_ctx = { NULL, /* preconfiguration */ NULL, /* postconfiguration */ - NULL, /* create main configuration */ + ngx_http_uwsgi_create_main_conf, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ @@ -462,7 +589,7 @@ static ngx_keyval_t ngx_http_uwsgi_cache_headers[] = { { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("$upstream_cache_last_modified") }, { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") }, - { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") }, + { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("$upstream_cache_etag") }, { ngx_string("HTTP_IF_MATCH"), ngx_string("") }, { ngx_string("HTTP_RANGE"), ngx_string("") }, { ngx_string("HTTP_IF_RANGE"), ngx_string("") }, @@ -480,10 +607,13 @@ static ngx_path_init_t ngx_http_uwsgi_temp_path = { static ngx_int_t ngx_http_uwsgi_handler(ngx_http_request_t *r) { - ngx_int_t rc; - ngx_http_status_t *status; - ngx_http_upstream_t *u; - ngx_http_uwsgi_loc_conf_t *uwcf; + ngx_int_t rc; + ngx_http_status_t *status; + ngx_http_upstream_t *u; + ngx_http_uwsgi_loc_conf_t *uwcf; +#if (NGX_HTTP_CACHE) + ngx_http_uwsgi_main_conf_t *uwmcf; +#endif if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -526,8 +656,12 @@ ngx_http_uwsgi_handler(ngx_http_request_t *r) u->conf = &uwcf->upstream; #if (NGX_HTTP_CACHE) + uwmcf = ngx_http_get_module_main_conf(r, ngx_http_uwsgi_module); + + u->caches = &uwmcf->caches; u->create_key = ngx_http_uwsgi_create_key; #endif + u->create_request = ngx_http_uwsgi_create_request; u->reinit_request = ngx_http_uwsgi_reinit_request; u->process_header = ngx_http_uwsgi_process_status_line; @@ -545,6 +679,13 @@ ngx_http_uwsgi_handler(ngx_http_request_t *r) u->pipe->input_filter = ngx_event_pipe_copy_input_filter; u->pipe->input_ctx = r; + if (!uwcf->upstream.request_buffering + && uwcf->upstream.pass_request_body + && !r->headers_in.chunked) + { + r->request_body_no_buffering = 1; + } + rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { @@ -673,6 +814,7 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) ngx_chain_t *cl, *body; ngx_list_part_t *part; ngx_table_elt_t *header, **ignored; + ngx_http_uwsgi_params_t *params; ngx_http_script_code_pt code; ngx_http_script_engine_t e, le; ngx_http_uwsgi_loc_conf_t *uwcf; @@ -684,13 +826,19 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) uwcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module); - if (uwcf->params_len) { +#if (NGX_HTTP_CACHE) + params = r->upstream->cacheable ? &uwcf->params_cache : &uwcf->params; +#else + params = &uwcf->params; +#endif + + if (params->lengths) { ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); - ngx_http_script_flush_no_cacheable_variables(r, uwcf->flushes); + ngx_http_script_flush_no_cacheable_variables(r, params->flushes); le.flushed = 1; - le.ip = uwcf->params_len->elts; + le.ip = params->lengths->elts; le.request = r; while (*(uintptr_t *) le.ip) { @@ -719,7 +867,7 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) allocated = 0; lowcase_key = NULL; - if (uwcf->header_params) { + if (params->number) { n = 0; part = &r->headers_in.headers.part; @@ -749,7 +897,7 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) i = 0; } - if (uwcf->header_params) { + if (params->number) { if (allocated < header[i].key.len) { allocated = header[i].key.len + 16; lowcase_key = ngx_pnalloc(r->pool, allocated); @@ -774,7 +922,7 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) lowcase_key[n] = ch; } - if (ngx_hash_find(&uwcf->headers_hash, hash, lowcase_key, n)) { + if (ngx_hash_find(¶ms->hash, hash, lowcase_key, n)) { ignored[header_params++] = &header[i]; continue; } @@ -813,15 +961,15 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) *b->last++ = (u_char) ((len >> 8) & 0xff); *b->last++ = (u_char) uwcf->modifier2; - if (uwcf->params_len) { + if (params->lengths) { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); - e.ip = uwcf->params->elts; + e.ip = params->values->elts; e.pos = b->last; e.request = r; e.flushed = 1; - le.ip = uwcf->params_len->elts; + le.ip = params->lengths->elts; while (*(uintptr_t *) le.ip) { @@ -934,7 +1082,10 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) b->last = ngx_copy(b->last, uwcf->uwsgi_string.data, uwcf->uwsgi_string.len); - if (uwcf->upstream.pass_request_body) { + if (r->request_body_no_buffering) { + r->upstream->request_bufs = cl; + + } else if (uwcf->upstream.pass_request_body) { body = r->upstream->request_bufs; r->upstream->request_bufs = cl; @@ -1194,6 +1345,29 @@ ngx_http_uwsgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc) } +static void * +ngx_http_uwsgi_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_uwsgi_main_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_uwsgi_main_conf_t)); + if (conf == NULL) { + return NULL; + } + +#if (NGX_HTTP_CACHE) + if (ngx_array_init(&conf->caches, cf->pool, 4, + sizeof(ngx_http_file_cache_t *)) + != NGX_OK) + { + return NULL; + } +#endif + + return conf; +} + + static void * ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf) { @@ -1209,17 +1383,22 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf) conf->upstream.store = NGX_CONF_UNSET; conf->upstream.store_access = NGX_CONF_UNSET_UINT; + conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT; conf->upstream.buffering = NGX_CONF_UNSET; + conf->upstream.request_buffering = NGX_CONF_UNSET; conf->upstream.ignore_client_abort = NGX_CONF_UNSET; + conf->upstream.force_ranges = NGX_CONF_UNSET; conf->upstream.local = NGX_CONF_UNSET_PTR; conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; + conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE; conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE; conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; @@ -1229,13 +1408,14 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf) conf->upstream.pass_request_body = NGX_CONF_UNSET; #if (NGX_HTTP_CACHE) - conf->upstream.cache = NGX_CONF_UNSET_PTR; + conf->upstream.cache = NGX_CONF_UNSET; conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT; 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; + conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC; conf->upstream.cache_revalidate = NGX_CONF_UNSET; #endif @@ -1243,8 +1423,13 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf) conf->upstream.pass_headers = NGX_CONF_UNSET_PTR; conf->upstream.intercept_errors = NGX_CONF_UNSET; + #if (NGX_HTTP_SSL) conf->upstream.ssl_session_reuse = NGX_CONF_UNSET; + conf->upstream.ssl_server_name = NGX_CONF_UNSET; + conf->upstream.ssl_verify = NGX_CONF_UNSET; + conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; + conf->ssl_passwords = NGX_CONF_UNSET_PTR; #endif /* "uwsgi_cyclic_temp_file" is disabled */ @@ -1265,27 +1450,47 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_uwsgi_loc_conf_t *conf = child; size_t size; + ngx_int_t rc; ngx_hash_init_t hash; ngx_http_core_loc_conf_t *clcf; - if (conf->upstream.store != 0) { +#if (NGX_HTTP_CACHE) + + if (conf->upstream.store > 0) { + conf->upstream.cache = 0; + } + + if (conf->upstream.cache > 0) { + conf->upstream.store = 0; + } + +#endif + + if (conf->upstream.store == NGX_CONF_UNSET) { ngx_conf_merge_value(conf->upstream.store, prev->upstream.store, 0); - if (conf->upstream.store_lengths == NULL) { - conf->upstream.store_lengths = prev->upstream.store_lengths; - conf->upstream.store_values = prev->upstream.store_values; - } + conf->upstream.store_lengths = prev->upstream.store_lengths; + conf->upstream.store_values = prev->upstream.store_values; } ngx_conf_merge_uint_value(conf->upstream.store_access, prev->upstream.store_access, 0600); + ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries, + prev->upstream.next_upstream_tries, 0); + ngx_conf_merge_value(conf->upstream.buffering, prev->upstream.buffering, 1); + ngx_conf_merge_value(conf->upstream.request_buffering, + prev->upstream.request_buffering, 1); + ngx_conf_merge_value(conf->upstream.ignore_client_abort, prev->upstream.ignore_client_abort, 0); + ngx_conf_merge_value(conf->upstream.force_ranges, + prev->upstream.force_ranges, 0); + ngx_conf_merge_ptr_value(conf->upstream.local, prev->upstream.local, NULL); @@ -1298,6 +1503,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->upstream.read_timeout, prev->upstream.read_timeout, 60000); + ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout, + prev->upstream.next_upstream_timeout, 0); + ngx_conf_merge_size_value(conf->upstream.send_lowat, prev->upstream.send_lowat, 0); @@ -1305,6 +1513,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->upstream.buffer_size, (size_t) ngx_pagesize); + ngx_conf_merge_size_value(conf->upstream.limit_rate, + prev->upstream.limit_rate, 0); + ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, 8, ngx_pagesize); @@ -1386,7 +1597,8 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) } if (conf->upstream.max_temp_file_size != 0 - && conf->upstream.max_temp_file_size < size) { + && 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 " "temporary files usage or must be equal to or greater than " @@ -1423,13 +1635,18 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #if (NGX_HTTP_CACHE) - ngx_conf_merge_ptr_value(conf->upstream.cache, - prev->upstream.cache, NULL); + if (conf->upstream.cache == NGX_CONF_UNSET) { + ngx_conf_merge_value(conf->upstream.cache, + prev->upstream.cache, 0); - if (conf->upstream.cache && conf->upstream.cache->data == NULL) { + conf->upstream.cache_zone = prev->upstream.cache_zone; + conf->upstream.cache_value = prev->upstream.cache_value; + } + + if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) { ngx_shm_zone_t *shm_zone; - shm_zone = conf->upstream.cache; + shm_zone = conf->upstream.cache_zone; ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"uwsgi_cache\" zone \"%V\" is unknown", @@ -1474,12 +1691,20 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) conf->cache_key = prev->cache_key; } + if (conf->upstream.cache && conf->cache_key.value.data == NULL) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "no \"uwsgi_cache_key\" for \"uwsgi_cache\""); + } + 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); + ngx_conf_merge_msec_value(conf->upstream.cache_lock_age, + prev->upstream.cache_lock_age, 5000); + ngx_conf_merge_value(conf->upstream.cache_revalidate, prev->upstream.cache_revalidate, 0); @@ -1494,24 +1719,41 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->upstream.intercept_errors, 0); #if (NGX_HTTP_SSL) + ngx_conf_merge_value(conf->upstream.ssl_session_reuse, prev->upstream.ssl_session_reuse, 1); ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3 - |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 - |NGX_SSL_TLSv1_2)); + (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 + |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); + if (conf->upstream.ssl_name == NULL) { + conf->upstream.ssl_name = prev->upstream.ssl_name; + } + + ngx_conf_merge_value(conf->upstream.ssl_server_name, + prev->upstream.ssl_server_name, 0); + ngx_conf_merge_value(conf->upstream.ssl_verify, + prev->upstream.ssl_verify, 0); + ngx_conf_merge_uint_value(conf->ssl_verify_depth, + prev->ssl_verify_depth, 1); + ngx_conf_merge_str_value(conf->ssl_trusted_certificate, + prev->ssl_trusted_certificate, ""); + ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); + + ngx_conf_merge_str_value(conf->ssl_certificate, + prev->ssl_certificate, ""); + ngx_conf_merge_str_value(conf->ssl_certificate_key, + prev->ssl_certificate_key, ""); + ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); + if (conf->ssl && ngx_http_uwsgi_set_ssl(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; } - if (conf->upstream.ssl == NULL) { - conf->upstream.ssl = prev->upstream.ssl; - } #endif ngx_conf_merge_str_value(conf->uwsgi_string, prev->uwsgi_string, ""); @@ -1527,88 +1769,91 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } - if (conf->upstream.upstream == NULL) { - conf->upstream.upstream = prev->upstream.upstream; - } + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + + if (clcf->noname + && conf->upstream.upstream == NULL && conf->uwsgi_lengths == NULL) + { + conf->upstream.upstream = prev->upstream.upstream; - if (conf->uwsgi_lengths == NULL) { conf->uwsgi_lengths = prev->uwsgi_lengths; conf->uwsgi_values = prev->uwsgi_values; + +#if (NGX_HTTP_SSL) + conf->upstream.ssl = prev->upstream.ssl; +#endif } - if (conf->upstream.upstream || conf->uwsgi_lengths) { - clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); - if (clcf->handler == NULL && clcf->lmt_excpt) { - clcf->handler = ngx_http_uwsgi_handler; - } + if (clcf->lmt_excpt && clcf->handler == NULL + && (conf->upstream.upstream || conf->uwsgi_lengths)) + { + clcf->handler = ngx_http_uwsgi_handler; } ngx_conf_merge_uint_value(conf->modifier1, prev->modifier1, 0); ngx_conf_merge_uint_value(conf->modifier2, prev->modifier2, 0); - if (ngx_http_uwsgi_merge_params(cf, conf, prev) != NGX_OK) { + if (conf->params_source == NULL) { + conf->params = prev->params; +#if (NGX_HTTP_CACHE) + conf->params_cache = prev->params_cache; +#endif + conf->params_source = prev->params_source; + } + + rc = ngx_http_uwsgi_init_params(cf, conf, &conf->params, NULL); + if (rc != NGX_OK) { return NGX_CONF_ERROR; } +#if (NGX_HTTP_CACHE) + + if (conf->upstream.cache) { + rc = ngx_http_uwsgi_init_params(cf, conf, &conf->params_cache, + ngx_http_uwsgi_cache_headers); + if (rc != NGX_OK) { + return NGX_CONF_ERROR; + } + } + +#endif + return NGX_CONF_OK; } static ngx_int_t -ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf, - ngx_http_uwsgi_loc_conf_t *prev) +ngx_http_uwsgi_init_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf, + ngx_http_uwsgi_params_t *params, ngx_keyval_t *default_params) { u_char *p; size_t size; uintptr_t *code; ngx_uint_t i, nsrc; - ngx_array_t headers_names; -#if (NGX_HTTP_CACHE) - ngx_array_t params_merged; -#endif + ngx_array_t headers_names, params_merged; + ngx_keyval_t *h; ngx_hash_key_t *hk; ngx_hash_init_t hash; - ngx_http_upstream_param_t *src; + ngx_http_upstream_param_t *src, *s; ngx_http_script_compile_t sc; ngx_http_script_copy_code_t *copy; - if (conf->params_source == NULL) { - conf->params_source = prev->params_source; - - if (prev->headers_hash.buckets -#if (NGX_HTTP_CACHE) - && ((conf->upstream.cache == NULL) - == (prev->upstream.cache == NULL)) -#endif - ) - { - conf->flushes = prev->flushes; - conf->params_len = prev->params_len; - conf->params = prev->params; - conf->headers_hash = prev->headers_hash; - conf->header_params = prev->header_params; - - return NGX_OK; - } - } - - if (conf->params_source == NULL -#if (NGX_HTTP_CACHE) - && (conf->upstream.cache == NULL) -#endif - ) - { - conf->headers_hash.buckets = (void *) 1; + if (params->hash.buckets) { return NGX_OK; } - conf->params_len = ngx_array_create(cf->pool, 64, 1); - if (conf->params_len == NULL) { + if (conf->params_source == NULL && default_params == NULL) { + params->hash.buckets = (void *) 1; + return NGX_OK; + } + + params->lengths = ngx_array_create(cf->pool, 64, 1); + if (params->lengths == NULL) { return NGX_ERROR; } - conf->params = ngx_array_create(cf->pool, 512, 1); - if (conf->params == NULL) { + params->values = ngx_array_create(cf->pool, 512, 1); + if (params->values == NULL) { return NGX_ERROR; } @@ -1627,12 +1872,7 @@ ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf, nsrc = 0; } -#if (NGX_HTTP_CACHE) - - if (conf->upstream.cache) { - ngx_keyval_t *h; - ngx_http_upstream_param_t *s; - + if (default_params) { if (ngx_array_init(¶ms_merged, cf->temp_pool, 4, sizeof(ngx_http_upstream_param_t)) != NGX_OK) @@ -1650,7 +1890,7 @@ ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf, *s = src[i]; } - h = ngx_http_uwsgi_cache_headers; + h = default_params; while (h->key.len) { @@ -1681,8 +1921,6 @@ ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf, nsrc = params_merged.nelts; } -#endif - for (i = 0; i < nsrc; i++) { if (src[i].key.len > sizeof("HTTP_") - 1 @@ -1703,7 +1941,7 @@ ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf, } } - copy = ngx_array_push_n(conf->params_len, + copy = ngx_array_push_n(params->lengths, sizeof(ngx_http_script_copy_code_t)); if (copy == NULL) { return NGX_ERROR; @@ -1712,7 +1950,7 @@ 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, + copy = ngx_array_push_n(params->lengths, sizeof(ngx_http_script_copy_code_t)); if (copy == NULL) { return NGX_ERROR; @@ -1726,7 +1964,7 @@ ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf, + src[i].key.len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); - copy = ngx_array_push_n(conf->params, size); + copy = ngx_array_push_n(params->values, size); if (copy == NULL) { return NGX_ERROR; } @@ -1742,15 +1980,15 @@ ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf, sc.cf = cf; sc.source = &src[i].value; - sc.flushes = &conf->flushes; - sc.lengths = &conf->params_len; - sc.values = &conf->params; + sc.flushes = ¶ms->flushes; + sc.lengths = ¶ms->lengths; + sc.values = ¶ms->values; if (ngx_http_script_compile(&sc) != NGX_OK) { return NGX_ERROR; } - code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t)); + code = ngx_array_push_n(params->lengths, sizeof(uintptr_t)); if (code == NULL) { return NGX_ERROR; } @@ -1758,7 +1996,7 @@ ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf, *code = (uintptr_t) NULL; - code = ngx_array_push_n(conf->params, sizeof(uintptr_t)); + code = ngx_array_push_n(params->values, sizeof(uintptr_t)); if (code == NULL) { return NGX_ERROR; } @@ -1766,16 +2004,16 @@ ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf, *code = (uintptr_t) NULL; } - code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t)); + code = ngx_array_push_n(params->lengths, sizeof(uintptr_t)); if (code == NULL) { return NGX_ERROR; } *code = (uintptr_t) NULL; - conf->header_params = headers_names.nelts; + params->number = headers_names.nelts; - hash.hash = &conf->headers_hash; + hash.hash = ¶ms->hash; hash.key = ngx_hash_key_lc; hash.max_size = 512; hash.bucket_size = 64; @@ -1803,7 +2041,7 @@ ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return "is duplicate"; } - clcf = ngx_http_conf_get_module_loc_conf (cf, ngx_http_core_module); + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); clcf->handler = ngx_http_uwsgi_handler; value = cf->args->elts; @@ -1880,8 +2118,7 @@ ngx_http_uwsgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; ngx_http_script_compile_t sc; - if (uwcf->upstream.store != NGX_CONF_UNSET || uwcf->upstream.store_lengths) - { + if (uwcf->upstream.store != NGX_CONF_UNSET) { return "is duplicate"; } @@ -1894,16 +2131,15 @@ ngx_http_uwsgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #if (NGX_HTTP_CACHE) - if (uwcf->upstream.cache != NGX_CONF_UNSET_PTR - && uwcf->upstream.cache != NULL) - { + if (uwcf->upstream.cache > 0) { return "is incompatible with \"uwsgi_cache\""; } #endif + uwcf->upstream.store = 1; + if (ngx_strcmp(value[1].data, "on") == 0) { - uwcf->upstream.store = 1; return NGX_CONF_OK; } @@ -1935,26 +2171,53 @@ ngx_http_uwsgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_uwsgi_loc_conf_t *uwcf = conf; - ngx_str_t *value; + ngx_str_t *value; + ngx_http_complex_value_t cv; + ngx_http_compile_complex_value_t ccv; value = cf->args->elts; - if (uwcf->upstream.cache != NGX_CONF_UNSET_PTR) { + if (uwcf->upstream.cache != NGX_CONF_UNSET) { return "is duplicate"; } if (ngx_strcmp(value[1].data, "off") == 0) { - uwcf->upstream.cache = NULL; + uwcf->upstream.cache = 0; return NGX_CONF_OK; } - if (uwcf->upstream.store > 0 || uwcf->upstream.store_lengths) { + if (uwcf->upstream.store > 0) { return "is incompatible with \"uwsgi_store\""; } - uwcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, - &ngx_http_uwsgi_module); - if (uwcf->upstream.cache == NULL) { + uwcf->upstream.cache = 1; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + + uwcf->upstream.cache_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (uwcf->upstream.cache_value == NULL) { + return NGX_CONF_ERROR; + } + + *uwcf->upstream.cache_value = cv; + + return NGX_CONF_OK; + } + + uwcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_uwsgi_module); + if (uwcf->upstream.cache_zone == NULL) { return NGX_CONF_ERROR; } @@ -1994,6 +2257,29 @@ ngx_http_uwsgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #if (NGX_HTTP_SSL) +static char * +ngx_http_uwsgi_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_uwsgi_loc_conf_t *uwcf = conf; + + ngx_str_t *value; + + if (uwcf->ssl_passwords != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + uwcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); + + if (uwcf->ssl_passwords == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + static ngx_int_t ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf) { @@ -2012,6 +2298,31 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf) return NGX_ERROR; } + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_ssl_cleanup_ctx; + cln->data = uwcf->upstream.ssl; + + if (uwcf->ssl_certificate.len) { + + if (uwcf->ssl_certificate_key.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"uwsgi_ssl_certificate_key\" is defined " + "for certificate \"%V\"", &uwcf->ssl_certificate); + return NGX_ERROR; + } + + if (ngx_ssl_certificate(cf, uwcf->upstream.ssl, &uwcf->ssl_certificate, + &uwcf->ssl_certificate_key, uwcf->ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + } + if (SSL_CTX_set_cipher_list(uwcf->upstream.ssl->ctx, (const char *) uwcf->ssl_ciphers.data) == 0) @@ -2022,13 +2333,25 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf) return NGX_ERROR; } - cln = ngx_pool_cleanup_add(cf->pool, 0); - if (cln == NULL) { - return NGX_ERROR; - } + if (uwcf->upstream.ssl_verify) { + if (uwcf->ssl_trusted_certificate.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no uwsgi_ssl_trusted_certificate for uwsgi_ssl_verify"); + return NGX_ERROR; + } - cln->handler = ngx_ssl_cleanup_ctx; - cln->data = uwcf->upstream.ssl; + if (ngx_ssl_trusted_certificate(cf, uwcf->upstream.ssl, + &uwcf->ssl_trusted_certificate, + uwcf->ssl_verify_depth) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_ssl_crl(cf, uwcf->upstream.ssl, &uwcf->ssl_crl) != NGX_OK) { + return NGX_ERROR; + } + } return NGX_OK; } diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c index 9e85693..315081e 100644 --- a/src/http/modules/ngx_http_xslt_filter_module.c +++ b/src/http/modules/ngx_http_xslt_filter_module.c @@ -337,12 +337,14 @@ ngx_http_xslt_send(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, r->headers_out.content_length = NULL; } - ngx_http_clear_etag(r); - conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module); if (!conf->last_modified) { ngx_http_clear_last_modified(r); + ngx_http_clear_etag(r); + + } else { + ngx_http_weak_etag(r); } } diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c index bf4d1fe..6a8894c 100644 --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -577,7 +577,7 @@ ngx_http_perl_create_interpreter(ngx_conf_t *cf, n = (pmcf->modules != NGX_CONF_UNSET_PTR) ? pmcf->modules->nelts * 2 : 0; - embedding = ngx_palloc(cf->pool, (4 + n) * sizeof(char *)); + embedding = ngx_palloc(cf->pool, (5 + n) * sizeof(char *)); if (embedding == NULL) { goto fail; } @@ -595,6 +595,7 @@ ngx_http_perl_create_interpreter(ngx_conf_t *cf, embedding[n++] = "-Mnginx"; embedding[n++] = "-e"; embedding[n++] = "0"; + embedding[n] = NULL; n = perl_parse(perl, ngx_http_perl_xs_init, n, embedding, NULL); diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index ce5adb7..4642559 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -69,8 +69,9 @@ static ngx_int_t ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport, ngx_uint_t ngx_http_max_module; -ngx_int_t (*ngx_http_top_header_filter) (ngx_http_request_t *r); -ngx_int_t (*ngx_http_top_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch); +ngx_http_output_header_filter_pt ngx_http_top_header_filter; +ngx_http_output_body_filter_pt ngx_http_top_body_filter; +ngx_http_request_body_filter_pt ngx_http_top_request_body_filter; ngx_str_t ngx_http_html_default_types[] = { @@ -742,7 +743,7 @@ ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, if (named) { clcfp = ngx_palloc(cf->pool, - (n + 1) * sizeof(ngx_http_core_loc_conf_t **)); + (n + 1) * sizeof(ngx_http_core_loc_conf_t *)); if (clcfp == NULL) { return NGX_ERROR; } @@ -768,7 +769,7 @@ ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, if (regex) { clcfp = ngx_palloc(cf->pool, - (r + 1) * sizeof(ngx_http_core_loc_conf_t **)); + (r + 1) * sizeof(ngx_http_core_loc_conf_t *)); if (clcfp == NULL) { return NGX_ERROR; } @@ -1219,7 +1220,7 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, { u_char *p; size_t len, off; - ngx_uint_t i, default_server; + ngx_uint_t i, default_server, proxy_protocol; struct sockaddr *sa; ngx_http_conf_addr_t *addr; #if (NGX_HAVE_UNIX_DOMAIN) @@ -1280,6 +1281,8 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, /* preserve default_server bit during listen options overwriting */ default_server = addr[i].opt.default_server; + proxy_protocol = lsopt->proxy_protocol || addr[i].opt.proxy_protocol; + #if (NGX_HTTP_SSL) ssl = lsopt->ssl || addr[i].opt.ssl; #endif @@ -1313,6 +1316,7 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, } addr[i].opt.default_server = default_server; + addr[i].opt.proxy_protocol = proxy_protocol; #if (NGX_HTTP_SSL) addr[i].opt.ssl = ssl; #endif @@ -1715,13 +1719,7 @@ ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_port_t *port) ls->servers = hport; - if (i == last - 1) { - hport->naddrs = last; - - } else { - hport->naddrs = 1; - i = 0; - } + hport->naddrs = i + 1; switch (ls->sockaddr->sa_family) { @@ -1739,6 +1737,10 @@ ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_port_t *port) break; } + if (ngx_clone_listening(cf, ls) != NGX_OK) { + return NGX_ERROR; + } + addr++; last--; } @@ -1817,6 +1819,10 @@ ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) ls->fastopen = addr->opt.fastopen; #endif +#if (NGX_HAVE_REUSEPORT) + ls->reuseport = addr->opt.reuseport; +#endif + return ls; } @@ -2005,7 +2011,7 @@ ngx_http_types_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strcmp(value[i].data, type[n].key.data) == 0) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "duplicate MIME type \"%V\"", &value[i]); - continue; + goto next; } } @@ -2017,6 +2023,10 @@ ngx_http_types_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) type->key = value[i]; type->key_hash = hash; type->value = (void *) 4; + + next: + + continue; } return NGX_CONF_OK; diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index d4dc1bd..b1e5fae 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -36,7 +36,6 @@ typedef u_char *(*ngx_http_log_handler_pt)(ngx_http_request_t *r, #include #include #include -#include #include #if (NGX_HTTP_SPDY) @@ -105,6 +104,8 @@ ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, ngx_uint_t allow_underscores); ngx_int_t ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name, ngx_str_t *value); +ngx_int_t ngx_http_parse_set_cookie_lines(ngx_array_t *headers, + ngx_str_t *name, ngx_str_t *value); ngx_int_t ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len, ngx_str_t *value); void ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, @@ -129,9 +130,6 @@ void ngx_http_empty_handler(ngx_event_t *wev); void ngx_http_request_empty_handler(ngx_http_request_t *r); -#define ngx_http_ephemeral(r) (void *) (&r->uri_start) - - #define NGX_HTTP_LAST 1 #define NGX_HTTP_FLUSH 2 @@ -140,6 +138,7 @@ ngx_int_t ngx_http_send_special(ngx_http_request_t *r, ngx_uint_t flags); ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler); +ngx_int_t ngx_http_read_unbuffered_request_body(ngx_http_request_t *r); ngx_int_t ngx_http_send_header(ngx_http_request_t *r); ngx_int_t ngx_http_special_response_handler(ngx_http_request_t *r, @@ -179,6 +178,7 @@ extern ngx_str_t ngx_http_html_default_types[]; extern ngx_http_output_header_filter_pt ngx_http_top_header_filter; extern ngx_http_output_body_filter_pt ngx_http_top_body_filter; +extern ngx_http_request_body_filter_pt ngx_http_top_request_body_filter; #endif /* _NGX_HTTP_H_INCLUDED_ */ diff --git a/src/http/ngx_http_busy_lock.c b/src/http/ngx_http_busy_lock.c deleted file mode 100644 index 3b4b28c..0000000 --- a/src/http/ngx_http_busy_lock.c +++ /dev/null @@ -1,307 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - */ - - -#include -#include -#include - - - -static int ngx_http_busy_lock_look_cacheable(ngx_http_busy_lock_t *bl, - ngx_http_busy_lock_ctx_t *bc, - int lock); - - -int ngx_http_busy_lock(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc) -{ - if (bl->busy < bl->max_busy) { - bl->busy++; - - if (bc->time) { - bc->time = 0; - bl->waiting--; - } - - return NGX_OK; - } - - if (bc->time) { - if (bc->time < bl->timeout) { - ngx_add_timer(bc->event, 1000); - return NGX_AGAIN; - } - - bl->waiting--; - return NGX_DONE; - - } - - if (bl->timeout == 0) { - return NGX_DONE; - } - - if (bl->waiting < bl->max_waiting) { - bl->waiting++; - -#if 0 - ngx_add_timer(bc->event, 1000); - bc->event->event_handler = bc->event_handler; -#endif - - /* TODO: ngx_handle_level_read_event() */ - - return NGX_AGAIN; - } - - return NGX_ERROR; -} - - -int ngx_http_busy_lock_cacheable(ngx_http_busy_lock_t *bl, - ngx_http_busy_lock_ctx_t *bc, int lock) -{ - int rc; - - rc = ngx_http_busy_lock_look_cacheable(bl, bc, lock); - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, bc->event->log, 0, - "http busylock: %d w:%d mw::%d", - rc, bl->waiting, bl->max_waiting); - - if (rc == NGX_OK) { /* no the same request, there's free slot */ - return NGX_OK; - } - - if (rc == NGX_ERROR && !lock) { /* no the same request, no free slot */ - return NGX_OK; - } - - /* rc == NGX_AGAIN: the same request */ - - if (bc->time) { - if (bc->time < bl->timeout) { - ngx_add_timer(bc->event, 1000); - return NGX_AGAIN; - } - - bl->waiting--; - return NGX_DONE; - - } - - if (bl->timeout == 0) { - return NGX_DONE; - } - - if (bl->waiting < bl->max_waiting) { -#if 0 - bl->waiting++; - ngx_add_timer(bc->event, 1000); - bc->event->event_handler = bc->event_handler; -#endif - - /* TODO: ngx_handle_level_read_event() */ - - return NGX_AGAIN; - } - - return NGX_ERROR; -} - - -void ngx_http_busy_unlock(ngx_http_busy_lock_t *bl, - ngx_http_busy_lock_ctx_t *bc) -{ - if (bl == NULL) { - return; - } - - if (bl->md5) { - bl->md5_mask[bc->slot / 8] &= ~(1 << (bc->slot & 7)); - bl->cacheable--; - } - - bl->busy--; -} - - -static int ngx_http_busy_lock_look_cacheable(ngx_http_busy_lock_t *bl, - ngx_http_busy_lock_ctx_t *bc, - int lock) -{ - int i, b, cacheable, free; - u_int mask; - - b = 0; - cacheable = 0; - free = -1; - -#if (NGX_SUPPRESS_WARN) - mask = 0; -#endif - - for (i = 0; i < bl->max_busy; i++) { - - if ((b & 7) == 0) { - mask = bl->md5_mask[i / 8]; - } - - if (mask & 1) { - if (ngx_memcmp(&bl->md5[i * 16], bc->md5, 16) == 0) { - return NGX_AGAIN; - } - cacheable++; - - } else if (free == -1) { - free = i; - } - -#if 1 - if (cacheable == bl->cacheable) { - if (free == -1 && cacheable < bl->max_busy) { - free = i + 1; - } - - break; - } -#endif - - mask >>= 1; - b++; - } - - if (free == -1) { - return NGX_ERROR; - } - - if (lock) { - if (bl->busy == bl->max_busy) { - return NGX_ERROR; - } - - ngx_memcpy(&bl->md5[free * 16], bc->md5, 16); - bl->md5_mask[free / 8] |= 1 << (free & 7); - bc->slot = free; - - bl->cacheable++; - bl->busy++; - } - - return NGX_OK; -} - - -char *ngx_http_set_busy_lock_slot(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - char *p = conf; - - ngx_uint_t i, dup, invalid; - ngx_str_t *value, line; - ngx_http_busy_lock_t *bl, **blp; - - blp = (ngx_http_busy_lock_t **) (p + cmd->offset); - if (*blp) { - return "is duplicate"; - } - - /* ngx_calloc_shared() */ - bl = ngx_pcalloc(cf->pool, sizeof(ngx_http_busy_lock_t)); - if (bl == NULL) { - return NGX_CONF_ERROR; - } - *blp = bl; - - /* ngx_calloc_shared() */ - bl->mutex = ngx_pcalloc(cf->pool, sizeof(ngx_event_mutex_t)); - if (bl->mutex == NULL) { - return NGX_CONF_ERROR; - } - - dup = 0; - invalid = 0; - value = cf->args->elts; - - for (i = 1; i < cf->args->nelts; i++) { - - if (value[i].data[1] != '=') { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid value \"%s\"", value[i].data); - return NGX_CONF_ERROR; - } - - switch (value[i].data[0]) { - - case 'b': - if (bl->max_busy) { - dup = 1; - break; - } - - bl->max_busy = ngx_atoi(value[i].data + 2, value[i].len - 2); - if (bl->max_busy == NGX_ERROR) { - invalid = 1; - break; - } - - continue; - - case 'w': - if (bl->max_waiting) { - dup = 1; - break; - } - - bl->max_waiting = ngx_atoi(value[i].data + 2, value[i].len - 2); - if (bl->max_waiting == NGX_ERROR) { - invalid = 1; - break; - } - - continue; - - case 't': - if (bl->timeout) { - dup = 1; - break; - } - - line.len = value[i].len - 2; - line.data = value[i].data + 2; - - bl->timeout = ngx_parse_time(&line, 1); - if (bl->timeout == (time_t) NGX_ERROR) { - invalid = 1; - break; - } - - continue; - - default: - invalid = 1; - } - - if (dup) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "duplicate value \"%s\"", value[i].data); - return NGX_CONF_ERROR; - } - - if (invalid) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid value \"%s\"", value[i].data); - return NGX_CONF_ERROR; - } - } - - 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"); - } - - return NGX_CONF_OK; -} diff --git a/src/http/ngx_http_busy_lock.h b/src/http/ngx_http_busy_lock.h deleted file mode 100644 index c676382..0000000 --- a/src/http/ngx_http_busy_lock.h +++ /dev/null @@ -1,54 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - */ - - -#ifndef _NGX_HTTP_BUSY_LOCK_H_INCLUDED_ -#define _NGX_HTTP_BUSY_LOCK_H_INCLUDED_ - - -#include -#include -#include -#include - - -typedef struct { - u_char *md5_mask; - char *md5; - int cacheable; - - int busy; - int max_busy; - - int waiting; - int max_waiting; - - time_t timeout; - - ngx_event_mutex_t *mutex; -} ngx_http_busy_lock_t; - - -typedef struct { - time_t time; - ngx_event_t *event; - void (*event_handler)(ngx_event_t *ev); - u_char *md5; - int slot; -} ngx_http_busy_lock_ctx_t; - - -int ngx_http_busy_lock(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc); -int ngx_http_busy_lock_cacheable(ngx_http_busy_lock_t *bl, - ngx_http_busy_lock_ctx_t *bc, int lock); -void ngx_http_busy_unlock(ngx_http_busy_lock_t *bl, - ngx_http_busy_lock_ctx_t *bc); - -char *ngx_http_set_busy_lock_slot(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - - -#endif /* _NGX_HTTP_BUSY_LOCK_H_INCLUDED_ */ diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h index 193a353..d36fa77 100644 --- a/src/http/ngx_http_cache.h +++ b/src/http/ngx_http_cache.h @@ -24,6 +24,10 @@ #define NGX_HTTP_CACHE_SCARCE 8 #define NGX_HTTP_CACHE_KEY_LEN 16 +#define NGX_HTTP_CACHE_ETAG_LEN 42 +#define NGX_HTTP_CACHE_VARY_LEN 42 + +#define NGX_HTTP_CACHE_VERSION 3 typedef struct { @@ -53,6 +57,7 @@ typedef struct { time_t valid_sec; size_t body_start; off_t fs_size; + ngx_msec_t lock_time; } ngx_http_file_cache_node_t; @@ -61,12 +66,17 @@ struct ngx_http_cache_s { ngx_array_t keys; uint32_t crc32; u_char key[NGX_HTTP_CACHE_KEY_LEN]; + u_char main[NGX_HTTP_CACHE_KEY_LEN]; ngx_file_uniq_t uniq; time_t valid_sec; time_t last_modified; time_t date; + ngx_str_t etag; + ngx_str_t vary; + u_char variant[NGX_HTTP_CACHE_KEY_LEN]; + size_t header_start; size_t body_start; off_t length; @@ -81,7 +91,13 @@ struct ngx_http_cache_s { ngx_http_file_cache_t *file_cache; ngx_http_file_cache_node_t *node; +#if (NGX_THREADS) + ngx_thread_task_t *thread_task; +#endif + ngx_msec_t lock_timeout; + ngx_msec_t lock_age; + ngx_msec_t lock_time; ngx_msec_t wait_time; ngx_event_t wait_event; @@ -93,10 +109,13 @@ struct ngx_http_cache_s { unsigned updating:1; unsigned exists:1; unsigned temp_file:1; + unsigned reading:1; + unsigned secondary:1; }; typedef struct { + ngx_uint_t version; time_t valid_sec; time_t last_modified; time_t date; @@ -104,6 +123,11 @@ typedef struct { u_short valid_msec; u_short header_start; u_short body_start; + u_char etag_len; + u_char etag[NGX_HTTP_CACHE_ETAG_LEN]; + u_char vary_len; + u_char vary[NGX_HTTP_CACHE_VARY_LEN]; + u_char variant[NGX_HTTP_CACHE_KEY_LEN]; } ngx_http_file_cache_header_t; @@ -122,6 +146,7 @@ struct ngx_http_file_cache_s { ngx_slab_pool_t *shpool; ngx_path_t *path; + ngx_path_t *temp_path; off_t max_size; size_t bsize; @@ -142,7 +167,7 @@ ngx_int_t ngx_http_file_cache_new(ngx_http_request_t *r); ngx_int_t ngx_http_file_cache_create(ngx_http_request_t *r); void ngx_http_file_cache_create_key(ngx_http_request_t *r); ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r); -void ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf); +ngx_int_t ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf); void ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf); void ngx_http_file_cache_update_header(ngx_http_request_t *r); ngx_int_t ngx_http_cache_send(ngx_http_request_t *); diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c index 3ad27b0..0f908ad 100644 --- a/src/http/ngx_http_copy_filter_module.c +++ b/src/http/ngx_http_copy_filter_module.c @@ -20,9 +20,15 @@ static void ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx, ngx_file_t *file); static void ngx_http_copy_aio_event_handler(ngx_event_t *ev); #if (NGX_HAVE_AIO_SENDFILE) +static ssize_t ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file); static void ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev); #endif #endif +#if (NGX_THREADS) +static ngx_int_t ngx_http_copy_thread_handler(ngx_thread_task_t *task, + ngx_file_t *file); +static void ngx_http_copy_thread_event_handler(ngx_event_t *ev); +#endif static void *ngx_http_copy_filter_create_conf(ngx_conf_t *cf); static char *ngx_http_copy_filter_merge_conf(ngx_conf_t *cf, @@ -120,91 +126,42 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) ctx->filter_ctx = r; #if (NGX_HAVE_FILE_AIO) - if (ngx_file_aio) { - if (clcf->aio) { - ctx->aio_handler = ngx_http_copy_aio_handler; - } + if (ngx_file_aio && clcf->aio == NGX_HTTP_AIO_ON) { + ctx->aio_handler = ngx_http_copy_aio_handler; #if (NGX_HAVE_AIO_SENDFILE) - c->aio_sendfile = (clcf->aio == NGX_HTTP_AIO_SENDFILE); + ctx->aio_preload = ngx_http_copy_aio_sendfile_preload; #endif } #endif +#if (NGX_THREADS) + if (clcf->aio == NGX_HTTP_AIO_THREADS) { + ctx->thread_handler = ngx_http_copy_thread_handler; + } +#endif + if (in && in->buf && ngx_buf_size(in->buf)) { r->request_output = 1; } } -#if (NGX_HAVE_FILE_AIO) +#if (NGX_HAVE_FILE_AIO || NGX_THREADS) ctx->aio = r->aio; #endif - for ( ;; ) { - rc = ngx_output_chain(ctx, in); + rc = ngx_output_chain(ctx, in); - if (ctx->in == NULL) { - r->buffered &= ~NGX_HTTP_COPY_BUFFERED; + if (ctx->in == NULL) { + r->buffered &= ~NGX_HTTP_COPY_BUFFERED; - } else { - r->buffered |= NGX_HTTP_COPY_BUFFERED; - } - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args); - -#if (NGX_HAVE_FILE_AIO && NGX_HAVE_AIO_SENDFILE) - - if (c->busy_sendfile) { - ssize_t n; - off_t offset; - ngx_file_t *file; - ngx_http_ephemeral_t *e; - - if (r->aio) { - c->busy_sendfile = NULL; - return rc; - } - - file = c->busy_sendfile->file; - offset = c->busy_sendfile->file_pos; - - if (file->aio) { - c->busy_count = (offset == file->aio->last_offset) ? - c->busy_count + 1 : 0; - file->aio->last_offset = offset; - - if (c->busy_count > 2) { - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "sendfile(%V) returned busy again", - &file->name); - c->aio_sendfile = 0; - } - } - - c->busy_sendfile = NULL; - e = (ngx_http_ephemeral_t *) &r->uri_start; - - n = ngx_file_aio_read(file, &e->aio_preload, 1, offset, r->pool); - - if (n > 0) { - in = NULL; - continue; - } - - rc = n; - - if (rc == NGX_AGAIN) { - file->aio->data = r; - file->aio->handler = ngx_http_copy_aio_sendfile_event_handler; - - r->main->blocked++; - r->aio = 1; - } - } -#endif - - return rc; + } else { + r->buffered |= NGX_HTTP_COPY_BUFFERED; } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args); + + return rc; } @@ -244,6 +201,29 @@ ngx_http_copy_aio_event_handler(ngx_event_t *ev) #if (NGX_HAVE_AIO_SENDFILE) +static ssize_t +ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file) +{ + ssize_t n; + static u_char buf[1]; + ngx_event_aio_t *aio; + ngx_http_request_t *r; + + n = ngx_file_aio_read(file->file, buf, 1, file->file_pos, NULL); + + if (n == NGX_AGAIN) { + aio = file->file->aio; + aio->handler = ngx_http_copy_aio_sendfile_event_handler; + + r = aio->data; + r->main->blocked++; + r->aio = 1; + } + + return n; +} + + static void ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev) { @@ -264,6 +244,67 @@ ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev) #endif +#if (NGX_THREADS) + +static ngx_int_t +ngx_http_copy_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) +{ + ngx_str_t name; + ngx_thread_pool_t *tp; + ngx_http_request_t *r; + ngx_http_core_loc_conf_t *clcf; + + r = file->thread_ctx; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + tp = clcf->thread_pool; + + if (tp == NULL) { + if (ngx_http_complex_value(r, clcf->thread_pool_value, &name) + != NGX_OK) + { + return NGX_ERROR; + } + + tp = ngx_thread_pool_get((ngx_cycle_t *) ngx_cycle, &name); + + if (tp == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "thread pool \"%V\" not found", &name); + return NGX_ERROR; + } + } + + task->event.data = r; + task->event.handler = ngx_http_copy_thread_event_handler; + + if (ngx_thread_task_post(tp, task) != NGX_OK) { + return NGX_ERROR; + } + + r->main->blocked++; + r->aio = 1; + + return NGX_OK; +} + + +static void +ngx_http_copy_thread_event_handler(ngx_event_t *ev) +{ + ngx_http_request_t *r; + + r = ev->data; + + r->main->blocked--; + r->aio = 0; + + r->connection->write->handler(r->connection->write); +} + +#endif + + static void * ngx_http_copy_filter_create_conf(ngx_conf_t *cf) { diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 1bcd104..f525526 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -26,6 +26,7 @@ static ngx_int_t ngx_http_core_find_static_location(ngx_http_request_t *r, ngx_http_location_tree_node_t *node); static ngx_int_t ngx_http_core_preconfiguration(ngx_conf_t *cf); +static ngx_int_t ngx_http_core_postconfiguration(ngx_conf_t *cf); static void *ngx_http_core_create_main_conf(ngx_conf_t *cf); static char *ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf); static void *ngx_http_core_create_srv_conf(ngx_conf_t *cf); @@ -54,6 +55,8 @@ static char *ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, static char *ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_core_set_aio(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_core_directio(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, @@ -93,18 +96,6 @@ static ngx_conf_post_t ngx_http_core_lowat_post = static ngx_conf_post_handler_pt ngx_http_core_pool_size_p = ngx_http_core_pool_size; -static ngx_conf_deprecated_t ngx_conf_deprecated_optimize_server_names = { - ngx_conf_deprecated, "optimize_server_names", "server_name_in_redirect" -}; - -static ngx_conf_deprecated_t ngx_conf_deprecated_open_file_cache_retest = { - ngx_conf_deprecated, "open_file_cache_retest", "open_file_cache_valid" -}; - -static ngx_conf_deprecated_t ngx_conf_deprecated_satisfy_any = { - ngx_conf_deprecated, "satisfy_any", "satisfy" -}; - static ngx_conf_enum_t ngx_http_core_request_body_in_file[] = { { ngx_string("off"), NGX_HTTP_REQUEST_BODY_FILE_OFF }, @@ -114,20 +105,6 @@ static ngx_conf_enum_t ngx_http_core_request_body_in_file[] = { }; -#if (NGX_HAVE_FILE_AIO) - -static ngx_conf_enum_t ngx_http_core_aio[] = { - { ngx_string("off"), NGX_HTTP_AIO_OFF }, - { ngx_string("on"), NGX_HTTP_AIO_ON }, -#if (NGX_HAVE_AIO_SENDFILE) - { ngx_string("sendfile"), NGX_HTTP_AIO_SENDFILE }, -#endif - { ngx_null_string, 0 } -}; - -#endif - - static ngx_conf_enum_t ngx_http_core_satisfy[] = { { ngx_string("all"), NGX_HTTP_SATISFY_ALL }, { ngx_string("any"), NGX_HTTP_SATISFY_ANY }, @@ -266,13 +243,6 @@ static ngx_command_t ngx_http_core_commands[] = { offsetof(ngx_http_core_srv_conf_t, large_client_header_buffers), NULL }, - { ngx_string("optimize_server_names"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_core_loc_conf_t, server_name_in_redirect), - &ngx_conf_deprecated_optimize_server_names }, - { ngx_string("ignore_invalid_headers"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -423,16 +393,12 @@ static ngx_command_t ngx_http_core_commands[] = { offsetof(ngx_http_core_loc_conf_t, sendfile_max_chunk), NULL }, -#if (NGX_HAVE_FILE_AIO) - { ngx_string("aio"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_enum_slot, + ngx_http_core_set_aio, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_core_loc_conf_t, aio), - &ngx_http_core_aio }, - -#endif + 0, + NULL }, { ngx_string("read_ahead"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, @@ -534,13 +500,6 @@ static ngx_command_t ngx_http_core_commands[] = { offsetof(ngx_http_core_loc_conf_t, satisfy), &ngx_http_core_satisfy }, - { ngx_string("satisfy_any"), - 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_core_loc_conf_t, satisfy), - &ngx_conf_deprecated_satisfy_any }, - { ngx_string("internal"), NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, ngx_http_core_internal, @@ -704,13 +663,6 @@ static ngx_command_t ngx_http_core_commands[] = { offsetof(ngx_http_core_loc_conf_t, open_file_cache_valid), NULL }, - { ngx_string("open_file_cache_retest"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_sec_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_core_loc_conf_t, open_file_cache_valid), - &ngx_conf_deprecated_open_file_cache_retest }, - { ngx_string("open_file_cache_min_uses"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, @@ -795,7 +747,7 @@ static ngx_command_t ngx_http_core_commands[] = { static ngx_http_module_t ngx_http_core_module_ctx = { ngx_http_core_preconfiguration, /* preconfiguration */ - NULL, /* postconfiguration */ + ngx_http_core_postconfiguration, /* postconfiguration */ ngx_http_core_create_main_conf, /* create main configuration */ ngx_http_core_init_main_conf, /* init main configuration */ @@ -1245,10 +1197,8 @@ ngx_http_core_try_files_phase(ngx_http_request_t *r, if (!alias) { reserve = len > r->uri.len ? len - r->uri.len : 0; -#if (NGX_PCRE) - } else if (clcf->regex) { + } else if (alias == NGX_MAX_SIZE_T_VALUE) { reserve = len; -#endif } else { reserve = len > r->uri.len - alias ? len - (r->uri.len - alias) : 0; @@ -1355,7 +1305,7 @@ ngx_http_core_try_files_phase(ngx_http_request_t *r, continue; } - if (of.is_dir && !test_dir) { + if (of.is_dir != test_dir) { continue; } @@ -1365,13 +1315,12 @@ ngx_http_core_try_files_phase(ngx_http_request_t *r, if (!alias) { r->uri = path; -#if (NGX_PCRE) - } else if (clcf->regex) { + } else if (alias == NGX_MAX_SIZE_T_VALUE) { if (!test_dir) { r->uri = path; r->add_uri_to_alias = 1; } -#endif + } else { r->uri.len = alias + path.len; r->uri.data = ngx_pnalloc(r->pool, r->uri.len); @@ -1463,7 +1412,7 @@ ngx_http_update_location_config(ngx_http_request_t *r) } if (r == r->main) { - ngx_http_set_connection_log(r->connection, clcf->error_log); + ngx_set_connection_log(r->connection, clcf->error_log); } if ((ngx_io.flags & NGX_IO_SENDFILE) && clcf->sendfile) { @@ -1840,6 +1789,7 @@ ngx_http_set_etag(ngx_http_request_t *r) etag->value.data = ngx_pnalloc(r->pool, NGX_OFF_T_LEN + NGX_TIME_T_LEN + 3); if (etag->value.data == NULL) { + etag->hash = 0; return NGX_ERROR; } @@ -1854,6 +1804,46 @@ ngx_http_set_etag(ngx_http_request_t *r) } +void +ngx_http_weak_etag(ngx_http_request_t *r) +{ + size_t len; + u_char *p; + ngx_table_elt_t *etag; + + etag = r->headers_out.etag; + + if (etag == NULL) { + return; + } + + if (etag->value.len > 2 + && etag->value.data[0] == 'W' + && etag->value.data[1] == '/') + { + return; + } + + if (etag->value.len < 1 || etag->value.data[0] != '"') { + r->headers_out.etag->hash = 0; + r->headers_out.etag = NULL; + return; + } + + p = ngx_pnalloc(r->pool, etag->value.len + 2); + if (p == NULL) { + r->headers_out.etag->hash = 0; + r->headers_out.etag = NULL; + return; + } + + len = ngx_sprintf(p, "W/%V", &etag->value) - p; + + etag->value.data = p; + etag->value.len = len; +} + + ngx_int_t ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status, ngx_str_t *ct, ngx_http_complex_value_t *cv) @@ -2010,16 +2000,12 @@ ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *path, } else { -#if (NGX_PCRE) - ngx_uint_t captures; + if (alias == NGX_MAX_SIZE_T_VALUE) { + reserved += r->add_uri_to_alias ? r->uri.len + 1 : 1; - captures = alias && clcf->regex; - - reserved += captures ? r->add_uri_to_alias ? r->uri.len + 1 : 1 - : r->uri.len - alias + 1; -#else - reserved += r->uri.len - alias + 1; -#endif + } else { + reserved += r->uri.len - alias + 1; + } if (ngx_http_script_run(r, path, clcf->root_lengths->elts, reserved, clcf->root_values->elts) @@ -2037,8 +2023,7 @@ ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *path, *root_length = path->len - reserved; last = path->data + *root_length; -#if (NGX_PCRE) - if (captures) { + if (alias == NGX_MAX_SIZE_T_VALUE) { if (!r->add_uri_to_alias) { *last = '\0'; return last; @@ -2046,7 +2031,6 @@ ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *path, alias = 0; } -#endif } last = ngx_cpystrn(last, r->uri.data + alias, r->uri.len - alias + 1); @@ -2328,7 +2312,7 @@ ngx_http_gzip_accept_encoding(ngx_str_t *ae) p += 4; while (p < last) { - switch(*p++) { + switch (*p++) { case ',': return NGX_OK; case ';': @@ -2345,7 +2329,7 @@ ngx_http_gzip_accept_encoding(ngx_str_t *ae) quantity: while (p < last) { - switch(*p++) { + switch (*p++) { case 'q': case 'Q': goto equal; @@ -3404,6 +3388,15 @@ ngx_http_core_preconfiguration(ngx_conf_t *cf) } +static ngx_int_t +ngx_http_core_postconfiguration(ngx_conf_t *cf) +{ + ngx_http_top_request_body_filter = ngx_http_request_body_save_filter; + + return NGX_OK; +} + + static void * ngx_http_core_create_main_conf(ngx_conf_t *cf) { @@ -3607,8 +3600,10 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf) clcf->internal = NGX_CONF_UNSET; clcf->sendfile = NGX_CONF_UNSET; clcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE; -#if (NGX_HAVE_FILE_AIO) clcf->aio = NGX_CONF_UNSET; +#if (NGX_THREADS) + clcf->thread_pool = NGX_CONF_UNSET_PTR; + clcf->thread_pool_value = NGX_CONF_UNSET_PTR; #endif clcf->read_ahead = NGX_CONF_UNSET_SIZE; clcf->directio = NGX_CONF_UNSET; @@ -3825,8 +3820,13 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0); ngx_conf_merge_size_value(conf->sendfile_max_chunk, prev->sendfile_max_chunk, 0); -#if (NGX_HAVE_FILE_AIO) +#if (NGX_HAVE_FILE_AIO || NGX_THREADS) ngx_conf_merge_value(conf->aio, prev->aio, NGX_HTTP_AIO_OFF); +#endif +#if (NGX_THREADS) + ngx_conf_merge_ptr_value(conf->thread_pool, prev->thread_pool, NULL); + ngx_conf_merge_ptr_value(conf->thread_pool_value, prev->thread_pool_value, + NULL); #endif ngx_conf_merge_size_value(conf->read_ahead, prev->read_ahead, 0); ngx_conf_merge_off_value(conf->directio, prev->directio, @@ -4166,6 +4166,19 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } + if (ngx_strcmp(value[n].data, "reuseport") == 0) { +#if (NGX_HAVE_REUSEPORT) + lsopt.reuseport = 1; + lsopt.set = 1; + lsopt.bind = 1; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "reuseport is not supported " + "on this platform, ignored"); +#endif + continue; + } + if (ngx_strcmp(value[n].data, "ssl") == 0) { #if (NGX_HTTP_SSL) lsopt.ssl = 1; @@ -4480,6 +4493,7 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #if (NGX_PCRE) if (alias && clcf->regex) { + clcf->alias = NGX_MAX_SIZE_T_VALUE; n = 1; } #endif @@ -4620,6 +4634,116 @@ ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +static char * +ngx_http_core_set_aio(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_core_loc_conf_t *clcf = conf; + + ngx_str_t *value; + + if (clcf->aio != NGX_CONF_UNSET) { + return "is duplicate"; + } + +#if (NGX_THREADS) + clcf->thread_pool = NULL; + clcf->thread_pool_value = NULL; +#endif + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "off") == 0) { + clcf->aio = NGX_HTTP_AIO_OFF; + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[1].data, "on") == 0) { +#if (NGX_HAVE_FILE_AIO) + clcf->aio = NGX_HTTP_AIO_ON; + return NGX_CONF_OK; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"aio on\" " + "is unsupported on this platform"); + return NGX_CONF_ERROR; +#endif + } + +#if (NGX_HAVE_AIO_SENDFILE) + + if (ngx_strcmp(value[1].data, "sendfile") == 0) { + clcf->aio = NGX_HTTP_AIO_ON; + + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "the \"sendfile\" parameter of " + "the \"aio\" directive is deprecated"); + return NGX_CONF_OK; + } + +#endif + + if (ngx_strncmp(value[1].data, "threads", 7) == 0 + && (value[1].len == 7 || value[1].data[7] == '=')) + { +#if (NGX_THREADS) + ngx_str_t name; + ngx_thread_pool_t *tp; + ngx_http_complex_value_t cv; + ngx_http_compile_complex_value_t ccv; + + clcf->aio = NGX_HTTP_AIO_THREADS; + + if (value[1].len >= 8) { + name.len = value[1].len - 8; + name.data = value[1].data + 8; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &name; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + clcf->thread_pool_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (clcf->thread_pool_value == NULL) { + return NGX_CONF_ERROR; + } + + *clcf->thread_pool_value = cv; + + return NGX_CONF_OK; + } + + tp = ngx_thread_pool_add(cf, &name); + + } else { + tp = ngx_thread_pool_add(cf, NULL); + } + + if (tp == NULL) { + return NGX_CONF_ERROR; + } + + clcf->thread_pool = tp; + + return NGX_CONF_OK; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"aio threads\" " + "is unsupported on this platform"); + return NGX_CONF_ERROR; +#endif + } + + return "invalid value"; +} + + static char * ngx_http_core_directio(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { @@ -4801,7 +4925,8 @@ ngx_http_core_try_files(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) tf[i].name = value[i + 1]; if (tf[i].name.len > 0 - && tf[i].name.data[tf[i].name.len - 1] == '/') + && tf[i].name.data[tf[i].name.len - 1] == '/' + && i + 2 < cf->args->nelts) { tf[i].test_dir = 1; tf[i].name.len--; diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 799d2fe..e6be5ac 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -13,6 +13,10 @@ #include #include +#if (NGX_THREADS) +#include +#endif + #define NGX_HTTP_GZIP_PROXIED_OFF 0x0002 #define NGX_HTTP_GZIP_PROXIED_EXPIRED 0x0004 @@ -27,7 +31,7 @@ #define NGX_HTTP_AIO_OFF 0 #define NGX_HTTP_AIO_ON 1 -#define NGX_HTTP_AIO_SENDFILE 2 +#define NGX_HTTP_AIO_THREADS 2 #define NGX_HTTP_SATISFY_ALL 0 @@ -80,6 +84,9 @@ typedef struct { #endif #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) unsigned ipv6only:1; +#endif +#if (NGX_HAVE_REUSEPORT) + unsigned reuseport:1; #endif unsigned so_keepalive:2; unsigned proxy_protocol:1; @@ -396,9 +403,7 @@ struct ngx_http_core_loc_conf_s { /* client_body_in_singe_buffer */ ngx_flag_t internal; /* internal */ ngx_flag_t sendfile; /* sendfile */ -#if (NGX_HAVE_FILE_AIO) ngx_flag_t aio; /* aio */ -#endif ngx_flag_t tcp_nopush; /* tcp_nopush */ ngx_flag_t tcp_nodelay; /* tcp_nodelay */ ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */ @@ -424,6 +429,11 @@ struct ngx_http_core_loc_conf_s { #endif #endif +#if (NGX_THREADS) + ngx_thread_pool_t *thread_pool; + ngx_http_complex_value_t *thread_pool_value; +#endif + #if (NGX_HAVE_OPENAT) ngx_uint_t disable_symlinks; /* disable_symlinks */ ngx_http_complex_value_t *disable_symlinks_from; @@ -501,6 +511,7 @@ void *ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash); ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r); void ngx_http_set_exten(ngx_http_request_t *r); ngx_int_t ngx_http_set_etag(ngx_http_request_t *r); +void ngx_http_weak_etag(ngx_http_request_t *r); ngx_int_t ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status, ngx_str_t *ct, ngx_http_complex_value_t *cv); u_char *ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *name, @@ -525,10 +536,14 @@ ngx_http_cleanup_t *ngx_http_cleanup_add(ngx_http_request_t *r, size_t size); typedef ngx_int_t (*ngx_http_output_header_filter_pt)(ngx_http_request_t *r); typedef ngx_int_t (*ngx_http_output_body_filter_pt) (ngx_http_request_t *r, ngx_chain_t *chain); +typedef ngx_int_t (*ngx_http_request_body_filter_pt) + (ngx_http_request_t *r, ngx_chain_t *chain); 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_request_body_save_filter(ngx_http_request_t *r, + ngx_chain_t *chain); ngx_int_t ngx_http_set_disable_symlinks(ngx_http_request_t *r, @@ -553,7 +568,7 @@ extern ngx_str_t ngx_http_core_get_method; r->headers_out.content_length->hash = 0; \ r->headers_out.content_length = NULL; \ } - \ + #define ngx_http_clear_accept_ranges(r) \ \ r->allow_ranges = 0; \ diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index 9e6be15..fc14761 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -14,6 +14,8 @@ 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 void ngx_http_file_cache_lock_wait(ngx_http_request_t *r, + ngx_http_cache_t *c); 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, @@ -21,6 +23,11 @@ static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r, #if (NGX_HAVE_FILE_AIO) static void ngx_http_cache_aio_event_handler(ngx_event_t *ev); #endif +#if (NGX_THREADS) +static ngx_int_t ngx_http_cache_thread_handler(ngx_thread_task_t *task, + ngx_file_t *file); +static void ngx_http_cache_thread_event_handler(ngx_event_t *ev); +#endif static ngx_int_t ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c); static ngx_int_t ngx_http_file_cache_name(ngx_http_request_t *r, @@ -29,6 +36,14 @@ static ngx_http_file_cache_node_t * ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key); static void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +static void ngx_http_file_cache_vary(ngx_http_request_t *r, u_char *vary, + size_t len, u_char *hash); +static void ngx_http_file_cache_vary_header(ngx_http_request_t *r, + ngx_md5_t *md5, ngx_str_t *name); +static ngx_int_t ngx_http_file_cache_reopen(ngx_http_request_t *r, + ngx_http_cache_t *c); +static ngx_int_t ngx_http_file_cache_update_variant(ngx_http_request_t *r, + ngx_http_cache_t *c); static void ngx_http_file_cache_cleanup(void *data); 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); @@ -39,6 +54,8 @@ 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, ngx_str_t *path); +static ngx_int_t ngx_http_file_cache_manage_directory(ngx_tree_ctx_t *ctx, + ngx_str_t *path); static ngx_int_t ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx, ngx_str_t *path); static ngx_int_t ngx_http_file_cache_add(ngx_http_file_cache_t *cache, @@ -145,6 +162,8 @@ ngx_http_file_cache_init(ngx_shm_zone_t *shm_zone, void *data) ngx_sprintf(cache->shpool->log_ctx, " in cache keys zone \"%V\"%Z", &shm_zone->shm.name); + cache->shpool->log_nomem = 0; + return NGX_OK; } @@ -233,6 +252,8 @@ ngx_http_file_cache_create_key(ngx_http_request_t *r) ngx_crc32_final(c->crc32); ngx_md5_final(c->key, &md5); + + ngx_memcpy(c->main, c->key, NGX_HTTP_CACHE_KEY_LEN); } @@ -240,7 +261,7 @@ ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r) { ngx_int_t rc, rv; - ngx_uint_t cold, test; + ngx_uint_t test; ngx_http_cache_t *c; ngx_pool_cleanup_t *cln; ngx_open_file_info_t of; @@ -253,7 +274,7 @@ ngx_http_file_cache_open(ngx_http_request_t *r) return NGX_AGAIN; } - if (c->buf) { + if (c->reading) { return ngx_http_file_cache_read(r, c); } @@ -282,8 +303,6 @@ ngx_http_file_cache_open(ngx_http_request_t *r) return NGX_HTTP_CACHE_SCARCE; } - cold = cache->sh->cold; - if (rc == NGX_OK) { if (c->error) { @@ -296,18 +315,18 @@ ngx_http_file_cache_open(ngx_http_request_t *r) } else { /* rc == NGX_DECLINED */ + test = cache->sh->cold ? 1 : 0; + if (c->min_uses > 1) { - if (!cold) { + if (!test) { return NGX_HTTP_CACHE_SCARCE; } - test = 1; rv = NGX_HTTP_CACHE_SCARCE; } else { c->temp_file = 1; - test = cold ? 1 : 0; rv = NGX_DECLINED; } } @@ -386,13 +405,19 @@ ngx_http_file_cache_lock(ngx_http_request_t *r, ngx_http_cache_t *c) return NGX_DECLINED; } + now = ngx_current_msec; + cache = c->file_cache; ngx_shmtx_lock(&cache->shpool->mutex); - if (!c->node->updating) { + timer = c->node->lock_time - now; + + if (!c->node->updating || (ngx_msec_int_t) timer <= 0) { c->node->updating = 1; + c->node->lock_time = now + c->lock_age; c->updating = 1; + c->lock_time = c->node->lock_time; } ngx_shmtx_unlock(&cache->shpool->mutex); @@ -405,9 +430,11 @@ ngx_http_file_cache_lock(ngx_http_request_t *r, ngx_http_cache_t *c) return NGX_DECLINED; } - c->waiting = 1; + if (c->lock_timeout == 0) { + return NGX_HTTP_CACHE_SCARCE; + } - now = ngx_current_msec; + c->waiting = 1; if (c->wait_time == 0) { c->wait_time = now + c->lock_timeout; @@ -430,24 +457,38 @@ 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) { - ngx_uint_t wait; - ngx_msec_t timer; - ngx_http_cache_t *c; - ngx_http_request_t *r; - ngx_http_file_cache_t *cache; + ngx_connection_t *c; + ngx_http_request_t *r; r = ev->data; - c = r->cache; + c = r->connection; - 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); + ngx_http_set_log_request(c->log, r); - timer = c->wait_time - ngx_current_msec; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http file cache wait: \"%V?%V\"", &r->uri, &r->args); + + ngx_http_file_cache_lock_wait(r, r->cache); + + ngx_http_run_posted_requests(c); +} + + +static void +ngx_http_file_cache_lock_wait(ngx_http_request_t *r, ngx_http_cache_t *c) +{ + ngx_uint_t wait; + ngx_msec_t now, timer; + ngx_http_file_cache_t *cache; + + now = ngx_current_msec; + + timer = c->wait_time - now; if ((ngx_msec_int_t) timer <= 0) { - ngx_log_error(NGX_LOG_INFO, ev->log, 0, "cache lock timeout"); - c->lock = 0; + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "cache lock timeout"); + c->lock_timeout = 0; goto wakeup; } @@ -456,14 +497,16 @@ ngx_http_file_cache_lock_wait_handler(ngx_event_t *ev) ngx_shmtx_lock(&cache->shpool->mutex); - if (c->node->updating) { + timer = c->node->lock_time - now; + + if (c->node->updating && (ngx_msec_int_t) timer > 0) { wait = 1; } ngx_shmtx_unlock(&cache->shpool->mutex); if (wait) { - ngx_add_timer(ev, (timer > 500) ? 500 : timer); + ngx_add_timer(&c->wait_event, (timer > 500) ? 500 : timer); return; } @@ -471,7 +514,7 @@ wakeup: c->waiting = 0; r->main->blocked--; - r->connection->write->handler(r->connection->write); + r->write_event_handler(r); } @@ -498,6 +541,12 @@ ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c) h = (ngx_http_file_cache_header_t *) c->buf->pos; + if (h->version != NGX_HTTP_CACHE_VERSION) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "cache file \"%s\" version mismatch", c->file.name.data); + return NGX_DECLINED; + } + if (h->crc32 != c->crc32) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, "cache file \"%s\" has md5 collision", c->file.name.data); @@ -511,6 +560,23 @@ ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c) return NGX_DECLINED; } + if (h->vary_len > NGX_HTTP_CACHE_VARY_LEN) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + "cache file \"%s\" has incorrect vary length", + c->file.name.data); + return NGX_DECLINED; + } + + if (h->vary_len) { + ngx_http_file_cache_vary(r, h->vary, h->vary_len, c->variant); + + if (ngx_memcmp(c->variant, h->variant, NGX_HTTP_CACHE_KEY_LEN) != 0) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache vary mismatch"); + return ngx_http_file_cache_reopen(r, c); + } + } + c->buf->last += n; c->valid_sec = h->valid_sec; @@ -519,6 +585,8 @@ ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c) c->valid_msec = h->valid_msec; c->header_start = h->header_start; c->body_start = h->body_start; + c->etag.len = h->etag_len; + c->etag.data = h->etag; r->cached = 1; @@ -553,6 +621,7 @@ ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c) } else { c->node->updating = 1; c->updating = 1; + c->lock_time = c->node->lock_time; rc = NGX_HTTP_CACHE_STALE; } @@ -572,36 +641,50 @@ 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, ngx_http_cache_t *c) { -#if (NGX_HAVE_FILE_AIO) +#if (NGX_HAVE_FILE_AIO || NGX_THREADS) ssize_t n; ngx_http_core_loc_conf_t *clcf; - if (!ngx_file_aio) { - goto noaio; - } - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); +#endif - if (!clcf->aio) { - goto noaio; +#if (NGX_HAVE_FILE_AIO) + + if (clcf->aio == NGX_HTTP_AIO_ON && ngx_file_aio) { + n = ngx_file_aio_read(&c->file, c->buf->pos, c->body_start, 0, r->pool); + + if (n != NGX_AGAIN) { + c->reading = 0; + return n; + } + + c->reading = 1; + + c->file.aio->data = r; + c->file.aio->handler = ngx_http_cache_aio_event_handler; + + r->main->blocked++; + r->aio = 1; + + return NGX_AGAIN; } - n = ngx_file_aio_read(&c->file, c->buf->pos, c->body_start, 0, r->pool); +#endif + +#if (NGX_THREADS) + + if (clcf->aio == NGX_HTTP_AIO_THREADS) { + c->file.thread_handler = ngx_http_cache_thread_handler; + c->file.thread_ctx = r; + + n = ngx_thread_read(&c->thread_task, &c->file, c->buf->pos, + c->body_start, 0, r->pool); + + c->reading = (n == NGX_AGAIN); - if (n != NGX_AGAIN) { return n; } - c->file.aio->data = r; - c->file.aio->handler = ngx_http_cache_aio_event_handler; - - r->main->blocked++; - r->aio = 1; - - return NGX_AGAIN; - -noaio: - #endif return ngx_read_file(&c->file, c->buf->pos, c->body_start, 0); @@ -614,15 +697,94 @@ static void ngx_http_cache_aio_event_handler(ngx_event_t *ev) { ngx_event_aio_t *aio; + ngx_connection_t *c; ngx_http_request_t *r; aio = ev->data; r = aio->data; + c = r->connection; + + ngx_http_set_log_request(c->log, r); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http file cache aio: \"%V?%V\"", &r->uri, &r->args); r->main->blocked--; r->aio = 0; - r->connection->write->handler(r->connection->write); + r->write_event_handler(r); + + ngx_http_run_posted_requests(c); +} + +#endif + + +#if (NGX_THREADS) + +static ngx_int_t +ngx_http_cache_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) +{ + ngx_str_t name; + ngx_thread_pool_t *tp; + ngx_http_request_t *r; + ngx_http_core_loc_conf_t *clcf; + + r = file->thread_ctx; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + tp = clcf->thread_pool; + + if (tp == NULL) { + if (ngx_http_complex_value(r, clcf->thread_pool_value, &name) + != NGX_OK) + { + return NGX_ERROR; + } + + tp = ngx_thread_pool_get((ngx_cycle_t *) ngx_cycle, &name); + + if (tp == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "thread pool \"%V\" not found", &name); + return NGX_ERROR; + } + } + + task->event.data = r; + task->event.handler = ngx_http_cache_thread_event_handler; + + if (ngx_thread_task_post(tp, task) != NGX_OK) { + return NGX_ERROR; + } + + r->main->blocked++; + r->aio = 1; + + return NGX_OK; +} + + +static void +ngx_http_cache_thread_event_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + ngx_http_request_t *r; + + r = ev->data; + c = r->connection; + + ngx_http_set_log_request(c->log, r); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http file cache thread: \"%V?%V\"", &r->uri, &r->args); + + r->main->blocked--; + r->aio = 0; + + r->write_event_handler(r); + + ngx_http_run_posted_requests(c); } #endif @@ -678,8 +840,8 @@ ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) goto done; } - fcn = ngx_slab_alloc_locked(cache->shpool, - sizeof(ngx_http_file_cache_node_t)); + fcn = ngx_slab_calloc_locked(cache->shpool, + sizeof(ngx_http_file_cache_node_t)); if (fcn == NULL) { ngx_shmtx_unlock(&cache->shpool->mutex); @@ -687,9 +849,11 @@ ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) ngx_shmtx_lock(&cache->shpool->mutex); - fcn = ngx_slab_alloc_locked(cache->shpool, - sizeof(ngx_http_file_cache_node_t)); + fcn = ngx_slab_calloc_locked(cache->shpool, + sizeof(ngx_http_file_cache_node_t)); if (fcn == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "could not allocate node%s", cache->shpool->log_ctx); rc = NGX_ERROR; goto failed; } @@ -704,8 +868,6 @@ ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) fcn->uses = 1; fcn->count = 1; - fcn->updating = 0; - fcn->deleting = 0; renew: @@ -860,7 +1022,193 @@ ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, } -void +static void +ngx_http_file_cache_vary(ngx_http_request_t *r, u_char *vary, size_t len, + u_char *hash) +{ + u_char *p, *last; + ngx_str_t name; + ngx_md5_t md5; + u_char buf[NGX_HTTP_CACHE_VARY_LEN]; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache vary: \"%*s\"", len, vary); + + ngx_md5_init(&md5); + ngx_md5_update(&md5, r->cache->main, NGX_HTTP_CACHE_KEY_LEN); + + ngx_strlow(buf, vary, len); + + p = buf; + last = buf + len; + + while (p < last) { + + while (p < last && (*p == ' ' || *p == ',')) { p++; } + + name.data = p; + + while (p < last && *p != ',' && *p != ' ') { p++; } + + name.len = p - name.data; + + if (name.len == 0) { + break; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache vary: %V", &name); + + ngx_md5_update(&md5, name.data, name.len); + ngx_md5_update(&md5, (u_char *) ":", sizeof(":") - 1); + + ngx_http_file_cache_vary_header(r, &md5, &name); + + ngx_md5_update(&md5, (u_char *) CRLF, sizeof(CRLF) - 1); + } + + ngx_md5_final(hash, &md5); +} + + +static void +ngx_http_file_cache_vary_header(ngx_http_request_t *r, ngx_md5_t *md5, + ngx_str_t *name) +{ + size_t len; + u_char *p, *start, *last; + ngx_uint_t i, multiple, normalize; + ngx_list_part_t *part; + ngx_table_elt_t *header; + + multiple = 0; + normalize = 0; + + if (name->len == sizeof("Accept-Charset") - 1 + && ngx_strncasecmp(name->data, (u_char *) "Accept-Charset", + sizeof("Accept-Charset") - 1) == 0) + { + normalize = 1; + + } else if (name->len == sizeof("Accept-Encoding") - 1 + && ngx_strncasecmp(name->data, (u_char *) "Accept-Encoding", + sizeof("Accept-Encoding") - 1) == 0) + { + normalize = 1; + + } else if (name->len == sizeof("Accept-Language") - 1 + && ngx_strncasecmp(name->data, (u_char *) "Accept-Language", + sizeof("Accept-Language") - 1) == 0) + { + normalize = 1; + } + + part = &r->headers_in.headers.part; + header = part->elts; + + for (i = 0; /* void */ ; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].hash == 0) { + continue; + } + + if (header[i].key.len != name->len) { + continue; + } + + if (ngx_strncasecmp(header[i].key.data, name->data, name->len) != 0) { + continue; + } + + if (!normalize) { + + if (multiple) { + ngx_md5_update(md5, (u_char *) ",", sizeof(",") - 1); + } + + ngx_md5_update(md5, header[i].value.data, header[i].value.len); + + multiple = 1; + + continue; + } + + /* normalize spaces */ + + p = header[i].value.data; + last = p + header[i].value.len; + + while (p < last) { + + while (p < last && (*p == ' ' || *p == ',')) { p++; } + + start = p; + + while (p < last && *p != ',' && *p != ' ') { p++; } + + len = p - start; + + if (len == 0) { + break; + } + + if (multiple) { + ngx_md5_update(md5, (u_char *) ",", sizeof(",") - 1); + } + + ngx_md5_update(md5, start, len); + + multiple = 1; + } + } +} + + +static ngx_int_t +ngx_http_file_cache_reopen(ngx_http_request_t *r, ngx_http_cache_t *c) +{ + ngx_http_file_cache_t *cache; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->file.log, 0, + "http file cache reopen"); + + if (c->secondary) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + "cache file \"%s\" has incorrect vary hash", + c->file.name.data); + return NGX_DECLINED; + } + + cache = c->file_cache; + + ngx_shmtx_lock(&cache->shpool->mutex); + + c->node->count--; + c->node = NULL; + + ngx_shmtx_unlock(&cache->shpool->mutex); + + c->secondary = 1; + c->file.name.len = 0; + c->body_start = c->buf->end - c->buf->start; + + ngx_memcpy(c->key, c->variant, NGX_HTTP_CACHE_KEY_LEN); + + return ngx_http_file_cache_open(r); +} + + +ngx_int_t ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf) { ngx_http_file_cache_header_t *h = (ngx_http_file_cache_header_t *) buf; @@ -877,6 +1225,7 @@ ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf) ngx_memzero(h, sizeof(ngx_http_file_cache_header_t)); + h->version = NGX_HTTP_CACHE_VERSION; h->valid_sec = c->valid_sec; h->last_modified = c->last_modified; h->date = c->date; @@ -885,6 +1234,28 @@ ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf) h->header_start = (u_short) c->header_start; h->body_start = (u_short) c->body_start; + if (c->etag.len <= NGX_HTTP_CACHE_ETAG_LEN) { + h->etag_len = (u_char) c->etag.len; + ngx_memcpy(h->etag, c->etag.data, c->etag.len); + } + + if (c->vary.len) { + if (c->vary.len > NGX_HTTP_CACHE_VARY_LEN) { + /* should not happen */ + c->vary.len = NGX_HTTP_CACHE_VARY_LEN; + } + + h->vary_len = (u_char) c->vary.len; + ngx_memcpy(h->vary, c->vary.data, c->vary.len); + + ngx_http_file_cache_vary(r, c->vary.data, c->vary.len, c->variant); + ngx_memcpy(h->variant, c->variant, NGX_HTTP_CACHE_KEY_LEN); + } + + if (ngx_http_file_cache_update_variant(r, c) != NGX_OK) { + return NGX_ERROR; + } + p = buf + sizeof(ngx_http_file_cache_header_t); p = ngx_cpymem(p, ngx_http_file_cache_key, sizeof(ngx_http_file_cache_key)); @@ -895,6 +1266,57 @@ ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf) } *p = LF; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_file_cache_update_variant(ngx_http_request_t *r, ngx_http_cache_t *c) +{ + ngx_http_file_cache_t *cache; + + if (!c->secondary) { + return NGX_OK; + } + + if (c->vary.len + && ngx_memcmp(c->variant, c->key, NGX_HTTP_CACHE_KEY_LEN) == 0) + { + return NGX_OK; + } + + /* + * if the variant hash doesn't match one we used as a secondary + * cache key, switch back to the original key + */ + + cache = c->file_cache; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache main key"); + + ngx_shmtx_lock(&cache->shpool->mutex); + + c->node->count--; + c->node->updating = 0; + c->node = NULL; + + ngx_shmtx_unlock(&cache->shpool->mutex); + + c->file.name.len = 0; + + ngx_memcpy(c->key, c->main, NGX_HTTP_CACHE_KEY_LEN); + + if (ngx_http_file_cache_exists(cache, c) == NGX_ERROR) { + return NGX_ERROR; + } + + if (ngx_http_file_cache_name(r, cache->path) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; } @@ -918,11 +1340,11 @@ ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http file cache update"); + cache = c->file_cache; + c->updated = 1; c->updating = 0; - cache = c->file_cache; - uniq = 0; fs_size = 0; @@ -1044,7 +1466,8 @@ ngx_http_file_cache_update_header(ngx_http_request_t *r) goto done; } - if (h.last_modified != c->last_modified + if (h.version != NGX_HTTP_CACHE_VERSION + || h.last_modified != c->last_modified || h.crc32 != c->crc32 || h.header_start != c->header_start || h.body_start != c->body_start) @@ -1062,6 +1485,7 @@ ngx_http_file_cache_update_header(ngx_http_request_t *r) ngx_memzero(&h, sizeof(ngx_http_file_cache_header_t)); + h.version = NGX_HTTP_CACHE_VERSION; h.valid_sec = c->valid_sec; h.last_modified = c->last_modified; h.date = c->date; @@ -1070,6 +1494,24 @@ ngx_http_file_cache_update_header(ngx_http_request_t *r) h.header_start = (u_short) c->header_start; h.body_start = (u_short) c->body_start; + if (c->etag.len <= NGX_HTTP_CACHE_ETAG_LEN) { + h.etag_len = (u_char) c->etag.len; + ngx_memcpy(h.etag, c->etag.data, c->etag.len); + } + + if (c->vary.len) { + if (c->vary.len > NGX_HTTP_CACHE_VARY_LEN) { + /* should not happen */ + c->vary.len = NGX_HTTP_CACHE_VARY_LEN; + } + + h.vary_len = (u_char) c->vary.len; + ngx_memcpy(h.vary, c->vary.data, c->vary.len); + + ngx_http_file_cache_vary(r, c->vary.data, c->vary.len, c->variant); + ngx_memcpy(h.variant, c->variant, NGX_HTTP_CACHE_KEY_LEN); + } + (void) ngx_write_file(&file, (u_char *) &h, sizeof(ngx_http_file_cache_header_t), 0); @@ -1155,7 +1597,7 @@ ngx_http_file_cache_free(ngx_http_cache_t *c, ngx_temp_file_t *tf) fcn = c->node; fcn->count--; - if (c->updating) { + if (c->updating && fcn->lock_time == c->lock_time) { fcn->updating = 0; } @@ -1313,6 +1755,11 @@ ngx_http_file_cache_expire(ngx_http_file_cache_t *cache) for ( ;; ) { + if (ngx_quit || ngx_terminate) { + wait = 1; + break; + } + if (ngx_queue_empty(&cache->sh->queue)) { wait = 10; break; @@ -1482,7 +1929,7 @@ ngx_http_file_cache_loader(void *data) tree.init_handler = NULL; tree.file_handler = ngx_http_file_cache_manage_file; - tree.pre_tree_handler = ngx_http_file_cache_noop; + tree.pre_tree_handler = ngx_http_file_cache_manage_directory; tree.post_tree_handler = ngx_http_file_cache_noop; tree.spec_handler = ngx_http_file_cache_delete_file; tree.data = cache; @@ -1547,6 +1994,19 @@ ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) } +static ngx_int_t +ngx_http_file_cache_manage_directory(ngx_tree_ctx_t *ctx, ngx_str_t *path) +{ + if (path->len >= 5 + && ngx_strncmp(path->data + path->len - 5, "/temp", 5) == 0) + { + return NGX_DECLINED; + } + + return NGX_OK; +} + + static void ngx_http_file_cache_loader_sleep(ngx_http_file_cache_t *cache) { @@ -1613,8 +2073,8 @@ ngx_http_file_cache_add(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) if (fcn == NULL) { - fcn = ngx_slab_alloc_locked(cache->shpool, - sizeof(ngx_http_file_cache_node_t)); + fcn = ngx_slab_calloc_locked(cache->shpool, + sizeof(ngx_http_file_cache_node_t)); if (fcn == NULL) { ngx_shmtx_unlock(&cache->shpool->mutex); return NGX_ERROR; @@ -1628,15 +2088,7 @@ ngx_http_file_cache_add(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node); fcn->uses = 1; - fcn->count = 0; - fcn->valid_msec = 0; - fcn->error = 0; fcn->exists = 1; - fcn->updating = 0; - fcn->deleting = 0; - fcn->uniq = 0; - fcn->valid_sec = 0; - fcn->body_start = 0; fcn->fs_size = c->fs_size; cache->sh->size += c->fs_size; @@ -1699,15 +2151,19 @@ ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status) char * ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + char *confp = conf; + off_t max_size; u_char *last, *p; time_t inactive; + size_t len; 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; + ngx_uint_t i, n, use_temp_path; + ngx_array_t *caches; + ngx_http_file_cache_t *cache, **ce; cache = ngx_pcalloc(cf->pool, sizeof(ngx_http_file_cache_t)); if (cache == NULL) { @@ -1719,6 +2175,8 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } + use_temp_path = 1; + inactive = 600; loader_files = 100; loader_sleep = 50; @@ -1779,6 +2237,25 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } + if (ngx_strncmp(value[i].data, "use_temp_path=", 14) == 0) { + + if (ngx_strcmp(&value[i].data[14], "on") == 0) { + use_temp_path = 1; + + } else if (ngx_strcmp(&value[i].data[14], "off") == 0) { + use_temp_path = 0; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid use_temp_path value \"%V\", " + "it must be \"on\" or \"off\"", + &value[i]); + return NGX_CONF_ERROR; + } + + continue; + } + if (ngx_strncmp(value[i].data, "keys_zone=", 10) == 0) { name.data = value[i].data + 10; @@ -1901,6 +2378,37 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } + if (!use_temp_path) { + cache->temp_path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t)); + if (cache->temp_path == NULL) { + return NGX_CONF_ERROR; + } + + len = cache->path->name.len + sizeof("/temp") - 1; + + p = ngx_pnalloc(cf->pool, len + 1); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + cache->temp_path->name.len = len; + cache->temp_path->name.data = p; + + p = ngx_cpymem(p, cache->path->name.data, cache->path->name.len); + ngx_memcpy(p, "/temp", sizeof("/temp")); + + ngx_memcpy(&cache->temp_path->level, &cache->path->level, + 3 * sizeof(size_t)); + + cache->temp_path->len = cache->path->len; + cache->temp_path->conf_file = cf->conf_file->file.name.data; + cache->temp_path->line = cf->conf_file->line; + + if (ngx_add_path(cf, &cache->temp_path) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + cache->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post); if (cache->shm_zone == NULL) { return NGX_CONF_ERROR; @@ -1919,6 +2427,15 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) cache->inactive = inactive; cache->max_size = max_size; + caches = (ngx_array_t *) (confp + cmd->offset); + + ce = ngx_array_push(caches); + if (ce == NULL) { + return NGX_CONF_ERROR; + } + + *ce = cache; + return NGX_CONF_OK; } diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index 8d38a19..0e0b3a2 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -1287,7 +1287,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) break; } - switch(ch) { + switch (ch) { #if (NGX_WIN32) case '\\': if (u - 2 >= r->uri.data @@ -1357,7 +1357,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) break; } - switch(ch) { + switch (ch) { #if (NGX_WIN32) case '\\': break; @@ -1400,7 +1400,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) break; } - switch(ch) { + switch (ch) { #if (NGX_WIN32) case '\\': #endif @@ -1441,7 +1441,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) break; } - switch(ch) { + switch (ch) { #if (NGX_WIN32) case '\\': #endif @@ -1984,6 +1984,57 @@ ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name, } +ngx_int_t +ngx_http_parse_set_cookie_lines(ngx_array_t *headers, ngx_str_t *name, + ngx_str_t *value) +{ + ngx_uint_t i; + u_char *start, *last, *end; + ngx_table_elt_t **h; + + h = headers->elts; + + for (i = 0; i < headers->nelts; i++) { + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, headers->pool->log, 0, + "parse header: \"%V: %V\"", &h[i]->key, &h[i]->value); + + if (name->len >= h[i]->value.len) { + continue; + } + + start = h[i]->value.data; + end = h[i]->value.data + h[i]->value.len; + + if (ngx_strncasecmp(start, name->data, name->len) != 0) { + continue; + } + + for (start += name->len; start < end && *start == ' '; start++) { + /* void */ + } + + if (start == end || *start++ != '=') { + /* the invalid header value */ + continue; + } + + while (start < end && *start == ' ') { start++; } + + for (last = start; last < end && *last != ';'; last++) { + /* void */ + } + + value->len = last - start; + value->data = start; + + return i; + } + + return NGX_DECLINED; +} + + ngx_int_t ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len, ngx_str_t *value) { diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 560c5f5..2669b52 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -349,7 +349,7 @@ ngx_http_init_connection(ngx_connection_t *c) } if (rev->ready) { - /* the deferred accept(), rtsig, aio, iocp */ + /* the deferred accept(), iocp */ if (ngx_use_accept_mutex) { ngx_post_event(rev, &ngx_posted_events); @@ -543,7 +543,7 @@ ngx_http_create_request(ngx_connection_t *c) clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_http_set_connection_log(r->connection, clcf->error_log); + ngx_set_connection_log(r->connection, clcf->error_log); r->header_in = hc->nbusy ? hc->busy[0] : c->buffer; @@ -652,6 +652,7 @@ ngx_http_ssl_handshake(ngx_event_t *rev) if (n == -1) { if (err == NGX_EAGAIN) { + rev->ready = 0; if (!rev->timer_set) { ngx_add_timer(rev, c->listening->post_accept_timeout); @@ -866,7 +867,7 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, ngx_http_core_module); - ngx_http_set_connection_log(c, clcf->error_log); + ngx_set_connection_log(c, clcf->error_log); sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); @@ -2072,7 +2073,7 @@ ngx_http_set_virtual_server(ngx_http_request_t *r, ngx_str_t *host) clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_http_set_connection_log(r->connection, clcf->error_log); + ngx_set_connection_log(r->connection, clcf->error_log); return NGX_OK; } @@ -2169,13 +2170,11 @@ ngx_http_request_handler(ngx_event_t *ev) { ngx_connection_t *c; ngx_http_request_t *r; - ngx_http_log_ctx_t *ctx; c = ev->data; r = c->data; - ctx = c->log->data; - ctx->current_request = r; + ngx_http_set_log_request(c->log, r); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http run request: \"%V?%V\"", &r->uri, &r->args); @@ -2195,7 +2194,6 @@ void ngx_http_run_posted_requests(ngx_connection_t *c) { ngx_http_request_t *r; - ngx_http_log_ctx_t *ctx; ngx_http_posted_request_t *pr; for ( ;; ) { @@ -2215,8 +2213,7 @@ ngx_http_run_posted_requests(ngx_connection_t *c) r = pr->request; - ctx = c->log->data; - ctx->current_request = r; + ngx_http_set_log_request(c->log, r); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http posted request: \"%V?%V\"", &r->uri, &r->args); @@ -2528,6 +2525,11 @@ ngx_http_finalize_connection(ngx_http_request_t *r) return; } + if (r->reading_body) { + r->keepalive = 0; + r->lingering_close = 1; + } + if (!ngx_terminate && !ngx_exiting && r->keepalive @@ -2655,6 +2657,12 @@ ngx_http_writer(ngx_http_request_t *r) if (r->buffered || r->postponed || (r == r->main && c->buffered)) { +#if (NGX_HTTP_SPDY) + if (r->spdy_stream) { + return; + } +#endif + if (!wev->delayed) { ngx_add_timer(wev, clcf->send_timeout); } diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 705c4e9..3954de3 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -473,6 +473,7 @@ struct ngx_http_request_s { unsigned request_body_in_clean_file:1; unsigned request_body_file_group_access:1; unsigned request_body_file_log_level:3; + unsigned request_body_no_buffering:1; unsigned subrequest_in_memory:1; unsigned waited:1; @@ -509,9 +510,9 @@ struct ngx_http_request_s { unsigned keepalive:1; unsigned lingering_close:1; unsigned discard_body:1; + unsigned reading_body:1; unsigned internal:1; unsigned error_page:1; - unsigned ignore_content_encoding:1; unsigned filter_finalize:1; unsigned post_action:1; unsigned request_complete:1; @@ -529,6 +530,7 @@ struct ngx_http_request_s { unsigned filter_need_temporary:1; unsigned allow_ranges:1; unsigned single_range:1; + unsigned disable_not_modified:1; #if (NGX_STAT_STUB) unsigned stat_reading:1; @@ -574,23 +576,18 @@ struct ngx_http_request_s { typedef struct { ngx_http_posted_request_t terminal_posted_request; -#if (NGX_HAVE_AIO_SENDFILE) - u_char aio_preload; -#endif } ngx_http_ephemeral_t; +#define ngx_http_ephemeral(r) (void *) (&r->uri_start) + + extern ngx_http_header_t ngx_http_headers_in[]; extern ngx_http_header_out_t ngx_http_headers_out[]; -#define ngx_http_set_connection_log(c, l) \ - \ - c->log->file = l->file; \ - c->log->next = l->next; \ - if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { \ - c->log->log_level = l->log_level; \ - } +#define ngx_http_set_log_request(log, r) \ + ((ngx_http_log_ctx_t *) log->data)->current_request = r #endif /* _NGX_HTTP_REQUEST_H_INCLUDED_ */ diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c index bbf16fd..9c16984 100644 --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -24,8 +24,6 @@ static ngx_int_t ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in); static ngx_int_t ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in); -static ngx_int_t ngx_http_request_body_save_filter(ngx_http_request_t *r, - ngx_chain_t *in); ngx_int_t @@ -44,12 +42,14 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, #if (NGX_HTTP_SPDY) if (r->spdy_stream && r == r->main) { + r->request_body_no_buffering = 0; rc = ngx_http_spdy_read_request_body(r, post_handler); goto done; } #endif if (r != r->main || r->request_body || r->discard_body) { + r->request_body_no_buffering = 0; post_handler(r); return NGX_OK; } @@ -59,6 +59,10 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, goto done; } + if (r->request_body_no_buffering) { + r->request_body_in_file_only = 0; + } + rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -81,6 +85,7 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, r->request_body = rb; if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) { + r->request_body_no_buffering = 0; post_handler(r); return NGX_OK; } @@ -173,6 +178,8 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, } } + r->request_body_no_buffering = 0; + post_handler(r); return NGX_OK; @@ -216,6 +223,21 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, done: + if (r->request_body_no_buffering + && (rc == NGX_OK || rc == NGX_AGAIN)) + { + if (rc == NGX_OK) { + r->request_body_no_buffering = 0; + + } else { + /* rc == NGX_AGAIN */ + r->reading_body = 1; + } + + r->read_event_handler = ngx_http_block_reading; + post_handler(r); + } + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { r->main->count--; } @@ -224,6 +246,26 @@ done: } +ngx_int_t +ngx_http_read_unbuffered_request_body(ngx_http_request_t *r) +{ + ngx_int_t rc; + + if (r->connection->read->timedout) { + r->connection->timedout = 1; + return NGX_HTTP_REQUEST_TIME_OUT; + } + + rc = ngx_http_do_read_client_request_body(r); + + if (rc == NGX_OK) { + r->reading_body = 0; + } + + return rc; +} + + static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r) { @@ -266,32 +308,43 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) for ( ;; ) { if (rb->buf->last == rb->buf->end) { - /* pass buffer to request body filter chain */ + if (rb->buf->pos != rb->buf->last) { - out.buf = rb->buf; - out.next = NULL; + /* pass buffer to request body filter chain */ - rc = ngx_http_request_body_filter(r, &out); + out.buf = rb->buf; + out.next = NULL; - if (rc != NGX_OK) { - return rc; - } + rc = ngx_http_request_body_filter(r, &out); - /* write to file */ + if (rc != NGX_OK) { + return rc; + } - if (ngx_http_write_request_body(r) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } + } else { - /* update chains */ + /* update chains */ - rc = ngx_http_request_body_filter(r, NULL); + rc = ngx_http_request_body_filter(r, NULL); - if (rc != NGX_OK) { - return rc; + if (rc != NGX_OK) { + return rc; + } } if (rb->busy != NULL) { + if (r->request_body_no_buffering) { + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + return NGX_AGAIN; + } + return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -358,6 +411,22 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) } if (!c->read->ready) { + + if (r->request_body_no_buffering + && rb->buf->pos != rb->buf->last) + { + /* pass buffer to request body filter chain */ + + out.buf = rb->buf; + out.next = NULL; + + rc = ngx_http_request_body_filter(r, &out); + + if (rc != NGX_OK) { + return rc; + } + } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_add_timer(c->read, clcf->client_body_timeout); @@ -403,9 +472,10 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) } } - r->read_event_handler = ngx_http_block_reading; - - rb->post_handler(r); + if (!r->request_body_no_buffering) { + r->read_event_handler = ngx_http_block_reading; + rb->post_handler(r); + } return NGX_OK; } @@ -415,7 +485,7 @@ static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r) { ssize_t n; - ngx_chain_t *cl; + ngx_chain_t *cl, *ln; ngx_temp_file_t *tf; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; @@ -478,8 +548,13 @@ ngx_http_write_request_body(ngx_http_request_t *r) /* mark all buffers as written */ - for (cl = rb->bufs; cl; cl = cl->next) { + for (cl = rb->bufs; cl; /* void */) { + cl->buf->pos = cl->buf->last; + + ln = cl; + cl = cl->next; + ngx_free_chain(r->pool, ln); } rb->bufs = NULL; @@ -874,6 +949,7 @@ ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in) b->pos = cl->buf->pos; b->last = cl->buf->last; b->end = cl->buf->end; + b->flush = r->request_body_no_buffering; size = cl->buf->last - cl->buf->pos; @@ -892,7 +968,7 @@ ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in) ll = &tl->next; } - rc = ngx_http_request_body_save_filter(r, out); + rc = ngx_http_top_request_body_filter(r, out); ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out, (ngx_buf_tag_t) &ngx_http_read_client_request_body); @@ -936,7 +1012,7 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "http body chunked buf " - "t:%d f:%d %p, pos %p, size: %z file: %O, size: %z", + "t:%d f:%d %p, pos %p, size: %z file: %O, size: %O", cl->buf->temporary, cl->buf->in_file, cl->buf->start, cl->buf->pos, cl->buf->last - cl->buf->pos, @@ -981,6 +1057,7 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) b->pos = cl->buf->pos; b->last = cl->buf->last; b->end = cl->buf->end; + b->flush = r->request_body_no_buffering; *ll = tl; ll = &tl->next; @@ -1044,7 +1121,7 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) } } - rc = ngx_http_request_body_save_filter(r, out); + rc = ngx_http_top_request_body_filter(r, out); ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out, (ngx_buf_tag_t) &ngx_http_read_client_request_body); @@ -1053,7 +1130,7 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) } -static ngx_int_t +ngx_int_t ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) { #if (NGX_DEBUG) @@ -1068,7 +1145,7 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) for (cl = rb->bufs; cl; cl = cl->next) { ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "http body old buf t:%d f:%d %p, pos %p, size: %z " - "file: %O, size: %z", + "file: %O, size: %O", cl->buf->temporary, cl->buf->in_file, cl->buf->start, cl->buf->pos, cl->buf->last - cl->buf->pos, @@ -1079,7 +1156,7 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) for (cl = in; cl; cl = cl->next) { ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "http body new buf t:%d f:%d %p, pos %p, size: %z " - "file: %O, size: %z", + "file: %O, size: %O", cl->buf->temporary, cl->buf->in_file, cl->buf->start, cl->buf->pos, cl->buf->last - cl->buf->pos, @@ -1095,5 +1172,14 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) return NGX_HTTP_INTERNAL_SERVER_ERROR; } + if (rb->rest > 0 + && rb->buf && rb->buf->last == rb->buf->end + && !r->request_body_no_buffering) + { + if (ngx_http_write_request_body(r) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + } + return NGX_OK; } diff --git a/src/http/ngx_http_spdy.c b/src/http/ngx_http_spdy.c index bd6d73d..6bb79b8 100644 --- a/src/http/ngx_http_spdy.c +++ b/src/http/ngx_http_spdy.c @@ -103,10 +103,10 @@ static u_char *ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end); static u_char *ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end); -static u_char *ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end); static u_char *ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end); +static u_char *ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc, + u_char *pos, u_char *end); static u_char *ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end); static u_char *ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, @@ -125,6 +125,9 @@ static u_char *ngx_http_spdy_state_complete(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end); static u_char *ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end, ngx_http_spdy_handler_pt handler); + +static u_char *ngx_http_spdy_state_inflate_error( + ngx_http_spdy_connection_t *sc, int rc); static u_char *ngx_http_spdy_state_protocol_error( ngx_http_spdy_connection_t *sc); static u_char *ngx_http_spdy_state_internal_error( @@ -392,8 +395,7 @@ ngx_http_spdy_init(ngx_event_t *rev) c = rev->data; hc = c->data; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "init spdy request"); + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "init spdy request"); c->log->action = "processing SPDY"; @@ -421,12 +423,8 @@ ngx_http_spdy_init(ngx_event_t *rev) sc->init_window = NGX_SPDY_INIT_STREAM_WINDOW; - sc->handler = ngx_http_spdy_state_head; - - if (hc->proxy_protocol) { - c->log->action = "reading PROXY protocol"; - sc->handler = ngx_http_spdy_proxy_protocol; - } + sc->handler = hc->proxy_protocol ? ngx_http_spdy_proxy_protocol + : ngx_http_spdy_state_head; sc->zstream_in.zalloc = ngx_http_spdy_zalloc; sc->zstream_in.zfree = ngx_http_spdy_zfree; @@ -557,7 +555,7 @@ ngx_http_spdy_read_handler(ngx_event_t *rev) if (n == 0 && (sc->incomplete || sc->processing)) { ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client closed prematurely connection"); + "client prematurely closed connection"); } if (n == 0 || n == NGX_ERROR) { @@ -645,7 +643,7 @@ ngx_http_spdy_write_handler(ngx_event_t *wev) stream->handled = 0; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "spdy run stream %ui", stream->id); + "run spdy stream %ui", stream->id); wev = stream->request->connection->write; wev->handler(wev); @@ -664,6 +662,7 @@ ngx_http_spdy_write_handler(ngx_event_t *wev) ngx_int_t ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc) { + int tcp_nodelay; ngx_chain_t *cl; ngx_event_t *wev; ngx_connection_t *c; @@ -702,20 +701,52 @@ ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc) cl = c->send_chain(c, cl, 0); if (cl == NGX_CHAIN_ERROR) { - c->error = 1; - - if (!sc->blocked) { - ngx_post_event(wev, &ngx_posted_events); - } - - return NGX_ERROR; + goto error; } clcf = ngx_http_get_module_loc_conf(sc->http_connection->conf_ctx, ngx_http_core_module); if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { - return NGX_ERROR; /* FIXME */ + goto error; + } + + if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) { + if (ngx_tcp_push(c->fd) == -1) { + ngx_connection_error(c, ngx_socket_errno, ngx_tcp_push_n " failed"); + goto error; + } + + c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; + tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0; + + } else { + tcp_nodelay = 1; + } + + if (tcp_nodelay + && clcf->tcp_nodelay + && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) + { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); + + if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, + (const void *) &tcp_nodelay, sizeof(int)) + == -1) + { +#if (NGX_SOLARIS) + /* Solaris returns EINVAL if a socket has been shut down */ + c->log_error = NGX_ERROR_IGNORE_EINVAL; +#endif + + ngx_connection_error(c, ngx_socket_errno, + "setsockopt(TCP_NODELAY) failed"); + + c->log_error = NGX_ERROR_INFO; + goto error; + } + + c->tcp_nodelay = NGX_TCP_NODELAY_SET; } if (cl) { @@ -753,6 +784,16 @@ ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc) sc->last_out = frame; return NGX_OK; + +error: + + c->error = 1; + + if (!sc->blocked) { + ngx_post_event(wev, &ngx_posted_events); + } + + return NGX_ERROR; } @@ -820,14 +861,19 @@ static u_char * ngx_http_spdy_proxy_protocol(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end) { + ngx_log_t *log; + + log = sc->connection->log; + log->action = "reading PROXY protocol"; + pos = ngx_proxy_protocol_parse(sc->connection, pos, end); + log->action = "processing SPDY"; + if (pos == NULL) { return ngx_http_spdy_state_protocol_error(sc); } - sc->connection->log->action = "processing SPDY"; - return ngx_http_spdy_state_complete(sc, pos, end); } @@ -856,7 +902,7 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos, pos += sizeof(uint32_t); ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy process frame head:%08XD f:%Xd l:%uz", + "process spdy frame head:%08XD f:%Xd l:%uz", head, sc->flags, sc->length); if (ngx_spdy_ctl_frame_check(head)) { @@ -868,6 +914,8 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos, return ngx_http_spdy_state_syn_stream(sc, pos, end); case NGX_SPDY_SYN_REPLY: + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client sent unexpected SYN_REPLY frame"); return ngx_http_spdy_state_protocol_error(sc); case NGX_SPDY_RST_STREAM: @@ -883,6 +931,8 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos, return ngx_http_spdy_state_skip(sc, pos, end); /* TODO */ case NGX_SPDY_HEADERS: + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client sent unexpected HEADERS frame"); return ngx_http_spdy_state_protocol_error(sc); case NGX_SPDY_WINDOW_UPDATE: @@ -900,10 +950,8 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos, return ngx_http_spdy_state_data(sc, pos, end); } - - /* TODO version & type check */ - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy unknown frame"); + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client sent invalid frame"); return ngx_http_spdy_state_protocol_error(sc); } @@ -923,7 +971,10 @@ ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, u_char *pos, } if (sc->length <= NGX_SPDY_SYN_STREAM_SIZE) { - /* TODO logging */ + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client sent SYN_STREAM frame with incorrect length %uz", + sc->length); + return ngx_http_spdy_state_protocol_error(sc); } @@ -937,13 +988,34 @@ ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, u_char *pos, ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, "spdy SYN_STREAM frame sid:%ui prio:%ui", sid, prio); + if (sid % 2 == 0 || sid <= sc->last_sid) { + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client sent SYN_STREAM frame " + "with invalid Stream-ID %ui", sid); + + stream = ngx_http_spdy_get_stream_by_id(sc, sid); + + if (stream) { + if (ngx_http_spdy_terminate_stream(sc, stream, + NGX_SPDY_PROTOCOL_ERROR) + != NGX_OK) + { + return ngx_http_spdy_state_internal_error(sc); + } + } + + return ngx_http_spdy_state_protocol_error(sc); + } + + sc->last_sid = sid; + sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx, ngx_http_spdy_module); if (sc->processing >= sscf->concurrent_streams) { ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "spdy concurrent streams exceeded %ui", sc->processing); + "concurrent streams exceeded %ui", sc->processing); if (ngx_http_spdy_send_rst_stream(sc, sid, NGX_SPDY_REFUSED_STREAM, prio) @@ -968,8 +1040,6 @@ ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, u_char *pos, sc->stream = stream; - sc->last_sid = sid; - return ngx_http_spdy_state_headers(sc, pos, end); } @@ -982,7 +1052,6 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, size_t size; ngx_buf_t *buf; ngx_int_t rc; - ngx_uint_t complete; ngx_http_request_t *r; size = end - pos; @@ -992,18 +1061,14 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, ngx_http_spdy_state_headers); } - if (size >= sc->length) { + if (size > sc->length) { size = sc->length; - complete = 1; - - } else { - complete = 0; } r = sc->stream->request; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy process HEADERS %uz of %uz", size, sc->length); + "process spdy header block %uz of %uz", size, sc->length); buf = r->header_in; @@ -1019,11 +1084,21 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, if (z == Z_NEED_DICT) { z = inflateSetDictionary(&sc->zstream_in, ngx_http_spdy_dict, sizeof(ngx_http_spdy_dict)); + if (z != Z_OK) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "spdy inflateSetDictionary() failed: %d", z); - ngx_http_spdy_close_stream(sc->stream, 0); - return ngx_http_spdy_state_protocol_error(sc); + if (z == Z_DATA_ERROR) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent SYN_STREAM frame with header " + "block encoded using wrong dictionary: %ul", + (u_long) sc->zstream_in.adler); + + return ngx_http_spdy_state_protocol_error(sc); + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "inflateSetDictionary() failed: %d", z); + + return ngx_http_spdy_state_internal_error(sc); } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1033,19 +1108,16 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, : Z_OK; } - if (z != Z_OK) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "spdy inflate() failed: %d", z); - ngx_http_spdy_close_stream(sc->stream, 0); - return ngx_http_spdy_state_protocol_error(sc); - } - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "spdy inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d", sc->zstream_in.next_in, sc->zstream_in.next_out, sc->zstream_in.avail_in, sc->zstream_in.avail_out, z); + if (z != Z_OK) { + return ngx_http_spdy_state_inflate_error(sc, z); + } + sc->length -= sc->zstream_in.next_in - pos; pos = sc->zstream_in.next_in; @@ -1055,12 +1127,11 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, if (buf->last - buf->pos < NGX_SPDY_NV_NUM_SIZE) { - if (complete) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent SYN_STREAM frame " - "with invalid HEADERS block"); - ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST); - return ngx_http_spdy_state_protocol_error(sc); + if (sc->length == 0) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "premature end of spdy header block"); + + return ngx_http_spdy_state_headers_error(sc, pos, end); } return ngx_http_spdy_state_save(sc, pos, end, @@ -1072,7 +1143,7 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, buf->pos += NGX_SPDY_NV_NUM_SIZE; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy HEADERS block consists of %ui entries", + "spdy header block has %ui entries", sc->entries); if (ngx_list_init(&r->headers_in.headers, r->pool, 20, @@ -1081,7 +1152,7 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, { ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_INTERNAL_SERVER_ERROR); - return ngx_http_spdy_state_headers_error(sc, pos, end); + return ngx_http_spdy_state_headers_skip(sc, pos, end); } if (ngx_array_init(&r->headers_in.cookies, r->pool, 2, @@ -1090,7 +1161,7 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, { ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_INTERNAL_SERVER_ERROR); - return ngx_http_spdy_state_headers_error(sc, pos, end); + return ngx_http_spdy_state_headers_skip(sc, pos, end); } } @@ -1113,16 +1184,15 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, rc = ngx_http_spdy_alloc_large_header_buffer(r); if (rc == NGX_DECLINED) { - /* TODO logging */ ngx_http_finalize_request(r, NGX_HTTP_REQUEST_HEADER_TOO_LARGE); - return ngx_http_spdy_state_headers_error(sc, pos, end); + return ngx_http_spdy_state_headers_skip(sc, pos, end); } if (rc != NGX_OK) { ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_INTERNAL_SERVER_ERROR); - return ngx_http_spdy_state_headers_error(sc, pos, end); + return ngx_http_spdy_state_headers_skip(sc, pos, end); } /* null-terminate the last processed header name or value */ @@ -1137,11 +1207,14 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, z = inflate(&sc->zstream_in, Z_NO_FLUSH); + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "spdy inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d", + sc->zstream_in.next_in, sc->zstream_in.next_out, + sc->zstream_in.avail_in, sc->zstream_in.avail_out, + z); + if (z != Z_OK) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "spdy inflate() failed: %d", z); - ngx_http_spdy_close_stream(sc->stream, 0); - return ngx_http_spdy_state_protocol_error(sc); + return ngx_http_spdy_state_inflate_error(sc, z); } sc->length -= sc->zstream_in.next_in - pos; @@ -1152,33 +1225,22 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, continue; } - if (complete) { - /* TODO: improve error message */ + if (sc->length == 0) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy again while last chunk"); - ngx_http_spdy_close_stream(sc->stream, 0); - return ngx_http_spdy_state_protocol_error(sc); + "premature end of spdy header block"); + + return ngx_http_spdy_state_headers_error(sc, pos, end); } return ngx_http_spdy_state_save(sc, pos, end, ngx_http_spdy_state_headers); - case NGX_HTTP_PARSE_INVALID_REQUEST: - - /* TODO: improve error message */ - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent invalid header line"); - + case NGX_HTTP_PARSE_INVALID_HEADER: ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return ngx_http_spdy_state_headers_skip(sc, pos, end); + default: /* NGX_ERROR */ return ngx_http_spdy_state_headers_error(sc, pos, end); - - default: /* NGX_HTTP_PARSE_INVALID_HEADER */ - - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent invalid HEADERS spdy frame"); - ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST); - return ngx_http_spdy_state_protocol_error(sc); } /* a header line has been parsed successfully */ @@ -1187,29 +1249,27 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, if (rc != NGX_OK) { if (rc == NGX_HTTP_PARSE_INVALID_HEADER) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent invalid HEADERS spdy frame"); - ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST); - return ngx_http_spdy_state_protocol_error(sc); - } - - if (rc == NGX_HTTP_PARSE_INVALID_REQUEST) { ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return ngx_http_spdy_state_headers_skip(sc, pos, end); } - return ngx_http_spdy_state_headers_error(sc, pos, end); + if (rc != NGX_ABORT) { + ngx_http_spdy_close_stream(sc->stream, + NGX_HTTP_INTERNAL_SERVER_ERROR); + } + + return ngx_http_spdy_state_headers_skip(sc, pos, end); } } if (buf->pos != buf->last || sc->zstream_in.avail_in) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent SYN_STREAM frame " - "with invalid HEADERS block"); - ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST); - return ngx_http_spdy_state_protocol_error(sc); + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "incorrect number of spdy header block entries"); + + return ngx_http_spdy_state_headers_error(sc, pos, end); } - if (!complete) { + if (sc->length) { return ngx_http_spdy_state_save(sc, pos, end, ngx_http_spdy_state_headers); } @@ -1223,18 +1283,6 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, } -static u_char * -ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc, u_char *pos, - u_char *end) -{ - if (sc->connection->error) { - return ngx_http_spdy_state_internal_error(sc); - } - - return ngx_http_spdy_state_headers_skip(sc, pos, end); -} - - static u_char * ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end) @@ -1254,6 +1302,9 @@ ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos, ngx_http_spdy_state_headers_skip); } + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, + "spdy header block skip %uz of %uz", size, sc->length); + sc->zstream_in.next_in = pos; sc->zstream_in.avail_in = (size < sc->length) ? size : sc->length; @@ -1263,12 +1314,14 @@ ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos, n = inflate(&sc->zstream_in, Z_NO_FLUSH); - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy inflate(): %d", n); + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, + "spdy inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d", + sc->zstream_in.next_in, sc->zstream_in.next_out, + sc->zstream_in.avail_in, sc->zstream_in.avail_out, + n); if (n != Z_OK) { - /* TODO: logging */ - return ngx_http_spdy_state_protocol_error(sc); + return ngx_http_spdy_state_inflate_error(sc, n); } } @@ -1284,6 +1337,33 @@ ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos, } +static u_char * +ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc, u_char *pos, + u_char *end) +{ + ngx_http_spdy_stream_t *stream; + + stream = sc->stream; + + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client sent SYN_STREAM frame for stream %ui " + "with invalid header block", stream->id); + + if (ngx_http_spdy_send_rst_stream(sc, stream->id, NGX_SPDY_PROTOCOL_ERROR, + stream->priority) + != NGX_OK) + { + return ngx_http_spdy_state_internal_error(sc); + } + + stream->out_closed = 1; + + ngx_http_spdy_close_stream(stream, NGX_HTTP_BAD_REQUEST); + + return ngx_http_spdy_state_headers_skip(sc, pos, end); +} + + static u_char * ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end) @@ -1316,22 +1396,14 @@ ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, u_char *pos, pos += NGX_SPDY_DELTA_SIZE; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy WINDOW_UPDATE sid:%ui delta:%ui", sid, delta); + "spdy WINDOW_UPDATE sid:%ui delta:%uz", sid, delta); if (sid) { stream = ngx_http_spdy_get_stream_by_id(sc, sid); if (stream == NULL) { - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client sent WINDOW_UPDATE frame " - "for unknown stream %ui", sid); - - if (ngx_http_spdy_send_rst_stream(sc, sid, NGX_SPDY_INVALID_STREAM, - NGX_SPDY_LOWEST_PRIORITY) - == NGX_ERROR) - { - return ngx_http_spdy_state_internal_error(sc); - } + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, + "unknown spdy stream"); return ngx_http_spdy_state_complete(sc, pos, end); } @@ -1341,7 +1413,7 @@ ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, u_char *pos, ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, "client violated flow control for stream %ui: " "received WINDOW_UPDATE frame with delta %uz " - "that is not allowed for window %z", + "not allowed for window %z", sid, delta, stream->send_window); if (ngx_http_spdy_terminate_stream(sc, stream, @@ -1374,7 +1446,7 @@ ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, u_char *pos, ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, "client violated connection flow control: " "received WINDOW_UPDATE frame with delta %uz " - "that is not allowed for window %uz", + "not allowed for window %uz", delta, sc->send_window); return ngx_http_spdy_state_protocol_error(sc); @@ -1417,8 +1489,8 @@ ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos, if (sc->length > sc->recv_window) { ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client violated connection flow control: length of " - "received DATA frame %uz, while available window %uz", + "client violated connection flow control: " + "received DATA frame length %uz, available window %uz", sc->length, sc->recv_window); return ngx_http_spdy_state_protocol_error(sc); @@ -1442,13 +1514,16 @@ ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos, stream = sc->stream; if (stream == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, + "unknown spdy stream"); + return ngx_http_spdy_state_skip(sc, pos, end); } if (sc->length > stream->recv_window) { ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client violated flow control for stream %ui: length of " - "received DATA frame %uz, while available window %uz", + "client violated flow control for stream %ui: " + "received DATA frame length %uz, available window %uz", stream->id, sc->length, stream->recv_window); if (ngx_http_spdy_terminate_stream(sc, stream, @@ -1478,7 +1553,7 @@ ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos, if (stream->in_closed) { ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client sent DATA frame for half closed stream %ui", + "client sent DATA frame for half-closed stream %ui", stream->id); if (ngx_http_spdy_terminate_stream(sc, stream, @@ -1521,7 +1596,10 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos, stream->in_closed = 1; } - /* TODO log and accounting */ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, + "skipping spdy DATA frame, reason: %d", + stream->skip_data); + return ngx_http_spdy_state_skip(sc, pos, end); } @@ -1550,7 +1628,10 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos, if (r->headers_in.content_length_n != -1 && r->headers_in.content_length_n < rb->rest) { - /* TODO logging */ + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client intended to send body data " + "larger than declared"); + stream->skip_data = NGX_SPDY_DATA_ERROR; goto error; @@ -1561,9 +1642,8 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos, && clcf->client_max_body_size < rb->rest) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "client intended to send too large chunked " - "body: %O bytes", - rb->rest); + "client intended to send " + "too large chunked body: %O bytes", rb->rest); stream->skip_data = NGX_SPDY_DATA_ERROR; goto error; @@ -1615,7 +1695,7 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos, } else if (r->headers_in.content_length_n != rb->rest) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client prematurely closed stream: " - "%O of %O bytes of request body received", + "only %O out of %O bytes of request body received", rb->rest, r->headers_in.content_length_n); stream->skip_data = NGX_SPDY_DATA_ERROR; @@ -1694,9 +1774,11 @@ ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos, "spdy RST_STREAM sid:%ui st:%ui", sid, status); stream = ngx_http_spdy_get_stream_by_id(sc, sid); + if (stream == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "unknown stream, probably it has been closed already"); + "unknown spdy stream"); + return ngx_http_spdy_state_complete(sc, pos, end); } @@ -1715,7 +1797,7 @@ ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos, case NGX_SPDY_INTERNAL_ERROR: ngx_log_error(NGX_LOG_INFO, fc->log, 0, - "client terminated stream %ui because of internal error", + "client terminated stream %ui due to internal error", sid); break; @@ -1747,7 +1829,10 @@ ngx_http_spdy_state_ping(ngx_http_spdy_connection_t *sc, u_char *pos, } if (sc->length != NGX_SPDY_PING_SIZE) { - /* TODO logging */ + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client sent PING frame with incorrect length %uz", + sc->length); + return ngx_http_spdy_state_protocol_error(sc); } @@ -1787,6 +1872,9 @@ ngx_http_spdy_state_skip(ngx_http_spdy_connection_t *sc, u_char *pos, size = end - pos; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, + "spdy frame skip %uz of %uz", size, sc->length); + if (size < sc->length) { sc->length -= size; return ngx_http_spdy_state_save(sc, end, end, @@ -1816,13 +1904,16 @@ ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc, u_char *pos, sc->length -= NGX_SPDY_SETTINGS_NUM_SIZE; if (sc->length < sc->entries * NGX_SPDY_SETTINGS_PAIR_SIZE) { - /* TODO logging */ + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client sent SETTINGS frame with incorrect " + "length %uz or number of entries %ui", + sc->length, sc->entries); + return ngx_http_spdy_state_protocol_error(sc); } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy SETTINGS frame consists of %ui entries", - sc->entries); + "spdy SETTINGS frame has %ui entries", sc->entries); } while (sc->entries) { @@ -1882,7 +1973,20 @@ static u_char * ngx_http_spdy_state_complete(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, + "spdy frame complete pos:%p end:%p", pos, end); + + if (pos > end) { + ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0, + "receive buffer overrun"); + + ngx_debug_point(); + return ngx_http_spdy_state_internal_error(sc); + } + sc->handler = ngx_http_spdy_state_head; + sc->stream = NULL; + return pos; } @@ -1893,12 +1997,17 @@ ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc, { size_t size; + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, + "spdy frame state save pos:%p end:%p handler:%p", + pos, end, handler); + size = end - pos; if (size > NGX_SPDY_STATE_BUFFER_SIZE) { ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0, - "spdy state buffer overflow: " - "%uz bytes required", size); + "state buffer overflow: %uz bytes required", size); + + ngx_debug_point(); return ngx_http_spdy_state_internal_error(sc); } @@ -1912,14 +2021,37 @@ ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc, } +static u_char * +ngx_http_spdy_state_inflate_error(ngx_http_spdy_connection_t *sc, int rc) +{ + if (rc == Z_DATA_ERROR || rc == Z_STREAM_END) { + ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, + "client sent SYN_STREAM frame with " + "corrupted header block, inflate() failed: %d", rc); + + return ngx_http_spdy_state_protocol_error(sc); + } + + ngx_log_error(NGX_LOG_ERR, sc->connection->log, 0, + "inflate() failed: %d", rc); + + return ngx_http_spdy_state_internal_error(sc); +} + + static u_char * ngx_http_spdy_state_protocol_error(ngx_http_spdy_connection_t *sc) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, "spdy state protocol error"); - /* TODO */ + if (sc->stream) { + sc->stream->out_closed = 1; + ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST); + } + ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST); + return NULL; } @@ -1930,8 +2062,13 @@ ngx_http_spdy_state_internal_error(ngx_http_spdy_connection_t *sc) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, "spdy state internal error"); - /* TODO */ + if (sc->stream) { + sc->stream->out_closed = 1; + ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_INTERNAL_SERVER_ERROR); + } + ngx_http_spdy_finalize_connection(sc, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NULL; } @@ -1945,7 +2082,7 @@ ngx_http_spdy_send_window_update(ngx_http_spdy_connection_t *sc, ngx_uint_t sid, ngx_http_spdy_out_frame_t *frame; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy write WINDOW_UPDATE sid:%ui delta:%ui", sid, delta); + "spdy send WINDOW_UPDATE sid:%ui delta:%ui", sid, delta); frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_WINDOW_UPDATE_SIZE, NGX_SPDY_HIGHEST_PRIORITY); @@ -1984,7 +2121,7 @@ ngx_http_spdy_send_rst_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t sid, } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy write RST_STREAM sid:%ui st:%ui", sid, status); + "spdy send RST_STREAM sid:%ui st:%ui", sid, status); frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_RST_STREAM_SIZE, priority); @@ -2019,7 +2156,7 @@ ngx_http_spdy_send_goaway(ngx_http_spdy_connection_t *sc) ngx_http_spdy_out_frame_t *frame; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy create GOAWAY sid:%ui", sc->last_sid); + "spdy send GOAWAY sid:%ui", sc->last_sid); frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_GOAWAY_SIZE, NGX_SPDY_HIGHEST_PRIORITY); @@ -2055,7 +2192,7 @@ ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc) ngx_http_spdy_out_frame_t *frame; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy create SETTINGS frame"); + "spdy send SETTINGS frame"); frame = ngx_palloc(sc->pool, sizeof(ngx_http_spdy_out_frame_t)); if (frame == NULL) { @@ -2177,7 +2314,7 @@ ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t length, #if (NGX_DEBUG) if (length > NGX_SPDY_CTL_FRAME_BUFFER_SIZE - NGX_SPDY_FRAME_HEADER_SIZE) { ngx_log_error(NGX_LOG_ALERT, sc->pool->log, 0, - "requested control frame is too big: %uz", length); + "requested control frame is too large: %uz", length); return NULL; } @@ -2395,7 +2532,7 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r) r->lowcase_index = ngx_spdy_frame_parse_uint32(p); if (r->lowcase_index == 0) { - return NGX_HTTP_PARSE_INVALID_HEADER; + return NGX_ERROR; } /* null-terminate the previous header value */ @@ -2445,11 +2582,15 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r) case LF: case CR: case ':': - return NGX_HTTP_PARSE_INVALID_REQUEST; + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid header name: \"%*s\"", + r->lowcase_index, r->header_name_start); + + return NGX_HTTP_PARSE_INVALID_HEADER; } if (ch >= 'A' && ch <= 'Z') { - return NGX_HTTP_PARSE_INVALID_HEADER; + return NGX_ERROR; } r->invalid_header = 1; @@ -2498,10 +2639,21 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r) r->header_end = p; r->header_in->pos = p + 1; + r->state = sw_value; + return NGX_OK; } if (ch == CR || ch == LF) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent header \"%*s\" with " + "invalid value: \"%*s\\%c...\"", + r->header_name_end - r->header_name_start, + r->header_name_start, + p - r->header_start, + r->header_start, + ch == CR ? 'r' : 'n'); + return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -2526,7 +2678,7 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r) static ngx_int_t ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r) { - u_char *old, *new; + u_char *old, *new, *p; size_t rest; ngx_buf_t *buf; ngx_http_spdy_stream_t *stream; @@ -2542,12 +2694,29 @@ ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r) if (stream->header_buffers == (ngx_uint_t) cscf->large_client_header_buffers.num) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent too large request"); + return NGX_DECLINED; } rest = r->header_in->last - r->header_in->pos; - if (rest >= cscf->large_client_header_buffers.size) { + /* + * One more byte is needed for null-termination + * and another one for further progress. + */ + if (rest > cscf->large_client_header_buffers.size - 2) { + p = r->header_in->pos; + + if (rest > NGX_MAX_ERROR_STR - 300) { + rest = NGX_MAX_ERROR_STR - 300; + } + + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent too long header name or value: \"%*s...\"", + rest, p); + return NGX_DECLINED; } @@ -2557,7 +2726,7 @@ ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r) } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy large header alloc: %p %z", + "spdy large header alloc: %p %uz", buf->pos, buf->end - buf->last); old = r->header_in->pos; @@ -2612,13 +2781,16 @@ ngx_http_spdy_handle_request_header(ngx_http_request_t *r) return sh->handler(r); } - return NGX_HTTP_PARSE_INVALID_REQUEST; + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid header name: \":%*s\"", + r->header_end - r->header_name_start, + r->header_name_start); + + return NGX_HTTP_PARSE_INVALID_HEADER; } h = ngx_list_push(&r->headers_in.headers); if (h == NULL) { - ngx_http_spdy_close_stream(r->spdy_stream, - NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_ERROR; } @@ -2684,6 +2856,9 @@ ngx_http_spdy_parse_method(ngx_http_request_t *r) }, *test; if (r->method_name.len) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent duplicate :method header"); + return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -2721,8 +2896,10 @@ ngx_http_spdy_parse_method(ngx_http_request_t *r) do { if ((*p < 'A' || *p > 'Z') && *p != '_') { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent invalid method"); - return NGX_HTTP_PARSE_INVALID_REQUEST; + "client sent invalid method: \"%V\"", + &r->method_name); + + return NGX_HTTP_PARSE_INVALID_HEADER; } p++; @@ -2737,6 +2914,9 @@ static ngx_int_t ngx_http_spdy_parse_scheme(ngx_http_request_t *r) { if (r->schema_start) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent duplicate :schema header"); + return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -2753,13 +2933,14 @@ ngx_http_spdy_parse_host(ngx_http_request_t *r) ngx_table_elt_t *h; if (r->headers_in.host) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent duplicate :host header"); + return NGX_HTTP_PARSE_INVALID_HEADER; } h = ngx_list_push(&r->headers_in.headers); if (h == NULL) { - ngx_http_spdy_close_stream(r->spdy_stream, - NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_ERROR; } @@ -2783,6 +2964,9 @@ static ngx_int_t ngx_http_spdy_parse_path(ngx_http_request_t *r) { if (r->unparsed_uri.len) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent duplicate :path header"); + return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -2790,11 +2974,19 @@ ngx_http_spdy_parse_path(ngx_http_request_t *r) r->uri_end = r->header_end; if (ngx_http_parse_uri(r) != NGX_OK) { - return NGX_HTTP_PARSE_INVALID_REQUEST; + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid URI: \"%*s\"", + r->uri_end - r->uri_start, r->uri_start); + + return NGX_HTTP_PARSE_INVALID_HEADER; } if (ngx_http_process_request_uri(r) != NGX_OK) { - return NGX_ERROR; + /* + * request has been finalized already + * in ngx_http_process_request_uri() + */ + return NGX_ABORT; } return NGX_OK; @@ -2807,19 +2999,22 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r) u_char *p, ch; if (r->http_protocol.len) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent duplicate :version header"); + return NGX_HTTP_PARSE_INVALID_HEADER; } p = r->header_start; if (r->header_end - p < 8 || !(ngx_str5cmp(p, 'H', 'T', 'T', 'P', '/'))) { - return NGX_HTTP_PARSE_INVALID_REQUEST; + goto invalid; } ch = *(p + 5); if (ch < '1' || ch > '9') { - return NGX_HTTP_PARSE_INVALID_REQUEST; + goto invalid; } r->http_major = ch - '0'; @@ -2833,20 +3028,20 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r) } if (ch < '0' || ch > '9') { - return NGX_HTTP_PARSE_INVALID_REQUEST; + goto invalid; } r->http_major = r->http_major * 10 + ch - '0'; } if (*p != '.') { - return NGX_HTTP_PARSE_INVALID_REQUEST; + goto invalid; } ch = *(p + 1); if (ch < '0' || ch > '9') { - return NGX_HTTP_PARSE_INVALID_REQUEST; + goto invalid; } r->http_minor = ch - '0'; @@ -2856,7 +3051,7 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r) ch = *p; if (ch < '0' || ch > '9') { - return NGX_HTTP_PARSE_INVALID_REQUEST; + goto invalid; } r->http_minor = r->http_minor * 10 + ch - '0'; @@ -2867,6 +3062,14 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r) r->http_version = r->http_major * 1000 + r->http_minor; return NGX_OK; + +invalid: + + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid http version: \"%*s\"", + r->header_end - r->header_start, r->header_start); + + return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -2889,7 +3092,8 @@ ngx_http_spdy_construct_request_line(ngx_http_request_t *r) p = ngx_pnalloc(r->pool, r->request_line.len + 1); if (p == NULL) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_spdy_close_stream(r->spdy_stream, + NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_ERROR; } @@ -2953,7 +3157,7 @@ ngx_http_spdy_run_request(ngx_http_request_t *r) } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http header: \"%V: %V\"", &h[i].key, &h[i].value); + "spdy http header: \"%V: %V\"", &h[i].key, &h[i].value); } r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE; @@ -3156,10 +3360,8 @@ ngx_http_spdy_close_stream_handler(ngx_event_t *ev) void ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc) { - int tcp_nodelay; ngx_event_t *ev; - ngx_connection_t *c, *fc; - ngx_http_core_loc_conf_t *clcf; + ngx_connection_t *fc; ngx_http_spdy_stream_t **index, *s; ngx_http_spdy_srv_conf_t *sscf; ngx_http_spdy_connection_t *sc; @@ -3185,54 +3387,6 @@ ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc) { sc->connection->error = 1; } - - } else { - c = sc->connection; - - if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) { - if (ngx_tcp_push(c->fd) == -1) { - ngx_connection_error(c, ngx_socket_errno, - ngx_tcp_push_n " failed"); - c->error = 1; - tcp_nodelay = 0; - - } else { - c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; - tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0; - } - - } else { - tcp_nodelay = 1; - } - - clcf = ngx_http_get_module_loc_conf(stream->request, - ngx_http_core_module); - - if (tcp_nodelay - && clcf->tcp_nodelay - && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) - { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); - - if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, - (const void *) &tcp_nodelay, sizeof(int)) - == -1) - { -#if (NGX_SOLARIS) - /* Solaris returns EINVAL if a socket has been shut down */ - c->log_error = NGX_ERROR_IGNORE_EINVAL; -#endif - - ngx_connection_error(c, ngx_socket_errno, - "setsockopt(TCP_NODELAY) failed"); - - c->log_error = NGX_ERROR_INFO; - c->error = 1; - - } else { - c->tcp_nodelay = NGX_TCP_NODELAY_SET; - } - } } if (sc->stream == stream) { @@ -3265,14 +3419,14 @@ ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc) if (ev->active || ev->disabled) { ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0, - "spdy fake read event was activated"); + "fake read event was activated"); } if (ev->timer_set) { ngx_del_timer(ev); } - if (ev->prev) { + if (ev->posted) { ngx_delete_posted_event(ev); } @@ -3280,14 +3434,14 @@ ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc) if (ev->active || ev->disabled) { ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0, - "spdy fake write event was activated"); + "fake write event was activated"); } if (ev->timer_set) { ngx_del_timer(ev); } - if (ev->prev) { + if (ev->posted) { ngx_delete_posted_event(ev); } diff --git a/src/http/ngx_http_spdy.h b/src/http/ngx_http_spdy.h index 55aceda..df24495 100644 --- a/src/http/ngx_http_spdy.h +++ b/src/http/ngx_http_spdy.h @@ -230,13 +230,16 @@ ngx_int_t ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc); #else #define ngx_spdy_frame_write_uint16(p, s) \ - ((p)[0] = (u_char) (s) >> 8, (p)[1] = (u_char) (s), (p) + sizeof(uint16_t)) + ((p)[0] = (u_char) ((s) >> 8), \ + (p)[1] = (u_char) (s), \ + (p) + sizeof(uint16_t)) #define ngx_spdy_frame_write_uint32(p, s) \ - ((p)[0] = (u_char) (s) >> 24, \ - (p)[1] = (u_char) (s) >> 16, \ - (p)[2] = (u_char) (s) >> 8, \ - (p)[3] = (u_char) (s), (p) + sizeof(uint32_t)) + ((p)[0] = (u_char) ((s) >> 24), \ + (p)[1] = (u_char) ((s) >> 16), \ + (p)[2] = (u_char) ((s) >> 8), \ + (p)[3] = (u_char) (s), \ + (p) + sizeof(uint32_t)) #endif diff --git a/src/http/ngx_http_spdy_filter_module.c b/src/http/ngx_http_spdy_filter_module.c index 559fb4a..377e935 100644 --- a/src/http/ngx_http_spdy_filter_module.c +++ b/src/http/ngx_http_spdy_filter_module.c @@ -493,9 +493,13 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r) continue; } - *last++ = '\0'; + if (h[j].value.len) { + if (last != p) { + *last++ = '\0'; + } - last = ngx_cpymem(last, h[j].value.data, h[j].value.len); + last = ngx_cpymem(last, h[j].value.data, h[j].value.len); + } h[j].hash = 2; } @@ -533,8 +537,7 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r) ngx_free(buf); if (rc != Z_OK) { - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "spdy deflate() failed: %d", rc); + ngx_log_error(NGX_LOG_ALERT, c->log, 0, "deflate() failed: %d", rc); return NGX_ERROR; } @@ -1142,6 +1145,11 @@ ngx_http_spdy_handle_stream(ngx_http_spdy_connection_t *sc, wev = stream->request->connection->write; + /* + * This timer can only be set if the stream was delayed because of rate + * limit. In that case the event should be triggered by the timer. + */ + if (!wev->timer_set) { wev->delayed = 0; diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c index 5464005..a97791e 100644 --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -553,7 +553,7 @@ ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page) return NGX_ERROR; } - if (uri.data[0] == '/') { + if (uri.len && uri.data[0] == '/') { if (err_page->value.lengths) { ngx_http_split_args(r, &uri, &args); @@ -570,7 +570,7 @@ ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page) return ngx_http_internal_redirect(r, &uri, &args); } - if (uri.data[0] == '@') { + if (uri.len && uri.data[0] == '@') { return ngx_http_named_location(r, &uri); } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 040bda1..47b574e 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -13,12 +13,16 @@ #if (NGX_HTTP_CACHE) static ngx_int_t ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u); +static ngx_int_t ngx_http_upstream_cache_get(ngx_http_request_t *r, + ngx_http_upstream_t *u, ngx_http_file_cache_t **cache); static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u); static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_upstream_cache_last_modified(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_upstream_cache_etag(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); #endif static void ngx_http_upstream_init_request(ngx_http_request_t *r); @@ -32,9 +36,12 @@ static void ngx_http_upstream_connect(ngx_http_request_t *r, static ngx_int_t ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u); static void ngx_http_upstream_send_request(ngx_http_request_t *r, - ngx_http_upstream_t *u); + ngx_http_upstream_t *u, ngx_uint_t do_write); +static ngx_int_t ngx_http_upstream_send_request_body(ngx_http_request_t *r, + ngx_http_upstream_t *u, ngx_uint_t do_write); static void ngx_http_upstream_send_request_handler(ngx_http_request_t *r, ngx_http_upstream_t *u); +static void ngx_http_upstream_read_request_handler(ngx_http_request_t *r); static void ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u); static ngx_int_t ngx_http_upstream_test_next(ngx_http_request_t *r, @@ -72,7 +79,8 @@ static ngx_int_t ngx_http_upstream_non_buffered_filter(void *data, static void ngx_http_upstream_process_downstream(ngx_http_request_t *r); static void ngx_http_upstream_process_upstream(ngx_http_request_t *r, ngx_http_upstream_t *u); -static void ngx_http_upstream_process_request(ngx_http_request_t *r); +static void ngx_http_upstream_process_request(ngx_http_request_t *r, + ngx_http_upstream_t *u); static void ngx_http_upstream_store(ngx_http_request_t *r, ngx_http_upstream_t *u); static void ngx_http_upstream_dummy_handler(ngx_http_request_t *r, @@ -87,6 +95,8 @@ 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_last_modified(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 @@ -109,6 +119,8 @@ static ngx_int_t ngx_http_upstream_process_connection(ngx_http_request_t *r, 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_process_vary(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 @@ -156,6 +168,8 @@ static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf); static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *, ngx_http_upstream_t *u, ngx_connection_t *c); static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c); +static ngx_int_t ngx_http_upstream_ssl_name(ngx_http_request_t *r, + ngx_http_upstream_t *u, ngx_connection_t *c); #endif @@ -172,8 +186,7 @@ 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_content_length, - offsetof(ngx_http_upstream_headers_in_t, content_length), + ngx_http_upstream_process_content_length, 0, ngx_http_upstream_ignore_header_line, 0, 0 }, { ngx_string("Date"), @@ -183,8 +196,7 @@ ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = { offsetof(ngx_http_headers_out_t, date), 0 }, { ngx_string("Last-Modified"), - ngx_http_upstream_process_header_line, - offsetof(ngx_http_upstream_headers_in_t, last_modified), + ngx_http_upstream_process_last_modified, 0, ngx_http_upstream_copy_last_modified, 0, 0 }, { ngx_string("ETag"), @@ -214,7 +226,8 @@ ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = { ngx_http_upstream_rewrite_refresh, 0, 0 }, { ngx_string("Set-Cookie"), - ngx_http_upstream_process_set_cookie, 0, + ngx_http_upstream_process_set_cookie, + offsetof(ngx_http_upstream_headers_in_t, cookies), ngx_http_upstream_rewrite_set_cookie, 0, 1 }, { ngx_string("Content-Disposition"), @@ -245,6 +258,10 @@ ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = { ngx_http_upstream_ignore_header_line, 0, ngx_http_upstream_ignore_header_line, 0, 0 }, + { ngx_string("Vary"), + ngx_http_upstream_process_vary, 0, + ngx_http_upstream_copy_header_line, 0, 0 }, + { ngx_string("X-Powered-By"), ngx_http_upstream_ignore_header_line, 0, ngx_http_upstream_copy_header_line, 0, 0 }, @@ -346,6 +363,14 @@ static ngx_http_variable_t ngx_http_upstream_vars[] = { ngx_http_upstream_status_variable, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, + { ngx_string("upstream_connect_time"), NULL, + ngx_http_upstream_response_time_variable, 2, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("upstream_header_time"), NULL, + ngx_http_upstream_response_time_variable, 1, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + { ngx_string("upstream_response_time"), NULL, ngx_http_upstream_response_time_variable, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, @@ -364,6 +389,10 @@ static ngx_http_variable_t ngx_http_upstream_vars[] = { ngx_http_upstream_cache_last_modified, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, + { ngx_string("upstream_cache_etag"), NULL, + ngx_http_upstream_cache_etag, 0, + NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, + #endif { ngx_null_string, NULL, NULL, 0, 0, 0 } @@ -398,6 +427,7 @@ ngx_conf_bitmask_t ngx_http_upstream_ignore_headers_masks[] = { { ngx_string("Expires"), NGX_HTTP_UPSTREAM_IGN_EXPIRES }, { ngx_string("Cache-Control"), NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL }, { ngx_string("Set-Cookie"), NGX_HTTP_UPSTREAM_IGN_SET_COOKIE }, + { ngx_string("Vary"), NGX_HTTP_UPSTREAM_IGN_VARY }, { ngx_null_string, 0 } }; @@ -423,15 +453,13 @@ ngx_http_upstream_create(ngx_http_request_t *r) u->peer.log = r->connection->log; u->peer.log_error = NGX_ERROR_ERR; -#if (NGX_THREADS) - u->peer.lock = &r->connection->lock; -#endif #if (NGX_HTTP_CACHE) r->cache = NULL; #endif u->headers_in.content_length_n = -1; + u->headers_in.last_modified_time = -1; return NGX_OK; } @@ -510,6 +538,11 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) return; } + if (rc == NGX_ERROR) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + if (rc != NGX_DECLINED) { ngx_http_finalize_request(r, rc); return; @@ -518,7 +551,7 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) #endif - u->store = (u->conf->store || u->conf->store_lengths); + u->store = u->conf->store; if (!u->store && !r->post_action && !u->conf->ignore_client_abort) { r->read_event_handler = ngx_http_upstream_rd_check_broken_connection; @@ -542,8 +575,11 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) u->output.pool = r->pool; u->output.bufs.num = 1; u->output.bufs.size = clcf->client_body_buffer_size; - u->output.output_filter = ngx_chain_writer; - u->output.filter_ctx = &u->writer; + + if (u->output.output_filter == NULL) { + u->output.output_filter = ngx_chain_writer; + u->output.filter_ctx = &u->writer; + } u->writer.pool = r->pool; @@ -584,6 +620,10 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) } else { +#if (NGX_HTTP_SSL) + u->ssl_name = u->resolved->host; +#endif + if (u->resolved->sockaddr) { if (ngx_http_upstream_create_round_robin_peer(r, u->resolved) @@ -670,12 +710,24 @@ found: return; } +#if (NGX_HTTP_SSL) + u->ssl_name = uscf->host; +#endif + if (uscf->peer.init(r, uscf) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } + u->peer.start_time = ngx_current_msec; + + if (u->conf->next_upstream_tries + && u->peer.tries > u->conf->next_upstream_tries) + { + u->peer.tries = u->conf->next_upstream_tries; + } + ngx_http_upstream_connect(r, u); } @@ -685,8 +737,9 @@ found: static ngx_int_t ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u) { - ngx_int_t rc; - ngx_http_cache_t *c; + ngx_int_t rc; + ngx_http_cache_t *c; + ngx_http_file_cache_t *cache; c = r->cache; @@ -696,6 +749,12 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u) return NGX_DECLINED; } + rc = ngx_http_upstream_cache_get(r, u, &cache); + + if (rc != NGX_OK) { + return rc; + } + if (r->method & NGX_HTTP_HEAD) { u->method = ngx_http_core_get_method; } @@ -725,6 +784,12 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u) u->cacheable = 1; + c = r->cache; + + c->body_start = u->conf->buffer_size; + c->min_uses = u->conf->cache_min_uses; + c->file_cache = cache; + switch (ngx_http_test_predicates(r, u->conf->cache_bypass)) { case NGX_ERROR: @@ -738,14 +803,9 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u) break; } - c = r->cache; - - c->min_uses = u->conf->cache_min_uses; - 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; + c->lock_age = u->conf->cache_lock_age; u->cache_status = NGX_HTTP_CACHE_MISS; } @@ -834,6 +894,49 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u) } +static ngx_int_t +ngx_http_upstream_cache_get(ngx_http_request_t *r, ngx_http_upstream_t *u, + ngx_http_file_cache_t **cache) +{ + ngx_str_t *name, val; + ngx_uint_t i; + ngx_http_file_cache_t **caches; + + if (u->conf->cache_zone) { + *cache = u->conf->cache_zone->data; + return NGX_OK; + } + + if (ngx_http_complex_value(r, u->conf->cache_value, &val) != NGX_OK) { + return NGX_ERROR; + } + + if (val.len == 0 + || (val.len == 3 && ngx_strncmp(val.data, "off", 3) == 0)) + { + return NGX_DECLINED; + } + + caches = u->caches->elts; + + for (i = 0; i < u->caches->nelts; i++) { + name = &caches[i]->shm_zone->shm.name; + + if (name->len == val.len + && ngx_strncmp(name->data, val.data, val.len) == 0) + { + *cache = caches[i]; + return NGX_OK; + } + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "cache \"%V\" not found", &val); + + return NGX_ERROR; +} + + static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u) { @@ -855,6 +958,7 @@ ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u) ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t)); u->headers_in.content_length_n = -1; + u->headers_in.last_modified_time = -1; if (ngx_list_init(&u->headers_in.headers, r->pool, 8, sizeof(ngx_table_elt_t)) @@ -902,6 +1006,11 @@ ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx) u = r->upstream; ur = u->resolved; + ngx_http_set_log_request(c->log, r); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream resolve: \"%V?%V\"", &r->uri, &r->args); + if (ctx->state) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%V could not be resolved (%i: %s)", @@ -942,6 +1051,14 @@ ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx) ngx_resolve_name_done(ctx); ur->ctx = NULL; + u->peer.start_time = ngx_current_msec; + + if (u->conf->next_upstream_tries + && u->peer.tries > u->conf->next_upstream_tries) + { + u->peer.tries = u->conf->next_upstream_tries; + } + ngx_http_upstream_connect(r, u); failed: @@ -955,7 +1072,6 @@ ngx_http_upstream_handler(ngx_event_t *ev) { ngx_connection_t *c; ngx_http_request_t *r; - ngx_http_log_ctx_t *ctx; ngx_http_upstream_t *u; c = ev->data; @@ -964,8 +1080,7 @@ ngx_http_upstream_handler(ngx_event_t *ev) u = r->upstream; c = r->connection; - ctx = c->log->data; - ctx->current_request = r; + ngx_http_set_log_request(c->log, r); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http upstream request: \"%V?%V\"", &r->uri, &r->args); @@ -1189,15 +1304,12 @@ static void ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) { ngx_int_t rc; - ngx_time_t *tp; ngx_connection_t *c; r->connection->log->action = "connecting to upstream"; - if (u->state && u->state->response_sec) { - tp = ngx_timeofday(); - u->state->response_sec = tp->sec - u->state->response_sec; - u->state->response_msec = tp->msec - u->state->response_msec; + if (u->state && u->state->response_time) { + u->state->response_time = ngx_current_msec - u->state->response_time; } u->state = ngx_array_push(r->upstream_states); @@ -1209,9 +1321,9 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t)); - tp = ngx_timeofday(); - u->state->response_sec = tp->sec; - u->state->response_msec = tp->msec; + u->state->response_time = ngx_current_msec; + u->state->connect_time = (ngx_msec_t) -1; + u->state->header_time = (ngx_msec_t) -1; rc = ngx_event_connect_peer(&u->peer); @@ -1326,7 +1438,7 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) #endif - ngx_http_upstream_send_request(r, u); + ngx_http_upstream_send_request(r, u, 1); } @@ -1336,7 +1448,9 @@ static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_connection_t *c) { - ngx_int_t rc; + int tcp_nodelay; + ngx_int_t rc; + ngx_http_core_loc_conf_t *clcf; if (ngx_http_upstream_test_connect(c) != NGX_OK) { ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); @@ -1355,12 +1469,42 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, c->sendfile = 0; u->output.sendfile = 0; + if (u->conf->ssl_server_name || u->conf->ssl_verify) { + if (ngx_http_upstream_ssl_name(r, u, c) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + } + if (u->conf->ssl_session_reuse) { if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } + + /* abbreviated SSL handshake may interact badly with Nagle */ + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); + + tcp_nodelay = 1; + + if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, + (const void *) &tcp_nodelay, sizeof(int)) == -1) + { + ngx_connection_error(c, ngx_socket_errno, + "setsockopt(TCP_NODELAY) failed"); + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + c->tcp_nodelay = NGX_TCP_NODELAY_SET; + } } r->connection->log->action = "SSL handshaking to upstream"; @@ -1368,6 +1512,11 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, rc = ngx_ssl_handshake(c); if (rc == NGX_AGAIN) { + + if (!c->write->timer_set) { + ngx_add_timer(c->write, u->conf->connect_timeout); + } + c->ssl->handler = ngx_http_upstream_ssl_handshake; return; } @@ -1379,14 +1528,35 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c) { + long rc; ngx_http_request_t *r; ngx_http_upstream_t *u; r = c->data; u = r->upstream; + ngx_http_set_log_request(c->log, r); + if (c->ssl->handshaked) { + if (u->conf->ssl_verify) { + rc = SSL_get_verify_result(c->ssl->connection); + + if (rc != X509_V_OK) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "upstream SSL certificate verify error: (%l:%s)", + rc, X509_verify_cert_error_string(rc)); + goto failed; + } + + if (ngx_ssl_check_host(c, &u->ssl_name) != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "upstream SSL certificate does not match \"%V\"", + &u->ssl_name); + goto failed; + } + } + if (u->conf->ssl_session_reuse) { u->peer.save_session(&u->peer, u->peer.data); } @@ -1396,12 +1566,14 @@ ngx_http_upstream_ssl_handshake(ngx_connection_t *c) c = r->connection; - ngx_http_upstream_send_request(r, u); + ngx_http_upstream_send_request(r, u, 1); ngx_http_run_posted_requests(c); return; } +failed: + c = r->connection; ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); @@ -1409,12 +1581,104 @@ ngx_http_upstream_ssl_handshake(ngx_connection_t *c) ngx_http_run_posted_requests(c); } + +static ngx_int_t +ngx_http_upstream_ssl_name(ngx_http_request_t *r, ngx_http_upstream_t *u, + ngx_connection_t *c) +{ + u_char *p, *last; + ngx_str_t name; + + if (u->conf->ssl_name) { + if (ngx_http_complex_value(r, u->conf->ssl_name, &name) != NGX_OK) { + return NGX_ERROR; + } + + } else { + name = u->ssl_name; + } + + if (name.len == 0) { + goto done; + } + + /* + * ssl name here may contain port, notably if derived from $proxy_host + * or $http_host; we have to strip it + */ + + p = name.data; + last = name.data + name.len; + + if (*p == '[') { + p = ngx_strlchr(p, last, ']'); + + if (p == NULL) { + p = name.data; + } + } + + p = ngx_strlchr(p, last, ':'); + + if (p != NULL) { + name.len = p - name.data; + } + + if (!u->conf->ssl_server_name) { + goto done; + } + +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + + /* as per RFC 6066, literal IPv4 and IPv6 addresses are not permitted */ + + if (name.len == 0 || *name.data == '[') { + goto done; + } + + if (ngx_inet_addr(name.data, name.len) != INADDR_NONE) { + goto done; + } + + /* + * SSL_set_tlsext_host_name() needs a null-terminated string, + * hence we explicitly null-terminate name here + */ + + p = ngx_pnalloc(r->pool, name.len + 1); + if (p == NULL) { + return NGX_ERROR; + } + + (void) ngx_cpystrn(p, name.data, name.len + 1); + + name.data = p; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "upstream SSL server name: \"%s\"", name.data); + + if (SSL_set_tlsext_host_name(c->ssl->connection, name.data) == 0) { + ngx_ssl_error(NGX_LOG_ERR, r->connection->log, 0, + "SSL_set_tlsext_host_name(\"%s\") failed", name.data); + return NGX_ERROR; + } + +#endif + +done: + + u->ssl_name = name; + + return NGX_OK; +} + #endif static ngx_int_t ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u) { + off_t file_pos; ngx_chain_t *cl; if (u->reinit_request(r) != NGX_OK) { @@ -1426,6 +1690,7 @@ ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u) ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t)); u->headers_in.content_length_n = -1; + u->headers_in.last_modified_time = -1; if (ngx_list_init(&u->headers_in.headers, r->pool, 8, sizeof(ngx_table_elt_t)) @@ -1436,9 +1701,17 @@ ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u) /* reinit the request chain */ + file_pos = 0; + for (cl = u->request_bufs; cl; cl = cl->next) { cl->buf->pos = cl->buf->start; - cl->buf->file_pos = 0; + + /* there is at most one file */ + + if (cl->buf->in_file) { + cl->buf->file_pos = file_pos; + file_pos = cl->buf->file_last; + } } /* reinit the subrequest's ngx_output_chain() context */ @@ -1481,7 +1754,8 @@ ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u) static void -ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u) +ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u, + ngx_uint_t do_write) { ngx_int_t rc; ngx_connection_t *c; @@ -1491,6 +1765,10 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http upstream send request"); + if (u->state->connect_time == (ngx_msec_t) -1) { + u->state->connect_time = ngx_current_msec - u->state->response_time; + } + if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) { ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); return; @@ -1498,21 +1776,25 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u) c->log->action = "sending request to upstream"; - rc = ngx_output_chain(&u->output, u->request_sent ? NULL : u->request_bufs); - - u->request_sent = 1; + rc = ngx_http_upstream_send_request_body(r, u, do_write); if (rc == NGX_ERROR) { ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); return; } - if (c->write->timer_set) { - ngx_del_timer(c->write); + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + ngx_http_upstream_finalize_request(r, u, rc); + return; } if (rc == NGX_AGAIN) { - ngx_add_timer(c->write, u->conf->send_timeout); + if (!c->write->ready) { + ngx_add_timer(c->write, u->conf->send_timeout); + + } else if (c->write->timer_set) { + ngx_del_timer(c->write); + } if (ngx_handle_write_event(c->write, u->conf->send_lowat) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, @@ -1525,6 +1807,10 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u) /* rc == NGX_OK */ + if (c->write->timer_set) { + ngx_del_timer(c->write); + } + if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) { if (ngx_tcp_push(c->fd) == NGX_ERROR) { ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno, @@ -1537,13 +1823,6 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u) c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; } - ngx_add_timer(c->read, u->conf->read_timeout); - - if (c->read->ready) { - ngx_http_upstream_process_header(r, u); - return; - } - u->write_event_handler = ngx_http_upstream_dummy_handler; if (ngx_handle_write_event(c->write, 0) != NGX_OK) { @@ -1551,6 +1830,130 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u) NGX_HTTP_INTERNAL_SERVER_ERROR); return; } + + ngx_add_timer(c->read, u->conf->read_timeout); + + if (c->read->ready) { + ngx_http_upstream_process_header(r, u); + return; + } +} + + +static ngx_int_t +ngx_http_upstream_send_request_body(ngx_http_request_t *r, + ngx_http_upstream_t *u, ngx_uint_t do_write) +{ + int tcp_nodelay; + ngx_int_t rc; + ngx_chain_t *out, *cl, *ln; + ngx_connection_t *c; + ngx_http_core_loc_conf_t *clcf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http upstream send request body"); + + if (!r->request_body_no_buffering) { + + /* buffered request body */ + + if (!u->request_sent) { + u->request_sent = 1; + out = u->request_bufs; + + } else { + out = NULL; + } + + return ngx_output_chain(&u->output, out); + } + + if (!u->request_sent) { + u->request_sent = 1; + out = u->request_bufs; + + if (r->request_body->bufs) { + for (cl = out; cl->next; cl = out->next) { /* void */ } + cl->next = r->request_body->bufs; + r->request_body->bufs = NULL; + } + + c = u->peer.connection; + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); + + tcp_nodelay = 1; + + if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, + (const void *) &tcp_nodelay, sizeof(int)) == -1) + { + ngx_connection_error(c, ngx_socket_errno, + "setsockopt(TCP_NODELAY) failed"); + return NGX_ERROR; + } + + c->tcp_nodelay = NGX_TCP_NODELAY_SET; + } + + r->read_event_handler = ngx_http_upstream_read_request_handler; + + } else { + out = NULL; + } + + for ( ;; ) { + + if (do_write) { + rc = ngx_output_chain(&u->output, out); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + while (out) { + ln = out; + out = out->next; + ngx_free_chain(r->pool, ln); + } + + if (rc == NGX_OK && !r->reading_body) { + break; + } + } + + if (r->reading_body) { + /* read client request body */ + + rc = ngx_http_read_unbuffered_request_body(r); + + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + return rc; + } + + out = r->request_body->bufs; + r->request_body->bufs = NULL; + } + + /* stop if there is nothing to send */ + + if (out == NULL) { + rc = NGX_AGAIN; + break; + } + + do_write = 1; + } + + if (!r->reading_body) { + if (!u->store && !r->post_action && !u->conf->ignore_client_abort) { + r->read_event_handler = + ngx_http_upstream_rd_check_broken_connection; + } + } + + return rc; } @@ -1587,7 +1990,29 @@ ngx_http_upstream_send_request_handler(ngx_http_request_t *r, return; } - ngx_http_upstream_send_request(r, u); + ngx_http_upstream_send_request(r, u, 1); +} + + +static void +ngx_http_upstream_read_request_handler(ngx_http_request_t *r) +{ + ngx_connection_t *c; + ngx_http_upstream_t *u; + + c = r->connection; + u = r->upstream; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http upstream read request handler"); + + if (c->read->timedout) { + c->timedout = 1; + ngx_http_upstream_finalize_request(r, u, NGX_HTTP_REQUEST_TIME_OUT); + return; + } + + ngx_http_upstream_send_request(r, u, 0); } @@ -1716,6 +2141,8 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u) /* rc == NGX_OK */ + u->state->header_time = ngx_current_msec - u->state->response_time; + if (u->headers_in.status_n >= NGX_HTTP_SPECIAL_RESPONSE) { if (ngx_http_upstream_test_next(r, u) == NGX_OK) { @@ -2036,19 +2463,26 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) } uri = u->headers_in.x_accel_redirect->value; - ngx_str_null(&args); - flags = NGX_HTTP_LOG_UNSAFE; - if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { - ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND); - return NGX_DONE; + if (uri.data[0] == '@') { + ngx_http_named_location(r, &uri); + + } else { + ngx_str_null(&args); + flags = NGX_HTTP_LOG_UNSAFE; + + if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND); + return NGX_DONE; + } + + if (r->method != NGX_HTTP_HEAD) { + r->method = NGX_HTTP_GET; + } + + ngx_http_internal_redirect(r, &uri, &args); } - if (r->method != NGX_HTTP_HEAD) { - r->method = NGX_HTTP_GET; - } - - ngx_http_internal_redirect(r, &uri, &args); ngx_http_finalize_request(r, NGX_DONE); return NGX_DONE; } @@ -2107,6 +2541,19 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) r->headers_out.content_length_n = u->headers_in.content_length_n; + r->disable_not_modified = !u->cacheable; + + if (u->conf->force_ranges) { + r->allow_ranges = 1; + r->single_range = 1; + +#if (NGX_HTTP_CACHE) + if (r->cached) { + r->single_range = 0; + } +#endif + } + u->length = -1; return NGX_OK; @@ -2218,21 +2665,17 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) if (r->header_only) { - if (u->cacheable || u->store) { - - if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { - ngx_connection_error(c, ngx_socket_errno, - ngx_shutdown_socket_n " failed"); - } - - r->read_event_handler = ngx_http_request_empty_handler; - r->write_event_handler = ngx_http_request_empty_handler; - c->error = 1; - - } else { + if (!u->buffering) { ngx_http_upstream_finalize_request(r, u, rc); return; } + + if (!u->cacheable && !u->store) { + ngx_http_upstream_finalize_request(r, u, rc); + return; + } + + u->pipe->downstream_error = 1; } if (r->request_body && r->request_body->temp_file) { @@ -2332,9 +2775,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) if (u->cache_status == NGX_HTTP_CACHE_BYPASS) { - r->cache->min_uses = u->conf->cache_min_uses; - r->cache->body_start = u->conf->buffer_size; - r->cache->file_cache = u->conf->cache->data; + /* create cache if previously bypassed */ if (ngx_http_file_cache_create(r) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_ERROR); @@ -2361,15 +2802,33 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) } if (valid) { - r->cache->last_modified = r->headers_out.last_modified_time; r->cache->date = now; r->cache->body_start = (u_short) (u->buffer.pos - u->buffer.start); - ngx_http_file_cache_set_header(r, u->buffer.start); + if (u->headers_in.status_n == NGX_HTTP_OK + || u->headers_in.status_n == NGX_HTTP_PARTIAL_CONTENT) + { + r->cache->last_modified = u->headers_in.last_modified_time; + + if (u->headers_in.etag) { + r->cache->etag = u->headers_in.etag->value; + + } else { + ngx_str_null(&r->cache->etag); + } + + } else { + r->cache->last_modified = -1; + ngx_str_null(&r->cache->etag); + } + + if (ngx_http_file_cache_set_header(r, u->buffer.start) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); + return; + } } else { u->cacheable = 0; - r->headers_out.last_modified_time = -1; } } @@ -2393,6 +2852,8 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) p->downstream = c; p->pool = r->pool; p->log = c->log; + p->limit_rate = u->conf->limit_rate; + p->start_sec = ngx_time(); p->cacheable = u->cacheable || u->store; @@ -2410,6 +2871,12 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) if (p->cacheable) { p->temp_file->persistent = 1; +#if (NGX_HTTP_CACHE) + if (r->cache && r->cache->file_cache->temp_path) { + p->temp_file->path = r->cache->file_cache->temp_path; + } +#endif + } else { p->temp_file->log_level = NGX_LOG_WARN; p->temp_file->warn = "an upstream response is buffered " @@ -2445,7 +2912,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) p->buf_to_file->temporary = 1; } - if (ngx_event_flags & NGX_USE_AIO_EVENT) { + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { /* the posted aio operation may corrupt a shadow buffer */ p->single_buf = 1; } @@ -3059,7 +3526,7 @@ ngx_http_upstream_process_downstream(ngx_http_request_t *r) } } - ngx_http_upstream_process_request(r); + ngx_http_upstream_process_request(r, u); } @@ -3067,38 +3534,77 @@ static void ngx_http_upstream_process_upstream(ngx_http_request_t *r, ngx_http_upstream_t *u) { + ngx_event_t *rev; + ngx_event_pipe_t *p; ngx_connection_t *c; c = u->peer.connection; + p = u->pipe; + rev = c->read; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http upstream process upstream"); c->log->action = "reading upstream"; - if (c->read->timedout) { - u->pipe->upstream_error = 1; - ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out"); + if (rev->timedout) { + + if (rev->delayed) { + + rev->timedout = 0; + rev->delayed = 0; + + if (!rev->ready) { + ngx_add_timer(rev, p->read_timeout); + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); + } + + return; + } + + if (ngx_event_pipe(p, 0) == NGX_ABORT) { + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); + return; + } + + } else { + p->upstream_error = 1; + ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out"); + } } else { - if (ngx_event_pipe(u->pipe, 0) == NGX_ABORT) { + + if (rev->delayed) { + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream delayed"); + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); + } + + return; + } + + if (ngx_event_pipe(p, 0) == NGX_ABORT) { ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } } - ngx_http_upstream_process_request(r); + ngx_http_upstream_process_request(r, u); } static void -ngx_http_upstream_process_request(ngx_http_request_t *r) +ngx_http_upstream_process_request(ngx_http_request_t *r, + ngx_http_upstream_t *u) { - ngx_temp_file_t *tf; - ngx_event_pipe_t *p; - ngx_http_upstream_t *u; + ngx_temp_file_t *tf; + ngx_event_pipe_t *p; - u = r->upstream; p = u->pipe; if (u->peer.connection) { @@ -3115,7 +3621,6 @@ ngx_http_upstream_process_request(ngx_http_request_t *r) || u->headers_in.content_length_n == tf->offset)) { ngx_http_upstream_store(r, u); - u->store = 0; } } } @@ -3237,7 +3742,9 @@ ngx_http_upstream_store(ngx_http_request_t *r, ngx_http_upstream_t *u) if (u->conf->store_lengths == NULL) { - ngx_http_map_uri_to_path(r, &path, &root, 0); + if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) { + return; + } } else { if (ngx_http_script_run(r, &path, u->conf->store_lengths->elts, 0, @@ -3255,6 +3762,8 @@ ngx_http_upstream_store(ngx_http_request_t *r, ngx_http_upstream_t *u) tf->file.name.data, path.data); (void) ngx_ext_rename_file(&tf->file.name, &path, &ext); + + u->store = 0; } @@ -3270,6 +3779,7 @@ static void ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_uint_t ft_type) { + ngx_msec_t timeout; ngx_uint_t status, state; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -3295,7 +3805,9 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, "upstream timed out"); } - if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) { + if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR + && (!u->request_sent || !r->request_body_no_buffering)) + { status = 0; /* TODO: inform balancer instead */ @@ -3303,7 +3815,7 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, u->peer.tries++; } else { - switch(ft_type) { + switch (ft_type) { case NGX_HTTP_UPSTREAM_FT_TIMEOUT: status = NGX_HTTP_GATEWAY_TIME_OUT; @@ -3339,9 +3851,13 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, if (status) { u->state->status = status; + timeout = u->conf->next_upstream_timeout; - if (u->peer.tries == 0 || !(u->conf->next_upstream & ft_type)) { - + if (u->peer.tries == 0 + || !(u->conf->next_upstream & ft_type) + || (u->request_sent && r->request_body_no_buffering) + || (timeout && ngx_current_msec - u->peer.start_time >= timeout)) + { #if (NGX_HTTP_CACHE) if (u->cache_status == NGX_HTTP_CACHE_EXPIRED @@ -3408,26 +3924,27 @@ static void ngx_http_upstream_finalize_request(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_int_t rc) { - ngx_uint_t flush; - ngx_time_t *tp; + ngx_uint_t flush; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "finalize http upstream request: %i", rc); - if (u->cleanup) { - *u->cleanup = NULL; - u->cleanup = NULL; + if (u->cleanup == NULL) { + /* the request was already finalized */ + ngx_http_finalize_request(r, NGX_DONE); + return; } + *u->cleanup = NULL; + u->cleanup = NULL; + if (u->resolved && u->resolved->ctx) { ngx_resolve_name_done(u->resolved->ctx); u->resolved->ctx = NULL; } - if (u->state && u->state->response_sec) { - tp = ngx_timeofday(); - u->state->response_sec = tp->sec - u->state->response_sec; - u->state->response_msec = tp->msec - u->state->response_msec; + if (u->state && u->state->response_time) { + u->state->response_time = ngx_current_msec - u->state->response_time; if (u->pipe && u->pipe->read_length) { u->state->response_length = u->pipe->read_length; @@ -3599,14 +4116,54 @@ ngx_http_upstream_process_content_length(ngx_http_request_t *r, static ngx_int_t -ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h, - ngx_uint_t offset) +ngx_http_upstream_process_last_modified(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset) { -#if (NGX_HTTP_CACHE) ngx_http_upstream_t *u; u = r->upstream; + u->headers_in.last_modified = h; + +#if (NGX_HTTP_CACHE) + + if (u->cacheable) { + u->headers_in.last_modified_time = ngx_http_parse_time(h->value.data, + h->value.len); + } + +#endif + + 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) +{ + ngx_array_t *pa; + ngx_table_elt_t **ph; + ngx_http_upstream_t *u; + + u = r->upstream; + pa = &u->headers_in.cookies; + + if (pa->elts == NULL) { + if (ngx_array_init(pa, r->pool, 1, sizeof(ngx_table_elt_t *)) != NGX_OK) + { + return NGX_ERROR; + } + } + + ph = ngx_array_push(pa); + if (ph == NULL) { + return NGX_ERROR; + } + + *ph = h; + +#if (NGX_HTTP_CACHE) if (!(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_SET_COOKIE)) { u->cacheable = 0; } @@ -3643,7 +4200,7 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r, #if (NGX_HTTP_CACHE) { - u_char *p, *last; + u_char *p, *start, *last; ngx_int_t n; if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL) { @@ -3658,18 +4215,24 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r, return NGX_OK; } - p = h->value.data; - last = p + h->value.len; + start = h->value.data; + last = start + h->value.len; - if (ngx_strlcasestrn(p, last, (u_char *) "no-cache", 8 - 1) != NULL - || ngx_strlcasestrn(p, last, (u_char *) "no-store", 8 - 1) != NULL - || ngx_strlcasestrn(p, last, (u_char *) "private", 7 - 1) != NULL) + if (ngx_strlcasestrn(start, last, (u_char *) "no-cache", 8 - 1) != NULL + || ngx_strlcasestrn(start, last, (u_char *) "no-store", 8 - 1) != NULL + || ngx_strlcasestrn(start, last, (u_char *) "private", 7 - 1) != NULL) { u->cacheable = 0; return NGX_OK; } - p = ngx_strlcasestrn(p, last, (u_char *) "max-age=", 8 - 1); + p = ngx_strlcasestrn(start, last, (u_char *) "s-maxage=", 9 - 1); + offset = 9; + + if (p == NULL) { + p = ngx_strlcasestrn(start, last, (u_char *) "max-age=", 8 - 1); + offset = 8; + } if (p == NULL) { return NGX_OK; @@ -3677,7 +4240,7 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r, n = 0; - for (p += 8; p < last; p++) { + for (p += offset; p < last; p++) { if (*p == ',' || *p == ';' || *p == ' ') { break; } @@ -3912,6 +4475,39 @@ ngx_http_upstream_process_transfer_encoding(ngx_http_request_t *r, } +static ngx_int_t +ngx_http_upstream_process_vary(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset) +{ + ngx_http_upstream_t *u; + + u = r->upstream; + u->headers_in.vary = h; + +#if (NGX_HTTP_CACHE) + + if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_VARY) { + return NGX_OK; + } + + if (r->cache == NULL) { + return NGX_OK; + } + + if (h->value.len > NGX_HTTP_CACHE_VARY_LEN + || (h->value.len == 1 && h->value.data[0] == '*')) + { + u->cacheable = 0; + } + + r->cache->vary = h->value; + +#endif + + 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) @@ -4037,8 +4633,8 @@ ngx_http_upstream_copy_last_modified(ngx_http_request_t *r, ngx_table_elt_t *h, #if (NGX_HTTP_CACHE) if (r->upstream->cacheable) { - r->headers_out.last_modified_time = ngx_http_parse_time(h->value.data, - h->value.len); + r->headers_out.last_modified_time = + r->upstream->headers_in.last_modified_time; } #endif @@ -4178,6 +4774,10 @@ ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r, { ngx_table_elt_t *ho; + if (r->upstream->conf->force_ranges) { + return NGX_OK; + } + #if (NGX_HTTP_CACHE) if (r->cached) { @@ -4417,8 +5017,17 @@ ngx_http_upstream_response_time_variable(ngx_http_request_t *r, for ( ;; ) { if (state[i].status) { - ms = (ngx_msec_int_t) - (state[i].response_sec * 1000 + state[i].response_msec); + + if (data == 1 && state[i].header_time != (ngx_msec_t) -1) { + ms = state[i].header_time; + + } else if (data == 2 && state[i].connect_time != (ngx_msec_t) -1) { + ms = state[i].connect_time; + + } else { + ms = state[i].response_time; + } + ms = ngx_max(ms, 0); p = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000); @@ -4528,6 +5137,40 @@ ngx_http_upstream_header_variable(ngx_http_request_t *r, } +ngx_int_t +ngx_http_upstream_cookie_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_str_t *name = (ngx_str_t *) data; + + ngx_str_t cookie, s; + + if (r->upstream == NULL) { + v->not_found = 1; + return NGX_OK; + } + + s.len = name->len - (sizeof("upstream_cookie_") - 1); + s.data = name->data + sizeof("upstream_cookie_") - 1; + + if (ngx_http_parse_set_cookie_lines(&r->upstream->headers_in.cookies, + &s, &cookie) + == NGX_DECLINED) + { + v->not_found = 1; + return NGX_OK; + } + + v->len = cookie.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = cookie.data; + + return NGX_OK; +} + + #if (NGX_HTTP_CACHE) ngx_int_t @@ -4582,6 +5225,29 @@ ngx_http_upstream_cache_last_modified(ngx_http_request_t *r, return NGX_OK; } + +static ngx_int_t +ngx_http_upstream_cache_etag(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + if (r->upstream == NULL + || !r->upstream->conf->cache_revalidate + || r->upstream->cache_status != NGX_HTTP_CACHE_EXPIRED + || r->cache->etag.len == 0) + { + v->not_found = 1; + return NGX_OK; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->len = r->cache->etag.len; + v->data = r->cache->etag.data; + + return NGX_OK; +} + #endif @@ -4669,6 +5335,12 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) } } + uscf->servers = ngx_array_create(cf->pool, 4, + sizeof(ngx_http_upstream_server_t)); + if (uscf->servers == NULL) { + return NGX_CONF_ERROR; + } + /* parse inside upstream{} */ @@ -4684,7 +5356,7 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) return rv; } - if (uscf->servers == NULL) { + if (uscf->servers->nelts == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "no servers are inside upstream"); return NGX_CONF_ERROR; @@ -4706,14 +5378,6 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_uint_t i; ngx_http_upstream_server_t *us; - if (uscf->servers == NULL) { - uscf->servers = ngx_array_create(cf->pool, 4, - sizeof(ngx_http_upstream_server_t)); - if (uscf->servers == NULL) { - return NGX_CONF_ERROR; - } - } - us = ngx_array_push(uscf->servers); if (us == NULL) { return NGX_CONF_ERROR; @@ -4723,20 +5387,6 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) value = cf->args->elts; - ngx_memzero(&u, sizeof(ngx_url_t)); - - u.url = value[1]; - u.default_port = 80; - - if (ngx_parse_url(cf->pool, &u) != NGX_OK) { - if (u.err) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "%s in upstream \"%V\"", u.err, &u.url); - } - - return NGX_CONF_ERROR; - } - weight = 1; max_fails = 1; fail_timeout = 10; @@ -4746,7 +5396,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strncmp(value[i].data, "weight=", 7) == 0) { if (!(uscf->flags & NGX_HTTP_UPSTREAM_WEIGHT)) { - goto invalid; + goto not_supported; } weight = ngx_atoi(&value[i].data[7], value[i].len - 7); @@ -4761,7 +5411,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) { if (!(uscf->flags & NGX_HTTP_UPSTREAM_MAX_FAILS)) { - goto invalid; + goto not_supported; } max_fails = ngx_atoi(&value[i].data[10], value[i].len - 10); @@ -4776,7 +5426,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strncmp(value[i].data, "fail_timeout=", 13) == 0) { if (!(uscf->flags & NGX_HTTP_UPSTREAM_FAIL_TIMEOUT)) { - goto invalid; + goto not_supported; } s.len = value[i].len - 13; @@ -4794,7 +5444,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strcmp(value[i].data, "backup") == 0) { if (!(uscf->flags & NGX_HTTP_UPSTREAM_BACKUP)) { - goto invalid; + goto not_supported; } us->backup = 1; @@ -4805,7 +5455,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strcmp(value[i].data, "down") == 0) { if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) { - goto invalid; + goto not_supported; } us->down = 1; @@ -4816,6 +5466,21 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) goto invalid; } + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url = value[1]; + u.default_port = 80; + + if (ngx_parse_url(cf->pool, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in upstream \"%V\"", u.err, &u.url); + } + + return NGX_CONF_ERROR; + } + + us->name = u.url; us->addrs = u.addrs; us->naddrs = u.naddrs; us->weight = weight; @@ -4830,6 +5495,14 @@ invalid: "invalid parameter \"%V\"", &value[i]); return NGX_CONF_ERROR; + +not_supported: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "balancing method does not support parameter \"%V\"", + &value[i]); + + return NGX_CONF_ERROR; } @@ -4921,7 +5594,7 @@ ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags) uscf->default_port = u->default_port; uscf->no_port = u->no_port; - if (u->naddrs == 1) { + if (u->naddrs == 1 && (u->port || u->family == AF_UNIX)) { uscf->servers = ngx_array_create(cf->pool, 1, sizeof(ngx_http_upstream_server_t)); if (uscf->servers == NULL) { @@ -5137,7 +5810,7 @@ ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf, if (conf->hide_headers_hash.buckets #if (NGX_HTTP_CACHE) - && ((conf->cache == NULL) == (prev->cache == NULL)) + && ((conf->cache == 0) == (prev->cache == 0)) #endif ) { diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index 9f96c50..64157e6 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -50,6 +50,7 @@ #define NGX_HTTP_UPSTREAM_IGN_XA_LIMIT_RATE 0x00000040 #define NGX_HTTP_UPSTREAM_IGN_XA_BUFFERING 0x00000080 #define NGX_HTTP_UPSTREAM_IGN_XA_CHARSET 0x00000100 +#define NGX_HTTP_UPSTREAM_IGN_VARY 0x00000200 typedef struct { @@ -57,8 +58,9 @@ typedef struct { ngx_uint_t bl_state; ngx_uint_t status; - time_t response_sec; - ngx_uint_t response_msec; + ngx_msec_t response_time; + ngx_msec_t connect_time; + ngx_msec_t header_time; off_t response_length; ngx_str_t *peer; @@ -87,6 +89,7 @@ typedef struct { typedef struct { + ngx_str_t name; ngx_addr_t *addrs; ngx_uint_t naddrs; ngx_uint_t weight; @@ -119,6 +122,10 @@ struct ngx_http_upstream_srv_conf_s { in_port_t port; in_port_t default_port; ngx_uint_t no_port; /* unsigned no_port:1 */ + +#if (NGX_HTTP_UPSTREAM_ZONE) + ngx_shm_zone_t *shm_zone; +#endif }; @@ -135,9 +142,11 @@ typedef struct { ngx_msec_t send_timeout; ngx_msec_t read_timeout; ngx_msec_t timeout; + ngx_msec_t next_upstream_timeout; size_t send_lowat; size_t buffer_size; + size_t limit_rate; size_t busy_buffers_size; size_t max_temp_file_size; @@ -152,13 +161,16 @@ typedef struct { ngx_uint_t ignore_headers; ngx_uint_t next_upstream; ngx_uint_t store_access; + ngx_uint_t next_upstream_tries; ngx_flag_t buffering; + ngx_flag_t request_buffering; ngx_flag_t pass_request_headers; ngx_flag_t pass_request_body; ngx_flag_t ignore_client_abort; ngx_flag_t intercept_errors; ngx_flag_t cyclic_temp_file; + ngx_flag_t force_ranges; ngx_path_t *temp_path; @@ -169,7 +181,8 @@ typedef struct { ngx_http_upstream_local_t *local; #if (NGX_HTTP_CACHE) - ngx_shm_zone_t *cache; + ngx_shm_zone_t *cache_zone; + ngx_http_complex_value_t *cache_value; ngx_uint_t cache_min_uses; ngx_uint_t cache_use_stale; @@ -177,6 +190,7 @@ typedef struct { ngx_flag_t cache_lock; ngx_msec_t cache_lock_timeout; + ngx_msec_t cache_lock_age; ngx_flag_t cache_revalidate; @@ -188,6 +202,9 @@ typedef struct { ngx_array_t *store_lengths; ngx_array_t *store_values; +#if (NGX_HTTP_CACHE) + signed cache:2; +#endif signed store:2; unsigned intercept_404:1; unsigned change_buffering:1; @@ -195,6 +212,10 @@ typedef struct { #if (NGX_HTTP_SSL) ngx_ssl_t *ssl; ngx_flag_t ssl_session_reuse; + + ngx_http_complex_value_t *ssl_name; + ngx_flag_t ssl_server_name; + ngx_flag_t ssl_verify; #endif ngx_str_t module; @@ -236,14 +257,17 @@ typedef struct { ngx_table_elt_t *accept_ranges; ngx_table_elt_t *www_authenticate; ngx_table_elt_t *transfer_encoding; + ngx_table_elt_t *vary; #if (NGX_HTTP_GZIP) ngx_table_elt_t *content_encoding; #endif - off_t content_length_n; - ngx_array_t cache_control; + ngx_array_t cookies; + + off_t content_length_n; + time_t last_modified_time; unsigned connection_close:1; unsigned chunked:1; @@ -283,6 +307,9 @@ struct ngx_http_upstream_s { ngx_chain_writer_ctx_t writer; ngx_http_upstream_conf_t *conf; +#if (NGX_HTTP_CACHE) + ngx_array_t *caches; +#endif ngx_http_upstream_headers_in_t headers_in; @@ -323,6 +350,10 @@ struct ngx_http_upstream_s { ngx_str_t schema; ngx_str_t uri; +#if (NGX_HTTP_SSL) + ngx_str_t ssl_name; +#endif + ngx_http_cleanup_pt *cleanup; unsigned store:1; @@ -355,6 +386,8 @@ typedef struct { } ngx_http_upstream_param_t; +ngx_int_t ngx_http_upstream_cookie_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); ngx_int_t ngx_http_upstream_header_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c index 85ff558..d6ae33b 100644 --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -10,6 +10,10 @@ #include +#define ngx_http_upstream_tries(p) ((p)->number \ + + ((p)->next ? (p)->next->number : 0)) + + static ngx_http_upstream_rr_peer_t *ngx_http_upstream_get_peer( ngx_http_upstream_rr_peer_data_t *rrp); @@ -30,6 +34,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, ngx_url_t u; ngx_uint_t i, j, n, w; ngx_http_upstream_server_t *server; + ngx_http_upstream_rr_peer_t *peer, **peerp; ngx_http_upstream_rr_peers_t *peers, *backup; us->peer.init = ngx_http_upstream_init_round_robin_peer; @@ -56,12 +61,16 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, return NGX_ERROR; } - peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t) - + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1)); + peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)); if (peers == NULL) { return NGX_ERROR; } + peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n); + if (peer == NULL) { + return NGX_ERROR; + } + peers->single = (n == 1); peers->number = n; peers->weighted = (w != n); @@ -69,6 +78,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, peers->name = &us->host; n = 0; + peerp = &peers->peer; for (i = 0; i < us->servers->nelts; i++) { if (server[i].backup) { @@ -76,15 +86,19 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, } for (j = 0; j < server[i].naddrs; j++) { - peers->peer[n].sockaddr = server[i].addrs[j].sockaddr; - peers->peer[n].socklen = server[i].addrs[j].socklen; - peers->peer[n].name = server[i].addrs[j].name; - peers->peer[n].weight = server[i].weight; - peers->peer[n].effective_weight = server[i].weight; - peers->peer[n].current_weight = 0; - peers->peer[n].max_fails = server[i].max_fails; - peers->peer[n].fail_timeout = server[i].fail_timeout; - peers->peer[n].down = server[i].down; + peer[n].sockaddr = server[i].addrs[j].sockaddr; + peer[n].socklen = server[i].addrs[j].socklen; + peer[n].name = server[i].addrs[j].name; + peer[n].weight = server[i].weight; + peer[n].effective_weight = server[i].weight; + peer[n].current_weight = 0; + peer[n].max_fails = server[i].max_fails; + peer[n].fail_timeout = server[i].fail_timeout; + peer[n].down = server[i].down; + peer[n].server = server[i].name; + + *peerp = &peer[n]; + peerp = &peer[n].next; n++; } } @@ -109,12 +123,16 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, return NGX_OK; } - backup = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t) - + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1)); + backup = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)); if (backup == NULL) { return NGX_ERROR; } + peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n); + if (peer == NULL) { + return NGX_ERROR; + } + peers->single = 0; backup->single = 0; backup->number = n; @@ -123,6 +141,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, backup->name = &us->host; n = 0; + peerp = &backup->peer; for (i = 0; i < us->servers->nelts; i++) { if (!server[i].backup) { @@ -130,15 +149,19 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, } for (j = 0; j < server[i].naddrs; j++) { - backup->peer[n].sockaddr = server[i].addrs[j].sockaddr; - backup->peer[n].socklen = server[i].addrs[j].socklen; - backup->peer[n].name = server[i].addrs[j].name; - backup->peer[n].weight = server[i].weight; - backup->peer[n].effective_weight = server[i].weight; - backup->peer[n].current_weight = 0; - backup->peer[n].max_fails = server[i].max_fails; - backup->peer[n].fail_timeout = server[i].fail_timeout; - backup->peer[n].down = server[i].down; + peer[n].sockaddr = server[i].addrs[j].sockaddr; + peer[n].socklen = server[i].addrs[j].socklen; + peer[n].name = server[i].addrs[j].name; + peer[n].weight = server[i].weight; + peer[n].effective_weight = server[i].weight; + peer[n].current_weight = 0; + peer[n].max_fails = server[i].max_fails; + peer[n].fail_timeout = server[i].fail_timeout; + peer[n].down = server[i].down; + peer[n].server = server[i].name; + + *peerp = &peer[n]; + peerp = &peer[n].next; n++; } } @@ -175,27 +198,35 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, n = u.naddrs; - peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t) - + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1)); + peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)); if (peers == NULL) { return NGX_ERROR; } + peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n); + if (peer == NULL) { + return NGX_ERROR; + } + peers->single = (n == 1); peers->number = n; peers->weighted = 0; peers->total_weight = n; peers->name = &us->host; + peerp = &peers->peer; + for (i = 0; i < u.naddrs; i++) { - peers->peer[i].sockaddr = u.addrs[i].sockaddr; - peers->peer[i].socklen = u.addrs[i].socklen; - peers->peer[i].name = u.addrs[i].name; - peers->peer[i].weight = 1; - peers->peer[i].effective_weight = 1; - peers->peer[i].current_weight = 0; - peers->peer[i].max_fails = 1; - peers->peer[i].fail_timeout = 10; + peer[i].sockaddr = u.addrs[i].sockaddr; + peer[i].socklen = u.addrs[i].socklen; + peer[i].name = u.addrs[i].name; + peer[i].weight = 1; + peer[i].effective_weight = 1; + peer[i].current_weight = 0; + peer[i].max_fails = 1; + peer[i].fail_timeout = 10; + *peerp = &peer[i]; + peerp = &peer[i].next; } us->peer.data = peers; @@ -225,7 +256,7 @@ ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r, } rrp->peers = us->peer.data; - rrp->current = 0; + rrp->current = NULL; n = rrp->peers->number; @@ -248,7 +279,7 @@ ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r, r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer; r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer; - r->upstream->peer.tries = rrp->peers->number; + r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers); #if (NGX_HTTP_SSL) r->upstream->peer.set_session = ngx_http_upstream_set_round_robin_peer_session; @@ -269,6 +300,7 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, socklen_t socklen; ngx_uint_t i, n; struct sockaddr *sockaddr; + ngx_http_upstream_rr_peer_t *peer, **peerp; ngx_http_upstream_rr_peers_t *peers; ngx_http_upstream_rr_peer_data_t *rrp; @@ -283,27 +315,34 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, r->upstream->peer.data = rrp; } - peers = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peers_t) - + sizeof(ngx_http_upstream_rr_peer_t) * (ur->naddrs - 1)); + peers = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peers_t)); if (peers == NULL) { return NGX_ERROR; } + peer = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peer_t) + * ur->naddrs); + if (peer == NULL) { + return NGX_ERROR; + } + peers->single = (ur->naddrs == 1); peers->number = ur->naddrs; peers->name = &ur->host; if (ur->sockaddr) { - peers->peer[0].sockaddr = ur->sockaddr; - peers->peer[0].socklen = ur->socklen; - peers->peer[0].name = ur->host; - peers->peer[0].weight = 1; - peers->peer[0].effective_weight = 1; - peers->peer[0].current_weight = 0; - peers->peer[0].max_fails = 1; - peers->peer[0].fail_timeout = 10; + peer[0].sockaddr = ur->sockaddr; + peer[0].socklen = ur->socklen; + peer[0].name = ur->host; + peer[0].weight = 1; + peer[0].effective_weight = 1; + peer[0].current_weight = 0; + peer[0].max_fails = 1; + peer[0].fail_timeout = 10; + peers->peer = peer; } else { + peerp = &peers->peer; for (i = 0; i < ur->naddrs; i++) { @@ -333,20 +372,22 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1); - peers->peer[i].sockaddr = sockaddr; - peers->peer[i].socklen = socklen; - peers->peer[i].name.len = len; - peers->peer[i].name.data = p; - peers->peer[i].weight = 1; - peers->peer[i].effective_weight = 1; - peers->peer[i].current_weight = 0; - peers->peer[i].max_fails = 1; - peers->peer[i].fail_timeout = 10; + peer[i].sockaddr = sockaddr; + peer[i].socklen = socklen; + peer[i].name.len = len; + peer[i].name.data = p; + peer[i].weight = 1; + peer[i].effective_weight = 1; + peer[i].current_weight = 0; + peer[i].max_fails = 1; + peer[i].fail_timeout = 10; + *peerp = &peer[i]; + peerp = &peer[i].next; } } rrp->peers = peers; - rrp->current = 0; + rrp->current = NULL; if (rrp->peers->number <= 8 * sizeof(uintptr_t)) { rrp->tried = &rrp->data; @@ -364,7 +405,7 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer; r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer; - r->upstream->peer.tries = rrp->peers->number; + r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers); #if (NGX_HTTP_SSL) r->upstream->peer.set_session = ngx_http_upstream_empty_set_session; r->upstream->peer.save_session = ngx_http_upstream_empty_save_session; @@ -387,18 +428,21 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get rr peer, try: %ui", pc->tries); - /* ngx_lock_mutex(rrp->peers->mutex); */ - pc->cached = 0; pc->connection = NULL; - if (rrp->peers->single) { - peer = &rrp->peers->peer[0]; + peers = rrp->peers; + ngx_http_upstream_rr_peers_wlock(peers); + + if (peers->single) { + peer = peers->peer; if (peer->down) { goto failed; } + rrp->current = peer; + } else { /* there are several peers */ @@ -410,34 +454,27 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "get rr peer, current: %ui %i", - rrp->current, peer->current_weight); + "get rr peer, current: %p %i", + peer, peer->current_weight); } pc->sockaddr = peer->sockaddr; pc->socklen = peer->socklen; pc->name = &peer->name; - /* ngx_unlock_mutex(rrp->peers->mutex); */ + peer->conns++; - if (pc->tries == 1 && rrp->peers->next) { - pc->tries += rrp->peers->next->number; - } + ngx_http_upstream_rr_peers_unlock(peers); return NGX_OK; failed: - peers = rrp->peers; - if (peers->next) { - /* ngx_unlock_mutex(peers->mutex); */ - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "backup servers"); rrp->peers = peers->next; - pc->tries = rrp->peers->number; n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t)); @@ -446,22 +483,24 @@ failed: rrp->tried[i] = 0; } + ngx_http_upstream_rr_peers_unlock(peers); + rc = ngx_http_upstream_get_round_robin_peer(pc, rrp); if (rc != NGX_BUSY) { return rc; } - /* ngx_lock_mutex(peers->mutex); */ + ngx_http_upstream_rr_peers_wlock(peers); } /* all peers failed, mark them as live for quick recovery */ - for (i = 0; i < peers->number; i++) { - peers->peer[i].fails = 0; + for (peer = peers->peer; peer; peer = peer->next) { + peer->fails = 0; } - /* ngx_unlock_mutex(peers->mutex); */ + ngx_http_upstream_rr_peers_unlock(peers); pc->name = peers->name; @@ -475,7 +514,7 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp) time_t now; uintptr_t m; ngx_int_t total; - ngx_uint_t i, n; + ngx_uint_t i, n, p; ngx_http_upstream_rr_peer_t *peer, *best; now = ngx_time(); @@ -483,7 +522,14 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp) best = NULL; total = 0; - for (i = 0; i < rrp->peers->number; i++) { +#if (NGX_SUPPRESS_WARN) + p = 0; +#endif + + for (peer = rrp->peers->peer, i = 0; + peer; + peer = peer->next, i++) + { n = i / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); @@ -492,8 +538,6 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp) continue; } - peer = &rrp->peers->peer[i]; - if (peer->down) { continue; } @@ -514,6 +558,7 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp) if (best == NULL || peer->current_weight > best->current_weight) { best = peer; + p = i; } } @@ -521,12 +566,10 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp) return NULL; } - i = best - &rrp->peers->peer[0]; + rrp->current = best; - rrp->current = i; - - n = i / (8 * sizeof(uintptr_t)); - m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); + n = p / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); rrp->tried[n] |= m; @@ -554,36 +597,46 @@ ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data, /* TODO: NGX_PEER_KEEPALIVE */ + peer = rrp->current; + + ngx_http_upstream_rr_peers_rlock(rrp->peers); + ngx_http_upstream_rr_peer_lock(rrp->peers, peer); + if (rrp->peers->single) { + + peer->conns--; + + ngx_http_upstream_rr_peer_unlock(rrp->peers, peer); + ngx_http_upstream_rr_peers_unlock(rrp->peers); + pc->tries = 0; return; } - peer = &rrp->peers->peer[rrp->current]; - if (state & NGX_PEER_FAILED) { now = ngx_time(); - /* ngx_lock_mutex(rrp->peers->mutex); */ - peer->fails++; peer->accessed = now; peer->checked = now; if (peer->max_fails) { peer->effective_weight -= peer->weight / peer->max_fails; + + if (peer->fails >= peer->max_fails) { + ngx_log_error(NGX_LOG_WARN, pc->log, 0, + "upstream server temporarily disabled"); + } } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "free rr peer failed: %ui %i", - rrp->current, peer->effective_weight); + "free rr peer failed: %p %i", + peer, peer->effective_weight); if (peer->effective_weight < 0) { peer->effective_weight = 0; } - /* ngx_unlock_mutex(rrp->peers->mutex); */ - } else { /* mark peer live if check passed */ @@ -593,11 +646,14 @@ ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data, } } + peer->conns--; + + ngx_http_upstream_rr_peer_unlock(rrp->peers, peer); + ngx_http_upstream_rr_peers_unlock(rrp->peers); + if (pc->tries) { pc->tries--; } - - /* ngx_unlock_mutex(rrp->peers->mutex); */ } @@ -609,24 +665,61 @@ ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc, { ngx_http_upstream_rr_peer_data_t *rrp = data; - ngx_int_t rc; - ngx_ssl_session_t *ssl_session; - ngx_http_upstream_rr_peer_t *peer; + ngx_int_t rc; + ngx_ssl_session_t *ssl_session; + ngx_http_upstream_rr_peer_t *peer; +#if (NGX_HTTP_UPSTREAM_ZONE) + int len; +#if OPENSSL_VERSION_NUMBER >= 0x0090707fL + const +#endif + u_char *p; + ngx_http_upstream_rr_peers_t *peers; + u_char buf[NGX_SSL_MAX_SESSION_SIZE]; +#endif - peer = &rrp->peers->peer[rrp->current]; + peer = rrp->current; - /* TODO: threads only mutex */ - /* ngx_lock_mutex(rrp->peers->mutex); */ +#if (NGX_HTTP_UPSTREAM_ZONE) + peers = rrp->peers; + + if (peers->shpool) { + ngx_http_upstream_rr_peers_rlock(peers); + ngx_http_upstream_rr_peer_lock(peers, peer); + + if (peer->ssl_session == NULL) { + ngx_http_upstream_rr_peer_unlock(peers, peer); + ngx_http_upstream_rr_peers_unlock(peers); + return NGX_OK; + } + + len = peer->ssl_session_len; + + ngx_memcpy(buf, peer->ssl_session, len); + + ngx_http_upstream_rr_peer_unlock(peers, peer); + ngx_http_upstream_rr_peers_unlock(peers); + + p = buf; + ssl_session = d2i_SSL_SESSION(NULL, &p, len); + + rc = ngx_ssl_set_session(pc->connection, ssl_session); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "set session: %p", ssl_session); + + ngx_ssl_free_session(ssl_session); + + return rc; + } +#endif ssl_session = peer->ssl_session; rc = ngx_ssl_set_session(pc->connection, ssl_session); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "set session: %p:%d", - ssl_session, ssl_session ? ssl_session->references : 0); - - /* ngx_unlock_mutex(rrp->peers->mutex); */ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "set session: %p", ssl_session); return rc; } @@ -638,8 +731,75 @@ ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc, { ngx_http_upstream_rr_peer_data_t *rrp = data; - ngx_ssl_session_t *old_ssl_session, *ssl_session; - ngx_http_upstream_rr_peer_t *peer; + ngx_ssl_session_t *old_ssl_session, *ssl_session; + ngx_http_upstream_rr_peer_t *peer; +#if (NGX_HTTP_UPSTREAM_ZONE) + int len; + u_char *p; + ngx_http_upstream_rr_peers_t *peers; + u_char buf[NGX_SSL_MAX_SESSION_SIZE]; +#endif + +#if (NGX_HTTP_UPSTREAM_ZONE) + peers = rrp->peers; + + if (peers->shpool) { + + ssl_session = SSL_get0_session(pc->connection->ssl->connection); + + if (ssl_session == NULL) { + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "save session: %p", ssl_session); + + len = i2d_SSL_SESSION(ssl_session, NULL); + + /* do not cache too big session */ + + if (len > NGX_SSL_MAX_SESSION_SIZE) { + return; + } + + p = buf; + (void) i2d_SSL_SESSION(ssl_session, &p); + + peer = rrp->current; + + ngx_http_upstream_rr_peers_rlock(peers); + ngx_http_upstream_rr_peer_lock(peers, peer); + + if (len > peer->ssl_session_len) { + ngx_shmtx_lock(&peers->shpool->mutex); + + if (peer->ssl_session) { + ngx_slab_free_locked(peers->shpool, peer->ssl_session); + } + + peer->ssl_session = ngx_slab_alloc_locked(peers->shpool, len); + + ngx_shmtx_unlock(&peers->shpool->mutex); + + if (peer->ssl_session == NULL) { + peer->ssl_session_len = 0; + + ngx_http_upstream_rr_peer_unlock(peers, peer); + ngx_http_upstream_rr_peers_unlock(peers); + return; + } + + peer->ssl_session_len = len; + } + + ngx_memcpy(peer->ssl_session, buf, len); + + ngx_http_upstream_rr_peer_unlock(peers, peer); + ngx_http_upstream_rr_peers_unlock(peers); + + return; + } +#endif ssl_session = ngx_ssl_get_session(pc->connection); @@ -647,24 +807,18 @@ ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc, return; } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "save session: %p:%d", ssl_session, ssl_session->references); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "save session: %p", ssl_session); - peer = &rrp->peers->peer[rrp->current]; - - /* TODO: threads only mutex */ - /* ngx_lock_mutex(rrp->peers->mutex); */ + peer = rrp->current; old_ssl_session = peer->ssl_session; peer->ssl_session = ssl_session; - /* ngx_unlock_mutex(rrp->peers->mutex); */ - if (old_ssl_session) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "old session: %p:%d", - old_ssl_session, old_ssl_session->references); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "old session: %p", old_ssl_session); /* TODO: may block */ diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h index ea90ab9..454515c 100644 --- a/src/http/ngx_http_upstream_round_robin.h +++ b/src/http/ngx_http_upstream_round_robin.h @@ -14,15 +14,20 @@ #include -typedef struct { +typedef struct ngx_http_upstream_rr_peer_s ngx_http_upstream_rr_peer_t; + +struct ngx_http_upstream_rr_peer_s { struct sockaddr *sockaddr; socklen_t socklen; ngx_str_t name; + ngx_str_t server; ngx_int_t current_weight; ngx_int_t effective_weight; ngx_int_t weight; + ngx_uint_t conns; + ngx_uint_t fails; time_t accessed; time_t checked; @@ -33,9 +38,16 @@ typedef struct { ngx_uint_t down; /* unsigned down:1; */ #if (NGX_HTTP_SSL) - ngx_ssl_session_t *ssl_session; /* local to a process */ + void *ssl_session; + int ssl_session_len; #endif -} ngx_http_upstream_rr_peer_t; + + ngx_http_upstream_rr_peer_t *next; + +#if (NGX_HTTP_UPSTREAM_ZONE) + ngx_atomic_t lock; +#endif +}; typedef struct ngx_http_upstream_rr_peers_s ngx_http_upstream_rr_peers_t; @@ -43,7 +55,10 @@ typedef struct ngx_http_upstream_rr_peers_s ngx_http_upstream_rr_peers_t; struct ngx_http_upstream_rr_peers_s { ngx_uint_t number; - /* ngx_mutex_t *mutex; */ +#if (NGX_HTTP_UPSTREAM_ZONE) + ngx_slab_pool_t *shpool; + ngx_atomic_t rwlock; +#endif ngx_uint_t total_weight; @@ -54,13 +69,57 @@ struct ngx_http_upstream_rr_peers_s { ngx_http_upstream_rr_peers_t *next; - ngx_http_upstream_rr_peer_t peer[1]; + ngx_http_upstream_rr_peer_t *peer; }; +#if (NGX_HTTP_UPSTREAM_ZONE) + +#define ngx_http_upstream_rr_peers_rlock(peers) \ + \ + if (peers->shpool) { \ + ngx_rwlock_rlock(&peers->rwlock); \ + } + +#define ngx_http_upstream_rr_peers_wlock(peers) \ + \ + if (peers->shpool) { \ + ngx_rwlock_wlock(&peers->rwlock); \ + } + +#define ngx_http_upstream_rr_peers_unlock(peers) \ + \ + if (peers->shpool) { \ + ngx_rwlock_unlock(&peers->rwlock); \ + } + + +#define ngx_http_upstream_rr_peer_lock(peers, peer) \ + \ + if (peers->shpool) { \ + ngx_rwlock_wlock(&peer->lock); \ + } + +#define ngx_http_upstream_rr_peer_unlock(peers, peer) \ + \ + if (peers->shpool) { \ + ngx_rwlock_unlock(&peer->lock); \ + } + +#else + +#define ngx_http_upstream_rr_peers_rlock(peers) +#define ngx_http_upstream_rr_peers_wlock(peers) +#define ngx_http_upstream_rr_peers_unlock(peers) +#define ngx_http_upstream_rr_peer_lock(peers, peer) +#define ngx_http_upstream_rr_peer_unlock(peers, peer) + +#endif + + typedef struct { ngx_http_upstream_rr_peers_t *peers; - ngx_uint_t current; + ngx_http_upstream_rr_peer_t *current; uintptr_t *tried; uintptr_t data; } ngx_http_upstream_rr_peer_data_t; diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index f618622..c65de35 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -13,8 +13,10 @@ static ngx_int_t ngx_http_variable_request(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +#if 0 static void ngx_http_variable_request_set(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +#endif static ngx_int_t ngx_http_variable_request_get_size(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static void ngx_http_variable_request_set_size(ngx_http_request_t *r, @@ -64,6 +66,8 @@ 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 void ngx_http_variable_set_args(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, @@ -223,7 +227,7 @@ static ngx_http_variable_t ngx_http_core_variables[] = { NGX_HTTP_VAR_NOCACHEABLE, 0 }, { ngx_string("args"), - ngx_http_variable_request_set, + ngx_http_variable_set_args, ngx_http_variable_request, offsetof(ngx_http_request_t, args), NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, @@ -613,6 +617,17 @@ ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key) return NULL; } + if (ngx_strncmp(name->data, "upstream_cookie_", 16) == 0) { + + if (ngx_http_upstream_cookie_variable(r, vv, (uintptr_t) name) + == NGX_OK) + { + return vv; + } + + return NULL; + } + if (ngx_strncmp(name->data, "arg_", 4) == 0) { if (ngx_http_variable_argument(r, vv, (uintptr_t) name) == NGX_OK) { @@ -651,6 +666,8 @@ ngx_http_variable_request(ngx_http_request_t *r, ngx_http_variable_value_t *v, } +#if 0 + static void ngx_http_variable_request_set(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) @@ -663,6 +680,8 @@ ngx_http_variable_request_set(ngx_http_request_t *r, s->data = v->data; } +#endif + static ngx_int_t ngx_http_variable_request_get_size(ngx_http_request_t *r, @@ -1062,6 +1081,10 @@ ngx_http_variable_content_length(ngx_http_request_t *r, v->no_cacheable = 0; v->not_found = 0; + } else if (r->reading_body) { + v->not_found = 1; + v->no_cacheable = 1; + } else if (r->headers_in.content_length_n >= 0) { p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN); if (p == NULL) { @@ -1360,6 +1383,16 @@ ngx_http_variable_https(ngx_http_request_t *r, } +static void +ngx_http_variable_set_args(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + r->args.len = v->len; + r->args.data = v->data; + r->valid_unparsed_uri = 0; +} + + static ngx_int_t ngx_http_variable_is_args(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) @@ -2482,8 +2515,7 @@ ngx_http_variables_init_vars(ngx_conf_t *cf) av = key[n].value; - if (av->get_handler - && v[i].name.len == key[n].key.len + if (v[i].name.len == key[n].key.len && ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len) == 0) { @@ -2495,6 +2527,10 @@ ngx_http_variables_init_vars(ngx_conf_t *cf) av->index = i; + if (av->get_handler == NULL) { + break; + } + goto next; } } @@ -2528,6 +2564,14 @@ ngx_http_variables_init_vars(ngx_conf_t *cf) continue; } + if (ngx_strncmp(v[i].name.data, "upstream_cookie_", 16) == 0) { + v[i].get_handler = ngx_http_upstream_cookie_variable; + v[i].data = (uintptr_t) &v[i].name; + v[i].flags = NGX_HTTP_VAR_NOCACHEABLE; + + continue; + } + if (ngx_strncmp(v[i].name.data, "arg_", 4) == 0) { v[i].get_handler = ngx_http_variable_argument; v[i].data = (uintptr_t) &v[i].name; diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c index 83cb1fa..c164440 100644 --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -48,7 +48,7 @@ ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) { off_t size, sent, nsent, limit; - ngx_uint_t last, flush; + ngx_uint_t last, flush, sync; ngx_msec_t delay; ngx_chain_t *cl, *ln, **ll, *chain; ngx_connection_t *c; @@ -62,6 +62,7 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) size = 0; flush = 0; + sync = 0; last = 0; ll = &r->out; @@ -72,7 +73,7 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0, "write old buf t:%d f:%d %p, pos %p, size: %z " - "file: %O, size: %z", + "file: %O, size: %O", cl->buf->temporary, cl->buf->in_file, cl->buf->start, cl->buf->pos, cl->buf->last - cl->buf->pos, @@ -105,6 +106,10 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) flush = 1; } + if (cl->buf->sync) { + sync = 1; + } + if (cl->buf->last_buf) { last = 1; } @@ -124,7 +129,7 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0, "write new buf t:%d f:%d %p, pos %p, size: %z " - "file: %O, size: %z", + "file: %O, size: %O", cl->buf->temporary, cl->buf->in_file, cl->buf->start, cl->buf->pos, cl->buf->last - cl->buf->pos, @@ -157,6 +162,10 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) flush = 1; } + if (cl->buf->sync) { + sync = 1; + } + if (cl->buf->last_buf) { last = 1; } @@ -188,7 +197,7 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) && !(c->buffered & NGX_LOWLEVEL_BUFFERED) && !(last && c->need_last_buf)) { - if (last || flush) { + if (last || flush || sync) { for (cl = r->out; cl; /* void */) { ln = cl; cl = cl->next; @@ -219,8 +228,8 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) if (limit <= 0) { c->write->delayed = 1; - ngx_add_timer(c->write, - (ngx_msec_t) (- limit * 1000 / r->limit_rate + 1)); + delay = (ngx_msec_t) (- limit * 1000 / r->limit_rate + 1); + ngx_add_timer(c->write, delay); c->buffered |= NGX_HTTP_WRITE_BUFFERED; diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c index 350d2cd..f10f08c 100644 --- a/src/mail/ngx_mail.c +++ b/src/mail/ngx_mail.c @@ -36,13 +36,6 @@ static ngx_command_t ngx_mail_commands[] = { 0, NULL }, - { ngx_string("imap"), - NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, - ngx_mail_block, - 0, - 0, - NULL }, - ngx_null_command }; @@ -83,12 +76,6 @@ ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_mail_core_srv_conf_t **cscfp; ngx_mail_core_main_conf_t *cmcf; - if (cmd->name.data[0] == 'i') { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "the \"imap\" directive is deprecated, " - "use the \"mail\" directive instead"); - } - /* the main mail context */ ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t)); @@ -98,7 +85,7 @@ ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) *(ngx_mail_conf_ctx_t **) conf = ctx; - /* count the number of the http modules and set up their indices */ + /* count the number of the mail modules and set up their indices */ ngx_mail_max_module = 0; for (m = 0; ngx_modules[m]; m++) { @@ -131,8 +118,7 @@ ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) /* - * create the main_conf's, the null srv_conf's, and the null loc_conf's - * of the all mail modules + * create the main_conf's and the null srv_conf's of the all mail modules */ for (m = 0; ngx_modules[m]; m++) { @@ -335,11 +321,12 @@ found: static char * ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) { - ngx_uint_t i, p, last, bind_wildcard; - ngx_listening_t *ls; - ngx_mail_port_t *mport; - ngx_mail_conf_port_t *port; - ngx_mail_conf_addr_t *addr; + ngx_uint_t i, p, last, bind_wildcard; + ngx_listening_t *ls; + ngx_mail_port_t *mport; + ngx_mail_conf_port_t *port; + ngx_mail_conf_addr_t *addr; + ngx_mail_core_srv_conf_t *cscf; port = ports->elts; for (p = 0; p < ports->nelts; p++) { @@ -381,8 +368,9 @@ ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) ls->handler = ngx_mail_init_connection; ls->pool_size = 256; - /* TODO: error_log directive */ - ls->logp = &cf->cycle->new_log; + cscf = addr->ctx->srv_conf[ngx_mail_core_module.ctx_index]; + + ls->logp = cscf->error_log; ls->log.data = &ls->addr_text; ls->log.handler = ngx_accept_log_error; @@ -404,13 +392,7 @@ ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) ls->servers = mport; - if (i == last - 1) { - mport->naddrs = last; - - } else { - mport->naddrs = 1; - i = 0; - } + mport->naddrs = i + 1; switch (ls->sockaddr->sa_family) { #if (NGX_HAVE_INET6) diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index dc39f1e..dd8a23a 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -131,14 +131,13 @@ typedef struct { ngx_msec_t timeout; ngx_msec_t resolver_timeout; - ngx_flag_t so_keepalive; - ngx_str_t server_name; u_char *file_name; ngx_int_t line; ngx_resolver_t *resolver; + ngx_log_t *error_log; /* server ctx */ ngx_mail_conf_ctx_t *ctx; @@ -336,6 +335,8 @@ struct ngx_mail_protocol_s { ngx_mail_auth_state_pt auth_state; ngx_str_t internal_server_error; + ngx_str_t cert_error; + ngx_str_t no_cert; }; diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c index 8094bbc..d93e946 100644 --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -16,6 +16,7 @@ typedef struct { ngx_addr_t *peer; ngx_msec_t timeout; + ngx_flag_t pass_client_cert; ngx_str_t host_header; ngx_str_t uri; @@ -106,6 +107,13 @@ static ngx_command_t ngx_mail_auth_http_commands[] = { 0, NULL }, + { ngx_string("auth_http_pass_client_cert"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_auth_http_conf_t, pass_client_cert), + NULL }, + ngx_null_command }; @@ -1143,6 +1151,12 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, size_t len; ngx_buf_t *b; ngx_str_t login, passwd; +#if (NGX_MAIL_SSL) + ngx_str_t verify, subject, issuer, serial, fingerprint, + raw_cert, cert; + ngx_connection_t *c; + ngx_mail_ssl_conf_t *sslcf; +#endif ngx_mail_core_srv_conf_t *cscf; if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) { @@ -1153,6 +1167,62 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, return NULL; } +#if (NGX_MAIL_SSL) + + c = s->connection; + sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); + + if (c->ssl && sslcf->verify) { + + /* certificate details */ + + if (ngx_ssl_get_client_verify(c, pool, &verify) != NGX_OK) { + return NULL; + } + + if (ngx_ssl_get_subject_dn(c, pool, &subject) != NGX_OK) { + return NULL; + } + + if (ngx_ssl_get_issuer_dn(c, pool, &issuer) != NGX_OK) { + return NULL; + } + + if (ngx_ssl_get_serial_number(c, pool, &serial) != NGX_OK) { + return NULL; + } + + if (ngx_ssl_get_fingerprint(c, pool, &fingerprint) != NGX_OK) { + return NULL; + } + + if (ahcf->pass_client_cert) { + + /* certificate itself, if configured */ + + if (ngx_ssl_get_raw_certificate(c, pool, &raw_cert) != NGX_OK) { + return NULL; + } + + if (ngx_mail_auth_http_escape(pool, &raw_cert, &cert) != NGX_OK) { + return NULL; + } + + } else { + ngx_str_null(&cert); + } + + } else { + ngx_str_null(&verify); + ngx_str_null(&subject); + ngx_str_null(&issuer); + ngx_str_null(&serial); + ngx_str_null(&fingerprint); + ngx_str_null(&cert); + } + +#endif + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1 @@ -1170,9 +1240,19 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, + sizeof("Client-IP: ") - 1 + s->connection->addr_text.len + sizeof(CRLF) - 1 + sizeof("Client-Host: ") - 1 + s->host.len + sizeof(CRLF) - 1 - + sizeof("Auth-SMTP-Helo: ") - 1 + s->smtp_helo.len - + sizeof("Auth-SMTP-From: ") - 1 + s->smtp_from.len - + sizeof("Auth-SMTP-To: ") - 1 + s->smtp_to.len + + sizeof("Auth-SMTP-Helo: ") - 1 + s->smtp_helo.len + sizeof(CRLF) - 1 + + sizeof("Auth-SMTP-From: ") - 1 + s->smtp_from.len + sizeof(CRLF) - 1 + + sizeof("Auth-SMTP-To: ") - 1 + s->smtp_to.len + sizeof(CRLF) - 1 +#if (NGX_MAIL_SSL) + + sizeof("Auth-SSL: on" CRLF) - 1 + + sizeof("Auth-SSL-Verify: ") - 1 + verify.len + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Subject: ") - 1 + subject.len + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Issuer: ") - 1 + issuer.len + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Serial: ") - 1 + serial.len + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Fingerprint: ") - 1 + fingerprint.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Cert: ") - 1 + cert.len + sizeof(CRLF) - 1 +#endif + ahcf->header.len + sizeof(CRLF) - 1; @@ -1255,6 +1335,57 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, } +#if (NGX_MAIL_SSL) + + if (c->ssl) { + b->last = ngx_cpymem(b->last, "Auth-SSL: on" CRLF, + sizeof("Auth-SSL: on" CRLF) - 1); + + if (verify.len) { + b->last = ngx_cpymem(b->last, "Auth-SSL-Verify: ", + sizeof("Auth-SSL-Verify: ") - 1); + b->last = ngx_copy(b->last, verify.data, verify.len); + *b->last++ = CR; *b->last++ = LF; + } + + if (subject.len) { + b->last = ngx_cpymem(b->last, "Auth-SSL-Subject: ", + sizeof("Auth-SSL-Subject: ") - 1); + b->last = ngx_copy(b->last, subject.data, subject.len); + *b->last++ = CR; *b->last++ = LF; + } + + if (issuer.len) { + b->last = ngx_cpymem(b->last, "Auth-SSL-Issuer: ", + sizeof("Auth-SSL-Issuer: ") - 1); + b->last = ngx_copy(b->last, issuer.data, issuer.len); + *b->last++ = CR; *b->last++ = LF; + } + + if (serial.len) { + b->last = ngx_cpymem(b->last, "Auth-SSL-Serial: ", + sizeof("Auth-SSL-Serial: ") - 1); + b->last = ngx_copy(b->last, serial.data, serial.len); + *b->last++ = CR; *b->last++ = LF; + } + + if (fingerprint.len) { + b->last = ngx_cpymem(b->last, "Auth-SSL-Fingerprint: ", + sizeof("Auth-SSL-Fingerprint: ") - 1); + b->last = ngx_copy(b->last, fingerprint.data, fingerprint.len); + *b->last++ = CR; *b->last++ = LF; + } + + if (cert.len) { + b->last = ngx_cpymem(b->last, "Auth-SSL-Cert: ", + sizeof("Auth-SSL-Cert: ") - 1); + b->last = ngx_copy(b->last, cert.data, cert.len); + *b->last++ = CR; *b->last++ = LF; + } + } + +#endif + if (ahcf->header.len) { b->last = ngx_copy(b->last, ahcf->header.data, ahcf->header.len); } @@ -1263,14 +1394,9 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, *b->last++ = CR; *b->last++ = LF; #if (NGX_DEBUG_MAIL_PASSWD) - { - ngx_str_t l; - - l.len = b->last - b->pos; - l.data = b->pos; - ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, - "mail auth http header:\n\"%V\"", &l); - } + ngx_log_debug2(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, + "mail auth http header:%N\"%*s\"", + (size_t) (b->last - b->pos), b->pos); #endif return b; @@ -1316,6 +1442,7 @@ ngx_mail_auth_http_create_conf(ngx_conf_t *cf) } ahcf->timeout = NGX_CONF_UNSET_MSEC; + ahcf->pass_client_cert = NGX_CONF_UNSET; ahcf->file = cf->conf_file->file.name.data; ahcf->line = cf->conf_file->line; @@ -1351,6 +1478,8 @@ ngx_mail_auth_http_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000); + ngx_conf_merge_value(conf->pass_client_cert, prev->pass_client_cert, 0); + if (conf->headers == NULL) { conf->headers = prev->headers; conf->header = prev->header; diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index 4ee7c8d..ab455b8 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -21,16 +21,12 @@ static char *ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_mail_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); 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"), @@ -41,7 +37,7 @@ static ngx_command_t ngx_mail_core_commands[] = { NULL }, { ngx_string("listen"), - NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12, + NGX_MAIL_SRV_CONF|NGX_CONF_1MORE, ngx_mail_core_listen, NGX_MAIL_SRV_CONF_OFFSET, 0, @@ -54,13 +50,6 @@ static ngx_command_t ngx_mail_core_commands[] = { 0, NULL }, - { ngx_string("so_keepalive"), - NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_MAIL_SRV_CONF_OFFSET, - offsetof(ngx_mail_core_srv_conf_t, so_keepalive), - &ngx_conf_deprecated_so_keepalive }, - { ngx_string("timeout"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -75,6 +64,13 @@ static ngx_command_t ngx_mail_core_commands[] = { offsetof(ngx_mail_core_srv_conf_t, server_name), NULL }, + { ngx_string("error_log"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE, + ngx_mail_core_error_log, + NGX_MAIL_SRV_CONF_OFFSET, + 0, + NULL }, + { ngx_string("resolver"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE, ngx_mail_core_resolver, @@ -161,11 +157,11 @@ ngx_mail_core_create_srv_conf(ngx_conf_t *cf) * set by ngx_pcalloc(): * * cscf->protocol = NULL; + * cscf->error_log = NULL; */ cscf->timeout = NGX_CONF_UNSET_MSEC; cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; - cscf->so_keepalive = NGX_CONF_UNSET; cscf->resolver = NGX_CONF_UNSET_PTR; @@ -186,8 +182,6 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout, 30000); - ngx_conf_merge_value(conf->so_keepalive, prev->so_keepalive, 0); - ngx_conf_merge_str_value(conf->server_name, prev->server_name, ""); @@ -202,6 +196,14 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } + if (conf->error_log == NULL) { + if (prev->error_log) { + conf->error_log = prev->error_log; + } else { + conf->error_log = &cf->cycle->new_log; + } + } + ngx_conf_merge_ptr_value(conf->resolver, prev->resolver, NULL); return NGX_CONF_OK; @@ -336,7 +338,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) off = offsetof(struct sockaddr_in6, sin6_addr); len = 16; sin6 = (struct sockaddr_in6 *) sa; - port = sin6->sin6_port; + port = ntohs(sin6->sin6_port); break; #endif @@ -352,7 +354,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) off = offsetof(struct sockaddr_in, sin_addr); len = 4; sin = (struct sockaddr_in *) sa; - port = sin->sin_port; + port = ntohs(sin->sin_port); break; } @@ -600,6 +602,15 @@ ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +static char * +ngx_mail_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_mail_core_srv_conf_t *cscf = conf; + + return ngx_log_set_log(cf, &cscf->error_log); +} + + static char * ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index 47ddb0d..901bb8f 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -16,23 +16,28 @@ static void ngx_mail_init_session(ngx_connection_t *c); #if (NGX_MAIL_SSL) static void ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c); static void ngx_mail_ssl_handshake_handler(ngx_connection_t *c); +static ngx_int_t ngx_mail_verify_cert(ngx_mail_session_t *s, + ngx_connection_t *c); #endif void ngx_mail_init_connection(ngx_connection_t *c) { - ngx_uint_t i; - ngx_mail_port_t *port; - struct sockaddr *sa; - struct sockaddr_in *sin; - ngx_mail_log_ctx_t *ctx; - ngx_mail_in_addr_t *addr; - ngx_mail_session_t *s; - ngx_mail_addr_conf_t *addr_conf; + size_t len; + ngx_uint_t i; + ngx_mail_port_t *port; + struct sockaddr *sa; + struct sockaddr_in *sin; + ngx_mail_log_ctx_t *ctx; + ngx_mail_in_addr_t *addr; + ngx_mail_session_t *s; + ngx_mail_addr_conf_t *addr_conf; + ngx_mail_core_srv_conf_t *cscf; + u_char text[NGX_SOCKADDR_STRLEN]; #if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; - ngx_mail_in6_addr_t *addr6; + struct sockaddr_in6 *sin6; + ngx_mail_in6_addr_t *addr6; #endif @@ -119,6 +124,8 @@ ngx_mail_init_connection(ngx_connection_t *c) return; } + s->signature = NGX_MAIL_MODULE; + s->main_conf = addr_conf->ctx->main_conf; s->srv_conf = addr_conf->ctx->srv_conf; @@ -127,8 +134,14 @@ ngx_mail_init_connection(ngx_connection_t *c) c->data = s; s->connection = c; - ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %V connected to %V", - c->number, &c->addr_text, s->addr_text); + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + + ngx_set_connection_log(c, cscf->error_log); + + len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1); + + ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %*s connected to %V", + c->number, len, text, s->addr_text); ctx = ngx_palloc(c->pool, sizeof(ngx_mail_log_ctx_t)); if (ctx == NULL) { @@ -241,6 +254,10 @@ ngx_mail_ssl_handshake_handler(ngx_connection_t *c) s = c->data; + if (ngx_mail_verify_cert(s, c) != NGX_OK) { + return; + } + if (s->starttls) { cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); @@ -261,6 +278,71 @@ ngx_mail_ssl_handshake_handler(ngx_connection_t *c) ngx_mail_close_connection(c); } + +static ngx_int_t +ngx_mail_verify_cert(ngx_mail_session_t *s, ngx_connection_t *c) +{ + long rc; + X509 *cert; + ngx_mail_ssl_conf_t *sslcf; + ngx_mail_core_srv_conf_t *cscf; + + sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); + + if (!sslcf->verify) { + return NGX_OK; + } + + rc = SSL_get_verify_result(c->ssl->connection); + + if (rc != X509_V_OK + && (sslcf->verify != 3 || !ngx_ssl_verify_error_optional(rc))) + { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client SSL certificate verify error: (%l:%s)", + rc, X509_verify_cert_error_string(rc)); + + ngx_ssl_remove_cached_session(sslcf->ssl.ctx, + (SSL_get0_session(c->ssl->connection))); + + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + + s->out = cscf->protocol->cert_error; + s->quit = 1; + + c->write->handler = ngx_mail_send; + + ngx_mail_send(s->connection->write); + return NGX_ERROR; + } + + if (sslcf->verify == 1) { + cert = SSL_get_peer_certificate(c->ssl->connection); + + if (cert == NULL) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent no required SSL certificate"); + + ngx_ssl_remove_cached_session(sslcf->ssl.ctx, + (SSL_get0_session(c->ssl->connection))); + + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + + s->out = cscf->protocol->no_cert; + s->quit = 1; + + c->write->handler = ngx_mail_send; + + ngx_mail_send(s->connection->write); + return NGX_ERROR; + } + + X509_free(cert); + } + + return NGX_OK; +} + #endif diff --git a/src/mail/ngx_mail_imap_module.c b/src/mail/ngx_mail_imap_module.c index dc80b4f..d281070 100644 --- a/src/mail/ngx_mail_imap_module.c +++ b/src/mail/ngx_mail_imap_module.c @@ -52,7 +52,9 @@ static ngx_mail_protocol_t ngx_mail_imap_protocol = { ngx_mail_imap_parse_command, ngx_mail_imap_auth_state, - ngx_string("* BAD internal server error" CRLF) + ngx_string("* BAD internal server error" CRLF), + ngx_string("* BYE SSL certificate error" CRLF), + ngx_string("* BYE No required SSL certificate" CRLF) }; diff --git a/src/mail/ngx_mail_pop3_module.c b/src/mail/ngx_mail_pop3_module.c index b597472..73f8531 100644 --- a/src/mail/ngx_mail_pop3_module.c +++ b/src/mail/ngx_mail_pop3_module.c @@ -58,7 +58,9 @@ static ngx_mail_protocol_t ngx_mail_pop3_protocol = { ngx_mail_pop3_parse_command, ngx_mail_pop3_auth_state, - ngx_string("-ERR internal server error" CRLF) + ngx_string("-ERR internal server error" CRLF), + ngx_string("-ERR SSL certificate error" CRLF), + ngx_string("-ERR No required SSL certificate" CRLF) }; diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c index 41cbcf6..3802c3e 100644 --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -111,7 +111,6 @@ static u_char smtp_auth_ok[] = "235 2.0.0 OK" CRLF; void ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer) { - int keepalive; ngx_int_t rc; ngx_mail_proxy_ctx_t *p; ngx_mail_proxy_conf_t *pcf; @@ -121,18 +120,6 @@ ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer) cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); - if (cscf->so_keepalive) { - keepalive = 1; - - if (setsockopt(s->connection->fd, SOL_SOCKET, SO_KEEPALIVE, - (const void *) &keepalive, sizeof(int)) - == -1) - { - ngx_log_error(NGX_LOG_ALERT, s->connection->log, ngx_socket_errno, - "setsockopt(SO_KEEPALIVE) failed"); - } - } - p = ngx_pcalloc(s->connection->pool, sizeof(ngx_mail_proxy_ctx_t)); if (p == NULL) { ngx_mail_session_internal_server_error(s); diff --git a/src/mail/ngx_mail_smtp_module.c b/src/mail/ngx_mail_smtp_module.c index 02bbf1f..d5bb51c 100644 --- a/src/mail/ngx_mail_smtp_module.c +++ b/src/mail/ngx_mail_smtp_module.c @@ -45,7 +45,9 @@ static ngx_mail_protocol_t ngx_mail_smtp_protocol = { ngx_mail_smtp_parse_command, ngx_mail_smtp_auth_state, - ngx_string("451 4.3.2 Internal server error" CRLF) + ngx_string("451 4.3.2 Internal server error" CRLF), + ngx_string("421 4.7.1 SSL certificate error" CRLF), + ngx_string("421 4.7.1 No required SSL certificate" CRLF) }; diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c index fe88f48..1075410 100644 --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -21,6 +21,8 @@ static char *ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_mail_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -44,6 +46,15 @@ static ngx_conf_bitmask_t ngx_mail_ssl_protocols[] = { }; +static ngx_conf_enum_t ngx_mail_ssl_verify[] = { + { ngx_string("off"), 0 }, + { ngx_string("on"), 1 }, + { ngx_string("optional"), 2 }, + { ngx_string("optional_no_ca"), 3 }, + { ngx_null_string, 0 } +}; + + static ngx_command_t ngx_mail_ssl_commands[] = { { ngx_string("ssl"), @@ -74,6 +85,13 @@ static ngx_command_t ngx_mail_ssl_commands[] = { offsetof(ngx_mail_ssl_conf_t, certificate_key), NULL }, + { ngx_string("ssl_password_file"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_mail_ssl_password_file, + NGX_MAIL_SRV_CONF_OFFSET, + 0, + NULL }, + { ngx_string("ssl_dhparam"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, @@ -137,6 +155,41 @@ static ngx_command_t ngx_mail_ssl_commands[] = { offsetof(ngx_mail_ssl_conf_t, session_timeout), NULL }, + { ngx_string("ssl_verify_client"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_ssl_conf_t, verify), + &ngx_mail_ssl_verify }, + + { ngx_string("ssl_verify_depth"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_ssl_conf_t, verify_depth), + NULL }, + + { ngx_string("ssl_client_certificate"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_ssl_conf_t, client_certificate), + NULL }, + + { ngx_string("ssl_trusted_certificate"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_ssl_conf_t, trusted_certificate), + NULL }, + + { ngx_string("ssl_crl"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_ssl_conf_t, crl), + NULL }, + ngx_null_command }; @@ -189,13 +242,19 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf) * scf->certificate_key = { 0, NULL }; * scf->dhparam = { 0, NULL }; * scf->ecdh_curve = { 0, NULL }; + * scf->client_certificate = { 0, NULL }; + * scf->trusted_certificate = { 0, NULL }; + * scf->crl = { 0, NULL }; * scf->ciphers = { 0, NULL }; * scf->shm_zone = NULL; */ scf->enable = NGX_CONF_UNSET; scf->starttls = NGX_CONF_UNSET_UINT; + scf->passwords = NGX_CONF_UNSET_PTR; scf->prefer_server_ciphers = NGX_CONF_UNSET; + scf->verify = NGX_CONF_UNSET_UINT; + scf->verify_depth = NGX_CONF_UNSET_UINT; scf->builtin_session_cache = NGX_CONF_UNSET; scf->session_timeout = NGX_CONF_UNSET; scf->session_tickets = NGX_CONF_UNSET; @@ -225,17 +284,28 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) prev->prefer_server_ciphers, 0); ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3|NGX_SSL_TLSv1 + (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + ngx_conf_merge_uint_value(conf->verify, prev->verify, 0); + ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1); + ngx_conf_merge_str_value(conf->certificate, prev->certificate, ""); ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, ""); + ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL); + ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve, NGX_DEFAULT_ECDH_CURVE); + ngx_conf_merge_str_value(conf->client_certificate, + prev->client_certificate, ""); + ngx_conf_merge_str_value(conf->trusted_certificate, + prev->trusted_certificate, ""); + ngx_conf_merge_str_value(conf->crl, prev->crl, ""); + ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); @@ -302,12 +372,41 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) cln->data = &conf->ssl; if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate, - &conf->certificate_key) + &conf->certificate_key, conf->passwords) != NGX_OK) { return NGX_CONF_ERROR; } + if (conf->verify) { + + if (conf->client_certificate.len == 0 && conf->verify != 3) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no ssl_client_certificate for ssl_client_verify"); + return NGX_CONF_ERROR; + } + + if (ngx_ssl_client_certificate(cf, &conf->ssl, + &conf->client_certificate, + conf->verify_depth) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + if (ngx_ssl_trusted_certificate(cf, &conf->ssl, + &conf->trusted_certificate, + conf->verify_depth) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + if (ngx_ssl_crl(cf, &conf->ssl, &conf->crl) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + if (SSL_CTX_set_cipher_list(conf->ssl.ctx, (const char *) conf->ciphers.data) == 0) @@ -322,7 +421,9 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } +#ifndef LIBRESSL_VERSION_NUMBER SSL_CTX_set_tmp_rsa_callback(conf->ssl.ctx, ngx_ssl_rsa512_key_callback); +#endif if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { return NGX_CONF_ERROR; @@ -421,6 +522,29 @@ ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +static char * +ngx_mail_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_mail_ssl_conf_t *scf = conf; + + ngx_str_t *value; + + if (scf->passwords != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + scf->passwords = ngx_ssl_read_password_file(cf, &value[1]); + + if (scf->passwords == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + static char * ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/mail/ngx_mail_ssl_module.h b/src/mail/ngx_mail_ssl_module.h index bef0e51..296a6a2 100644 --- a/src/mail/ngx_mail_ssl_module.h +++ b/src/mail/ngx_mail_ssl_module.h @@ -28,6 +28,9 @@ typedef struct { ngx_uint_t starttls; ngx_uint_t protocols; + ngx_uint_t verify; + ngx_uint_t verify_depth; + ssize_t builtin_session_cache; time_t session_timeout; @@ -36,9 +39,14 @@ typedef struct { ngx_str_t certificate_key; ngx_str_t dhparam; ngx_str_t ecdh_curve; + ngx_str_t client_certificate; + ngx_str_t trusted_certificate; + ngx_str_t crl; ngx_str_t ciphers; + ngx_array_t *passwords; + ngx_shm_zone_t *shm_zone; ngx_flag_t session_tickets; diff --git a/src/misc/ngx_cpp_test_module.cpp b/src/misc/ngx_cpp_test_module.cpp index 3cbc0a8..5d2f08d 100644 --- a/src/misc/ngx_cpp_test_module.cpp +++ b/src/misc/ngx_cpp_test_module.cpp @@ -1,5 +1,5 @@ -// stub module to test header files' C++ compatibilty +// stub module to test header files' C++ compatibility extern "C" { #include diff --git a/src/os/unix/ngx_aio_read.c b/src/os/unix/ngx_aio_read.c deleted file mode 100644 index 7849881..0000000 --- a/src/os/unix/ngx_aio_read.c +++ /dev/null @@ -1,109 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - */ - - -#include -#include -#include - - -extern int ngx_kqueue; - - -ssize_t -ngx_aio_read(ngx_connection_t *c, u_char *buf, size_t size) -{ - int n; - ngx_event_t *rev; - - rev = c->read; - - if (!rev->ready) { - ngx_log_error(NGX_LOG_ALERT, c->log, 0, "second aio post"); - return NGX_AGAIN; - } - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "rev->complete: %d", rev->complete); - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "aio size: %d", size); - - if (!rev->complete) { - ngx_memzero(&rev->aiocb, sizeof(struct aiocb)); - - rev->aiocb.aio_fildes = c->fd; - rev->aiocb.aio_buf = buf; - rev->aiocb.aio_nbytes = size; - -#if (NGX_HAVE_KQUEUE) - rev->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue; - rev->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT; - rev->aiocb.aio_sigevent.sigev_value.sigval_ptr = rev; -#endif - - if (aio_read(&rev->aiocb) == -1) { - ngx_log_error(NGX_LOG_CRIT, rev->log, ngx_errno, - "aio_read() failed"); - rev->error = 1; - return NGX_ERROR; - } - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "aio_read: #%d OK", c->fd); - - rev->active = 1; - rev->ready = 0; - } - - rev->complete = 0; - - n = aio_error(&rev->aiocb); - if (n == -1) { - ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, "aio_error() failed"); - rev->error = 1; - return NGX_ERROR; - } - - if (n != 0) { - if (n == NGX_EINPROGRESS) { - if (rev->ready) { - ngx_log_error(NGX_LOG_ALERT, c->log, n, - "aio_read() still in progress"); - rev->ready = 0; - } - return NGX_AGAIN; - } - - ngx_log_error(NGX_LOG_CRIT, c->log, n, "aio_read() failed"); - rev->error = 1; - rev->ready = 0; - return NGX_ERROR; - } - - n = aio_return(&rev->aiocb); - if (n == -1) { - ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, - "aio_return() failed"); - - rev->error = 1; - rev->ready = 0; - return NGX_ERROR; - } - - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, rev->log, 0, - "aio_read: #%d %d", c->fd, n); - - if (n == 0) { - rev->eof = 1; - rev->ready = 0; - } else { - rev->ready = 1; - } - - rev->active = 0; - - return n; -} diff --git a/src/os/unix/ngx_aio_read_chain.c b/src/os/unix/ngx_aio_read_chain.c deleted file mode 100644 index 8c831b9..0000000 --- a/src/os/unix/ngx_aio_read_chain.c +++ /dev/null @@ -1,78 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - */ - - -#include -#include -#include - - -ssize_t -ngx_aio_read_chain(ngx_connection_t *c, ngx_chain_t *cl) -{ - int n; - u_char *buf, *prev; - size_t size; - ssize_t total; - - if (c->read->pending_eof) { - c->read->ready = 0; - return 0; - } - - total = 0; - - while (cl) { - - /* we can post the single aio operation only */ - - if (!c->read->ready) { - return total ? total : NGX_AGAIN; - } - - buf = cl->buf->last; - prev = cl->buf->last; - size = 0; - - /* coalesce the neighbouring bufs */ - - while (cl && prev == cl->buf->last) { - size += cl->buf->end - cl->buf->last; - prev = cl->buf->end; - cl = cl->next; - } - - n = ngx_aio_read(c, buf, size); - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "aio_read: %d", n); - - if (n == NGX_AGAIN) { - return total ? total : NGX_AGAIN; - } - - if (n == NGX_ERROR) { - return NGX_ERROR; - } - - if (n == 0) { - c->read->pending_eof = 1; - if (total) { - c->read->eof = 0; - c->read->ready = 1; - } - return total; - } - - if (n > 0) { - total += n; - } - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "aio_read total: %d", total); - } - - return total ? total : NGX_AGAIN; -} diff --git a/src/os/unix/ngx_aio_write.c b/src/os/unix/ngx_aio_write.c deleted file mode 100644 index f0d9391..0000000 --- a/src/os/unix/ngx_aio_write.c +++ /dev/null @@ -1,109 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - */ - - -#include -#include -#include - - -extern int ngx_kqueue; - - -ssize_t -ngx_aio_write(ngx_connection_t *c, u_char *buf, size_t size) -{ - int n; - ngx_event_t *wev; - - wev = c->write; - - if (!wev->ready) { - return NGX_AGAIN; - } - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, wev->log, 0, - "aio: wev->complete: %d", wev->complete); - - if (!wev->complete) { - ngx_memzero(&wev->aiocb, sizeof(struct aiocb)); - - wev->aiocb.aio_fildes = c->fd; - wev->aiocb.aio_buf = buf; - wev->aiocb.aio_nbytes = size; - -#if (NGX_HAVE_KQUEUE) - wev->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue; - wev->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT; - wev->aiocb.aio_sigevent.sigev_value.sigval_ptr = wev; -#endif - - if (aio_write(&wev->aiocb) == -1) { - ngx_log_error(NGX_LOG_CRIT, wev->log, ngx_errno, - "aio_write() failed"); - return NGX_ERROR; - } - - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, wev->log, 0, "aio_write: OK"); - - wev->active = 1; - wev->ready = 0; - } - - wev->complete = 0; - - n = aio_error(&wev->aiocb); - if (n == -1) { - ngx_log_error(NGX_LOG_CRIT, wev->log, ngx_errno, "aio_error() failed"); - wev->error = 1; - return NGX_ERROR; - } - - if (n != 0) { - if (n == NGX_EINPROGRESS) { - if (wev->ready) { - ngx_log_error(NGX_LOG_ALERT, wev->log, n, - "aio_write() still in progress"); - wev->ready = 0; - } - return NGX_AGAIN; - } - - ngx_log_error(NGX_LOG_CRIT, wev->log, n, "aio_write() failed"); - wev->error = 1; - wev->ready = 0; - -#if 1 - n = aio_return(&wev->aiocb); - if (n == -1) { - ngx_log_error(NGX_LOG_ALERT, wev->log, ngx_errno, - "aio_return() failed"); - } - - ngx_log_error(NGX_LOG_CRIT, wev->log, n, "aio_return() %d", n); -#endif - - return NGX_ERROR; - } - - n = aio_return(&wev->aiocb); - if (n == -1) { - ngx_log_error(NGX_LOG_ALERT, wev->log, ngx_errno, - "aio_return() failed"); - - wev->error = 1; - wev->ready = 0; - return NGX_ERROR; - } - - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, wev->log, 0, "aio_write: %d", n); - - wev->active = 0; - wev->ready = 1; - - return n; -} diff --git a/src/os/unix/ngx_aio_write_chain.c b/src/os/unix/ngx_aio_write_chain.c deleted file mode 100644 index b0c2508..0000000 --- a/src/os/unix/ngx_aio_write_chain.c +++ /dev/null @@ -1,100 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - */ - - -#include -#include -#include - - -ngx_chain_t * -ngx_aio_write_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) -{ - u_char *buf, *prev; - off_t send, sent; - size_t len; - ssize_t n, size; - ngx_chain_t *cl; - - /* the maximum limit size is the maximum size_t value - the page size */ - - if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) { - limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize; - } - - send = 0; - sent = 0; - cl = in; - - while (cl) { - - if (cl->buf->pos == cl->buf->last) { - cl = cl->next; - continue; - } - - /* we can post the single aio operation only */ - - if (!c->write->ready) { - return cl; - } - - buf = cl->buf->pos; - prev = buf; - len = 0; - - /* coalesce the neighbouring bufs */ - - while (cl && prev == cl->buf->pos && send < limit) { - if (ngx_buf_special(cl->buf)) { - continue; - } - - size = cl->buf->last - cl->buf->pos; - - if (send + size > limit) { - size = limit - send; - } - - len += size; - prev = cl->buf->pos + size; - send += size; - cl = cl->next; - } - - n = ngx_aio_write(c, buf, len); - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "aio_write: %z", n); - - if (n == NGX_ERROR) { - return NGX_CHAIN_ERROR; - } - - if (n > 0) { - sent += n; - c->sent += n; - } - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "aio_write sent: %O", c->sent); - - for (cl = in; cl; cl = cl->next) { - - if (sent >= cl->buf->last - cl->buf->pos) { - sent -= cl->buf->last - cl->buf->pos; - cl->buf->pos = cl->buf->last; - - continue; - } - - cl->buf->pos += sent; - - break; - } - } - - return cl; -} diff --git a/src/os/unix/ngx_channel.c b/src/os/unix/ngx_channel.c index 8e90696..1efa066 100644 --- a/src/os/unix/ngx_channel.c +++ b/src/os/unix/ngx_channel.c @@ -216,13 +216,6 @@ ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd, ngx_int_t event, rev->log = cycle->log; wev->log = cycle->log; -#if (NGX_THREADS) - rev->lock = &c->lock; - wev->lock = &c->lock; - rev->own_lock = &c->lock; - wev->own_lock = &c->lock; -#endif - rev->channel = 1; wev->channel = 1; diff --git a/src/os/unix/ngx_darwin_config.h b/src/os/unix/ngx_darwin_config.h index 7ac86c7..bbad977 100644 --- a/src/os/unix/ngx_darwin_config.h +++ b/src/os/unix/ngx_darwin_config.h @@ -9,9 +9,6 @@ #define _NGX_DARWIN_CONFIG_H_INCLUDED_ -#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_0 - - #include #include #include diff --git a/src/os/unix/ngx_darwin_sendfile_chain.c b/src/os/unix/ngx_darwin_sendfile_chain.c index 76c4a3a..c802e9f 100644 --- a/src/os/unix/ngx_darwin_sendfile_chain.c +++ b/src/os/unix/ngx_darwin_sendfile_chain.c @@ -13,7 +13,7 @@ /* * It seems that Darwin 9.4 (Mac OS X 1.5) sendfile() has the same * old bug as early FreeBSD sendfile() syscall: - * http://www.freebsd.org/cgi/query-pr.cgi?pr=33771 + * http://bugs.freebsd.org/33771 * * Besides sendfile() has another bug: if one calls sendfile() * with both a header and a trailer, then sendfile() ignores a file part @@ -27,30 +27,22 @@ */ -#if (IOV_MAX > 64) -#define NGX_HEADERS 64 -#define NGX_TRAILERS 64 -#else -#define NGX_HEADERS IOV_MAX -#define NGX_TRAILERS IOV_MAX -#endif - - ngx_chain_t * ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { int rc; - u_char *prev; - off_t size, send, prev_send, aligned, sent, fprev; - off_t header_size, file_size; - ngx_uint_t eintr, complete; + off_t send, prev_send, sent; + off_t file_size; + ssize_t n; + ngx_uint_t eintr; ngx_err_t err; ngx_buf_t *file; - ngx_array_t header, trailer; ngx_event_t *wev; ngx_chain_t *cl; + ngx_iovec_t header, trailer; struct sf_hdtr hdtr; - struct iovec *iov, headers[NGX_HEADERS], trailers[NGX_TRAILERS]; + struct iovec headers[NGX_IOVS_PREALLOCATE]; + struct iovec trailers[NGX_IOVS_PREALLOCATE]; wev = c->write; @@ -77,166 +69,68 @@ ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) send = 0; - header.elts = headers; - header.size = sizeof(struct iovec); - header.nalloc = NGX_HEADERS; - header.pool = c->pool; + header.iovs = headers; + header.nalloc = NGX_IOVS_PREALLOCATE; - trailer.elts = trailers; - trailer.size = sizeof(struct iovec); - trailer.nalloc = NGX_TRAILERS; - trailer.pool = c->pool; + trailer.iovs = trailers; + trailer.nalloc = NGX_IOVS_PREALLOCATE; for ( ;; ) { - file = NULL; - file_size = 0; - header_size = 0; eintr = 0; - complete = 0; prev_send = send; - header.nelts = 0; - trailer.nelts = 0; - /* create the header iovec and coalesce the neighbouring bufs */ - prev = NULL; - iov = NULL; + cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log); - for (cl = in; cl && send < limit; cl = cl->next) { - - if (ngx_buf_special(cl->buf)) { - continue; - } - - if (!ngx_buf_in_memory_only(cl->buf)) { - break; - } - - size = cl->buf->last - cl->buf->pos; - - if (send + size > limit) { - size = limit - send; - } - - if (prev == cl->buf->pos) { - 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; - } - - iov->iov_base = (void *) cl->buf->pos; - iov->iov_len = (size_t) size; - } - - prev = cl->buf->pos + (size_t) size; - header_size += size; - send += size; + if (cl == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; } + send += header.size; if (cl && cl->buf->in_file && send < limit) { file = cl->buf; /* coalesce the neighbouring file bufs */ - do { - size = cl->buf->file_last - cl->buf->file_pos; + file_size = ngx_chain_coalesce_file(&cl, limit - send); - if (send + size > limit) { - size = limit - send; + send += file_size; - aligned = (cl->buf->file_pos + size + ngx_pagesize - 1) - & ~((off_t) ngx_pagesize - 1); + if (header.count == 0) { - if (aligned <= cl->buf->file_last) { - size = aligned - cl->buf->file_pos; - } + /* + * create the trailer iovec and coalesce the neighbouring bufs + */ + + cl = ngx_output_chain_to_iovec(&trailer, cl, limit - send, + c->log); + if (cl == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; } - file_size += size; - send += size; - fprev = cl->buf->file_pos + size; - cl = cl->next; + send += trailer.size; - } while (cl - && cl->buf->in_file - && send < limit - && file->file->fd == cl->buf->file->fd - && fprev == cl->buf->file_pos); - } - - if (file && header.nelts == 0) { - - /* create the trailer iovec and coalesce the neighbouring bufs */ - - prev = NULL; - iov = NULL; - - while (cl && send < limit) { - - if (ngx_buf_special(cl->buf)) { - cl = cl->next; - continue; - } - - if (!ngx_buf_in_memory_only(cl->buf)) { - break; - } - - size = cl->buf->last - cl->buf->pos; - - if (send + size > limit) { - size = limit - send; - } - - if (prev == cl->buf->pos) { - 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; - } - - iov->iov_base = (void *) cl->buf->pos; - iov->iov_len = (size_t) size; - } - - prev = cl->buf->pos + (size_t) size; - send += size; - cl = cl->next; + } else { + trailer.count = 0; } - } - - if (file) { /* * sendfile() returns EINVAL if sf_hdtr's count is 0, * but corresponding pointer is not NULL */ - hdtr.headers = header.nelts ? (struct iovec *) header.elts: NULL; - hdtr.hdr_cnt = header.nelts; - hdtr.trailers = trailer.nelts ? (struct iovec *) trailer.elts: NULL; - hdtr.trl_cnt = trailer.nelts; + hdtr.headers = header.count ? header.iovs : NULL; + hdtr.hdr_cnt = header.count; + hdtr.trailers = trailer.count ? trailer.iovs : NULL; + hdtr.trl_cnt = trailer.count; - sent = header_size + file_size; + sent = header.size + file_size; ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "sendfile: @%O %O h:%O", - file->file_pos, sent, header_size); + "sendfile: @%O %O h:%uz", + file->file_pos, sent, header.size); rc = sendfile(file->file->fd, c->fd, file->file_pos, &sent, &hdtr, 0); @@ -279,86 +173,28 @@ ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfile: %d, @%O %O:%O", - rc, file->file_pos, sent, file_size + header_size); + rc, file->file_pos, sent, file_size + header.size); } else { - rc = writev(c->fd, header.elts, header.nelts); + n = ngx_writev(c, &header); - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "writev: %d of %uz", rc, send); - - if (rc == -1) { - err = ngx_errno; - - switch (err) { - case NGX_EAGAIN: - break; - - case NGX_EINTR: - eintr = 1; - break; - - default: - wev->error = 1; - ngx_connection_error(c, err, "writev() failed"); - return NGX_CHAIN_ERROR; - } - - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, - "writev() not ready"); + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; } - sent = rc > 0 ? rc : 0; - } - - if (send - prev_send == sent) { - complete = 1; + sent = (n == NGX_AGAIN) ? 0 : n; } c->sent += sent; - for ( /* void */ ; in; in = in->next) { - - if (ngx_buf_special(in->buf)) { - continue; - } - - if (sent == 0) { - break; - } - - size = ngx_buf_size(in->buf); - - if (sent >= size) { - sent -= size; - - if (ngx_buf_in_memory(in->buf)) { - in->buf->pos = in->buf->last; - } - - if (in->buf->in_file) { - in->buf->file_pos = in->buf->file_last; - } - - continue; - } - - if (ngx_buf_in_memory(in->buf)) { - in->buf->pos += (size_t) sent; - } - - if (in->buf->in_file) { - in->buf->file_pos += sent; - } - - break; - } + in = ngx_chain_update_sent(in, sent); if (eintr) { + send = prev_send + sent; continue; } - if (!complete) { + if (send - prev_send != sent) { wev->ready = 0; return in; } diff --git a/src/os/unix/ngx_file_aio_read.c b/src/os/unix/ngx_file_aio_read.c index 0bb383d..b11cf8a 100644 --- a/src/os/unix/ngx_file_aio_read.c +++ b/src/os/unix/ngx_file_aio_read.c @@ -36,6 +36,28 @@ static ssize_t ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio, static void ngx_file_aio_event_handler(ngx_event_t *ev); +ngx_int_t +ngx_file_aio_init(ngx_file_t *file, ngx_pool_t *pool) +{ + ngx_event_aio_t *aio; + + aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t)); + if (aio == NULL) { + return NGX_ERROR; + } + + aio->file = file; + aio->fd = file->fd; + aio->event.data = aio; + aio->event.ready = 1; + aio->event.log = file->log; + + file->aio = aio; + + return NGX_OK; +} + + ssize_t ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, ngx_pool_t *pool) @@ -48,25 +70,11 @@ ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, return ngx_read_file(file, buf, size, offset); } - aio = file->aio; - - if (aio == NULL) { - aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t)); - if (aio == NULL) { - return NGX_ERROR; - } - - aio->file = file; - aio->fd = file->fd; - aio->event.data = aio; - aio->event.ready = 1; - aio->event.log = file->log; -#if (NGX_HAVE_AIO_SENDFILE) - aio->last_offset = -1; -#endif - file->aio = aio; + if (file->aio == NULL && ngx_file_aio_init(file, pool) != NGX_OK) { + return NGX_ERROR; } + aio = file->aio; ev = &aio->event; if (!ev->ready) { diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c index c3ae47f..2a3ed2f 100644 --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -9,6 +9,12 @@ #include +#if (NGX_THREADS) +#include +static void ngx_thread_read_handler(void *data, ngx_log_t *log); +#endif + + #if (NGX_HAVE_FILE_AIO) ngx_uint_t ngx_file_aio = 1; @@ -64,6 +70,109 @@ ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) } +#if (NGX_THREADS) + +typedef struct { + ngx_fd_t fd; + u_char *buf; + size_t size; + off_t offset; + + size_t read; + ngx_err_t err; +} ngx_thread_read_ctx_t; + + +ssize_t +ngx_thread_read(ngx_thread_task_t **taskp, ngx_file_t *file, u_char *buf, + size_t size, off_t offset, ngx_pool_t *pool) +{ + ngx_thread_task_t *task; + ngx_thread_read_ctx_t *ctx; + + ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, + "thread read: %d, %p, %uz, %O", + file->fd, buf, size, offset); + + task = *taskp; + + if (task == NULL) { + task = ngx_thread_task_alloc(pool, sizeof(ngx_thread_read_ctx_t)); + if (task == NULL) { + return NGX_ERROR; + } + + task->handler = ngx_thread_read_handler; + + *taskp = task; + } + + ctx = task->ctx; + + if (task->event.complete) { + task->event.complete = 0; + + if (ctx->err) { + ngx_log_error(NGX_LOG_CRIT, file->log, ctx->err, + "pread() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + return ctx->read; + } + + ctx->fd = file->fd; + ctx->buf = buf; + ctx->size = size; + ctx->offset = offset; + + if (file->thread_handler(task, file) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_AGAIN; +} + + +#if (NGX_HAVE_PREAD) + +static void +ngx_thread_read_handler(void *data, ngx_log_t *log) +{ + ngx_thread_read_ctx_t *ctx = data; + + ssize_t n; + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "thread read handler"); + + n = pread(ctx->fd, ctx->buf, ctx->size, ctx->offset); + + if (n == -1) { + ctx->err = ngx_errno; + + } else { + ctx->read = n; + ctx->err = 0; + } + +#if 0 + ngx_time_update(); +#endif + + ngx_log_debug4(NGX_LOG_DEBUG_CORE, log, 0, + "pread: %z (err: %i) of %uz @%O", + n, ctx->err, ctx->size, ctx->offset); +} + +#else + +#error pread() is required! + +#endif + +#endif /* NGX_THREADS */ + + ssize_t ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) { diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h index a78ec96..b6990bc 100644 --- a/src/os/unix/ngx_files.h +++ b/src/os/unix/ngx_files.h @@ -375,6 +375,7 @@ size_t ngx_fs_bsize(u_char *name); #if (NGX_HAVE_FILE_AIO) +ngx_int_t ngx_file_aio_init(ngx_file_t *file, ngx_pool_t *pool); ssize_t ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, ngx_pool_t *pool); @@ -382,5 +383,10 @@ extern ngx_uint_t ngx_file_aio; #endif +#if (NGX_THREADS) +ssize_t ngx_thread_read(ngx_thread_task_t **taskp, ngx_file_t *file, + u_char *buf, size_t size, off_t offset, ngx_pool_t *pool); +#endif + #endif /* _NGX_FILES_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h index 92b2928..9a25788 100644 --- a/src/os/unix/ngx_freebsd_config.h +++ b/src/os/unix/ngx_freebsd_config.h @@ -86,7 +86,7 @@ #endif -#if (NGX_HAVE_FILE_AIO || NGX_HAVE_AIO) +#if (NGX_HAVE_FILE_AIO) #include typedef struct aiocb ngx_aiocb_t; #endif @@ -100,12 +100,6 @@ typedef struct aiocb ngx_aiocb_t; #endif -#if (__FreeBSD_version < 430000 || __FreeBSD_version < 500012) - -pid_t rfork_thread(int flags, void *stack, int (*func)(void *arg), void *arg); - -#endif - #ifndef IOV_MAX #define IOV_MAX 1024 #endif diff --git a/src/os/unix/ngx_freebsd_rfork_thread.c b/src/os/unix/ngx_freebsd_rfork_thread.c deleted file mode 100644 index e92f9a9..0000000 --- a/src/os/unix/ngx_freebsd_rfork_thread.c +++ /dev/null @@ -1,756 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - */ - - -#include -#include - -/* - * 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 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 - * 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. - * - * The condition variable implementation uses the signal #64. - * The signal handler is SIG_IGN so the kill() is a cheap syscall. - * The thread waits a signal in kevent(). The use of the EVFILT_SIGNAL - * is safe since FreeBSD 4.10-STABLE. - * - * This threads implementation currently works on i386 (486+) and amd64 - * platforms only. - */ - - -char *ngx_freebsd_kern_usrstack; -size_t ngx_thread_stack_size; - - -static size_t rz_size; -static size_t usable_stack_size; -static char *last_stack; - -static ngx_uint_t nthreads; -static ngx_uint_t max_threads; - -static ngx_uint_t nkeys; -static ngx_tid_t *tids; /* the threads tids array */ -void **ngx_tls; /* the threads tls's array */ - -/* the thread-safe libc errno */ - -static int errno0; /* the main thread's errno */ -static int *errnos; /* the threads errno's array */ - -int * -__error() -{ - int tid; - - tid = ngx_gettid(); - - return tid ? &errnos[tid - 1] : &errno0; -} - - -/* - * __isthreaded enables the spinlocks in some libc functions, i.e. in malloc() - * and some other places. Nevertheless we protect our malloc()/free() calls - * by own mutex that is more efficient than the spinlock. - * - * _spinlock() is a weak referenced stub in src/lib/libc/gen/_spinlock_stub.c - * that does nothing. - */ - -extern int __isthreaded; - -void -_spinlock(ngx_atomic_t *lock) -{ - ngx_int_t tries; - - tries = 0; - - for ( ;; ) { - - if (*lock) { - if (ngx_ncpu > 1 && tries++ < 1000) { - continue; - } - - sched_yield(); - tries = 0; - - } else { - if (ngx_atomic_cmp_set(lock, 0, 1)) { - return; - } - } - } -} - - -/* - * Before FreeBSD 5.1 _spinunlock() is a simple #define in - * src/lib/libc/include/spinlock.h that zeroes lock. - * - * Since FreeBSD 5.1 _spinunlock() is a weak referenced stub in - * src/lib/libc/gen/_spinlock_stub.c that does nothing. - */ - -#ifndef _spinunlock - -void -_spinunlock(ngx_atomic_t *lock) -{ - *lock = 0; -} - -#endif - - -ngx_err_t -ngx_create_thread(ngx_tid_t *tid, ngx_thread_value_t (*func)(void *arg), - void *arg, ngx_log_t *log) -{ - ngx_pid_t id; - ngx_err_t err; - char *stack, *stack_top; - - if (nthreads >= max_threads) { - ngx_log_error(NGX_LOG_CRIT, log, 0, - "no more than %ui threads can be created", max_threads); - return NGX_ERROR; - } - - last_stack -= ngx_thread_stack_size; - - stack = mmap(last_stack, usable_stack_size, PROT_READ|PROT_WRITE, - MAP_STACK, -1, 0); - - if (stack == MAP_FAILED) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - "mmap(%p:%uz, MAP_STACK) thread stack failed", - last_stack, usable_stack_size); - return NGX_ERROR; - } - - if (stack != last_stack) { - ngx_log_error(NGX_LOG_ALERT, log, 0, - "stack %p address was changed to %p", last_stack, stack); - return NGX_ERROR; - } - - stack_top = stack + usable_stack_size; - - ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0, - "thread stack: %p-%p", stack, stack_top); - - ngx_set_errno(0); - - id = rfork_thread(RFPROC|RFTHREAD|RFMEM, stack_top, - (ngx_rfork_thread_func_pt) func, arg); - - err = ngx_errno; - - if (id == -1) { - ngx_log_error(NGX_LOG_ALERT, log, err, "rfork() failed"); - - } else { - *tid = id; - nthreads = (ngx_freebsd_kern_usrstack - stack_top) - / ngx_thread_stack_size; - tids[nthreads] = id; - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "rfork()ed thread: %P", id); - } - - return err; -} - - -ngx_int_t -ngx_init_threads(int n, size_t size, ngx_cycle_t *cycle) -{ - char *red_zone, *zone; - size_t len; - ngx_int_t i; - struct sigaction sa; - - max_threads = n + 1; - - for (i = 0; i < n; i++) { - ngx_memzero(&sa, sizeof(struct sigaction)); - sa.sa_handler = SIG_IGN; - sigemptyset(&sa.sa_mask); - if (sigaction(NGX_CV_SIGNAL, &sa, NULL) == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, - "sigaction(%d, SIG_IGN) failed", NGX_CV_SIGNAL); - return NGX_ERROR; - } - } - - len = sizeof(ngx_freebsd_kern_usrstack); - if (sysctlbyname("kern.usrstack", &ngx_freebsd_kern_usrstack, &len, - NULL, 0) == -1) - { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, - "sysctlbyname(kern.usrstack) failed"); - return NGX_ERROR; - } - - /* the main thread stack red zone */ - rz_size = ngx_pagesize; - red_zone = ngx_freebsd_kern_usrstack - (size + rz_size); - - ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, - "usrstack: %p red zone: %p", - ngx_freebsd_kern_usrstack, red_zone); - - zone = mmap(red_zone, rz_size, PROT_NONE, MAP_ANON, -1, 0); - if (zone == MAP_FAILED) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, - "mmap(%p:%uz, PROT_NONE, MAP_ANON) red zone failed", - red_zone, rz_size); - return NGX_ERROR; - } - - if (zone != red_zone) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - "red zone %p address was changed to %p", red_zone, zone); - return NGX_ERROR; - } - - /* create the thread errno' array */ - - errnos = ngx_calloc(n * sizeof(int), cycle->log); - if (errnos == NULL) { - return NGX_ERROR; - } - - /* create the thread tids array */ - - tids = ngx_calloc((n + 1) * sizeof(ngx_tid_t), cycle->log); - if (tids == NULL) { - return NGX_ERROR; - } - - tids[0] = ngx_pid; - - /* create the thread tls' array */ - - ngx_tls = ngx_calloc(NGX_THREAD_KEYS_MAX * (n + 1) * sizeof(void *), - cycle->log); - if (ngx_tls == NULL) { - return NGX_ERROR; - } - - nthreads = 1; - - last_stack = zone + rz_size; - usable_stack_size = size; - ngx_thread_stack_size = size + rz_size; - - /* allow the spinlock in libc malloc() */ - __isthreaded = 1; - - ngx_threaded = 1; - - return NGX_OK; -} - - -ngx_tid_t -ngx_thread_self(void) -{ - ngx_int_t tid; - - tid = ngx_gettid(); - - if (tids == NULL) { - return ngx_pid; - } - - return tids[tid]; -} - - -ngx_err_t -ngx_thread_key_create(ngx_tls_key_t *key) -{ - if (nkeys >= NGX_THREAD_KEYS_MAX) { - return NGX_ENOMEM; - } - - *key = nkeys++; - - return 0; -} - - -ngx_err_t -ngx_thread_set_tls(ngx_tls_key_t key, void *value) -{ - if (key >= NGX_THREAD_KEYS_MAX) { - return NGX_EINVAL; - } - - ngx_tls[key * NGX_THREAD_KEYS_MAX + ngx_gettid()] = value; - return 0; -} - - -ngx_mutex_t * -ngx_mutex_init(ngx_log_t *log, ngx_uint_t flags) -{ - ngx_mutex_t *m; - union semun op; - - m = ngx_alloc(sizeof(ngx_mutex_t), log); - if (m == NULL) { - return NULL; - } - - m->lock = 0; - m->log = log; - - if (flags & NGX_MUTEX_LIGHT) { - m->semid = -1; - return m; - } - - m->semid = semget(IPC_PRIVATE, 1, SEM_R|SEM_A); - if (m->semid == -1) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "semget() failed"); - return NULL; - } - - op.val = 0; - - if (semctl(m->semid, 0, SETVAL, op) == -1) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "semctl(SETVAL) failed"); - - if (semctl(m->semid, 0, IPC_RMID) == -1) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - "semctl(IPC_RMID) failed"); - } - - return NULL; - } - - return m; -} - - -void -ngx_mutex_destroy(ngx_mutex_t *m) -{ - if (semctl(m->semid, 0, IPC_RMID) == -1) { - ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, - "semctl(IPC_RMID) failed"); - } - - ngx_free((void *) m); -} - - -ngx_int_t -ngx_mutex_dolock(ngx_mutex_t *m, ngx_int_t try) -{ - uint32_t lock, old; - ngx_uint_t tries; - struct sembuf op; - - if (!ngx_threaded) { - return NGX_OK; - } - -#if (NGX_DEBUG) - if (try) { - ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0, - "try lock mutex %p lock:%XD", m, m->lock); - } else { - ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0, - "lock mutex %p lock:%XD", m, m->lock); - } -#endif - - old = m->lock; - tries = 0; - - for ( ;; ) { - if (old & NGX_MUTEX_LOCK_BUSY) { - - if (try) { - return NGX_AGAIN; - } - - if (ngx_ncpu > 1 && tries++ < 1000) { - - /* the spinlock is used only on the SMP system */ - - old = m->lock; - continue; - } - - if (m->semid == -1) { - sched_yield(); - - tries = 0; - old = m->lock; - continue; - } - - ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0, - "mutex %p lock:%XD", m, m->lock); - - /* - * The mutex is locked so we increase a number - * of the threads that are waiting on the mutex - */ - - lock = old + 1; - - if ((lock & ~NGX_MUTEX_LOCK_BUSY) > nthreads) { - ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, - "%D threads wait for mutex %p, " - "while only %ui threads are available", - lock & ~NGX_MUTEX_LOCK_BUSY, m, nthreads); - ngx_abort(); - } - - if (ngx_atomic_cmp_set(&m->lock, old, lock)) { - - ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0, - "wait mutex %p lock:%XD", m, m->lock); - - /* - * The number of the waiting threads has been increased - * and we would wait on the SysV semaphore. - * A semaphore should wake up us more efficiently than - * a simple sched_yield() or usleep(). - */ - - op.sem_num = 0; - op.sem_op = -1; - op.sem_flg = 0; - - if (semop(m->semid, &op, 1) == -1) { - ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, - "semop() failed while waiting on mutex %p", m); - ngx_abort(); - } - - ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0, - "mutex waked up %p lock:%XD", m, m->lock); - - tries = 0; - old = m->lock; - continue; - } - - old = m->lock; - - } else { - lock = old | NGX_MUTEX_LOCK_BUSY; - - if (ngx_atomic_cmp_set(&m->lock, old, lock)) { - - /* we locked the mutex */ - - break; - } - - old = m->lock; - } - - if (tries++ > 1000) { - - ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, - "mutex %p is contested", m); - - /* the mutex is probably contested so we are giving up now */ - - sched_yield(); - - tries = 0; - old = m->lock; - } - } - - ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0, - "mutex %p is locked, lock:%XD", m, m->lock); - - return NGX_OK; -} - - -void -ngx_mutex_unlock(ngx_mutex_t *m) -{ - uint32_t lock, old; - struct sembuf op; - - if (!ngx_threaded) { - return; - } - - old = m->lock; - - if (!(old & NGX_MUTEX_LOCK_BUSY)) { - ngx_log_error(NGX_LOG_ALERT, m->log, 0, - "trying to unlock the free mutex %p", m); - ngx_abort(); - } - - /* free the mutex */ - -#if 0 - ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0, - "unlock mutex %p lock:%XD", m, old); -#endif - - for ( ;; ) { - lock = old & ~NGX_MUTEX_LOCK_BUSY; - - if (ngx_atomic_cmp_set(&m->lock, old, lock)) { - break; - } - - old = m->lock; - } - - if (m->semid == -1) { - ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, - "mutex %p is unlocked", m); - - return; - } - - /* check whether we need to wake up a waiting thread */ - - old = m->lock; - - for ( ;; ) { - if (old & NGX_MUTEX_LOCK_BUSY) { - - /* the mutex is just locked by another thread */ - - break; - } - - if (old == 0) { - break; - } - - /* there are the waiting threads */ - - lock = old - 1; - - if (ngx_atomic_cmp_set(&m->lock, old, lock)) { - - /* wake up the thread that waits on semaphore */ - - ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, - "wake up mutex %p", m); - - op.sem_num = 0; - op.sem_op = 1; - op.sem_flg = 0; - - if (semop(m->semid, &op, 1) == -1) { - ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, - "semop() failed while waking up on mutex %p", m); - ngx_abort(); - } - - break; - } - - old = m->lock; - } - - ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, - "mutex %p is unlocked", m); - - return; -} - - -ngx_cond_t * -ngx_cond_init(ngx_log_t *log) -{ - ngx_cond_t *cv; - - cv = ngx_alloc(sizeof(ngx_cond_t), log); - if (cv == NULL) { - return NULL; - } - - cv->signo = NGX_CV_SIGNAL; - cv->tid = -1; - cv->log = log; - cv->kq = -1; - - return cv; -} - - -void -ngx_cond_destroy(ngx_cond_t *cv) -{ - if (close(cv->kq) == -1) { - ngx_log_error(NGX_LOG_ALERT, cv->log, ngx_errno, - "kqueue close() failed"); - } - - ngx_free(cv); -} - - -ngx_int_t -ngx_cond_wait(ngx_cond_t *cv, ngx_mutex_t *m) -{ - int n; - ngx_err_t err; - struct kevent kev; - struct timespec ts; - - if (cv->kq == -1) { - - /* - * We have to add the EVFILT_SIGNAL filter in the rfork()ed thread. - * Otherwise the thread would not get a signal event. - * - * However, we have not to open the kqueue in the thread, - * it is simply handy do it together. - */ - - cv->kq = kqueue(); - if (cv->kq == -1) { - ngx_log_error(NGX_LOG_ALERT, cv->log, ngx_errno, "kqueue() failed"); - return NGX_ERROR; - } - - ngx_log_debug2(NGX_LOG_DEBUG_CORE, cv->log, 0, - "cv kq:%d signo:%d", cv->kq, cv->signo); - - kev.ident = cv->signo; - kev.filter = EVFILT_SIGNAL; - kev.flags = EV_ADD; - kev.fflags = 0; - kev.data = 0; - kev.udata = NULL; - - ts.tv_sec = 0; - ts.tv_nsec = 0; - - if (kevent(cv->kq, &kev, 1, NULL, 0, &ts) == -1) { - ngx_log_error(NGX_LOG_ALERT, cv->log, ngx_errno, "kevent() failed"); - return NGX_ERROR; - } - - cv->tid = ngx_thread_self(); - } - - ngx_mutex_unlock(m); - - ngx_log_debug3(NGX_LOG_DEBUG_CORE, cv->log, 0, - "cv %p wait, kq:%d, signo:%d", cv, cv->kq, cv->signo); - - for ( ;; ) { - n = kevent(cv->kq, NULL, 0, &kev, 1, NULL); - - ngx_log_debug2(NGX_LOG_DEBUG_CORE, cv->log, 0, - "cv %p kevent: %d", cv, n); - - if (n == -1) { - err = ngx_errno; - ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT, - cv->log, ngx_errno, - "kevent() failed while waiting condition variable %p", - cv); - - if (err == NGX_EINTR) { - break; - } - - return NGX_ERROR; - } - - if (n == 0) { - ngx_log_error(NGX_LOG_ALERT, cv->log, 0, - "kevent() returned no events " - "while waiting condition variable %p", - cv); - continue; - } - - if (kev.filter != EVFILT_SIGNAL) { - ngx_log_error(NGX_LOG_ALERT, cv->log, 0, - "kevent() returned unexpected events: %d " - "while waiting condition variable %p", - kev.filter, cv); - continue; - } - - if (kev.ident != (uintptr_t) cv->signo) { - ngx_log_error(NGX_LOG_ALERT, cv->log, 0, - "kevent() returned unexpected signal: %d ", - "while waiting condition variable %p", - kev.ident, cv); - continue; - } - - break; - } - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, "cv %p is waked up", cv); - - ngx_mutex_lock(m); - - return NGX_OK; -} - - -ngx_int_t -ngx_cond_signal(ngx_cond_t *cv) -{ - ngx_err_t err; - - ngx_log_debug3(NGX_LOG_DEBUG_CORE, cv->log, 0, - "cv %p to signal %P %d", - cv, cv->tid, cv->signo); - - if (cv->tid == -1) { - return NGX_OK; - } - - if (kill(cv->tid, cv->signo) == -1) { - - err = ngx_errno; - - ngx_log_error(NGX_LOG_ALERT, cv->log, err, - "kill() failed while signaling condition variable %p", cv); - - if (err == NGX_ESRCH) { - cv->tid = -1; - } - - return NGX_ERROR; - } - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, "cv %p is signaled", cv); - - return NGX_OK; -} diff --git a/src/os/unix/ngx_freebsd_rfork_thread.h b/src/os/unix/ngx_freebsd_rfork_thread.h deleted file mode 100644 index ff16044..0000000 --- a/src/os/unix/ngx_freebsd_rfork_thread.h +++ /dev/null @@ -1,122 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - */ - - -#ifndef _NGX_FREEBSD_RFORK_THREAD_H_INCLUDED_ -#define _NGX_FREEBSD_RFORK_THREAD_H_INCLUDED_ - - -#include -#include -#include - -typedef pid_t ngx_tid_t; - -#define ngx_log_pid ngx_thread_self() -#define ngx_log_tid 0 - -#define NGX_TID_T_FMT "%P" - - -#define NGX_MUTEX_LIGHT 1 - -#define NGX_MUTEX_LOCK_BUSY 0x80000000 - -typedef volatile struct { - ngx_atomic_t lock; - ngx_log_t *log; - int semid; -} ngx_mutex_t; - - -#define NGX_CV_SIGNAL 64 - -typedef struct { - int signo; - int kq; - ngx_tid_t tid; - ngx_log_t *log; -} ngx_cond_t; - - -#define ngx_thread_sigmask(how, set, oset) \ - (sigprocmask(how, set, oset) == -1) ? ngx_errno : 0 - -#define ngx_thread_sigmask_n "sigprocmask()" - -#define ngx_thread_join(t, p) - -#define ngx_setthrtitle(n) setproctitle(n) - - -extern char *ngx_freebsd_kern_usrstack; -extern size_t ngx_thread_stack_size; - - -static ngx_inline ngx_int_t -ngx_gettid(void) -{ - char *sp; - - if (ngx_thread_stack_size == 0) { - return 0; - } - -#if ( __i386__ ) - - __asm__ volatile ("mov %%esp, %0" : "=q" (sp)); - -#elif ( __amd64__ ) - - __asm__ volatile ("mov %%rsp, %0" : "=q" (sp)); - -#else - -#error "rfork()ed threads are not supported on this platform" - -#endif - - return (ngx_freebsd_kern_usrstack - sp) / ngx_thread_stack_size; -} - - -ngx_tid_t ngx_thread_self(void); - - -typedef ngx_uint_t ngx_tls_key_t; - -#define NGX_THREAD_KEYS_MAX 16 - -extern void **ngx_tls; - -ngx_err_t ngx_thread_key_create(ngx_tls_key_t *key); -#define ngx_thread_key_create_n "the tls key creation" - -ngx_err_t ngx_thread_set_tls(ngx_tls_key_t key, void *value); -#define ngx_thread_set_tls_n "the tls key setting" - - -static void * -ngx_thread_get_tls(ngx_tls_key_t key) -{ - if (key >= NGX_THREAD_KEYS_MAX) { - return NULL; - } - - return ngx_tls[key * NGX_THREAD_KEYS_MAX + ngx_gettid()]; -} - - -#define ngx_mutex_trylock(m) ngx_mutex_dolock(m, 1) -#define ngx_mutex_lock(m) (void) ngx_mutex_dolock(m, 0) -ngx_int_t ngx_mutex_dolock(ngx_mutex_t *m, ngx_int_t try); -void ngx_mutex_unlock(ngx_mutex_t *m); - - -typedef int (*ngx_rfork_thread_func_pt)(void *arg); - - -#endif /* _NGX_FREEBSD_RFORK_THREAD_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c index 11cec82..3f17dc6 100644 --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -29,30 +29,26 @@ */ -#if (IOV_MAX > 64) -#define NGX_HEADERS 64 -#define NGX_TRAILERS 64 -#else -#define NGX_HEADERS IOV_MAX -#define NGX_TRAILERS IOV_MAX -#endif - - ngx_chain_t * ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { - int rc, flags; - u_char *prev; - off_t size, send, prev_send, aligned, sent, fprev; - size_t header_size, file_size; - ngx_uint_t eintr, eagain, complete; - ngx_err_t err; - ngx_buf_t *file; - ngx_array_t header, trailer; - ngx_event_t *wev; - ngx_chain_t *cl; - struct sf_hdtr hdtr; - struct iovec *iov, headers[NGX_HEADERS], trailers[NGX_TRAILERS]; + int rc, flags; + off_t send, prev_send, sent; + size_t file_size; + ssize_t n; + ngx_uint_t eintr, eagain; + ngx_err_t err; + ngx_buf_t *file; + ngx_event_t *wev; + ngx_chain_t *cl; + ngx_iovec_t header, trailer; + struct sf_hdtr hdtr; + struct iovec headers[NGX_IOVS_PREALLOCATE]; + struct iovec trailers[NGX_IOVS_PREALLOCATE]; +#if (NGX_HAVE_AIO_SENDFILE) + ngx_uint_t ebusy; + ngx_event_aio_t *aio; +#endif wev = c->write; @@ -81,151 +77,52 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) eagain = 0; flags = 0; - header.elts = headers; - header.size = sizeof(struct iovec); - header.nalloc = NGX_HEADERS; - header.pool = c->pool; +#if (NGX_HAVE_AIO_SENDFILE && NGX_SUPPRESS_WARN) + aio = NULL; + file = NULL; +#endif - trailer.elts = trailers; - trailer.size = sizeof(struct iovec); - trailer.nalloc = NGX_TRAILERS; - trailer.pool = c->pool; + header.iovs = headers; + header.nalloc = NGX_IOVS_PREALLOCATE; + + trailer.iovs = trailers; + trailer.nalloc = NGX_IOVS_PREALLOCATE; for ( ;; ) { - file = NULL; - file_size = 0; - header_size = 0; eintr = 0; - complete = 0; +#if (NGX_HAVE_AIO_SENDFILE) + ebusy = 0; +#endif prev_send = send; - header.nelts = 0; - trailer.nelts = 0; - /* create the header iovec and coalesce the neighbouring bufs */ - prev = NULL; - iov = NULL; + cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log); - for (cl = in; cl && send < limit; cl = cl->next) { - - if (ngx_buf_special(cl->buf)) { - continue; - } - - if (!ngx_buf_in_memory_only(cl->buf)) { - break; - } - - size = cl->buf->last - cl->buf->pos; - - if (send + size > limit) { - size = limit - send; - } - - if (prev == cl->buf->pos) { - 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; - } - - iov->iov_base = (void *) cl->buf->pos; - iov->iov_len = (size_t) size; - } - - prev = cl->buf->pos + (size_t) size; - header_size += (size_t) size; - send += size; + if (cl == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; } + send += header.size; if (cl && cl->buf->in_file && send < limit) { file = cl->buf; /* coalesce the neighbouring file bufs */ - do { - size = cl->buf->file_last - cl->buf->file_pos; + file_size = (size_t) ngx_chain_coalesce_file(&cl, limit - send); - if (send + size > limit) { - size = limit - send; - - aligned = (cl->buf->file_pos + size + ngx_pagesize - 1) - & ~((off_t) ngx_pagesize - 1); - - if (aligned <= cl->buf->file_last) { - size = aligned - cl->buf->file_pos; - } - } - - file_size += (size_t) size; - send += size; - fprev = cl->buf->file_pos + size; - cl = cl->next; - - } while (cl - && cl->buf->in_file - && send < limit - && file->file->fd == cl->buf->file->fd - && fprev == cl->buf->file_pos); - } - - - if (file) { + send += file_size; /* create the trailer iovec and coalesce the neighbouring bufs */ - prev = NULL; - iov = NULL; + cl = ngx_output_chain_to_iovec(&trailer, cl, limit - send, c->log); - while (cl && send < limit) { - - if (ngx_buf_special(cl->buf)) { - cl = cl->next; - continue; - } - - if (!ngx_buf_in_memory_only(cl->buf)) { - break; - } - - size = cl->buf->last - cl->buf->pos; - - if (send + size > limit) { - size = limit - send; - } - - if (prev == cl->buf->pos) { - 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; - } - - iov->iov_base = (void *) cl->buf->pos; - iov->iov_len = (size_t) size; - } - - prev = cl->buf->pos + (size_t) size; - send += size; - cl = cl->next; + if (cl == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; } - } - if (file) { + send += trailer.size; if (ngx_freebsd_use_tcp_nopush && c->tcp_nopush == NGX_TCP_NOPUSH_UNSET) @@ -258,28 +155,29 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) * but corresponding pointer is not NULL */ - hdtr.headers = header.nelts ? (struct iovec *) header.elts: NULL; - hdtr.hdr_cnt = header.nelts; - hdtr.trailers = trailer.nelts ? (struct iovec *) trailer.elts: NULL; - hdtr.trl_cnt = trailer.nelts; + hdtr.headers = header.count ? header.iovs : NULL; + hdtr.hdr_cnt = header.count; + hdtr.trailers = trailer.count ? trailer.iovs : NULL; + hdtr.trl_cnt = trailer.count; /* * the "nbytes bug" of the old sendfile() syscall: - * http://www.freebsd.org/cgi/query-pr.cgi?pr=33771 + * http://bugs.freebsd.org/33771 */ if (!ngx_freebsd_sendfile_nbytes_bug) { - header_size = 0; + header.size = 0; } sent = 0; #if (NGX_HAVE_AIO_SENDFILE) - flags = c->aio_sendfile ? SF_NODISKIO : 0; + aio = file->file->aio; + flags = (aio && aio->preload_handler) ? SF_NODISKIO : 0; #endif rc = sendfile(file->file->fd, c->fd, file->file_pos, - file_size + header_size, &hdtr, &sent, flags); + file_size + header.size, &hdtr, &sent, flags); if (rc == -1) { err = ngx_errno; @@ -295,7 +193,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) #if (NGX_HAVE_AIO_SENDFILE) case NGX_EBUSY: - c->busy_sendfile = file; + ebusy = 1; break; #endif @@ -330,85 +228,58 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfile: %d, @%O %O:%uz", - rc, file->file_pos, sent, file_size + header_size); + rc, file->file_pos, sent, file_size + header.size); } else { - rc = writev(c->fd, header.elts, header.nelts); + n = ngx_writev(c, &header); - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "writev: %d of %uz", rc, header_size); - - if (rc == -1) { - err = ngx_errno; - - switch (err) { - case NGX_EAGAIN: - break; - - case NGX_EINTR: - eintr = 1; - break; - - default: - wev->error = 1; - ngx_connection_error(c, err, "writev() failed"); - return NGX_CHAIN_ERROR; - } - - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, - "writev() not ready"); + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; } - sent = rc > 0 ? rc : 0; - } - - if (send - prev_send == sent) { - complete = 1; + sent = (n == NGX_AGAIN) ? 0 : n; } c->sent += sent; - for ( /* void */ ; in; in = in->next) { - - if (ngx_buf_special(in->buf)) { - continue; - } - - if (sent == 0) { - break; - } - - size = ngx_buf_size(in->buf); - - if (sent >= size) { - sent -= size; - - if (ngx_buf_in_memory(in->buf)) { - in->buf->pos = in->buf->last; - } - - if (in->buf->in_file) { - in->buf->file_pos = in->buf->file_last; - } - - continue; - } - - if (ngx_buf_in_memory(in->buf)) { - in->buf->pos += (size_t) sent; - } - - if (in->buf->in_file) { - in->buf->file_pos += sent; - } - - break; - } + in = ngx_chain_update_sent(in, sent); #if (NGX_HAVE_AIO_SENDFILE) - if (c->busy_sendfile) { + + if (ebusy) { + if (sent == 0) { + c->busy_count++; + + if (c->busy_count > 2) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "sendfile(%V) returned busy again", + &file->file->name); + + c->busy_count = 0; + aio->preload_handler = NULL; + + send = prev_send; + continue; + } + + } else { + c->busy_count = 0; + } + + n = aio->preload_handler(file); + + if (n > 0) { + send = prev_send + sent; + continue; + } + return in; } + + if (flags == SF_NODISKIO) { + c->busy_count = 0; + } + #endif if (eagain) { @@ -425,10 +296,11 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) } if (eintr) { + send = prev_send + sent; continue; } - if (!complete) { + if (send - prev_send != sent) { wev->ready = 0; return in; } diff --git a/src/os/unix/ngx_linux.h b/src/os/unix/ngx_linux.h index 1b8bdac..13d654e 100644 --- a/src/os/unix/ngx_linux.h +++ b/src/os/unix/ngx_linux.h @@ -12,7 +12,5 @@ ngx_chain_t *ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); -extern int ngx_linux_rtsig_max; - #endif /* _NGX_LINUX_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_linux_aio_read.c b/src/os/unix/ngx_linux_aio_read.c index 8273c13..b0a9236 100644 --- a/src/os/unix/ngx_linux_aio_read.c +++ b/src/os/unix/ngx_linux_aio_read.c @@ -24,6 +24,28 @@ io_submit(aio_context_t ctx, long n, struct iocb **paiocb) } +ngx_int_t +ngx_file_aio_init(ngx_file_t *file, ngx_pool_t *pool) +{ + ngx_event_aio_t *aio; + + aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t)); + if (aio == NULL) { + return NGX_ERROR; + } + + aio->file = file; + aio->fd = file->fd; + aio->event.data = aio; + aio->event.ready = 1; + aio->event.log = file->log; + + file->aio = aio; + + return NGX_OK; +} + + ssize_t ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, ngx_pool_t *pool) @@ -37,22 +59,11 @@ ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, return ngx_read_file(file, buf, size, offset); } - aio = file->aio; - - if (aio == NULL) { - aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t)); - if (aio == NULL) { - return NGX_ERROR; - } - - aio->file = file; - aio->fd = file->fd; - aio->event.data = aio; - aio->event.ready = 1; - aio->event.log = file->log; - file->aio = aio; + if (file->aio == NULL && ngx_file_aio_init(file, pool) != NGX_OK) { + return NGX_ERROR; } + aio = file->aio; ev = &aio->event; if (!ev->ready) { diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h index 72594ba..162a992 100644 --- a/src/os/unix/ngx_linux_config.h +++ b/src/os/unix/ngx_linux_config.h @@ -82,19 +82,16 @@ extern ssize_t sendfile(int s, int fd, int32_t *offset, size_t size); #endif -#if (NGX_HAVE_RTSIG) -#include -#include -#endif - - #if (NGX_HAVE_EPOLL) #include #endif -#if (NGX_HAVE_FILE_AIO) +#if (NGX_HAVE_SYS_EVENTFD_H) +#include +#endif #include +#if (NGX_HAVE_FILE_AIO) #include typedef struct iocb ngx_aiocb_t; #endif diff --git a/src/os/unix/ngx_linux_init.c b/src/os/unix/ngx_linux_init.c index b910380..b306cda 100644 --- a/src/os/unix/ngx_linux_init.c +++ b/src/os/unix/ngx_linux_init.c @@ -12,8 +12,6 @@ u_char ngx_linux_kern_ostype[50]; u_char ngx_linux_kern_osrelease[50]; -int ngx_linux_rtsig_max; - static ngx_os_io_t ngx_linux_io = { ngx_unix_recv, @@ -46,32 +44,6 @@ ngx_os_specific_init(ngx_log_t *log) (void) ngx_cpystrn(ngx_linux_kern_osrelease, (u_char *) u.release, sizeof(ngx_linux_kern_osrelease)); -#if (NGX_HAVE_RTSIG) - { - int name[2]; - size_t len; - ngx_err_t err; - - name[0] = CTL_KERN; - name[1] = KERN_RTSIGMAX; - len = sizeof(ngx_linux_rtsig_max); - - if (sysctl(name, 2, &ngx_linux_rtsig_max, &len, NULL, 0) == -1) { - err = ngx_errno; - - if (err != NGX_ENOTDIR && err != NGX_ENOSYS) { - ngx_log_error(NGX_LOG_ALERT, log, err, - "sysctl(KERN_RTSIGMAX) failed"); - - return NGX_ERROR; - } - - ngx_linux_rtsig_max = 0; - } - - } -#endif - ngx_os_io = ngx_linux_io; return NGX_OK; @@ -83,9 +55,4 @@ ngx_os_specific_status(ngx_log_t *log) { ngx_log_error(NGX_LOG_NOTICE, log, 0, "OS: %s %s", ngx_linux_kern_ostype, ngx_linux_kern_osrelease); - -#if (NGX_HAVE_RTSIG) - ngx_log_error(NGX_LOG_NOTICE, log, 0, "sysctl(KERN_RTSIGMAX): %d", - ngx_linux_rtsig_max); -#endif } diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c index 16395f9..97f741d 100644 --- a/src/os/unix/ngx_linux_sendfile_chain.c +++ b/src/os/unix/ngx_linux_sendfile_chain.c @@ -10,6 +10,22 @@ #include +static ssize_t ngx_linux_sendfile(ngx_connection_t *c, ngx_buf_t *file, + size_t size); + +#if (NGX_THREADS) +#include + +#if !(NGX_HAVE_SENDFILE64) +#error sendfile64() is required! +#endif + +static ngx_int_t ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, + size_t size, size_t *sent); +static void ngx_linux_sendfile_thread_handler(void *data, ngx_log_t *log); +#endif + + /* * On Linux up to 2.4.21 sendfile() (syscall #187) works with 32-bit * offsets only, and the including breaks the compiling, @@ -27,31 +43,22 @@ #define NGX_SENDFILE_MAXSIZE 2147483647L -#if (IOV_MAX > 64) -#define NGX_HEADERS 64 -#else -#define NGX_HEADERS IOV_MAX -#endif - - ngx_chain_t * ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { - int rc, tcp_nodelay; - off_t size, send, prev_send, aligned, sent, fprev; - u_char *prev; - size_t file_size; + int tcp_nodelay; + off_t send, prev_send; + size_t file_size, sent; + ssize_t n; ngx_err_t err; ngx_buf_t *file; - ngx_uint_t eintr, complete; - ngx_array_t header; ngx_event_t *wev; ngx_chain_t *cl; - struct iovec *iov, headers[NGX_HEADERS]; -#if (NGX_HAVE_SENDFILE64) - off_t offset; -#else - int32_t offset; + ngx_iovec_t header; + struct iovec headers[NGX_IOVS_PREALLOCATE]; +#if (NGX_THREADS) + ngx_int_t rc; + ngx_uint_t thread_handled, thread_complete; #endif wev = c->write; @@ -70,87 +77,30 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) send = 0; - header.elts = headers; - header.size = sizeof(struct iovec); - header.nalloc = NGX_HEADERS; - header.pool = c->pool; + header.iovs = headers; + header.nalloc = NGX_IOVS_PREALLOCATE; for ( ;; ) { - file = NULL; - file_size = 0; - eintr = 0; - complete = 0; prev_send = send; - - header.nelts = 0; - - prev = NULL; - iov = NULL; +#if (NGX_THREADS) + thread_handled = 0; + thread_complete = 0; +#endif /* create the iovec and coalesce the neighbouring bufs */ - for (cl = in; cl && send < limit; cl = cl->next) { + cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log); - if (ngx_buf_special(cl->buf)) { - continue; - } - -#if 1 - if (!ngx_buf_in_memory(cl->buf) && !cl->buf->in_file) { - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "zero size buf in sendfile " - "t:%d r:%d f:%d %p %p-%p %p %O-%O", - cl->buf->temporary, - cl->buf->recycled, - cl->buf->in_file, - cl->buf->start, - cl->buf->pos, - cl->buf->last, - cl->buf->file, - cl->buf->file_pos, - cl->buf->file_last); - - ngx_debug_point(); - - return NGX_CHAIN_ERROR; - } -#endif - - if (!ngx_buf_in_memory_only(cl->buf)) { - break; - } - - size = cl->buf->last - cl->buf->pos; - - if (send + size > limit) { - size = limit - send; - } - - if (prev == cl->buf->pos) { - 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; - } - - iov->iov_base = (void *) cl->buf->pos; - iov->iov_len = (size_t) size; - } - - prev = cl->buf->pos + (size_t) size; - send += size; + if (cl == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; } + send += header.size; + /* set TCP_CORK if there is a header before a file */ if (c->tcp_nopush == NGX_TCP_NOPUSH_UNSET - && header.nelts != 0 + && header.count != 0 && cl && cl->buf->in_file) { @@ -214,159 +164,78 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) /* get the file buf */ - if (header.nelts == 0 && cl && cl->buf->in_file && send < limit) { + if (header.count == 0 && cl && cl->buf->in_file && send < limit) { file = cl->buf; /* coalesce the neighbouring file bufs */ - do { - size = cl->buf->file_last - cl->buf->file_pos; + file_size = (size_t) ngx_chain_coalesce_file(&cl, limit - send); - if (send + size > limit) { - size = limit - send; - - aligned = (cl->buf->file_pos + size + ngx_pagesize - 1) - & ~((off_t) ngx_pagesize - 1); - - if (aligned <= cl->buf->file_last) { - size = aligned - cl->buf->file_pos; - } - } - - file_size += (size_t) size; - send += size; - fprev = cl->buf->file_pos + size; - cl = cl->next; - - } while (cl - && cl->buf->in_file - && send < limit - && file->file->fd == cl->buf->file->fd - && fprev == cl->buf->file_pos); - } - - if (file) { + send += file_size; #if 1 if (file_size == 0) { ngx_debug_point(); return NGX_CHAIN_ERROR; } #endif -#if (NGX_HAVE_SENDFILE64) - offset = file->file_pos; -#else - offset = (int32_t) file->file_pos; -#endif - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "sendfile: @%O %uz", file->file_pos, file_size); +#if (NGX_THREADS) + if (file->file->thread_handler) { + rc = ngx_linux_sendfile_thread(c, file, file_size, &sent); - rc = sendfile(c->fd, file->file->fd, &offset, file_size); - - if (rc == -1) { - err = ngx_errno; - - switch (err) { - case NGX_EAGAIN: + switch (rc) { + case NGX_OK: + thread_handled = 1; break; - case NGX_EINTR: - eintr = 1; + case NGX_DONE: + thread_complete = 1; break; - default: - wev->error = 1; - ngx_connection_error(c, err, "sendfile() failed"); + case NGX_AGAIN: + break; + + default: /* NGX_ERROR */ return NGX_CHAIN_ERROR; } - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, - "sendfile() is not ready"); + } else +#endif + { + n = ngx_linux_sendfile(c, file, file_size); + + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + sent = (n == NGX_AGAIN) ? 0 : n; } - sent = rc > 0 ? rc : 0; - - ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, - "sendfile: %d, @%O %O:%uz", - rc, file->file_pos, sent, file_size); - } else { - rc = writev(c->fd, header.elts, header.nelts); + n = ngx_writev(c, &header); - if (rc == -1) { - err = ngx_errno; - - switch (err) { - case NGX_EAGAIN: - break; - - case NGX_EINTR: - eintr = 1; - break; - - default: - wev->error = 1; - ngx_connection_error(c, err, "writev() failed"); - return NGX_CHAIN_ERROR; - } - - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, - "writev() not ready"); + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; } - sent = rc > 0 ? rc : 0; - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "writev: %O", sent); - } - - if (send - prev_send == sent) { - complete = 1; + sent = (n == NGX_AGAIN) ? 0 : n; } c->sent += sent; - for ( /* void */ ; in; in = in->next) { + in = ngx_chain_update_sent(in, sent); - if (ngx_buf_special(in->buf)) { + if ((size_t) (send - prev_send) != sent) { +#if (NGX_THREADS) + if (thread_handled) { + return in; + } + + if (thread_complete) { + send = prev_send + sent; continue; } - - if (sent == 0) { - break; - } - - size = ngx_buf_size(in->buf); - - if (sent >= size) { - sent -= size; - - if (ngx_buf_in_memory(in->buf)) { - in->buf->pos = in->buf->last; - } - - if (in->buf->in_file) { - in->buf->file_pos = in->buf->file_last; - } - - continue; - } - - if (ngx_buf_in_memory(in->buf)) { - in->buf->pos += (size_t) sent; - } - - if (in->buf->in_file) { - in->buf->file_pos += sent; - } - - break; - } - - if (eintr) { - continue; - } - - if (!complete) { +#endif wev->ready = 0; return in; } @@ -376,3 +245,175 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) } } } + + +static ssize_t +ngx_linux_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size) +{ +#if (NGX_HAVE_SENDFILE64) + off_t offset; +#else + int32_t offset; +#endif + ssize_t n; + ngx_err_t err; + +#if (NGX_HAVE_SENDFILE64) + offset = file->file_pos; +#else + offset = (int32_t) file->file_pos; +#endif + +eintr: + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendfile: @%O %uz", file->file_pos, size); + + n = sendfile(c->fd, file->file->fd, &offset, size); + + if (n == -1) { + err = ngx_errno; + + switch (err) { + case NGX_EAGAIN: + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "sendfile() is not ready"); + return NGX_AGAIN; + + case NGX_EINTR: + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "sendfile() was interrupted"); + goto eintr; + + default: + c->write->error = 1; + ngx_connection_error(c, err, "sendfile() failed"); + return NGX_ERROR; + } + } + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfile: %z of %uz @%O", + n, size, file->file_pos); + + return n; +} + + +#if (NGX_THREADS) + +typedef struct { + ngx_buf_t *file; + ngx_socket_t socket; + size_t size; + + size_t sent; + ngx_err_t err; +} ngx_linux_sendfile_ctx_t; + + +static ngx_int_t +ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size, + size_t *sent) +{ + ngx_uint_t flags; + ngx_event_t *wev; + ngx_thread_task_t *task; + ngx_linux_sendfile_ctx_t *ctx; + + ngx_log_debug3(NGX_LOG_DEBUG_CORE, c->log, 0, + "linux sendfile thread: %d, %uz, %O", + file->file->fd, size, file->file_pos); + + task = c->sendfile_task; + + if (task == NULL) { + task = ngx_thread_task_alloc(c->pool, sizeof(ngx_linux_sendfile_ctx_t)); + if (task == NULL) { + return NGX_ERROR; + } + + task->handler = ngx_linux_sendfile_thread_handler; + + c->sendfile_task = task; + } + + ctx = task->ctx; + wev = c->write; + + if (task->event.complete) { + task->event.complete = 0; + + if (ctx->err && ctx->err != NGX_EAGAIN) { + wev->error = 1; + ngx_connection_error(c, ctx->err, "sendfile() failed"); + return NGX_ERROR; + } + + *sent = ctx->sent; + + return (ctx->sent == ctx->size) ? NGX_DONE : NGX_AGAIN; + } + + ctx->file = file; + ctx->socket = c->fd; + ctx->size = size; + + if (wev->active) { + flags = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ? NGX_CLEAR_EVENT + : NGX_LEVEL_EVENT; + + if (ngx_del_event(wev, NGX_WRITE_EVENT, flags) == NGX_ERROR) { + return NGX_ERROR; + } + } + + if (file->file->thread_handler(task, file->file) != NGX_OK) { + return NGX_ERROR; + } + + *sent = 0; + + return NGX_OK; +} + + +static void +ngx_linux_sendfile_thread_handler(void *data, ngx_log_t *log) +{ + ngx_linux_sendfile_ctx_t *ctx = data; + + off_t offset; + ssize_t n; + ngx_buf_t *file; + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "linux sendfile thread handler"); + + file = ctx->file; + offset = file->file_pos; + +again: + + n = sendfile(ctx->socket, file->file->fd, &offset, ctx->size); + + if (n == -1) { + ctx->err = ngx_errno; + + } else { + ctx->sent = n; + ctx->err = 0; + } + +#if 0 + ngx_time_update(); +#endif + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0, + "sendfile: %z (err: %i) of %uz @%O", + n, ctx->err, ctx->size, file->file_pos); + + if (ctx->err == NGX_EINTR) { + goto again; + } +} + +#endif /* NGX_THREADS */ diff --git a/src/os/unix/ngx_os.h b/src/os/unix/ngx_os.h index c646e2a..d8bcb01 100644 --- a/src/os/unix/ngx_os.h +++ b/src/os/unix/ngx_os.h @@ -17,7 +17,8 @@ typedef ssize_t (*ngx_recv_pt)(ngx_connection_t *c, u_char *buf, size_t size); -typedef ssize_t (*ngx_recv_chain_pt)(ngx_connection_t *c, ngx_chain_t *in); +typedef ssize_t (*ngx_recv_chain_pt)(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); typedef ssize_t (*ngx_send_pt)(ngx_connection_t *c, u_char *buf, size_t size); typedef ngx_chain_t *(*ngx_send_chain_pt)(ngx_connection_t *c, ngx_chain_t *in, off_t limit); @@ -41,21 +42,34 @@ ngx_int_t ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_int_t pid); ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size); -ssize_t ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *entry); +ssize_t ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *entry, off_t limit); ssize_t ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size); ssize_t ngx_unix_send(ngx_connection_t *c, u_char *buf, size_t size); ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); -#if (NGX_HAVE_AIO) -ssize_t ngx_aio_read(ngx_connection_t *c, u_char *buf, size_t size); -ssize_t ngx_aio_read_chain(ngx_connection_t *c, ngx_chain_t *cl); -ssize_t ngx_aio_write(ngx_connection_t *c, u_char *buf, size_t size); -ngx_chain_t *ngx_aio_write_chain(ngx_connection_t *c, ngx_chain_t *in, - off_t limit); + +#if (IOV_MAX > 64) +#define NGX_IOVS_PREALLOCATE 64 +#else +#define NGX_IOVS_PREALLOCATE IOV_MAX #endif +typedef struct { + struct iovec *iovs; + ngx_uint_t count; + size_t size; + ngx_uint_t nalloc; +} ngx_iovec_t; + +ngx_chain_t *ngx_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, + size_t limit, ngx_log_t *log); + + +ssize_t ngx_writev(ngx_connection_t *c, ngx_iovec_t *vec); + + extern ngx_os_io_t ngx_os_io; extern ngx_int_t ngx_ncpu; extern ngx_int_t ngx_max_sockets; diff --git a/src/os/unix/ngx_posix_config.h b/src/os/unix/ngx_posix_config.h index d725659..443c4b0 100644 --- a/src/os/unix/ngx_posix_config.h +++ b/src/os/unix/ngx_posix_config.h @@ -21,6 +21,14 @@ #endif +#if (NGX_GNU_HURD) +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* accept4() */ +#endif +#define _FILE_OFFSET_BITS 64 +#endif + + #ifdef __CYGWIN__ #define timezonevar /* timezone is variable */ #define NGX_BROKEN_SCM_RIGHTS 1 diff --git a/src/os/unix/ngx_posix_init.c b/src/os/unix/ngx_posix_init.c index 58e6f76..bf3a310 100644 --- a/src/os/unix/ngx_posix_init.c +++ b/src/os/unix/ngx_posix_init.c @@ -40,7 +40,9 @@ ngx_os_init(ngx_log_t *log) } #endif - ngx_init_setproctitle(log); + if (ngx_init_setproctitle(log) != NGX_OK) { + return NGX_ERROR; + } ngx_pagesize = getpagesize(); ngx_cacheline_size = NGX_CPU_CACHE_LINE; @@ -82,7 +84,7 @@ ngx_os_init(ngx_log_t *log) void ngx_os_status(ngx_log_t *log) { - ngx_log_error(NGX_LOG_NOTICE, log, 0, NGINX_VER); + ngx_log_error(NGX_LOG_NOTICE, log, 0, NGINX_VER_BUILD); #ifdef NGX_COMPILER ngx_log_error(NGX_LOG_NOTICE, log, 0, "built by " NGX_COMPILER); diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c index be55cea..c69932e 100644 --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -23,18 +23,14 @@ static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data); static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker); static void ngx_worker_process_exit(ngx_cycle_t *cycle); static void ngx_channel_handler(ngx_event_t *ev); -#if (NGX_THREADS) -static void ngx_wakeup_worker_threads(ngx_cycle_t *cycle); -static ngx_thread_value_t ngx_worker_thread_cycle(void *data); -#endif static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data); static void ngx_cache_manager_process_handler(ngx_event_t *ev); static void ngx_cache_loader_process_handler(ngx_event_t *ev); ngx_uint_t ngx_process; +ngx_uint_t ngx_worker; ngx_pid_t ngx_pid; -ngx_uint_t ngx_threaded; sig_atomic_t ngx_reap; sig_atomic_t ngx_sigio; @@ -56,12 +52,6 @@ ngx_uint_t ngx_noaccepting; ngx_uint_t ngx_restart; -#if (NGX_THREADS) -volatile ngx_thread_t ngx_threads[NGX_MAX_THREADS]; -ngx_int_t ngx_threads_n; -#endif - - static u_char master_process[] = "master process"; @@ -121,6 +111,10 @@ ngx_master_process_cycle(ngx_cycle_t *cycle) } title = ngx_pnalloc(cycle->pool, size); + if (title == NULL) { + /* fatal */ + exit(2); + } p = ngx_cpymem(title, master_process, sizeof(master_process) - 1); for (i = 0; i < ngx_argc; i++) { @@ -710,11 +704,13 @@ ngx_master_process_exit(ngx_cycle_t *cycle) * ngx_cycle->pool is already destroyed. */ - ngx_exit_log_file.fd = ngx_cycle->log->file->fd; - ngx_exit_log = *ngx_cycle->log; + ngx_exit_log = *ngx_log_get_file_log(ngx_cycle->log); + + ngx_exit_log_file.fd = ngx_exit_log.file->fd; ngx_exit_log.file = &ngx_exit_log_file; ngx_exit_log.next = NULL; + ngx_exit_log.writer = NULL; ngx_exit_cycle.log = &ngx_exit_log; ngx_exit_cycle.files = ngx_cycle->files; @@ -736,57 +732,12 @@ ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) ngx_connection_t *c; ngx_process = NGX_PROCESS_WORKER; + ngx_worker = worker; ngx_worker_process_init(cycle, worker); ngx_setproctitle("worker process"); -#if (NGX_THREADS) - { - ngx_int_t n; - ngx_err_t err; - ngx_core_conf_t *ccf; - - ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); - - if (ngx_threads_n) { - if (ngx_init_threads(ngx_threads_n, ccf->thread_stack_size, cycle) - == NGX_ERROR) - { - /* fatal */ - exit(2); - } - - err = ngx_thread_key_create(&ngx_core_tls_key); - if (err != 0) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, err, - ngx_thread_key_create_n " failed"); - /* fatal */ - exit(2); - } - - for (n = 0; n < ngx_threads_n; n++) { - - ngx_threads[n].cv = ngx_cond_init(cycle->log); - - if (ngx_threads[n].cv == NULL) { - /* fatal */ - exit(2); - } - - if (ngx_create_thread((ngx_tid_t *) &ngx_threads[n].tid, - ngx_worker_thread_cycle, - (void *) &ngx_threads[n], cycle->log) - != 0) - { - /* fatal */ - exit(2); - } - } - } - } -#endif - for ( ;; ) { if (ngx_exiting) { @@ -803,6 +754,8 @@ ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) } } + ngx_event_cancel_timers(); + if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); @@ -889,19 +842,6 @@ ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker) } } -#ifdef RLIMIT_SIGPENDING - if (ccf->rlimit_sigpending != NGX_CONF_UNSET) { - rlmt.rlim_cur = (rlim_t) ccf->rlimit_sigpending; - rlmt.rlim_max = (rlim_t) ccf->rlimit_sigpending; - - if (setrlimit(RLIMIT_SIGPENDING, &rlmt) == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, - "setrlimit(RLIMIT_SIGPENDING, %i) failed", - ccf->rlimit_sigpending); - } - } -#endif - if (geteuid() == 0) { if (setgid(ccf->group) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, @@ -1024,12 +964,6 @@ ngx_worker_process_exit(ngx_cycle_t *cycle) ngx_uint_t i; ngx_connection_t *c; -#if (NGX_THREADS) - ngx_terminate = 1; - - ngx_wakeup_worker_threads(cycle); -#endif - for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->exit_process) { ngx_modules[i]->exit_process(cycle); @@ -1065,11 +999,12 @@ ngx_worker_process_exit(ngx_cycle_t *cycle) * ngx_cycle->pool is already destroyed. */ - ngx_exit_log_file.fd = ngx_cycle->log->file->fd; + ngx_exit_log = *ngx_log_get_file_log(ngx_cycle->log); - ngx_exit_log = *ngx_cycle->log; + ngx_exit_log_file.fd = ngx_exit_log.file->fd; ngx_exit_log.file = &ngx_exit_log_file; ngx_exit_log.next = NULL; + ngx_exit_log.writer = NULL; ngx_exit_cycle.log = &ngx_exit_log; ngx_exit_cycle.files = ngx_cycle->files; @@ -1172,134 +1107,6 @@ ngx_channel_handler(ngx_event_t *ev) } -#if (NGX_THREADS) - -static void -ngx_wakeup_worker_threads(ngx_cycle_t *cycle) -{ - ngx_int_t i; - ngx_uint_t live; - - for ( ;; ) { - - live = 0; - - for (i = 0; i < ngx_threads_n; i++) { - if (ngx_threads[i].state < NGX_THREAD_EXIT) { - if (ngx_cond_signal(ngx_threads[i].cv) == NGX_ERROR) { - ngx_threads[i].state = NGX_THREAD_DONE; - - } else { - live = 1; - } - } - - if (ngx_threads[i].state == NGX_THREAD_EXIT) { - ngx_thread_join(ngx_threads[i].tid, NULL); - ngx_threads[i].state = NGX_THREAD_DONE; - } - } - - if (live == 0) { - ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, - "all worker threads are joined"); - - /* STUB */ - ngx_done_events(cycle); - ngx_mutex_destroy(ngx_event_timer_mutex); - ngx_mutex_destroy(ngx_posted_events_mutex); - - return; - } - - ngx_sched_yield(); - } -} - - -static ngx_thread_value_t -ngx_worker_thread_cycle(void *data) -{ - ngx_thread_t *thr = data; - - sigset_t set; - ngx_err_t err; - ngx_core_tls_t *tls; - ngx_cycle_t *cycle; - - cycle = (ngx_cycle_t *) ngx_cycle; - - sigemptyset(&set); - sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); - sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); - sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL)); - - err = ngx_thread_sigmask(SIG_BLOCK, &set, NULL); - if (err) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, err, - ngx_thread_sigmask_n " failed"); - return (ngx_thread_value_t) 1; - } - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, - "thread " NGX_TID_T_FMT " started", ngx_thread_self()); - - ngx_setthrtitle("worker thread"); - - tls = ngx_calloc(sizeof(ngx_core_tls_t), cycle->log); - if (tls == NULL) { - return (ngx_thread_value_t) 1; - } - - err = ngx_thread_set_tls(ngx_core_tls_key, tls); - if (err != 0) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, err, - ngx_thread_set_tls_n " failed"); - return (ngx_thread_value_t) 1; - } - - ngx_mutex_lock(ngx_posted_events_mutex); - - for ( ;; ) { - thr->state = NGX_THREAD_FREE; - - if (ngx_cond_wait(thr->cv, ngx_posted_events_mutex) == NGX_ERROR) { - return (ngx_thread_value_t) 1; - } - - if (ngx_terminate) { - thr->state = NGX_THREAD_EXIT; - - ngx_mutex_unlock(ngx_posted_events_mutex); - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, - "thread " NGX_TID_T_FMT " is done", - ngx_thread_self()); - - return (ngx_thread_value_t) 0; - } - - thr->state = NGX_THREAD_BUSY; - - if (ngx_event_thread_process_posted(cycle) == NGX_ERROR) { - return (ngx_thread_value_t) 1; - } - - if (ngx_event_thread_process_posted(cycle) == NGX_ERROR) { - return (ngx_thread_value_t) 1; - } - - if (ngx_process_changes) { - if (ngx_process_changes(cycle, 1) == NGX_ERROR) { - return (ngx_thread_value_t) 1; - } - } - } -} - -#endif - - static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data) { diff --git a/src/os/unix/ngx_process_cycle.h b/src/os/unix/ngx_process_cycle.h index 94747b8..69495d5 100644 --- a/src/os/unix/ngx_process_cycle.h +++ b/src/os/unix/ngx_process_cycle.h @@ -39,11 +39,11 @@ void ngx_single_process_cycle(ngx_cycle_t *cycle); extern ngx_uint_t ngx_process; +extern ngx_uint_t ngx_worker; extern ngx_pid_t ngx_pid; extern ngx_pid_t ngx_new_binary; extern ngx_uint_t ngx_inherited; extern ngx_uint_t ngx_daemonized; -extern ngx_uint_t ngx_threaded; extern ngx_uint_t ngx_exiting; extern sig_atomic_t ngx_reap; diff --git a/src/os/unix/ngx_pthread_thread.c b/src/os/unix/ngx_pthread_thread.c deleted file mode 100644 index 1cf31c3..0000000 --- a/src/os/unix/ngx_pthread_thread.c +++ /dev/null @@ -1,278 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - */ - - -#include -#include - - -static ngx_uint_t nthreads; -static ngx_uint_t max_threads; - - -static pthread_attr_t thr_attr; - - -ngx_err_t -ngx_create_thread(ngx_tid_t *tid, ngx_thread_value_t (*func)(void *arg), - void *arg, ngx_log_t *log) -{ - int err; - - if (nthreads >= max_threads) { - ngx_log_error(NGX_LOG_CRIT, log, 0, - "no more than %ui threads can be created", max_threads); - return NGX_ERROR; - } - - err = pthread_create(tid, &thr_attr, func, arg); - - if (err != 0) { - ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_create() failed"); - return err; - } - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, - "thread is created: " NGX_TID_T_FMT, *tid); - - nthreads++; - - return err; -} - - -ngx_int_t -ngx_init_threads(int n, size_t size, ngx_cycle_t *cycle) -{ - int err; - - max_threads = n; - - err = pthread_attr_init(&thr_attr); - - if (err != 0) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, err, - "pthread_attr_init() failed"); - return NGX_ERROR; - } - - err = pthread_attr_setstacksize(&thr_attr, size); - - if (err != 0) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, err, - "pthread_attr_setstacksize() failed"); - return NGX_ERROR; - } - - ngx_threaded = 1; - - return NGX_OK; -} - - -ngx_mutex_t * -ngx_mutex_init(ngx_log_t *log, ngx_uint_t flags) -{ - int err; - ngx_mutex_t *m; - - m = ngx_alloc(sizeof(ngx_mutex_t), log); - if (m == NULL) { - return NULL; - } - - m->log = log; - - err = pthread_mutex_init(&m->mutex, NULL); - - if (err != 0) { - ngx_log_error(NGX_LOG_ALERT, m->log, err, - "pthread_mutex_init() failed"); - return NULL; - } - - return m; -} - - -void -ngx_mutex_destroy(ngx_mutex_t *m) -{ - int err; - - err = pthread_mutex_destroy(&m->mutex); - - if (err != 0) { - ngx_log_error(NGX_LOG_ALERT, m->log, err, - "pthread_mutex_destroy(%p) failed", m); - } - - ngx_free(m); -} - - -void -ngx_mutex_lock(ngx_mutex_t *m) -{ - int err; - - if (!ngx_threaded) { - return; - } - - ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, "lock mutex %p", m); - - err = pthread_mutex_lock(&m->mutex); - - if (err != 0) { - ngx_log_error(NGX_LOG_ALERT, m->log, err, - "pthread_mutex_lock(%p) failed", m); - ngx_abort(); - } - - ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, "mutex %p is locked", m); - - return; -} - - -ngx_int_t -ngx_mutex_trylock(ngx_mutex_t *m) -{ - int err; - - if (!ngx_threaded) { - return NGX_OK; - } - - ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, "try lock mutex %p", m); - - err = pthread_mutex_trylock(&m->mutex); - - if (err == NGX_EBUSY) { - return NGX_AGAIN; - } - - if (err != 0) { - ngx_log_error(NGX_LOG_ALERT, m->log, err, - "pthread_mutex_trylock(%p) failed", m); - ngx_abort(); - } - - ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, "mutex %p is locked", m); - - return NGX_OK; -} - - -void -ngx_mutex_unlock(ngx_mutex_t *m) -{ - int err; - - if (!ngx_threaded) { - return; - } - - ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, "unlock mutex %p", m); - - err = pthread_mutex_unlock(&m->mutex); - - if (err != 0) { - ngx_log_error(NGX_LOG_ALERT, m->log, err, - "pthread_mutex_unlock(%p) failed", m); - ngx_abort(); - } - - ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, "mutex %p is unlocked", m); - - return; -} - - -ngx_cond_t * -ngx_cond_init(ngx_log_t *log) -{ - int err; - ngx_cond_t *cv; - - cv = ngx_alloc(sizeof(ngx_cond_t), log); - if (cv == NULL) { - return NULL; - } - - cv->log = log; - - err = pthread_cond_init(&cv->cond, NULL); - - if (err != 0) { - ngx_log_error(NGX_LOG_ALERT, cv->log, err, - "pthread_cond_init() failed"); - return NULL; - } - - return cv; -} - - -void -ngx_cond_destroy(ngx_cond_t *cv) -{ - int err; - - err = pthread_cond_destroy(&cv->cond); - - if (err != 0) { - ngx_log_error(NGX_LOG_ALERT, cv->log, err, - "pthread_cond_destroy(%p) failed", cv); - } - - ngx_free(cv); -} - - -ngx_int_t -ngx_cond_wait(ngx_cond_t *cv, ngx_mutex_t *m) -{ - int err; - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, "cv %p wait", cv); - - err = pthread_cond_wait(&cv->cond, &m->mutex); - - if (err != 0) { - ngx_log_error(NGX_LOG_ALERT, cv->log, err, - "pthread_cond_wait(%p) failed", cv); - return NGX_ERROR; - } - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, "cv %p is waked up", cv); - - ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, "mutex %p is locked", m); - - return NGX_OK; -} - - -ngx_int_t -ngx_cond_signal(ngx_cond_t *cv) -{ - int err; - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, "cv %p to signal", cv); - - err = pthread_cond_signal(&cv->cond); - - if (err != 0) { - ngx_log_error(NGX_LOG_ALERT, cv->log, err, - "pthread_cond_signal(%p) failed", cv); - return NGX_ERROR; - } - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, "cv %p is signaled", cv); - - return NGX_OK; -} diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c index 8836c81..3544b4b 100644 --- a/src/os/unix/ngx_readv_chain.c +++ b/src/os/unix/ngx_readv_chain.c @@ -10,23 +10,20 @@ #include -#define NGX_IOVS 16 - - -#if (NGX_HAVE_KQUEUE) - ssize_t -ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain) +ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) { u_char *prev; ssize_t n, size; ngx_err_t err; ngx_array_t vec; ngx_event_t *rev; - struct iovec *iov, iovs[NGX_IOVS]; + struct iovec *iov, iovs[NGX_IOVS_PREALLOCATE]; rev = c->read; +#if (NGX_HAVE_KQUEUE) + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "readv: eof:%d, avail:%d, err:%d", @@ -54,6 +51,8 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain) } } +#endif + prev = NULL; iov = NULL; size = 0; @@ -61,14 +60,26 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain) vec.elts = iovs; vec.nelts = 0; vec.size = sizeof(struct iovec); - vec.nalloc = NGX_IOVS; + vec.nalloc = NGX_IOVS_PREALLOCATE; vec.pool = c->pool; /* coalesce the neighbouring bufs */ while (chain) { + n = chain->buf->end - chain->buf->last; + + if (limit) { + if (size >= limit) { + break; + } + + if (size + n > limit) { + n = (ssize_t) (limit - size); + } + } + if (prev == chain->buf->last) { - iov->iov_len += chain->buf->end - chain->buf->last; + iov->iov_len += n; } else { if (vec.nelts >= IOV_MAX) { @@ -81,10 +92,10 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain) } iov->iov_base = (void *) chain->buf->last; - iov->iov_len = chain->buf->end - chain->buf->last; + iov->iov_len = n; } - size += chain->buf->end - chain->buf->last; + size += n; prev = chain->buf->end; chain = chain->next; } @@ -92,12 +103,13 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain) ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "readv: %d, last:%d", vec.nelts, iov->iov_len); - rev = c->read; - do { n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts); if (n >= 0) { + +#if (NGX_HAVE_KQUEUE) + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { rev->available -= n; @@ -137,6 +149,8 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain) return n; } +#endif /* NGX_HAVE_KQUEUE */ + if (n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) { rev->ready = 0; } @@ -170,98 +184,3 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain) return n; } - -#else /* ! NGX_HAVE_KQUEUE */ - -ssize_t -ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain) -{ - u_char *prev; - ssize_t n, size; - ngx_err_t err; - ngx_array_t vec; - ngx_event_t *rev; - struct iovec *iov, iovs[NGX_IOVS]; - - prev = NULL; - iov = NULL; - size = 0; - - vec.elts = iovs; - vec.nelts = 0; - vec.size = sizeof(struct iovec); - vec.nalloc = NGX_IOVS; - vec.pool = c->pool; - - /* coalesce the neighbouring bufs */ - - while (chain) { - if (prev == chain->buf->last) { - 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; - } - - iov->iov_base = (void *) chain->buf->last; - iov->iov_len = chain->buf->end - chain->buf->last; - } - - size += chain->buf->end - chain->buf->last; - prev = chain->buf->end; - chain = chain->next; - } - - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "readv: %d:%d", vec.nelts, iov->iov_len); - - rev = c->read; - - do { - n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts); - - if (n == 0) { - rev->ready = 0; - rev->eof = 1; - - return n; - - } else if (n > 0) { - - if (n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) { - rev->ready = 0; - } - - return n; - } - - err = ngx_socket_errno; - - if (err == NGX_EAGAIN || err == NGX_EINTR) { - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, - "readv() not ready"); - n = NGX_AGAIN; - - } else { - n = ngx_connection_error(c, err, "readv() failed"); - break; - } - - } while (err == NGX_EINTR); - - rev->ready = 0; - - if (n == NGX_ERROR) { - c->read->error = 1; - } - - return n; -} - -#endif /* NGX_HAVE_KQUEUE */ diff --git a/src/os/unix/ngx_setproctitle.h b/src/os/unix/ngx_setproctitle.h index 2323408..c363662 100644 --- a/src/os/unix/ngx_setproctitle.h +++ b/src/os/unix/ngx_setproctitle.h @@ -13,7 +13,7 @@ /* FreeBSD, NetBSD, OpenBSD */ -#define ngx_init_setproctitle(log) +#define ngx_init_setproctitle(log) NGX_OK #define ngx_setproctitle(title) setproctitle("%s", title) @@ -39,7 +39,7 @@ void ngx_setproctitle(char *title); #else -#define ngx_init_setproctitle(log) +#define ngx_init_setproctitle(log) NGX_OK #define ngx_setproctitle(title) #endif /* OSes */ diff --git a/src/os/unix/ngx_solaris_sendfilev_chain.c b/src/os/unix/ngx_solaris_sendfilev_chain.c index 37bb09d..7504239 100644 --- a/src/os/unix/ngx_solaris_sendfilev_chain.c +++ b/src/os/unix/ngx_solaris_sendfilev_chain.c @@ -35,12 +35,7 @@ ngx_chain_t *ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, #endif -#if (IOV_MAX > 64) -#define NGX_SENDFILEVECS 64 -#else -#define NGX_SENDFILEVECS IOV_MAX -#endif - +#define NGX_SENDFILEVECS NGX_IOVS_PREALLOCATE ngx_chain_t * @@ -51,10 +46,10 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) off_t size, send, prev_send, aligned, fprev; size_t sent; ssize_t n; - ngx_int_t eintr, complete; + ngx_int_t eintr; ngx_err_t err; + ngx_uint_t nsfv; sendfilevec_t *sfv, sfvs[NGX_SENDFILEVECS]; - ngx_array_t vec; ngx_event_t *wev; ngx_chain_t *cl; @@ -78,22 +73,16 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) send = 0; - vec.elts = sfvs; - vec.size = sizeof(sendfilevec_t); - vec.nalloc = NGX_SENDFILEVECS; - vec.pool = c->pool; - for ( ;; ) { fd = SFV_FD_SELF; prev = NULL; fprev = 0; sfv = NULL; eintr = 0; - complete = 0; sent = 0; prev_send = send; - vec.nelts = 0; + nsfv = 0; /* create the sendfilevec and coalesce the neighbouring bufs */ @@ -116,14 +105,11 @@ 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) { + if (nsfv == NGX_SENDFILEVECS) { break; } - sfv = ngx_array_push(&vec); - if (sfv == NULL) { - return NGX_CHAIN_ERROR; - } + sfv = &sfvs[nsfv++]; sfv->sfv_fd = SFV_FD_SELF; sfv->sfv_flag = 0; @@ -154,14 +140,11 @@ 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) { + if (nsfv == NGX_SENDFILEVECS) { break; } - sfv = ngx_array_push(&vec); - if (sfv == NULL) { - return NGX_CHAIN_ERROR; - } + sfv = &sfvs[nsfv++]; fd = cl->buf->file->fd; sfv->sfv_fd = fd; @@ -175,7 +158,7 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) } } - n = sendfilev(c->fd, vec.elts, vec.nelts, &sent); + n = sendfilev(c->fd, sfvs, nsfv, &sent); if (n == -1) { err = ngx_errno; @@ -201,54 +184,16 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfilev: %z %z", n, sent); - if (send - prev_send == (off_t) sent) { - complete = 1; - } - c->sent += sent; - for ( /* void */ ; in; in = in->next) { - - if (ngx_buf_special(in->buf)) { - continue; - } - - if (sent == 0) { - break; - } - - size = ngx_buf_size(in->buf); - - if ((off_t) sent >= size) { - sent = (size_t) ((off_t) sent - size); - - if (ngx_buf_in_memory(in->buf)) { - in->buf->pos = in->buf->last; - } - - if (in->buf->in_file) { - in->buf->file_pos = in->buf->file_last; - } - - continue; - } - - if (ngx_buf_in_memory(in->buf)) { - in->buf->pos += sent; - } - - if (in->buf->in_file) { - in->buf->file_pos += sent; - } - - break; - } + in = ngx_chain_update_sent(in, sent); if (eintr) { + send = prev_send + sent; continue; } - if (!complete) { + if (send - prev_send != (off_t) sent) { wev->ready = 0; return in; } diff --git a/src/os/unix/ngx_thread.h b/src/os/unix/ngx_thread.h index 49c5d56..1b52dd7 100644 --- a/src/os/unix/ngx_thread.h +++ b/src/os/unix/ngx_thread.h @@ -14,114 +14,57 @@ #if (NGX_THREADS) -#define NGX_MAX_THREADS 128 - -#if (NGX_USE_RFORK) -#include - - -#else /* use pthreads */ - #include -typedef pthread_t ngx_tid_t; -#define ngx_thread_self() pthread_self() -#define ngx_log_tid (int) ngx_thread_self() +typedef pthread_mutex_t ngx_thread_mutex_t; + +ngx_int_t ngx_thread_mutex_create(ngx_thread_mutex_t *mtx, ngx_log_t *log); +ngx_int_t ngx_thread_mutex_destroy(ngx_thread_mutex_t *mtx, ngx_log_t *log); +ngx_int_t ngx_thread_mutex_lock(ngx_thread_mutex_t *mtx, ngx_log_t *log); +ngx_int_t ngx_thread_mutex_unlock(ngx_thread_mutex_t *mtx, ngx_log_t *log); + + +typedef pthread_cond_t ngx_thread_cond_t; + +ngx_int_t ngx_thread_cond_create(ngx_thread_cond_t *cond, ngx_log_t *log); +ngx_int_t ngx_thread_cond_destroy(ngx_thread_cond_t *cond, ngx_log_t *log); +ngx_int_t ngx_thread_cond_signal(ngx_thread_cond_t *cond, ngx_log_t *log); +ngx_int_t ngx_thread_cond_wait(ngx_thread_cond_t *cond, ngx_thread_mutex_t *mtx, + ngx_log_t *log); + + +#if (NGX_LINUX) + +typedef pid_t ngx_tid_t; +#define NGX_TID_T_FMT "%P" + +#elif (NGX_FREEBSD) + +typedef uint32_t ngx_tid_t; +#define NGX_TID_T_FMT "%uD" + +#elif (NGX_DARWIN) + +typedef uint64_t ngx_tid_t; +#define NGX_TID_T_FMT "%uA" -#if (NGX_FREEBSD) && !(NGX_LINUXTHREADS) -#define NGX_TID_T_FMT "%p" #else -#define NGX_TID_T_FMT "%d" -#endif - -typedef pthread_key_t ngx_tls_key_t; - -#define ngx_thread_key_create(key) pthread_key_create(key, NULL) -#define ngx_thread_key_create_n "pthread_key_create()" -#define ngx_thread_set_tls pthread_setspecific -#define ngx_thread_set_tls_n "pthread_setspecific()" -#define ngx_thread_get_tls pthread_getspecific - - -#define NGX_MUTEX_LIGHT 0 - -typedef struct { - pthread_mutex_t mutex; - ngx_log_t *log; -} ngx_mutex_t; - -typedef struct { - pthread_cond_t cond; - ngx_log_t *log; -} ngx_cond_t; - -#define ngx_thread_sigmask pthread_sigmask -#define ngx_thread_sigmask_n "pthread_sigmask()" - -#define ngx_thread_join(t, p) pthread_join(t, p) - -#define ngx_setthrtitle(n) - - - -ngx_int_t ngx_mutex_trylock(ngx_mutex_t *m); -void ngx_mutex_lock(ngx_mutex_t *m); -void ngx_mutex_unlock(ngx_mutex_t *m); +typedef uint64_t ngx_tid_t; +#define NGX_TID_T_FMT "%uA" #endif +ngx_tid_t ngx_thread_tid(void); -#define ngx_thread_volatile volatile +#define ngx_log_tid ngx_thread_tid() - -typedef struct { - ngx_tid_t tid; - ngx_cond_t *cv; - ngx_uint_t state; -} ngx_thread_t; - -#define NGX_THREAD_FREE 1 -#define NGX_THREAD_BUSY 2 -#define NGX_THREAD_EXIT 3 -#define NGX_THREAD_DONE 4 - -extern ngx_int_t ngx_threads_n; -extern volatile ngx_thread_t ngx_threads[NGX_MAX_THREADS]; - - -typedef void * ngx_thread_value_t; - -ngx_int_t ngx_init_threads(int n, size_t size, ngx_cycle_t *cycle); -ngx_err_t ngx_create_thread(ngx_tid_t *tid, - ngx_thread_value_t (*func)(void *arg), void *arg, ngx_log_t *log); - -ngx_mutex_t *ngx_mutex_init(ngx_log_t *log, ngx_uint_t flags); -void ngx_mutex_destroy(ngx_mutex_t *m); - - -ngx_cond_t *ngx_cond_init(ngx_log_t *log); -void ngx_cond_destroy(ngx_cond_t *cv); -ngx_int_t ngx_cond_wait(ngx_cond_t *cv, ngx_mutex_t *m); -ngx_int_t ngx_cond_signal(ngx_cond_t *cv); - - -#else /* !NGX_THREADS */ - -#define ngx_thread_volatile +#else #define ngx_log_tid 0 #define NGX_TID_T_FMT "%d" -#define ngx_mutex_trylock(m) NGX_OK -#define ngx_mutex_lock(m) -#define ngx_mutex_unlock(m) - -#define ngx_cond_signal(cv) - -#define ngx_thread_main() 1 - #endif diff --git a/src/os/unix/ngx_thread_cond.c b/src/os/unix/ngx_thread_cond.c new file mode 100644 index 0000000..f524696 --- /dev/null +++ b/src/os/unix/ngx_thread_cond.c @@ -0,0 +1,87 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +ngx_int_t +ngx_thread_cond_create(ngx_thread_cond_t *cond, ngx_log_t *log) +{ + ngx_err_t err; + + err = pthread_cond_init(cond, NULL); + if (err == 0) { + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, + "pthread_cond_init(%p)", cond); + return NGX_OK; + } + + ngx_log_error(NGX_LOG_EMERG, log, err, "pthread_cond_init() failed"); + return NGX_ERROR; +} + + +ngx_int_t +ngx_thread_cond_destroy(ngx_thread_cond_t *cond, ngx_log_t *log) +{ + ngx_err_t err; + + err = pthread_cond_destroy(cond); + if (err == 0) { + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, + "pthread_cond_destroy(%p)", cond); + return NGX_OK; + } + + ngx_log_error(NGX_LOG_EMERG, log, err, "pthread_cond_destroy() failed"); + return NGX_ERROR; +} + + +ngx_int_t +ngx_thread_cond_signal(ngx_thread_cond_t *cond, ngx_log_t *log) +{ + ngx_err_t err; + + err = pthread_cond_signal(cond); + if (err == 0) { + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, + "pthread_cond_signal(%p)", cond); + return NGX_OK; + } + + ngx_log_error(NGX_LOG_EMERG, log, err, "pthread_cond_signal() failed"); + return NGX_ERROR; +} + + +ngx_int_t +ngx_thread_cond_wait(ngx_thread_cond_t *cond, ngx_thread_mutex_t *mtx, + ngx_log_t *log) +{ + ngx_err_t err; + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, + "pthread_cond_wait(%p) enter", cond); + + err = pthread_cond_wait(cond, mtx); + +#if 0 + ngx_time_update(); +#endif + + if (err == 0) { + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, + "pthread_cond_wait(%p) exit", cond); + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_cond_wait() failed"); + + return NGX_ERROR; +} diff --git a/src/os/unix/ngx_thread_id.c b/src/os/unix/ngx_thread_id.c new file mode 100644 index 0000000..5174f1a --- /dev/null +++ b/src/os/unix/ngx_thread_id.c @@ -0,0 +1,70 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +#if (NGX_LINUX) + +/* + * Linux thread id is a pid of thread created by clone(2), + * glibc does not provide a wrapper for gettid(). + */ + +ngx_tid_t +ngx_thread_tid(void) +{ + return syscall(SYS_gettid); +} + +#elif (NGX_FREEBSD) && (__FreeBSD_version >= 900031) + +#include + +ngx_tid_t +ngx_thread_tid(void) +{ + return pthread_getthreadid_np(); +} + +#elif (NGX_DARWIN) + +/* + * MacOSX thread has two thread ids: + * + * 1) MacOSX 10.6 (Snow Leoprad) has pthread_threadid_np() returning + * an uint64_t value, which is obtained using the __thread_selfid() + * syscall. It is a number above 300,000. + */ + +ngx_tid_t +ngx_thread_tid(void) +{ + uint64_t tid; + + (void) pthread_threadid_np(NULL, &tid); + return tid; +} + +/* + * 2) Kernel thread mach_port_t returned by pthread_mach_thread_np(). + * It is a number in range 100-100,000. + * + * return pthread_mach_thread_np(pthread_self()); + */ + +#else + +ngx_tid_t +ngx_thread_tid(void) +{ + return (uint64_t) (uintptr_t) pthread_self(); +} + +#endif diff --git a/src/os/unix/ngx_thread_mutex.c b/src/os/unix/ngx_thread_mutex.c new file mode 100644 index 0000000..6e8385e --- /dev/null +++ b/src/os/unix/ngx_thread_mutex.c @@ -0,0 +1,174 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + +#include +#include + + +/* + * All modern pthread mutex implementations try to acquire a lock + * atomically in userland before going to sleep in kernel. Some + * spins before the sleeping. + * + * In Solaris since version 8 all mutex types spin before sleeping. + * The default spin count is 1000. It can be overridden using + * _THREAD_ADAPTIVE_SPIN=100 environment variable. + * + * In MacOSX all mutex types spin to acquire a lock protecting a mutex's + * internals. If the mutex is busy, thread calls Mach semaphore_wait(). + * + * + * PTHREAD_MUTEX_NORMAL lacks deadlock detection and is the fastest + * mutex type. + * + * Linux: No spinning. The internal name PTHREAD_MUTEX_TIMED_NP + * remains from the times when pthread_mutex_timedlock() was + * non-standard extension. Alias name: PTHREAD_MUTEX_FAST_NP. + * FreeBSD: No spinning. + * + * + * PTHREAD_MUTEX_ERRORCHECK is usually as fast as PTHREAD_MUTEX_NORMAL + * yet has lightweight deadlock detection. + * + * Linux: No spinning. The internal name: PTHREAD_MUTEX_ERRORCHECK_NP. + * FreeBSD: No spinning. + * + * + * PTHREAD_MUTEX_RECURSIVE allows recursive locking. + * + * Linux: No spinning. The internal name: PTHREAD_MUTEX_RECURSIVE_NP. + * FreeBSD: No spinning. + * + * + * PTHREAD_MUTEX_ADAPTIVE_NP spins on SMP systems before sleeping. + * + * Linux: No deadlock detection. Dynamically changes a spin count + * for each mutex from 10 to 100 based on spin count taken + * previously. + * FreeBSD: Deadlock detection. The default spin count is 2000. + * It can be overriden using LIBPTHREAD_SPINLOOPS environment + * variable or by pthread_mutex_setspinloops_np(). If a lock + * is still busy, sched_yield() can be called on both UP and + * SMP systems. The default yield loop count is zero, but + * it can be set by LIBPTHREAD_YIELDLOOPS environment + * variable or by pthread_mutex_setyieldloops_np(). + * Solaris: No PTHREAD_MUTEX_ADAPTIVE_NP. + * MacOSX: No PTHREAD_MUTEX_ADAPTIVE_NP. + * + * + * PTHREAD_MUTEX_ELISION_NP is a Linux extension to elide locks using + * Intel Restricted Transactional Memory. It is the most suitable for + * rwlock pattern access because it allows simultaneous reads without lock. + * Supported since glibc 2.18. + * + * + * PTHREAD_MUTEX_DEFAULT is default mutex type. + * + * Linux: PTHREAD_MUTEX_NORMAL. + * FreeBSD: PTHREAD_MUTEX_ERRORCHECK. + * Solaris: PTHREAD_MUTEX_NORMAL. + * MacOSX: PTHREAD_MUTEX_NORMAL. + */ + + +ngx_int_t +ngx_thread_mutex_create(ngx_thread_mutex_t *mtx, ngx_log_t *log) +{ + ngx_err_t err; + pthread_mutexattr_t attr; + + err = pthread_mutexattr_init(&attr); + if (err != 0) { + ngx_log_error(NGX_LOG_EMERG, log, err, + "pthread_mutexattr_init() failed"); + return NGX_ERROR; + } + + err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); + if (err != 0) { + ngx_log_error(NGX_LOG_EMERG, log, err, + "pthread_mutexattr_settype" + "(PTHREAD_MUTEX_ERRORCHECK) failed"); + return NGX_ERROR; + } + + err = pthread_mutex_init(mtx, &attr); + if (err != 0) { + ngx_log_error(NGX_LOG_EMERG, log, err, + "pthread_mutex_init() failed"); + return NGX_ERROR; + } + + err = pthread_mutexattr_destroy(&attr); + if (err != 0) { + ngx_log_error(NGX_LOG_ALERT, log, err, + "pthread_mutexattr_destroy() failed"); + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, + "pthread_mutex_init(%p)", mtx); + return NGX_OK; +} + + +ngx_int_t +ngx_thread_mutex_destroy(ngx_thread_mutex_t *mtx, ngx_log_t *log) +{ + ngx_err_t err; + + err = pthread_mutex_destroy(mtx); + if (err != 0) { + ngx_log_error(NGX_LOG_ALERT, log, err, + "pthread_mutex_destroy() failed"); + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, + "pthread_mutex_destroy(%p)", mtx); + return NGX_OK; +} + + +ngx_int_t +ngx_thread_mutex_lock(ngx_thread_mutex_t *mtx, ngx_log_t *log) +{ + ngx_err_t err; + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, + "pthread_mutex_lock(%p) enter", mtx); + + err = pthread_mutex_lock(mtx); + if (err == 0) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_mutex_lock() failed"); + + return NGX_ERROR; +} + + +ngx_int_t +ngx_thread_mutex_unlock(ngx_thread_mutex_t *mtx, ngx_log_t *log) +{ + ngx_err_t err; + + err = pthread_mutex_unlock(mtx); + +#if 0 + ngx_time_update(); +#endif + + if (err == 0) { + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, + "pthread_mutex_unlock(%p) exit", mtx); + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_mutex_unlock() failed"); + + return NGX_ERROR; +} diff --git a/src/os/unix/ngx_user.c b/src/os/unix/ngx_user.c index 7a71203..27c76ef 100644 --- a/src/os/unix/ngx_user.c +++ b/src/os/unix/ngx_user.c @@ -31,8 +31,10 @@ ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) struct crypt_data cd; cd.initialized = 0; +#ifdef __GLIBC__ /* work around the glibc bug */ cd.current_salt[0] = ~salt[0]; +#endif value = crypt_r((char *) key, (char *) salt, &cd); @@ -62,16 +64,6 @@ ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) size_t len; ngx_err_t err; -#if (NGX_THREADS && NGX_NONREENTRANT_CRYPT) - - /* crypt() is a time consuming function, so we only try to lock */ - - if (ngx_mutex_trylock(ngx_crypt_mutex) != NGX_OK) { - return NGX_AGAIN; - } - -#endif - value = crypt((char *) key, (char *) salt); if (value) { @@ -79,25 +71,15 @@ ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) *encrypted = ngx_pnalloc(pool, len); if (*encrypted == NULL) { -#if (NGX_THREADS && NGX_NONREENTRANT_CRYPT) - ngx_mutex_unlock(ngx_crypt_mutex); -#endif return NGX_ERROR; } ngx_memcpy(*encrypted, value, len); -#if (NGX_THREADS && NGX_NONREENTRANT_CRYPT) - ngx_mutex_unlock(ngx_crypt_mutex); -#endif return NGX_OK; } err = ngx_errno; -#if (NGX_THREADS && NGX_NONREENTRANT_CRYPT) - ngx_mutex_unlock(ngx_crypt_mutex); -#endif - ngx_log_error(NGX_LOG_CRIT, pool->log, err, "crypt() failed"); return NGX_ERROR; diff --git a/src/os/unix/ngx_writev_chain.c b/src/os/unix/ngx_writev_chain.c index 805982d..e38a3aa 100644 --- a/src/os/unix/ngx_writev_chain.c +++ b/src/os/unix/ngx_writev_chain.c @@ -10,25 +10,15 @@ #include -#if (IOV_MAX > 64) -#define NGX_IOVS 64 -#else -#define NGX_IOVS IOV_MAX -#endif - - ngx_chain_t * ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { - u_char *prev; - ssize_t n, size, sent; + ssize_t n, sent; off_t send, prev_send; - ngx_uint_t eintr, complete; - ngx_err_t err; - ngx_array_t vec; ngx_chain_t *cl; ngx_event_t *wev; - struct iovec *iov, iovs[NGX_IOVS]; + ngx_iovec_t vec; + struct iovec iovs[NGX_IOVS_PREALLOCATE]; wev = c->write; @@ -55,131 +45,172 @@ ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) send = 0; - vec.elts = iovs; - vec.size = sizeof(struct iovec); - vec.nalloc = NGX_IOVS; - vec.pool = c->pool; + vec.iovs = iovs; + vec.nalloc = NGX_IOVS_PREALLOCATE; for ( ;; ) { - 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 && send < limit; cl = cl->next) { + cl = ngx_output_chain_to_iovec(&vec, in, limit - send, c->log); - if (ngx_buf_special(cl->buf)) { - continue; - } - -#if 1 - if (!ngx_buf_in_memory(cl->buf)) { - ngx_debug_point(); - } -#endif - - size = cl->buf->last - cl->buf->pos; - - if (send + size > limit) { - size = (ssize_t) (limit - send); - } - - if (prev == cl->buf->pos) { - iov->iov_len += size; - - } else { - if (vec.nelts >= IOV_MAX) { - break; - } - - iov = ngx_array_push(&vec); - if (iov == NULL) { - return NGX_CHAIN_ERROR; - } - - iov->iov_base = (void *) cl->buf->pos; - iov->iov_len = size; - } - - prev = cl->buf->pos + size; - send += size; + if (cl == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; } - n = writev(c->fd, vec.elts, vec.nelts); + if (cl && cl->buf->in_file) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "file buf in writev " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); - if (n == -1) { - err = ngx_errno; + ngx_debug_point(); - switch (err) { - case NGX_EAGAIN: - break; - - case NGX_EINTR: - eintr = 1; - break; - - default: - wev->error = 1; - (void) ngx_connection_error(c, err, "writev() failed"); - return NGX_CHAIN_ERROR; - } - - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, - "writev() not ready"); + return NGX_CHAIN_ERROR; } - sent = n > 0 ? n : 0; + send += vec.size; - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "writev: %z", sent); + n = ngx_writev(c, &vec); - if (send - prev_send == sent) { - complete = 1; + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; } + sent = (n == NGX_AGAIN) ? 0 : n; + c->sent += sent; - for (cl = in; cl; cl = cl->next) { + in = ngx_chain_update_sent(in, sent); - if (ngx_buf_special(cl->buf)) { - continue; - } - - if (sent == 0) { - break; - } - - size = cl->buf->last - cl->buf->pos; - - if (sent >= size) { - sent -= size; - cl->buf->pos = cl->buf->last; - - continue; - } - - cl->buf->pos += sent; - - break; + if (send - prev_send != sent) { + wev->ready = 0; + return in; } - if (eintr) { + if (send >= limit || in == NULL) { + return in; + } + } +} + + +ngx_chain_t * +ngx_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, size_t limit, + ngx_log_t *log) +{ + size_t total, size; + u_char *prev; + ngx_uint_t n; + struct iovec *iov; + + iov = NULL; + prev = NULL; + total = 0; + n = 0; + + for ( /* void */ ; in && total < limit; in = in->next) { + + if (ngx_buf_special(in->buf)) { continue; } - if (!complete) { - wev->ready = 0; - return cl; + if (in->buf->in_file) { + break; } - if (send >= limit || cl == NULL) { - return cl; + if (!ngx_buf_in_memory(in->buf)) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "bad buf in output chain " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + in->buf->temporary, + in->buf->recycled, + in->buf->in_file, + in->buf->start, + in->buf->pos, + in->buf->last, + in->buf->file, + in->buf->file_pos, + in->buf->file_last); + + ngx_debug_point(); + + return NGX_CHAIN_ERROR; } - in = cl; + size = in->buf->last - in->buf->pos; + + if (size > limit - total) { + size = limit - total; + } + + if (prev == in->buf->pos) { + iov->iov_len += size; + + } else { + if (n == vec->nalloc) { + break; + } + + iov = &vec->iovs[n++]; + + iov->iov_base = (void *) in->buf->pos; + iov->iov_len = size; + } + + prev = in->buf->pos + size; + total += size; } + + vec->count = n; + vec->size = total; + + return in; +} + + +ssize_t +ngx_writev(ngx_connection_t *c, ngx_iovec_t *vec) +{ + ssize_t n; + ngx_err_t err; + +eintr: + + n = writev(c->fd, vec->iovs, vec->count); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "writev: %z of %uz", n, vec->size); + + if (n == -1) { + err = ngx_errno; + + switch (err) { + case NGX_EAGAIN: + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "writev() not ready"); + return NGX_AGAIN; + + case NGX_EINTR: + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "writev() was interrupted"); + goto eintr; + + default: + c->write->error = 1; + ngx_connection_error(c, err, "writev() failed"); + return NGX_ERROR; + } + } + + return n; } diff --git a/src/os/unix/rfork_thread.S b/src/os/unix/rfork_thread.S deleted file mode 100644 index e570349..0000000 --- a/src/os/unix/rfork_thread.S +++ /dev/null @@ -1,73 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - */ - - -#include -#include - -/* - * rfork_thread(3) - rfork_thread(flags, stack, func, arg); - */ - -#define KERNCALL int $0x80 - -ENTRY(rfork_thread) - push %ebp - mov %esp, %ebp - push %esi - - mov 12(%ebp), %esi # the thread stack address - - sub $4, %esi - mov 20(%ebp), %eax # the thread argument - mov %eax, (%esi) - - sub $4, %esi - mov 16(%ebp), %eax # the thread start address - mov %eax, (%esi) - - push 8(%ebp) # rfork(2) flags - push $0 - mov $SYS_rfork, %eax - KERNCALL - jc error - - cmp $0, %edx - jne child - -parent: - add $8, %esp - pop %esi - leave - ret - -child: - mov %esi, %esp - pop %eax - call *%eax # call a thread start address ... - add $4, %esp - - push %eax - push $0 - mov $SYS_exit, %eax # ... and exit(2) after a thread would return - KERNCALL - -error: - add $8, %esp - pop %esi - leave - PIC_PROLOGUE - - /* libc's cerror: jmp PIC_PLT(HIDENAME(cerror)) */ - - push %eax - call PIC_PLT(CNAME(__error)) - pop %ecx - PIC_EPILOGUE - mov %ecx, (%eax) - mov $-1, %eax - mov $-1, %edx - ret diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c new file mode 100644 index 0000000..1c5e7a8 --- /dev/null +++ b/src/stream/ngx_stream.c @@ -0,0 +1,555 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + + +static char *ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static ngx_int_t ngx_stream_add_ports(ngx_conf_t *cf, ngx_array_t *ports, + ngx_stream_listen_t *listen); +static char *ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports); +static ngx_int_t ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *stport, + ngx_stream_conf_addr_t *addr); +#if (NGX_HAVE_INET6) +static ngx_int_t ngx_stream_add_addrs6(ngx_conf_t *cf, + ngx_stream_port_t *stport, ngx_stream_conf_addr_t *addr); +#endif +static ngx_int_t ngx_stream_cmp_conf_addrs(const void *one, const void *two); + + +ngx_uint_t ngx_stream_max_module; + + +static ngx_command_t ngx_stream_commands[] = { + + { ngx_string("stream"), + NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_stream_block, + 0, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_core_module_t ngx_stream_module_ctx = { + ngx_string("stream"), + NULL, + NULL +}; + + +ngx_module_t ngx_stream_module = { + NGX_MODULE_V1, + &ngx_stream_module_ctx, /* module context */ + ngx_stream_commands, /* module directives */ + NGX_CORE_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 char * +ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *rv; + ngx_uint_t i, m, mi, s; + ngx_conf_t pcf; + ngx_array_t ports; + ngx_stream_listen_t *listen; + ngx_stream_module_t *module; + ngx_stream_conf_ctx_t *ctx; + ngx_stream_core_srv_conf_t **cscfp; + ngx_stream_core_main_conf_t *cmcf; + + /* the main stream context */ + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_stream_conf_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + *(ngx_stream_conf_ctx_t **) conf = ctx; + + /* count the number of the stream modules and set up their indices */ + + ngx_stream_max_module = 0; + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_STREAM_MODULE) { + continue; + } + + ngx_modules[m]->ctx_index = ngx_stream_max_module++; + } + + + /* the stream main_conf context, it's the same in the all stream contexts */ + + ctx->main_conf = ngx_pcalloc(cf->pool, + sizeof(void *) * ngx_stream_max_module); + if (ctx->main_conf == NULL) { + return NGX_CONF_ERROR; + } + + + /* + * the stream null srv_conf context, it is used to merge + * the server{}s' srv_conf's + */ + + ctx->srv_conf = ngx_pcalloc(cf->pool, + sizeof(void *) * ngx_stream_max_module); + if (ctx->srv_conf == NULL) { + return NGX_CONF_ERROR; + } + + + /* + * create the main_conf's and the null srv_conf's of the all stream modules + */ + + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_STREAM_MODULE) { + continue; + } + + module = ngx_modules[m]->ctx; + mi = ngx_modules[m]->ctx_index; + + if (module->create_main_conf) { + ctx->main_conf[mi] = module->create_main_conf(cf); + if (ctx->main_conf[mi] == NULL) { + return NGX_CONF_ERROR; + } + } + + if (module->create_srv_conf) { + ctx->srv_conf[mi] = module->create_srv_conf(cf); + if (ctx->srv_conf[mi] == NULL) { + return NGX_CONF_ERROR; + } + } + } + + + /* parse inside the stream{} block */ + + pcf = *cf; + cf->ctx = ctx; + + cf->module_type = NGX_STREAM_MODULE; + cf->cmd_type = NGX_STREAM_MAIN_CONF; + rv = ngx_conf_parse(cf, NULL); + + if (rv != NGX_CONF_OK) { + *cf = pcf; + return rv; + } + + + /* init stream{} main_conf's, merge the server{}s' srv_conf's */ + + cmcf = ctx->main_conf[ngx_stream_core_module.ctx_index]; + cscfp = cmcf->servers.elts; + + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_STREAM_MODULE) { + continue; + } + + module = ngx_modules[m]->ctx; + mi = ngx_modules[m]->ctx_index; + + /* init stream{} main_conf's */ + + cf->ctx = ctx; + + if (module->init_main_conf) { + rv = module->init_main_conf(cf, ctx->main_conf[mi]); + if (rv != NGX_CONF_OK) { + *cf = pcf; + return rv; + } + } + + for (s = 0; s < cmcf->servers.nelts; s++) { + + /* merge the server{}s' srv_conf's */ + + cf->ctx = cscfp[s]->ctx; + + if (module->merge_srv_conf) { + rv = module->merge_srv_conf(cf, + ctx->srv_conf[mi], + cscfp[s]->ctx->srv_conf[mi]); + if (rv != NGX_CONF_OK) { + *cf = pcf; + return rv; + } + } + } + } + + *cf = pcf; + + + if (ngx_array_init(&ports, cf->temp_pool, 4, sizeof(ngx_stream_conf_port_t)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + listen = cmcf->listen.elts; + + for (i = 0; i < cmcf->listen.nelts; i++) { + if (ngx_stream_add_ports(cf, &ports, &listen[i]) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + return ngx_stream_optimize_servers(cf, &ports); +} + + +static ngx_int_t +ngx_stream_add_ports(ngx_conf_t *cf, ngx_array_t *ports, + ngx_stream_listen_t *listen) +{ + in_port_t p; + ngx_uint_t i; + struct sockaddr *sa; + struct sockaddr_in *sin; + ngx_stream_conf_port_t *port; + ngx_stream_conf_addr_t *addr; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + sa = (struct sockaddr *) &listen->sockaddr; + + switch (sa->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) sa; + p = sin6->sin6_port; + break; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + p = 0; + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) sa; + p = sin->sin_port; + break; + } + + port = ports->elts; + for (i = 0; i < ports->nelts; i++) { + if (p == port[i].port && sa->sa_family == port[i].family) { + + /* a port is already in the port list */ + + port = &port[i]; + goto found; + } + } + + /* add a port to the port list */ + + port = ngx_array_push(ports); + if (port == NULL) { + return NGX_ERROR; + } + + port->family = sa->sa_family; + port->port = p; + + if (ngx_array_init(&port->addrs, cf->temp_pool, 2, + sizeof(ngx_stream_conf_addr_t)) + != NGX_OK) + { + return NGX_ERROR; + } + +found: + + addr = ngx_array_push(&port->addrs); + if (addr == NULL) { + return NGX_ERROR; + } + + addr->sockaddr = (struct sockaddr *) &listen->sockaddr; + addr->socklen = listen->socklen; + 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_STREAM_SSL) + addr->ssl = listen->ssl; +#endif +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + addr->ipv6only = listen->ipv6only; +#endif + + return NGX_OK; +} + + +static char * +ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) +{ + ngx_uint_t i, p, last, bind_wildcard; + ngx_listening_t *ls; + ngx_stream_port_t *stport; + ngx_stream_conf_port_t *port; + ngx_stream_conf_addr_t *addr; + ngx_stream_core_srv_conf_t *cscf; + + port = ports->elts; + for (p = 0; p < ports->nelts; p++) { + + ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts, + sizeof(ngx_stream_conf_addr_t), ngx_stream_cmp_conf_addrs); + + addr = port[p].addrs.elts; + last = port[p].addrs.nelts; + + /* + * if there is the binding to the "*:port" then we need to bind() + * to the "*:port" only and ignore the other bindings + */ + + if (addr[last - 1].wildcard) { + addr[last - 1].bind = 1; + bind_wildcard = 1; + + } else { + bind_wildcard = 0; + } + + i = 0; + + while (i < last) { + + if (bind_wildcard && !addr[i].bind) { + i++; + continue; + } + + ls = ngx_create_listening(cf, addr[i].sockaddr, addr[i].socklen); + if (ls == NULL) { + return NGX_CONF_ERROR; + } + + ls->addr_ntop = 1; + ls->handler = ngx_stream_init_connection; + ls->pool_size = 256; + + cscf = addr->ctx->srv_conf[ngx_stream_core_module.ctx_index]; + + ls->logp = cscf->error_log; + 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 + + stport = ngx_palloc(cf->pool, sizeof(ngx_stream_port_t)); + if (stport == NULL) { + return NGX_CONF_ERROR; + } + + ls->servers = stport; + + stport->naddrs = i + 1; + + switch (ls->sockaddr->sa_family) { +#if (NGX_HAVE_INET6) + case AF_INET6: + if (ngx_stream_add_addrs6(cf, stport, addr) != NGX_OK) { + return NGX_CONF_ERROR; + } + break; +#endif + default: /* AF_INET */ + if (ngx_stream_add_addrs(cf, stport, addr) != NGX_OK) { + return NGX_CONF_ERROR; + } + break; + } + + if (ngx_clone_listening(cf, ls) != NGX_OK) { + return NGX_CONF_ERROR; + } + + addr++; + last--; + } + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *stport, + ngx_stream_conf_addr_t *addr) +{ + u_char *p; + size_t len; + ngx_uint_t i; + struct sockaddr_in *sin; + ngx_stream_in_addr_t *addrs; + u_char buf[NGX_SOCKADDR_STRLEN]; + + stport->addrs = ngx_pcalloc(cf->pool, + stport->naddrs * sizeof(ngx_stream_in_addr_t)); + if (stport->addrs == NULL) { + return NGX_ERROR; + } + + addrs = stport->addrs; + + for (i = 0; i < stport->naddrs; i++) { + + sin = (struct sockaddr_in *) addr[i].sockaddr; + addrs[i].addr = sin->sin_addr.s_addr; + + addrs[i].conf.ctx = addr[i].ctx; +#if (NGX_STREAM_SSL) + addrs[i].conf.ssl = addr[i].ssl; +#endif + + len = ngx_sock_ntop(addr[i].sockaddr, addr[i].socklen, buf, + NGX_SOCKADDR_STRLEN, 1); + + p = ngx_pnalloc(cf->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, buf, len); + + addrs[i].conf.addr_text.len = len; + addrs[i].conf.addr_text.data = p; + } + + return NGX_OK; +} + + +#if (NGX_HAVE_INET6) + +static ngx_int_t +ngx_stream_add_addrs6(ngx_conf_t *cf, ngx_stream_port_t *stport, + ngx_stream_conf_addr_t *addr) +{ + u_char *p; + size_t len; + ngx_uint_t i; + struct sockaddr_in6 *sin6; + ngx_stream_in6_addr_t *addrs6; + u_char buf[NGX_SOCKADDR_STRLEN]; + + stport->addrs = ngx_pcalloc(cf->pool, + stport->naddrs * sizeof(ngx_stream_in6_addr_t)); + if (stport->addrs == NULL) { + return NGX_ERROR; + } + + addrs6 = stport->addrs; + + for (i = 0; i < stport->naddrs; i++) { + + sin6 = (struct sockaddr_in6 *) addr[i].sockaddr; + addrs6[i].addr6 = sin6->sin6_addr; + + addrs6[i].conf.ctx = addr[i].ctx; +#if (NGX_STREAM_SSL) + addrs6[i].conf.ssl = addr[i].ssl; +#endif + + len = ngx_sock_ntop(addr[i].sockaddr, addr[i].socklen, buf, + NGX_SOCKADDR_STRLEN, 1); + + p = ngx_pnalloc(cf->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, buf, len); + + addrs6[i].conf.addr_text.len = len; + addrs6[i].conf.addr_text.data = p; + } + + return NGX_OK; +} + +#endif + + +static ngx_int_t +ngx_stream_cmp_conf_addrs(const void *one, const void *two) +{ + ngx_stream_conf_addr_t *first, *second; + + first = (ngx_stream_conf_addr_t *) one; + second = (ngx_stream_conf_addr_t *) two; + + if (first->wildcard) { + /* a wildcard must be the last resort, shift it to the end */ + return 1; + } + + if (second->wildcard) { + /* a wildcard must be the last resort, shift it to the end */ + return -1; + } + + if (first->bind && !second->bind) { + /* shift explicit bind()ed addresses to the start */ + return -1; + } + + if (!first->bind && second->bind) { + /* shift explicit bind()ed addresses to the start */ + return 1; + } + + /* do not sort by default */ + + return 0; +} diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h new file mode 100644 index 0000000..a10f68f --- /dev/null +++ b/src/stream/ngx_stream.h @@ -0,0 +1,208 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_STREAM_H_INCLUDED_ +#define _NGX_STREAM_H_INCLUDED_ + + +#include +#include + +#if (NGX_STREAM_SSL) +#include +#endif + + +typedef struct ngx_stream_session_s ngx_stream_session_t; + + +#include +#include + + +typedef struct { + void **main_conf; + void **srv_conf; +} ngx_stream_conf_ctx_t; + + +typedef struct { + u_char sockaddr[NGX_SOCKADDRLEN]; + socklen_t socklen; + + /* server ctx */ + ngx_stream_conf_ctx_t *ctx; + + unsigned bind:1; + unsigned wildcard:1; +#if (NGX_STREAM_SSL) + unsigned ssl:1; +#endif +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + unsigned ipv6only:1; +#endif +#if (NGX_HAVE_REUSEPORT) + unsigned reuseport:1; +#endif + unsigned so_keepalive:2; +#if (NGX_HAVE_KEEPALIVE_TUNABLE) + int tcp_keepidle; + int tcp_keepintvl; + int tcp_keepcnt; +#endif +} ngx_stream_listen_t; + + +typedef struct { + ngx_stream_conf_ctx_t *ctx; + ngx_str_t addr_text; +#if (NGX_STREAM_SSL) + ngx_uint_t ssl; /* unsigned ssl:1; */ +#endif +} ngx_stream_addr_conf_t; + +typedef struct { + in_addr_t addr; + ngx_stream_addr_conf_t conf; +} ngx_stream_in_addr_t; + + +#if (NGX_HAVE_INET6) + +typedef struct { + struct in6_addr addr6; + ngx_stream_addr_conf_t conf; +} ngx_stream_in6_addr_t; + +#endif + + +typedef struct { + /* ngx_stream_in_addr_t or ngx_stream_in6_addr_t */ + void *addrs; + ngx_uint_t naddrs; +} ngx_stream_port_t; + + +typedef struct { + int family; + in_port_t port; + ngx_array_t addrs; /* array of ngx_stream_conf_addr_t */ +} ngx_stream_conf_port_t; + + +typedef struct { + struct sockaddr *sockaddr; + socklen_t socklen; + + ngx_stream_conf_ctx_t *ctx; + + unsigned bind:1; + unsigned wildcard:1; +#if (NGX_STREAM_SSL) + unsigned ssl:1; +#endif +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + unsigned ipv6only:1; +#endif + unsigned so_keepalive:2; +#if (NGX_HAVE_KEEPALIVE_TUNABLE) + int tcp_keepidle; + int tcp_keepintvl; + int tcp_keepcnt; +#endif +} ngx_stream_conf_addr_t; + + +typedef struct { + ngx_array_t servers; /* ngx_stream_core_srv_conf_t */ + ngx_array_t listen; /* ngx_stream_listen_t */ +} ngx_stream_core_main_conf_t; + + +typedef void (*ngx_stream_handler_pt)(ngx_stream_session_t *s); + + +typedef struct { + ngx_stream_handler_pt handler; + ngx_stream_conf_ctx_t *ctx; + u_char *file_name; + ngx_int_t line; + ngx_log_t *error_log; +} ngx_stream_core_srv_conf_t; + + +struct ngx_stream_session_s { + uint32_t signature; /* "STRM" */ + + ngx_connection_t *connection; + + off_t received; + + ngx_log_handler_pt log_handler; + + void **ctx; + void **main_conf; + void **srv_conf; + + ngx_stream_upstream_t *upstream; +}; + + +typedef struct { + void *(*create_main_conf)(ngx_conf_t *cf); + char *(*init_main_conf)(ngx_conf_t *cf, void *conf); + + void *(*create_srv_conf)(ngx_conf_t *cf); + char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, + void *conf); +} ngx_stream_module_t; + + +#define NGX_STREAM_MODULE 0x4d525453 /* "STRM" */ + +#define NGX_STREAM_MAIN_CONF 0x02000000 +#define NGX_STREAM_SRV_CONF 0x04000000 +#define NGX_STREAM_UPS_CONF 0x08000000 + + +#define NGX_STREAM_MAIN_CONF_OFFSET offsetof(ngx_stream_conf_ctx_t, main_conf) +#define NGX_STREAM_SRV_CONF_OFFSET offsetof(ngx_stream_conf_ctx_t, srv_conf) + + +#define ngx_stream_get_module_ctx(s, module) (s)->ctx[module.ctx_index] +#define ngx_stream_set_ctx(s, c, module) s->ctx[module.ctx_index] = c; +#define ngx_stream_delete_ctx(s, module) s->ctx[module.ctx_index] = NULL; + + +#define ngx_stream_get_module_main_conf(s, module) \ + (s)->main_conf[module.ctx_index] +#define ngx_stream_get_module_srv_conf(s, module) \ + (s)->srv_conf[module.ctx_index] + +#define ngx_stream_conf_get_module_main_conf(cf, module) \ + ((ngx_stream_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index] +#define ngx_stream_conf_get_module_srv_conf(cf, module) \ + ((ngx_stream_conf_ctx_t *) cf->ctx)->srv_conf[module.ctx_index] + +#define ngx_stream_cycle_get_module_main_conf(cycle, module) \ + (cycle->conf_ctx[ngx_stream_module.index] ? \ + ((ngx_stream_conf_ctx_t *) cycle->conf_ctx[ngx_stream_module.index]) \ + ->main_conf[module.ctx_index]: \ + NULL) + + +void ngx_stream_init_connection(ngx_connection_t *c); +void ngx_stream_close_connection(ngx_connection_t *c); + + +extern ngx_module_t ngx_stream_module; +extern ngx_uint_t ngx_stream_max_module; +extern ngx_module_t ngx_stream_core_module; + + +#endif /* _NGX_STREAM_H_INCLUDED_ */ diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c new file mode 100644 index 0000000..c8d8e66 --- /dev/null +++ b/src/stream/ngx_stream_core_module.c @@ -0,0 +1,507 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +static void *ngx_stream_core_create_main_conf(ngx_conf_t *cf); +static void *ngx_stream_core_create_srv_conf(ngx_conf_t *cf); +static char *ngx_stream_core_merge_srv_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_stream_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_core_server(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_command_t ngx_stream_core_commands[] = { + + { ngx_string("server"), + NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_stream_core_server, + 0, + 0, + NULL }, + + { ngx_string("listen"), + NGX_STREAM_SRV_CONF|NGX_CONF_1MORE, + ngx_stream_core_listen, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("error_log"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE, + ngx_stream_core_error_log, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_core_module_ctx = { + ngx_stream_core_create_main_conf, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_stream_core_create_srv_conf, /* create server configuration */ + ngx_stream_core_merge_srv_conf /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_core_module = { + NGX_MODULE_V1, + &ngx_stream_core_module_ctx, /* module context */ + ngx_stream_core_commands, /* module directives */ + NGX_STREAM_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 void * +ngx_stream_core_create_main_conf(ngx_conf_t *cf) +{ + ngx_stream_core_main_conf_t *cmcf; + + cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_core_main_conf_t)); + if (cmcf == NULL) { + return NULL; + } + + if (ngx_array_init(&cmcf->servers, cf->pool, 4, + sizeof(ngx_stream_core_srv_conf_t *)) + != NGX_OK) + { + return NULL; + } + + if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_stream_listen_t)) + != NGX_OK) + { + return NULL; + } + + return cmcf; +} + + +static void * +ngx_stream_core_create_srv_conf(ngx_conf_t *cf) +{ + ngx_stream_core_srv_conf_t *cscf; + + cscf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_core_srv_conf_t)); + if (cscf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * cscf->handler = NULL; + * cscf->error_log = NULL; + */ + + cscf->file_name = cf->conf_file->file.name.data; + cscf->line = cf->conf_file->line; + + return cscf; +} + + +static char * +ngx_stream_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_stream_core_srv_conf_t *prev = parent; + ngx_stream_core_srv_conf_t *conf = child; + + if (conf->handler == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no handler for server in %s:%ui", + conf->file_name, conf->line); + return NGX_CONF_ERROR; + } + + if (conf->error_log == NULL) { + if (prev->error_log) { + conf->error_log = prev->error_log; + } else { + conf->error_log = &cf->cycle->new_log; + } + } + + return NGX_CONF_OK; +} + + +static char * +ngx_stream_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_core_srv_conf_t *cscf = conf; + + return ngx_log_set_log(cf, &cscf->error_log); +} + + +static char * +ngx_stream_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *rv; + void *mconf; + ngx_uint_t m; + ngx_conf_t pcf; + ngx_stream_module_t *module; + ngx_stream_conf_ctx_t *ctx, *stream_ctx; + ngx_stream_core_srv_conf_t *cscf, **cscfp; + ngx_stream_core_main_conf_t *cmcf; + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_stream_conf_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + stream_ctx = cf->ctx; + ctx->main_conf = stream_ctx->main_conf; + + /* the server{}'s srv_conf */ + + ctx->srv_conf = ngx_pcalloc(cf->pool, + sizeof(void *) * ngx_stream_max_module); + if (ctx->srv_conf == NULL) { + return NGX_CONF_ERROR; + } + + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_STREAM_MODULE) { + continue; + } + + module = ngx_modules[m]->ctx; + + if (module->create_srv_conf) { + mconf = module->create_srv_conf(cf); + if (mconf == NULL) { + return NGX_CONF_ERROR; + } + + ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf; + } + } + + /* the server configuration context */ + + cscf = ctx->srv_conf[ngx_stream_core_module.ctx_index]; + cscf->ctx = ctx; + + cmcf = ctx->main_conf[ngx_stream_core_module.ctx_index]; + + cscfp = ngx_array_push(&cmcf->servers); + if (cscfp == NULL) { + return NGX_CONF_ERROR; + } + + *cscfp = cscf; + + + /* parse inside server{} */ + + pcf = *cf; + cf->ctx = ctx; + cf->cmd_type = NGX_STREAM_SRV_CONF; + + rv = ngx_conf_parse(cf, NULL); + + *cf = pcf; + + return rv; +} + + +static char * +ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + size_t len, off; + in_port_t port; + ngx_str_t *value; + ngx_url_t u; + ngx_uint_t i; + struct sockaddr *sa; + struct sockaddr_in *sin; + ngx_stream_listen_t *ls; + ngx_stream_core_main_conf_t *cmcf; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + value = cf->args->elts; + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url = value[1]; + u.listen = 1; + + if (ngx_parse_url(cf->pool, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in \"%V\" of the \"listen\" directive", + u.err, &u.url); + } + + return NGX_CONF_ERROR; + } + + cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); + + ls = cmcf->listen.elts; + + for (i = 0; i < cmcf->listen.nelts; i++) { + + sa = (struct sockaddr *) ls[i].sockaddr; + + if (sa->sa_family != u.family) { + continue; + } + + switch (sa->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + off = offsetof(struct sockaddr_in6, sin6_addr); + len = 16; + sin6 = (struct sockaddr_in6 *) sa; + port = sin6->sin6_port; + break; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + off = offsetof(struct sockaddr_un, sun_path); + len = sizeof(((struct sockaddr_un *) sa)->sun_path); + port = 0; + break; +#endif + + default: /* AF_INET */ + off = offsetof(struct sockaddr_in, sin_addr); + len = 4; + sin = (struct sockaddr_in *) sa; + port = sin->sin_port; + break; + } + + if (ngx_memcmp(ls[i].sockaddr + off, u.sockaddr + off, len) != 0) { + continue; + } + + if (port != u.port) { + continue; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate \"%V\" address and port pair", &u.url); + return NGX_CONF_ERROR; + } + + ls = ngx_array_push(&cmcf->listen); + if (ls == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(ls, sizeof(ngx_stream_listen_t)); + + ngx_memcpy(ls->sockaddr, u.sockaddr, u.socklen); + + ls->socklen = u.socklen; + ls->wildcard = u.wildcard; + ls->ctx = cf->ctx; + +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + ls->ipv6only = 1; +#endif + + for (i = 2; i < cf->args->nelts; i++) { + + if (ngx_strcmp(value[i].data, "bind") == 0) { + ls->bind = 1; + continue; + } + + if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) { +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + struct sockaddr *sa; + u_char buf[NGX_SOCKADDR_STRLEN]; + + sa = (struct sockaddr *) ls->sockaddr; + + if (sa->sa_family == AF_INET6) { + + if (ngx_strcmp(&value[i].data[10], "n") == 0) { + ls->ipv6only = 1; + + } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) { + ls->ipv6only = 0; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid ipv6only flags \"%s\"", + &value[i].data[9]); + return NGX_CONF_ERROR; + } + + ls->bind = 1; + + } else { + len = ngx_sock_ntop(sa, ls->socklen, buf, + NGX_SOCKADDR_STRLEN, 1); + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "ipv6only is not supported " + "on addr \"%*s\", ignored", len, buf); + } + + continue; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bind ipv6only is not supported " + "on this platform"); + return NGX_CONF_ERROR; +#endif + } + + if (ngx_strcmp(value[i].data, "reuseport") == 0) { +#if (NGX_HAVE_REUSEPORT) + ls->reuseport = 1; + ls->bind = 1; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "reuseport is not supported " + "on this platform, ignored"); +#endif + continue; + } + + if (ngx_strcmp(value[i].data, "ssl") == 0) { +#if (NGX_STREAM_SSL) + ls->ssl = 1; + continue; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the \"ssl\" parameter requires " + "ngx_stream_ssl_module"); + return NGX_CONF_ERROR; +#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; + } + + return NGX_CONF_OK; +} diff --git a/src/stream/ngx_stream_handler.c b/src/stream/ngx_stream_handler.c new file mode 100644 index 0000000..2be5183 --- /dev/null +++ b/src/stream/ngx_stream_handler.c @@ -0,0 +1,296 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + + +static u_char *ngx_stream_log_error(ngx_log_t *log, u_char *buf, size_t len); +static void ngx_stream_init_session(ngx_connection_t *c); + +#if (NGX_STREAM_SSL) +static void ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c); +static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c); +#endif + + +void +ngx_stream_init_connection(ngx_connection_t *c) +{ + u_char text[NGX_SOCKADDR_STRLEN]; + size_t len; + ngx_uint_t i; + struct sockaddr *sa; + ngx_stream_port_t *port; + struct sockaddr_in *sin; + ngx_stream_in_addr_t *addr; + ngx_stream_session_t *s; + ngx_stream_addr_conf_t *addr_conf; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; + ngx_stream_in6_addr_t *addr6; +#endif + ngx_stream_core_srv_conf_t *cscf; + + /* find the server configuration for the address:port */ + + port = c->listening->servers; + + if (port->naddrs > 1) { + + /* + * There are several addresses on this port and one of them + * is the "*:port" wildcard so getsockname() is needed to determine + * the server address. + * + * AcceptEx() already gave this address. + */ + + if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { + ngx_stream_close_connection(c); + return; + } + + sa = c->local_sockaddr; + + switch (sa->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) sa; + + addr6 = port->addrs; + + /* the last address is "*" */ + + for (i = 0; i < port->naddrs - 1; i++) { + if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) { + break; + } + } + + addr_conf = &addr6[i].conf; + + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) sa; + + addr = port->addrs; + + /* the last address is "*" */ + + for (i = 0; i < port->naddrs - 1; i++) { + if (addr[i].addr == sin->sin_addr.s_addr) { + break; + } + } + + addr_conf = &addr[i].conf; + + break; + } + + } else { + switch (c->local_sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + addr6 = port->addrs; + addr_conf = &addr6[0].conf; + break; +#endif + + default: /* AF_INET */ + addr = port->addrs; + addr_conf = &addr[0].conf; + break; + } + } + + s = ngx_pcalloc(c->pool, sizeof(ngx_stream_session_t)); + if (s == NULL) { + ngx_stream_close_connection(c); + return; + } + + s->signature = NGX_STREAM_MODULE; + s->main_conf = addr_conf->ctx->main_conf; + s->srv_conf = addr_conf->ctx->srv_conf; + + s->connection = c; + c->data = s; + + cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); + + ngx_set_connection_log(c, cscf->error_log); + + len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1); + + ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %*s connected to %V", + c->number, len, text, &addr_conf->addr_text); + + c->log->connection = c->number; + c->log->handler = ngx_stream_log_error; + c->log->data = s; + c->log->action = "initializing connection"; + c->log_error = NGX_ERROR_INFO; + +#if (NGX_STREAM_SSL) + { + ngx_stream_ssl_conf_t *sslcf; + + sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); + + if (addr_conf->ssl) { + c->log->action = "SSL handshaking"; + + if (sslcf->ssl.ctx == NULL) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no \"ssl_certificate\" is defined " + "in server listening on SSL port"); + ngx_stream_close_connection(c); + return; + } + + ngx_stream_ssl_init_connection(&sslcf->ssl, c); + return; + } + } +#endif + + ngx_stream_init_session(c); +} + + +static void +ngx_stream_init_session(ngx_connection_t *c) +{ + ngx_stream_session_t *s; + ngx_stream_core_srv_conf_t *cscf; + + s = c->data; + c->log->action = "handling client connection"; + + cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); + + s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_stream_max_module); + if (s->ctx == NULL) { + ngx_stream_close_connection(c); + return; + } + + cscf->handler(s); +} + + +#if (NGX_STREAM_SSL) + +static void +ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c) +{ + ngx_stream_session_t *s; + ngx_stream_ssl_conf_t *sslcf; + + if (ngx_ssl_create_connection(ssl, c, 0) == NGX_ERROR) { + ngx_stream_close_connection(c); + return; + } + + if (ngx_ssl_handshake(c) == NGX_AGAIN) { + + s = c->data; + + sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); + + ngx_add_timer(c->read, sslcf->handshake_timeout); + + c->ssl->handler = ngx_stream_ssl_handshake_handler; + + return; + } + + ngx_stream_ssl_handshake_handler(c); +} + + +static void +ngx_stream_ssl_handshake_handler(ngx_connection_t *c) +{ + if (!c->ssl->handshaked) { + ngx_stream_close_connection(c); + return; + } + + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + ngx_stream_init_session(c); +} + +#endif + + +void +ngx_stream_close_connection(ngx_connection_t *c) +{ + ngx_pool_t *pool; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "close stream connection: %d", c->fd); + +#if (NGX_STREAM_SSL) + + if (c->ssl) { + if (ngx_ssl_shutdown(c) == NGX_AGAIN) { + c->ssl->handler = ngx_stream_close_connection; + return; + } + } + +#endif + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_active, -1); +#endif + + pool = c->pool; + + ngx_close_connection(c); + + ngx_destroy_pool(pool); +} + + +static u_char * +ngx_stream_log_error(ngx_log_t *log, u_char *buf, size_t len) +{ + u_char *p; + ngx_stream_session_t *s; + + if (log->action) { + p = ngx_snprintf(buf, len, " while %s", log->action); + len -= p - buf; + buf = p; + } + + s = log->data; + + p = ngx_snprintf(buf, len, ", client: %V, server: %V", + &s->connection->addr_text, + &s->connection->listening->addr_text); + + if (s->log_handler) { + return s->log_handler(log, p, len); + } + + return p; +} diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c new file mode 100644 index 0000000..a34b7ce --- /dev/null +++ b/src/stream/ngx_stream_proxy_module.c @@ -0,0 +1,1290 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef void (*ngx_stream_proxy_handler_pt)(ngx_stream_session_t *s); + + +typedef struct { + ngx_msec_t connect_timeout; + ngx_msec_t timeout; + ngx_msec_t next_upstream_timeout; + size_t downstream_buf_size; + size_t upstream_buf_size; + ngx_uint_t next_upstream_tries; + ngx_flag_t next_upstream; + +#if (NGX_STREAM_SSL) + ngx_flag_t ssl_enable; + ngx_flag_t ssl_session_reuse; + ngx_uint_t ssl_protocols; + ngx_str_t ssl_ciphers; + ngx_str_t ssl_name; + ngx_flag_t ssl_server_name; + + ngx_flag_t ssl_verify; + ngx_uint_t ssl_verify_depth; + ngx_str_t ssl_trusted_certificate; + ngx_str_t ssl_crl; + ngx_str_t ssl_certificate; + ngx_str_t ssl_certificate_key; + ngx_array_t *ssl_passwords; + + ngx_ssl_t *ssl; +#endif + + ngx_stream_upstream_srv_conf_t *upstream; +} ngx_stream_proxy_srv_conf_t; + + +static void ngx_stream_proxy_handler(ngx_stream_session_t *s); +static void ngx_stream_proxy_connect(ngx_stream_session_t *s); +static void ngx_stream_proxy_init_upstream(ngx_stream_session_t *s); +static void ngx_stream_proxy_upstream_handler(ngx_event_t *ev); +static void ngx_stream_proxy_downstream_handler(ngx_event_t *ev); +static void ngx_stream_proxy_connect_handler(ngx_event_t *ev); +static ngx_int_t ngx_stream_proxy_test_connect(ngx_connection_t *c); +static ngx_int_t ngx_stream_proxy_process(ngx_stream_session_t *s, + ngx_uint_t from_upstream, ngx_uint_t do_write); +static void ngx_stream_proxy_next_upstream(ngx_stream_session_t *s); +static void ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_int_t rc); +static u_char *ngx_stream_proxy_log_error(ngx_log_t *log, u_char *buf, + size_t len); + +static void *ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf); +static char *ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_stream_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + +#if (NGX_STREAM_SSL) + +static char *ngx_stream_proxy_ssl_password_file(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static void ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s); +static void ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc); +static ngx_int_t ngx_stream_proxy_ssl_name(ngx_stream_session_t *s); +static ngx_int_t ngx_stream_proxy_set_ssl(ngx_conf_t *cf, + ngx_stream_proxy_srv_conf_t *pscf); + + +static ngx_conf_bitmask_t ngx_stream_proxy_ssl_protocols[] = { + { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, + { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, + { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, + { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 }, + { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 }, + { ngx_null_string, 0 } +}; + +#endif + + +static ngx_command_t ngx_stream_proxy_commands[] = { + + { ngx_string("proxy_pass"), + NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_stream_proxy_pass, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("proxy_connect_timeout"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, connect_timeout), + NULL }, + + { ngx_string("proxy_timeout"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, timeout), + NULL }, + + { ngx_string("proxy_downstream_buffer"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, downstream_buf_size), + NULL }, + + { ngx_string("proxy_upstream_buffer"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, upstream_buf_size), + NULL }, + + { ngx_string("proxy_next_upstream"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, next_upstream), + NULL }, + + { ngx_string("proxy_next_upstream_tries"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, next_upstream_tries), + NULL }, + + { ngx_string("proxy_next_upstream_timeout"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, next_upstream_timeout), + NULL }, + +#if (NGX_STREAM_SSL) + + { ngx_string("proxy_ssl"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, ssl_enable), + NULL }, + + { ngx_string("proxy_ssl_session_reuse"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, ssl_session_reuse), + NULL }, + + { ngx_string("proxy_ssl_protocols"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE, + ngx_conf_set_bitmask_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, ssl_protocols), + &ngx_stream_proxy_ssl_protocols }, + + { ngx_string("proxy_ssl_ciphers"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, ssl_ciphers), + NULL }, + + { ngx_string("proxy_ssl_name"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, ssl_name), + NULL }, + + { ngx_string("proxy_ssl_server_name"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, ssl_server_name), + NULL }, + + { ngx_string("proxy_ssl_verify"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, ssl_verify), + NULL }, + + { ngx_string("proxy_ssl_verify_depth"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, ssl_verify_depth), + NULL }, + + { ngx_string("proxy_ssl_trusted_certificate"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, ssl_trusted_certificate), + NULL }, + + { ngx_string("proxy_ssl_crl"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, ssl_crl), + NULL }, + + { ngx_string("proxy_ssl_certificate"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, ssl_certificate), + NULL }, + + { ngx_string("proxy_ssl_certificate_key"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, ssl_certificate_key), + NULL }, + + { ngx_string("proxy_ssl_password_file"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_stream_proxy_ssl_password_file, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + +#endif + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_proxy_module_ctx = { + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_stream_proxy_create_srv_conf, /* create server configuration */ + ngx_stream_proxy_merge_srv_conf /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_proxy_module = { + NGX_MODULE_V1, + &ngx_stream_proxy_module_ctx, /* module context */ + ngx_stream_proxy_commands, /* module directives */ + NGX_STREAM_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 void +ngx_stream_proxy_handler(ngx_stream_session_t *s) +{ + u_char *p; + ngx_connection_t *c; + ngx_stream_upstream_t *u; + ngx_stream_proxy_srv_conf_t *pscf; + ngx_stream_upstream_srv_conf_t *uscf; + + c = s->connection; + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, + "proxy connection handler"); + + u = ngx_pcalloc(c->pool, sizeof(ngx_stream_upstream_t)); + if (u == NULL) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + s->upstream = u; + + s->log_handler = ngx_stream_proxy_log_error; + + u->peer.log = c->log; + u->peer.log_error = NGX_ERROR_ERR; + + uscf = pscf->upstream; + + if (uscf->peer.init(s, uscf) != NGX_OK) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + u->peer.start_time = ngx_current_msec; + + if (pscf->next_upstream_tries + && u->peer.tries > pscf->next_upstream_tries) + { + u->peer.tries = pscf->next_upstream_tries; + } + + p = ngx_pnalloc(c->pool, pscf->downstream_buf_size); + if (p == NULL) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + u->downstream_buf.start = p; + u->downstream_buf.end = p + pscf->downstream_buf_size; + u->downstream_buf.pos = p; + u->downstream_buf.last = p; + + c->write->handler = ngx_stream_proxy_downstream_handler; + c->read->handler = ngx_stream_proxy_downstream_handler; + + if (ngx_stream_proxy_process(s, 0, 0) != NGX_OK) { + return; + } + + ngx_stream_proxy_connect(s); +} + + +static void +ngx_stream_proxy_connect(ngx_stream_session_t *s) +{ + ngx_int_t rc; + ngx_connection_t *c, *pc; + ngx_stream_upstream_t *u; + ngx_stream_proxy_srv_conf_t *pscf; + + c = s->connection; + + c->log->action = "connecting to upstream"; + + u = s->upstream; + + rc = ngx_event_connect_peer(&u->peer); + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "proxy connect: %i", rc); + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + + if (rc == NGX_ERROR) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + if (rc == NGX_BUSY) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, "no live upstreams"); + ngx_stream_proxy_finalize(s, NGX_DECLINED); + return; + } + + if (rc == NGX_DECLINED) { + ngx_stream_proxy_next_upstream(s); + return; + } + + /* rc == NGX_OK || rc == NGX_AGAIN || rc == NGX_DONE */ + + pc = u->peer.connection; + + pc->data = s; + pc->log = c->log; + pc->pool = c->pool; + pc->read->log = c->log; + pc->write->log = c->log; + + if (rc != NGX_AGAIN) { + ngx_stream_proxy_init_upstream(s); + return; + } + + pc->read->handler = ngx_stream_proxy_connect_handler; + pc->write->handler = ngx_stream_proxy_connect_handler; + + ngx_add_timer(pc->write, pscf->connect_timeout); +} + + +static void +ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) +{ + u_char *p; + ngx_connection_t *c, *pc; + ngx_log_handler_pt handler; + ngx_stream_upstream_t *u; + ngx_stream_proxy_srv_conf_t *pscf; + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + + u = s->upstream; + + pc = u->peer.connection; + +#if (NGX_STREAM_SSL) + if (pscf->ssl && pc->ssl == NULL) { + ngx_stream_proxy_ssl_init_connection(s); + return; + } +#endif + + c = s->connection; + + if (c->log->log_level >= NGX_LOG_INFO) { + ngx_str_t s; + u_char addr[NGX_SOCKADDR_STRLEN]; + + s.len = NGX_SOCKADDR_STRLEN; + s.data = addr; + + if (ngx_connection_local_sockaddr(pc, &s, 1) == NGX_OK) { + handler = c->log->handler; + c->log->handler = NULL; + + ngx_log_error(NGX_LOG_INFO, c->log, 0, "proxy %V connected to %V", + &s, u->peer.name); + + c->log->handler = handler; + } + } + + c->log->action = "proxying connection"; + + p = ngx_pnalloc(c->pool, pscf->upstream_buf_size); + if (p == NULL) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + u->upstream_buf.start = p; + u->upstream_buf.end = p + pscf->upstream_buf_size; + u->upstream_buf.pos = p; + u->upstream_buf.last = p; + + pc->read->handler = ngx_stream_proxy_upstream_handler; + pc->write->handler = ngx_stream_proxy_upstream_handler; + + if (ngx_stream_proxy_process(s, 1, 0) != NGX_OK) { + return; + } + + ngx_stream_proxy_process(s, 0, 1); +} + + +#if (NGX_STREAM_SSL) + +static char * +ngx_stream_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_stream_proxy_srv_conf_t *pscf = conf; + + ngx_str_t *value; + + if (pscf->ssl_passwords != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + pscf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); + + if (pscf->ssl_passwords == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static void +ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s) +{ + ngx_int_t rc; + ngx_connection_t *pc; + ngx_stream_upstream_t *u; + ngx_stream_proxy_srv_conf_t *pscf; + + u = s->upstream; + + pc = u->peer.connection; + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + + if (ngx_ssl_create_connection(pscf->ssl, pc, NGX_SSL_BUFFER|NGX_SSL_CLIENT) + != NGX_OK) + { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + if (pscf->ssl_server_name || pscf->ssl_verify) { + if (ngx_stream_proxy_ssl_name(s) != NGX_OK) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + } + + if (pscf->ssl_session_reuse) { + if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + } + + s->connection->log->action = "SSL handshaking to upstream"; + + rc = ngx_ssl_handshake(pc); + + if (rc == NGX_AGAIN) { + + if (!pc->write->timer_set) { + ngx_add_timer(pc->write, pscf->connect_timeout); + } + + pc->ssl->handler = ngx_stream_proxy_ssl_handshake; + return; + } + + ngx_stream_proxy_ssl_handshake(pc); +} + + +static void +ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc) +{ + long rc; + ngx_stream_session_t *s; + ngx_stream_upstream_t *u; + ngx_stream_proxy_srv_conf_t *pscf; + + s = pc->data; + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + + if (pc->ssl->handshaked) { + + if (pscf->ssl_verify) { + rc = SSL_get_verify_result(pc->ssl->connection); + + if (rc != X509_V_OK) { + ngx_log_error(NGX_LOG_ERR, pc->log, 0, + "upstream SSL certificate verify error: (%l:%s)", + rc, X509_verify_cert_error_string(rc)); + goto failed; + } + + u = s->upstream; + + if (ngx_ssl_check_host(pc, &u->ssl_name) != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, pc->log, 0, + "upstream SSL certificate does not match \"%V\"", + &u->ssl_name); + goto failed; + } + } + + if (pscf->ssl_session_reuse) { + u = s->upstream; + u->peer.save_session(&u->peer, u->peer.data); + } + + ngx_stream_proxy_init_upstream(s); + + return; + } + +failed: + + ngx_stream_proxy_next_upstream(s); +} + + +static ngx_int_t +ngx_stream_proxy_ssl_name(ngx_stream_session_t *s) +{ + u_char *p, *last; + ngx_str_t name; + ngx_stream_upstream_t *u; + ngx_stream_proxy_srv_conf_t *pscf; + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + + u = s->upstream; + + name = pscf->ssl_name; + + if (name.len == 0) { + name = pscf->upstream->host; + } + + if (name.len == 0) { + goto done; + } + + /* + * ssl name here may contain port, strip it for compatibility + * with the http module + */ + + p = name.data; + last = name.data + name.len; + + if (*p == '[') { + p = ngx_strlchr(p, last, ']'); + + if (p == NULL) { + p = name.data; + } + } + + p = ngx_strlchr(p, last, ':'); + + if (p != NULL) { + name.len = p - name.data; + } + + if (!pscf->ssl_server_name) { + goto done; + } + +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + + /* as per RFC 6066, literal IPv4 and IPv6 addresses are not permitted */ + + if (name.len == 0 || *name.data == '[') { + goto done; + } + + if (ngx_inet_addr(name.data, name.len) != INADDR_NONE) { + goto done; + } + + /* + * SSL_set_tlsext_host_name() needs a null-terminated string, + * hence we explicitly null-terminate name here + */ + + p = ngx_pnalloc(s->connection->pool, name.len + 1); + if (p == NULL) { + return NGX_ERROR; + } + + (void) ngx_cpystrn(p, name.data, name.len + 1); + + name.data = p; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "upstream SSL server name: \"%s\"", name.data); + + if (SSL_set_tlsext_host_name(u->peer.connection->ssl->connection, name.data) + == 0) + { + ngx_ssl_error(NGX_LOG_ERR, s->connection->log, 0, + "SSL_set_tlsext_host_name(\"%s\") failed", name.data); + return NGX_ERROR; + } + +#endif + +done: + + u->ssl_name = name; + + return NGX_OK; +} + +#endif + + +static void +ngx_stream_proxy_downstream_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + ngx_stream_session_t *s; + ngx_stream_upstream_t *u; + + c = ev->data; + s = c->data; + + if (ev->timedout) { + ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); + ngx_stream_proxy_finalize(s, NGX_DECLINED); + return; + } + + u = s->upstream; + + if (!ev->write) { + ngx_stream_proxy_process(s, 0, 0); + + } else if (u->upstream_buf.start) { + ngx_stream_proxy_process(s, 1, 1); + } +} + + +static void +ngx_stream_proxy_upstream_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + ngx_stream_session_t *s; + ngx_stream_upstream_t *u; + + c = ev->data; + s = c->data; + + u = s->upstream; + + if (ev->write) { + ngx_stream_proxy_process(s, 0, 1); + + } else if (u->upstream_buf.start) { + ngx_stream_proxy_process(s, 1, 0); + } +} + + +static void +ngx_stream_proxy_connect_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + ngx_stream_session_t *s; + + c = ev->data; + s = c->data; + + if (ev->timedout) { + ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT, "upstream timed out"); + ngx_stream_proxy_next_upstream(s); + return; + } + + ngx_del_timer(c->write); + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream proxy connect upstream"); + + if (ngx_stream_proxy_test_connect(c) != NGX_OK) { + ngx_stream_proxy_next_upstream(s); + return; + } + + ngx_stream_proxy_init_upstream(s); +} + + +static ngx_int_t +ngx_stream_proxy_test_connect(ngx_connection_t *c) +{ + int err; + socklen_t len; + +#if (NGX_HAVE_KQUEUE) + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + err = c->write->kq_errno ? c->write->kq_errno : c->read->kq_errno; + + if (err) { + (void) ngx_connection_error(c, err, + "kevent() reported that connect() failed"); + return NGX_ERROR; + } + + } else +#endif + { + err = 0; + len = sizeof(int); + + /* + * BSDs and Linux return 0 and set a pending error in err + * Solaris returns -1 and sets errno + */ + + if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) + == -1) + { + err = ngx_socket_errno; + } + + if (err) { + (void) ngx_connection_error(c, err, "connect() failed"); + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, + ngx_uint_t do_write) +{ + size_t size; + ssize_t n; + ngx_buf_t *b; + ngx_uint_t flags; + ngx_connection_t *c, *pc, *src, *dst; + ngx_log_handler_pt handler; + ngx_stream_upstream_t *u; + ngx_stream_proxy_srv_conf_t *pscf; + + u = s->upstream; + + c = s->connection; + pc = u->upstream_buf.start ? u->peer.connection : NULL; + + if (from_upstream) { + src = pc; + dst = c; + b = &u->upstream_buf; + + } else { + src = c; + dst = pc; + b = &u->downstream_buf; + } + + for ( ;; ) { + + if (do_write) { + + size = b->last - b->pos; + + if (size && dst && dst->write->ready) { + + n = dst->send(dst, b->pos, size); + + if (n == NGX_ERROR) { + ngx_stream_proxy_finalize(s, NGX_DECLINED); + return NGX_ERROR; + } + + if (n > 0) { + b->pos += n; + + if (b->pos == b->last) { + b->pos = b->start; + b->last = b->start; + } + } + } + } + + size = b->end - b->last; + + if (size && src->read->ready) { + + n = src->recv(src, b->last, size); + + if (n == NGX_AGAIN || n == 0) { + break; + } + + if (n > 0) { + if (from_upstream) { + u->received += n; + + } else { + s->received += n; + } + + do_write = 1; + b->last += n; + continue; + } + + if (n == NGX_ERROR) { + src->read->eof = 1; + } + } + + break; + } + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + + if (src->read->eof && (b->pos == b->last || (dst && dst->read->eof))) { + handler = c->log->handler; + c->log->handler = NULL; + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "%s disconnected" + ", bytes from/to client:%O/%O" + ", bytes from/to upstream:%O/%O", + from_upstream ? "upstream" : "client", + s->received, c->sent, u->received, pc ? pc->sent : 0); + + c->log->handler = handler; + + ngx_stream_proxy_finalize(s, NGX_OK); + return NGX_DONE; + } + + flags = src->read->eof ? NGX_CLOSE_EVENT : 0; + + if (ngx_handle_read_event(src->read, flags) != NGX_OK) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return NGX_ERROR; + } + + if (dst) { + if (ngx_handle_write_event(dst->write, 0) != NGX_OK) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return NGX_ERROR; + } + + ngx_add_timer(c->read, pscf->timeout); + } + + return NGX_OK; +} + + +static void +ngx_stream_proxy_next_upstream(ngx_stream_session_t *s) +{ + ngx_msec_t timeout; + ngx_connection_t *pc; + ngx_stream_upstream_t *u; + ngx_stream_proxy_srv_conf_t *pscf; + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream proxy next upstream"); + + u = s->upstream; + + if (u->peer.sockaddr) { + u->peer.free(&u->peer, u->peer.data, NGX_PEER_FAILED); + u->peer.sockaddr = NULL; + } + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + + timeout = pscf->next_upstream_timeout; + + if (u->peer.tries == 0 + || !pscf->next_upstream + || (timeout && ngx_current_msec - u->peer.start_time >= timeout)) + { + ngx_stream_proxy_finalize(s, NGX_DECLINED); + return; + } + + pc = u->peer.connection; + + if (pc) { + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "close proxy upstream connection: %d", pc->fd); + +#if (NGX_STREAM_SSL) + if (pc->ssl) { + pc->ssl->no_wait_shutdown = 1; + pc->ssl->no_send_shutdown = 1; + + (void) ngx_ssl_shutdown(pc); + } +#endif + + ngx_close_connection(pc); + u->peer.connection = NULL; + } + + ngx_stream_proxy_connect(s); +} + + +static void +ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_int_t rc) +{ + ngx_connection_t *pc; + ngx_stream_upstream_t *u; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "finalize stream proxy: %i", rc); + + u = s->upstream; + + if (u == NULL) { + goto noupstream; + } + + if (u->peer.free && u->peer.sockaddr) { + u->peer.free(&u->peer, u->peer.data, 0); + u->peer.sockaddr = NULL; + } + + pc = u->peer.connection; + + if (pc) { + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "close stream proxy upstream connection: %d", pc->fd); + +#if (NGX_STREAM_SSL) + if (pc->ssl) { + pc->ssl->no_wait_shutdown = 1; + (void) ngx_ssl_shutdown(pc); + } +#endif + + ngx_close_connection(pc); + u->peer.connection = NULL; + } + +noupstream: + + ngx_stream_close_connection(s->connection); +} + + +static u_char * +ngx_stream_proxy_log_error(ngx_log_t *log, u_char *buf, size_t len) +{ + u_char *p; + ngx_connection_t *pc; + ngx_stream_session_t *s; + ngx_stream_upstream_t *u; + + s = log->data; + + u = s->upstream; + + p = buf; + + if (u->peer.name) { + p = ngx_snprintf(p, len, ", upstream: \"%V\"", u->peer.name); + len -= p - buf; + } + + pc = u->peer.connection; + + p = ngx_snprintf(p, len, + ", bytes from/to client:%O/%O" + ", bytes from/to upstream:%O/%O", + s->received, s->connection->sent, + u->received, pc ? pc->sent : 0); + + return p; +} + + +static void * +ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) +{ + ngx_stream_proxy_srv_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_proxy_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->ssl_protocols = 0; + * conf->ssl_ciphers = { 0, NULL }; + * conf->ssl_name = { 0, NULL }; + * conf->ssl_trusted_certificate = { 0, NULL }; + * conf->ssl_crl = { 0, NULL }; + * conf->ssl_certificate = { 0, NULL }; + * conf->ssl_certificate_key = { 0, NULL }; + * + * conf->ssl = NULL; + * conf->upstream = NULL; + */ + + conf->connect_timeout = NGX_CONF_UNSET_MSEC; + conf->timeout = NGX_CONF_UNSET_MSEC; + conf->next_upstream_timeout = NGX_CONF_UNSET_MSEC; + conf->downstream_buf_size = NGX_CONF_UNSET_SIZE; + conf->upstream_buf_size = NGX_CONF_UNSET_SIZE; + conf->next_upstream_tries = NGX_CONF_UNSET_UINT; + conf->next_upstream = NGX_CONF_UNSET; + +#if (NGX_STREAM_SSL) + conf->ssl_enable = NGX_CONF_UNSET; + conf->ssl_session_reuse = NGX_CONF_UNSET; + conf->ssl_server_name = NGX_CONF_UNSET; + conf->ssl_verify = NGX_CONF_UNSET; + conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; + conf->ssl_passwords = NGX_CONF_UNSET_PTR; +#endif + + return conf; +} + + +static char * +ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_stream_proxy_srv_conf_t *prev = parent; + ngx_stream_proxy_srv_conf_t *conf = child; + + ngx_conf_merge_msec_value(conf->connect_timeout, + prev->connect_timeout, 60000); + + ngx_conf_merge_msec_value(conf->timeout, + prev->timeout, 10 * 60000); + + ngx_conf_merge_msec_value(conf->next_upstream_timeout, + prev->next_upstream_timeout, 0); + + ngx_conf_merge_size_value(conf->downstream_buf_size, + prev->downstream_buf_size, 16384); + + ngx_conf_merge_size_value(conf->upstream_buf_size, + prev->upstream_buf_size, 16384); + + ngx_conf_merge_uint_value(conf->next_upstream_tries, + prev->next_upstream_tries, 0); + + ngx_conf_merge_value(conf->next_upstream, prev->next_upstream, 1); + +#if (NGX_STREAM_SSL) + + ngx_conf_merge_value(conf->ssl_enable, prev->ssl_enable, 0); + + ngx_conf_merge_value(conf->ssl_session_reuse, + prev->ssl_session_reuse, 1); + + ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, + (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 + |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + + ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); + + ngx_conf_merge_str_value(conf->ssl_name, prev->ssl_name, ""); + + ngx_conf_merge_value(conf->ssl_server_name, prev->ssl_server_name, 0); + + ngx_conf_merge_value(conf->ssl_verify, prev->ssl_verify, 0); + + ngx_conf_merge_uint_value(conf->ssl_verify_depth, + prev->ssl_verify_depth, 1); + + ngx_conf_merge_str_value(conf->ssl_trusted_certificate, + prev->ssl_trusted_certificate, ""); + + ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); + + ngx_conf_merge_str_value(conf->ssl_certificate, + prev->ssl_certificate, ""); + + ngx_conf_merge_str_value(conf->ssl_certificate_key, + prev->ssl_certificate_key, ""); + + ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); + + if (conf->ssl_enable && ngx_stream_proxy_set_ssl(cf, conf) != NGX_OK) { + return NGX_CONF_ERROR; + } + +#endif + + return NGX_CONF_OK; +} + + +#if (NGX_STREAM_SSL) + +static ngx_int_t +ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf) +{ + ngx_pool_cleanup_t *cln; + + pscf->ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); + if (pscf->ssl == NULL) { + return NGX_ERROR; + } + + pscf->ssl->log = cf->log; + + if (ngx_ssl_create(pscf->ssl, pscf->ssl_protocols, NULL) != NGX_OK) { + return NGX_ERROR; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_ssl_cleanup_ctx; + cln->data = pscf->ssl; + + if (pscf->ssl_certificate.len) { + + if (pscf->ssl_certificate_key.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"proxy_ssl_certificate_key\" is defined " + "for certificate \"%V\"", &pscf->ssl_certificate); + return NGX_ERROR; + } + + if (ngx_ssl_certificate(cf, pscf->ssl, &pscf->ssl_certificate, + &pscf->ssl_certificate_key, pscf->ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + } + + if (SSL_CTX_set_cipher_list(pscf->ssl->ctx, + (const char *) pscf->ssl_ciphers.data) + == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, + "SSL_CTX_set_cipher_list(\"%V\") failed", + &pscf->ssl_ciphers); + return NGX_ERROR; + } + + if (pscf->ssl_verify) { + if (pscf->ssl_trusted_certificate.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no proxy_ssl_trusted_certificate for proxy_ssl_verify"); + return NGX_ERROR; + } + + if (ngx_ssl_trusted_certificate(cf, pscf->ssl, + &pscf->ssl_trusted_certificate, + pscf->ssl_verify_depth) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_ssl_crl(cf, pscf->ssl, &pscf->ssl_crl) != NGX_OK) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + +#endif + + +static char * +ngx_stream_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_proxy_srv_conf_t *pscf = conf; + + ngx_url_t u; + ngx_str_t *value, *url; + ngx_stream_core_srv_conf_t *cscf; + + if (pscf->upstream) { + return "is duplicate"; + } + + cscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_core_module); + + cscf->handler = ngx_stream_proxy_handler; + + value = cf->args->elts; + + url = &value[1]; + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url = *url; + u.no_resolve = 1; + + pscf->upstream = ngx_stream_upstream_add(cf, &u, 0); + if (pscf->upstream == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c new file mode 100644 index 0000000..4b27a1e --- /dev/null +++ b/src/stream/ngx_stream_ssl_module.c @@ -0,0 +1,456 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +#define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" +#define NGX_DEFAULT_ECDH_CURVE "prime256v1" + + +static void *ngx_stream_ssl_create_conf(ngx_conf_t *cf); +static char *ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, + void *child); + +static char *ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_conf_bitmask_t ngx_stream_ssl_protocols[] = { + { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, + { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, + { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, + { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 }, + { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_stream_ssl_commands[] = { + + { ngx_string("ssl_handshake_timeout"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_ssl_conf_t, handshake_timeout), + NULL }, + + { ngx_string("ssl_certificate"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_ssl_conf_t, certificate), + NULL }, + + { ngx_string("ssl_certificate_key"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_ssl_conf_t, certificate_key), + NULL }, + + { ngx_string("ssl_password_file"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_stream_ssl_password_file, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("ssl_dhparam"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_ssl_conf_t, dhparam), + NULL }, + + { ngx_string("ssl_ecdh_curve"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_ssl_conf_t, ecdh_curve), + NULL }, + + { ngx_string("ssl_protocols"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE, + ngx_conf_set_bitmask_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_ssl_conf_t, protocols), + &ngx_stream_ssl_protocols }, + + { ngx_string("ssl_ciphers"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_ssl_conf_t, ciphers), + NULL }, + + { ngx_string("ssl_prefer_server_ciphers"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_ssl_conf_t, prefer_server_ciphers), + NULL }, + + { ngx_string("ssl_session_cache"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE12, + ngx_stream_ssl_session_cache, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("ssl_session_tickets"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_ssl_conf_t, session_tickets), + NULL }, + + { ngx_string("ssl_session_ticket_key"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_array_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_ssl_conf_t, session_ticket_keys), + NULL }, + + { ngx_string("ssl_session_timeout"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_sec_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_ssl_conf_t, session_timeout), + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_ssl_module_ctx = { + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_stream_ssl_create_conf, /* create server configuration */ + ngx_stream_ssl_merge_conf /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_ssl_module = { + NGX_MODULE_V1, + &ngx_stream_ssl_module_ctx, /* module context */ + ngx_stream_ssl_commands, /* module directives */ + NGX_STREAM_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_str_t ngx_stream_ssl_sess_id_ctx = ngx_string("STREAM"); + + +static void * +ngx_stream_ssl_create_conf(ngx_conf_t *cf) +{ + ngx_stream_ssl_conf_t *scf; + + scf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_ssl_conf_t)); + if (scf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * scf->protocols = 0; + * scf->certificate = { 0, NULL }; + * scf->certificate_key = { 0, NULL }; + * scf->dhparam = { 0, NULL }; + * scf->ecdh_curve = { 0, NULL }; + * scf->ciphers = { 0, NULL }; + * scf->shm_zone = NULL; + */ + + scf->handshake_timeout = NGX_CONF_UNSET_MSEC; + scf->passwords = NGX_CONF_UNSET_PTR; + scf->prefer_server_ciphers = NGX_CONF_UNSET; + scf->builtin_session_cache = NGX_CONF_UNSET; + scf->session_timeout = NGX_CONF_UNSET; + scf->session_tickets = NGX_CONF_UNSET; + scf->session_ticket_keys = NGX_CONF_UNSET_PTR; + + return scf; +} + + +static char * +ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_stream_ssl_conf_t *prev = parent; + ngx_stream_ssl_conf_t *conf = child; + + ngx_pool_cleanup_t *cln; + + ngx_conf_merge_msec_value(conf->handshake_timeout, + prev->handshake_timeout, 60000); + + ngx_conf_merge_value(conf->session_timeout, + prev->session_timeout, 300); + + ngx_conf_merge_value(conf->prefer_server_ciphers, + prev->prefer_server_ciphers, 0); + + ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, + (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 + |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + + ngx_conf_merge_str_value(conf->certificate, prev->certificate, ""); + ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, ""); + + ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL); + + ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); + + ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve, + NGX_DEFAULT_ECDH_CURVE); + + ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); + + + conf->ssl.log = cf->log; + + if (conf->certificate.len == 0) { + return NGX_CONF_OK; + } + + if (conf->certificate_key.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate_key\" is defined " + "for certificate \"%V\"", + &conf->certificate); + return NGX_CONF_ERROR; + } + + if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) { + return NGX_CONF_ERROR; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_CONF_ERROR; + } + + cln->handler = ngx_ssl_cleanup_ctx; + cln->data = &conf->ssl; + + if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate, + &conf->certificate_key, conf->passwords) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + if (SSL_CTX_set_cipher_list(conf->ssl.ctx, + (const char *) conf->ciphers.data) + == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, + "SSL_CTX_set_cipher_list(\"%V\") failed", + &conf->ciphers); + return NGX_CONF_ERROR; + } + + if (conf->prefer_server_ciphers) { + SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); + } + + SSL_CTX_set_tmp_rsa_callback(conf->ssl.ctx, ngx_ssl_rsa512_key_callback); + + if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (ngx_ssl_ecdh_curve(cf, &conf->ssl, &conf->ecdh_curve) != NGX_OK) { + return NGX_CONF_ERROR; + } + + ngx_conf_merge_value(conf->builtin_session_cache, + prev->builtin_session_cache, NGX_SSL_NONE_SCACHE); + + if (conf->shm_zone == NULL) { + conf->shm_zone = prev->shm_zone; + } + + if (ngx_ssl_session_cache(&conf->ssl, &ngx_stream_ssl_sess_id_ctx, + conf->builtin_session_cache, + conf->shm_zone, conf->session_timeout) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + ngx_conf_merge_value(conf->session_tickets, + prev->session_tickets, 1); + +#ifdef SSL_OP_NO_TICKET + if (!conf->session_tickets) { + SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_NO_TICKET); + } +#endif + + ngx_conf_merge_ptr_value(conf->session_ticket_keys, + prev->session_ticket_keys, NULL); + + if (ngx_ssl_session_ticket_keys(cf, &conf->ssl, conf->session_ticket_keys) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_ssl_conf_t *scf = conf; + + ngx_str_t *value; + + if (scf->passwords != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + scf->passwords = ngx_ssl_read_password_file(cf, &value[1]); + + if (scf->passwords == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_ssl_conf_t *scf = conf; + + size_t len; + ngx_str_t *value, name, size; + ngx_int_t n; + ngx_uint_t i, j; + + value = cf->args->elts; + + for (i = 1; i < cf->args->nelts; i++) { + + if (ngx_strcmp(value[i].data, "off") == 0) { + scf->builtin_session_cache = NGX_SSL_NO_SCACHE; + continue; + } + + if (ngx_strcmp(value[i].data, "none") == 0) { + scf->builtin_session_cache = NGX_SSL_NONE_SCACHE; + continue; + } + + if (ngx_strcmp(value[i].data, "builtin") == 0) { + scf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE; + continue; + } + + if (value[i].len > sizeof("builtin:") - 1 + && ngx_strncmp(value[i].data, "builtin:", sizeof("builtin:") - 1) + == 0) + { + n = ngx_atoi(value[i].data + sizeof("builtin:") - 1, + value[i].len - (sizeof("builtin:") - 1)); + + if (n == NGX_ERROR) { + goto invalid; + } + + scf->builtin_session_cache = n; + + continue; + } + + if (value[i].len > sizeof("shared:") - 1 + && ngx_strncmp(value[i].data, "shared:", sizeof("shared:") - 1) + == 0) + { + len = 0; + + for (j = sizeof("shared:") - 1; j < value[i].len; j++) { + if (value[i].data[j] == ':') { + break; + } + + len++; + } + + if (len == 0) { + goto invalid; + } + + name.len = len; + name.data = value[i].data + sizeof("shared:") - 1; + + size.len = value[i].len - j - 1; + size.data = name.data + len + 1; + + n = ngx_parse_size(&size); + + if (n == NGX_ERROR) { + goto invalid; + } + + if (n < (ngx_int_t) (8 * ngx_pagesize)) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "session cache \"%V\" is too small", + &value[i]); + + return NGX_CONF_ERROR; + } + + scf->shm_zone = ngx_shared_memory_add(cf, &name, n, + &ngx_stream_ssl_module); + if (scf->shm_zone == NULL) { + return NGX_CONF_ERROR; + } + + scf->shm_zone->init = ngx_ssl_session_cache_init; + + continue; + } + + goto invalid; + } + + if (scf->shm_zone && scf->builtin_session_cache == NGX_CONF_UNSET) { + scf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE; + } + + return NGX_CONF_OK; + +invalid: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid session cache \"%V\"", &value[i]); + + return NGX_CONF_ERROR; +} diff --git a/src/stream/ngx_stream_ssl_module.h b/src/stream/ngx_stream_ssl_module.h new file mode 100644 index 0000000..85e8b6e --- /dev/null +++ b/src/stream/ngx_stream_ssl_module.h @@ -0,0 +1,49 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_STREAM_SSL_H_INCLUDED_ +#define _NGX_STREAM_SSL_H_INCLUDED_ + + +#include +#include +#include + + +typedef struct { + ngx_msec_t handshake_timeout; + + ngx_flag_t prefer_server_ciphers; + + ngx_ssl_t ssl; + + ngx_uint_t protocols; + + ssize_t builtin_session_cache; + + time_t session_timeout; + + ngx_str_t certificate; + ngx_str_t certificate_key; + ngx_str_t dhparam; + ngx_str_t ecdh_curve; + + ngx_str_t ciphers; + + ngx_array_t *passwords; + + ngx_shm_zone_t *shm_zone; + + ngx_flag_t session_tickets; + ngx_array_t *session_ticket_keys; +} ngx_stream_ssl_conf_t; + + +extern ngx_module_t ngx_stream_ssl_module; + + +#endif /* _NGX_STREAM_SSL_H_INCLUDED_ */ diff --git a/src/stream/ngx_stream_upstream.c b/src/stream/ngx_stream_upstream.c new file mode 100644 index 0000000..a991f8a --- /dev/null +++ b/src/stream/ngx_stream_upstream.c @@ -0,0 +1,462 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +static char *ngx_stream_upstream(ngx_conf_t *cf, ngx_command_t *cmd, + void *dummy); +static char *ngx_stream_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void *ngx_stream_upstream_create_main_conf(ngx_conf_t *cf); +static char *ngx_stream_upstream_init_main_conf(ngx_conf_t *cf, void *conf); + + +static ngx_command_t ngx_stream_upstream_commands[] = { + + { ngx_string("upstream"), + NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1, + ngx_stream_upstream, + 0, + 0, + NULL }, + + { ngx_string("server"), + NGX_STREAM_UPS_CONF|NGX_CONF_1MORE, + ngx_stream_upstream_server, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_upstream_module_ctx = { + ngx_stream_upstream_create_main_conf, /* create main configuration */ + ngx_stream_upstream_init_main_conf, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_upstream_module = { + NGX_MODULE_V1, + &ngx_stream_upstream_module_ctx, /* module context */ + ngx_stream_upstream_commands, /* module directives */ + NGX_STREAM_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 char * +ngx_stream_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) +{ + char *rv; + void *mconf; + ngx_str_t *value; + ngx_url_t u; + ngx_uint_t m; + ngx_conf_t pcf; + ngx_stream_module_t *module; + ngx_stream_conf_ctx_t *ctx, *stream_ctx; + ngx_stream_upstream_srv_conf_t *uscf; + + ngx_memzero(&u, sizeof(ngx_url_t)); + + value = cf->args->elts; + u.host = value[1]; + u.no_resolve = 1; + u.no_port = 1; + + uscf = ngx_stream_upstream_add(cf, &u, NGX_STREAM_UPSTREAM_CREATE + |NGX_STREAM_UPSTREAM_WEIGHT + |NGX_STREAM_UPSTREAM_MAX_FAILS + |NGX_STREAM_UPSTREAM_FAIL_TIMEOUT + |NGX_STREAM_UPSTREAM_DOWN + |NGX_STREAM_UPSTREAM_BACKUP); + if (uscf == NULL) { + return NGX_CONF_ERROR; + } + + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_stream_conf_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + stream_ctx = cf->ctx; + ctx->main_conf = stream_ctx->main_conf; + + /* the upstream{}'s srv_conf */ + + ctx->srv_conf = ngx_pcalloc(cf->pool, + sizeof(void *) * ngx_stream_max_module); + if (ctx->srv_conf == NULL) { + return NGX_CONF_ERROR; + } + + ctx->srv_conf[ngx_stream_upstream_module.ctx_index] = uscf; + + uscf->srv_conf = ctx->srv_conf; + + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_STREAM_MODULE) { + continue; + } + + module = ngx_modules[m]->ctx; + + if (module->create_srv_conf) { + mconf = module->create_srv_conf(cf); + if (mconf == NULL) { + return NGX_CONF_ERROR; + } + + ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf; + } + } + + uscf->servers = ngx_array_create(cf->pool, 4, + sizeof(ngx_stream_upstream_server_t)); + if (uscf->servers == NULL) { + return NGX_CONF_ERROR; + } + + + /* parse inside upstream{} */ + + pcf = *cf; + cf->ctx = ctx; + cf->cmd_type = NGX_STREAM_UPS_CONF; + + rv = ngx_conf_parse(cf, NULL); + + *cf = pcf; + + if (rv != NGX_CONF_OK) { + return rv; + } + + if (uscf->servers->nelts == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "no servers are inside upstream"); + return NGX_CONF_ERROR; + } + + return rv; +} + + +static char * +ngx_stream_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_upstream_srv_conf_t *uscf = conf; + + time_t fail_timeout; + ngx_str_t *value, s; + ngx_url_t u; + ngx_int_t weight, max_fails; + ngx_uint_t i; + ngx_stream_upstream_server_t *us; + + us = ngx_array_push(uscf->servers); + if (us == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(us, sizeof(ngx_stream_upstream_server_t)); + + value = cf->args->elts; + + weight = 1; + max_fails = 1; + fail_timeout = 10; + + for (i = 2; i < cf->args->nelts; i++) { + + if (ngx_strncmp(value[i].data, "weight=", 7) == 0) { + + if (!(uscf->flags & NGX_STREAM_UPSTREAM_WEIGHT)) { + goto not_supported; + } + + weight = ngx_atoi(&value[i].data[7], value[i].len - 7); + + if (weight == NGX_ERROR || weight == 0) { + goto invalid; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) { + + if (!(uscf->flags & NGX_STREAM_UPSTREAM_MAX_FAILS)) { + goto not_supported; + } + + max_fails = ngx_atoi(&value[i].data[10], value[i].len - 10); + + if (max_fails == NGX_ERROR) { + goto invalid; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "fail_timeout=", 13) == 0) { + + if (!(uscf->flags & NGX_STREAM_UPSTREAM_FAIL_TIMEOUT)) { + goto not_supported; + } + + s.len = value[i].len - 13; + s.data = &value[i].data[13]; + + fail_timeout = ngx_parse_time(&s, 1); + + if (fail_timeout == (time_t) NGX_ERROR) { + goto invalid; + } + + continue; + } + + if (ngx_strcmp(value[i].data, "backup") == 0) { + + if (!(uscf->flags & NGX_STREAM_UPSTREAM_BACKUP)) { + goto not_supported; + } + + us->backup = 1; + + continue; + } + + if (ngx_strcmp(value[i].data, "down") == 0) { + + if (!(uscf->flags & NGX_STREAM_UPSTREAM_DOWN)) { + goto not_supported; + } + + us->down = 1; + + continue; + } + + goto invalid; + } + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url = value[1]; + + if (ngx_parse_url(cf->pool, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in upstream \"%V\"", u.err, &u.url); + } + + return NGX_CONF_ERROR; + } + + if (u.no_port) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "no port in upstream \"%V\"", &u.url); + return NGX_CONF_ERROR; + } + + us->name = u.url; + us->addrs = u.addrs; + us->naddrs = u.naddrs; + us->weight = weight; + us->max_fails = max_fails; + us->fail_timeout = fail_timeout; + + return NGX_CONF_OK; + +invalid: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[i]); + + return NGX_CONF_ERROR; + +not_supported: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "balancing method does not support parameter \"%V\"", + &value[i]); + + return NGX_CONF_ERROR; +} + + +ngx_stream_upstream_srv_conf_t * +ngx_stream_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags) +{ + ngx_uint_t i; + ngx_stream_upstream_server_t *us; + ngx_stream_upstream_srv_conf_t *uscf, **uscfp; + ngx_stream_upstream_main_conf_t *umcf; + + if (!(flags & NGX_STREAM_UPSTREAM_CREATE)) { + + if (ngx_parse_url(cf->pool, u) != NGX_OK) { + if (u->err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in upstream \"%V\"", u->err, &u->url); + } + + return NULL; + } + } + + umcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_upstream_module); + + uscfp = umcf->upstreams.elts; + + for (i = 0; i < umcf->upstreams.nelts; i++) { + + if (uscfp[i]->host.len != u->host.len + || ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len) + != 0) + { + continue; + } + + if ((flags & NGX_STREAM_UPSTREAM_CREATE) + && (uscfp[i]->flags & NGX_STREAM_UPSTREAM_CREATE)) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate upstream \"%V\"", &u->host); + return NULL; + } + + if ((uscfp[i]->flags & NGX_STREAM_UPSTREAM_CREATE) && !u->no_port) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "upstream \"%V\" may not have port %d", + &u->host, u->port); + return NULL; + } + + if ((flags & NGX_STREAM_UPSTREAM_CREATE) && !uscfp[i]->no_port) { + ngx_log_error(NGX_LOG_WARN, cf->log, 0, + "upstream \"%V\" may not have port %d in %s:%ui", + &u->host, uscfp[i]->port, + uscfp[i]->file_name, uscfp[i]->line); + return NULL; + } + + if (uscfp[i]->port != u->port) { + continue; + } + + if (flags & NGX_STREAM_UPSTREAM_CREATE) { + uscfp[i]->flags = flags; + } + + return uscfp[i]; + } + + uscf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_srv_conf_t)); + if (uscf == NULL) { + return NULL; + } + + uscf->flags = flags; + uscf->host = u->host; + uscf->file_name = cf->conf_file->file.name.data; + uscf->line = cf->conf_file->line; + uscf->port = u->port; + uscf->no_port = u->no_port; + + if (u->naddrs == 1) { + uscf->servers = ngx_array_create(cf->pool, 1, + sizeof(ngx_stream_upstream_server_t)); + if (uscf->servers == NULL) { + return NULL; + } + + us = ngx_array_push(uscf->servers); + if (us == NULL) { + return NULL; + } + + ngx_memzero(us, sizeof(ngx_stream_upstream_server_t)); + + us->addrs = u->addrs; + us->naddrs = 1; + } + + uscfp = ngx_array_push(&umcf->upstreams); + if (uscfp == NULL) { + return NULL; + } + + *uscfp = uscf; + + return uscf; +} + + +static void * +ngx_stream_upstream_create_main_conf(ngx_conf_t *cf) +{ + ngx_stream_upstream_main_conf_t *umcf; + + umcf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_main_conf_t)); + if (umcf == NULL) { + return NULL; + } + + if (ngx_array_init(&umcf->upstreams, cf->pool, 4, + sizeof(ngx_stream_upstream_srv_conf_t *)) + != NGX_OK) + { + return NULL; + } + + return umcf; +} + + +static char * +ngx_stream_upstream_init_main_conf(ngx_conf_t *cf, void *conf) +{ + ngx_stream_upstream_main_conf_t *umcf = conf; + + ngx_uint_t i; + ngx_stream_upstream_init_pt init; + ngx_stream_upstream_srv_conf_t **uscfp; + + uscfp = umcf->upstreams.elts; + + for (i = 0; i < umcf->upstreams.nelts; i++) { + + init = uscfp[i]->peer.init_upstream + ? uscfp[i]->peer.init_upstream + : ngx_stream_upstream_init_round_robin; + + if (init(cf, uscfp[i]) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + return NGX_CONF_OK; +} diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h new file mode 100644 index 0000000..83353ed --- /dev/null +++ b/src/stream/ngx_stream_upstream.h @@ -0,0 +1,103 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_STREAM_UPSTREAM_H_INCLUDED_ +#define _NGX_STREAM_UPSTREAM_H_INCLUDED_ + + +#include +#include +#include +#include + + +#define NGX_STREAM_UPSTREAM_CREATE 0x0001 +#define NGX_STREAM_UPSTREAM_WEIGHT 0x0002 +#define NGX_STREAM_UPSTREAM_MAX_FAILS 0x0004 +#define NGX_STREAM_UPSTREAM_FAIL_TIMEOUT 0x0008 +#define NGX_STREAM_UPSTREAM_DOWN 0x0010 +#define NGX_STREAM_UPSTREAM_BACKUP 0x0020 + + +typedef struct { + ngx_array_t upstreams; + /* ngx_stream_upstream_srv_conf_t */ +} ngx_stream_upstream_main_conf_t; + + +typedef struct ngx_stream_upstream_srv_conf_s ngx_stream_upstream_srv_conf_t; + + +typedef ngx_int_t (*ngx_stream_upstream_init_pt)(ngx_conf_t *cf, + ngx_stream_upstream_srv_conf_t *us); +typedef ngx_int_t (*ngx_stream_upstream_init_peer_pt)(ngx_stream_session_t *s, + ngx_stream_upstream_srv_conf_t *us); + + +typedef struct { + ngx_stream_upstream_init_pt init_upstream; + ngx_stream_upstream_init_peer_pt init; + void *data; +} ngx_stream_upstream_peer_t; + + +typedef struct { + ngx_str_t name; + ngx_addr_t *addrs; + ngx_uint_t naddrs; + ngx_uint_t weight; + ngx_uint_t max_fails; + time_t fail_timeout; + + unsigned down:1; + unsigned backup:1; +} ngx_stream_upstream_server_t; + + +struct ngx_stream_upstream_srv_conf_s { + ngx_stream_upstream_peer_t peer; + void **srv_conf; + + ngx_array_t *servers; + /* ngx_stream_upstream_server_t */ + + ngx_uint_t flags; + ngx_str_t host; + u_char *file_name; + ngx_uint_t line; + in_port_t port; + ngx_uint_t no_port; /* unsigned no_port:1 */ + +#if (NGX_STREAM_UPSTREAM_ZONE) + ngx_shm_zone_t *shm_zone; +#endif +}; + + +typedef struct { + ngx_peer_connection_t peer; + ngx_buf_t downstream_buf; + ngx_buf_t upstream_buf; + off_t received; +#if (NGX_STREAM_SSL) + ngx_str_t ssl_name; +#endif +} ngx_stream_upstream_t; + + +ngx_stream_upstream_srv_conf_t *ngx_stream_upstream_add(ngx_conf_t *cf, + ngx_url_t *u, ngx_uint_t flags); + + +#define ngx_stream_conf_upstream_srv_conf(uscf, module) \ + uscf->srv_conf[module.ctx_index] + + +extern ngx_module_t ngx_stream_upstream_module; + + +#endif /* _NGX_STREAM_UPSTREAM_H_INCLUDED_ */ diff --git a/src/stream/ngx_stream_upstream_hash_module.c b/src/stream/ngx_stream_upstream_hash_module.c new file mode 100644 index 0000000..88e7414 --- /dev/null +++ b/src/stream/ngx_stream_upstream_hash_module.c @@ -0,0 +1,654 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + uint32_t hash; + ngx_str_t *server; +} ngx_stream_upstream_chash_point_t; + + +typedef struct { + ngx_uint_t number; + ngx_stream_upstream_chash_point_t point[1]; +} ngx_stream_upstream_chash_points_t; + + +typedef struct { + ngx_stream_upstream_chash_points_t *points; +} ngx_stream_upstream_hash_srv_conf_t; + + +typedef struct { + /* the round robin data must be first */ + ngx_stream_upstream_rr_peer_data_t rrp; + ngx_stream_upstream_hash_srv_conf_t *conf; + ngx_str_t key; + ngx_uint_t tries; + ngx_uint_t rehash; + uint32_t hash; + ngx_event_get_peer_pt get_rr_peer; +} ngx_stream_upstream_hash_peer_data_t; + + +static ngx_int_t ngx_stream_upstream_init_hash(ngx_conf_t *cf, + ngx_stream_upstream_srv_conf_t *us); +static ngx_int_t ngx_stream_upstream_init_hash_peer(ngx_stream_session_t *s, + ngx_stream_upstream_srv_conf_t *us); +static ngx_int_t ngx_stream_upstream_get_hash_peer(ngx_peer_connection_t *pc, + void *data); + +static ngx_int_t ngx_stream_upstream_init_chash(ngx_conf_t *cf, + ngx_stream_upstream_srv_conf_t *us); +static int ngx_libc_cdecl + ngx_stream_upstream_chash_cmp_points(const void *one, const void *two); +static ngx_uint_t ngx_stream_upstream_find_chash_point( + ngx_stream_upstream_chash_points_t *points, uint32_t hash); +static ngx_int_t ngx_stream_upstream_init_chash_peer(ngx_stream_session_t *s, + ngx_stream_upstream_srv_conf_t *us); +static ngx_int_t ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, + void *data); + +static void *ngx_stream_upstream_hash_create_conf(ngx_conf_t *cf); +static char *ngx_stream_upstream_hash(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_command_t ngx_stream_upstream_hash_commands[] = { + + { ngx_string("hash"), + NGX_STREAM_UPS_CONF|NGX_CONF_TAKE12, + ngx_stream_upstream_hash, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_upstream_hash_module_ctx = { + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_stream_upstream_hash_create_conf, /* create server configuration */ + NULL, /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_upstream_hash_module = { + NGX_MODULE_V1, + &ngx_stream_upstream_hash_module_ctx, /* module context */ + ngx_stream_upstream_hash_commands, /* module directives */ + NGX_STREAM_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_stream_upstream_init_hash(ngx_conf_t *cf, + ngx_stream_upstream_srv_conf_t *us) +{ + if (ngx_stream_upstream_init_round_robin(cf, us) != NGX_OK) { + return NGX_ERROR; + } + + us->peer.init = ngx_stream_upstream_init_hash_peer; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_upstream_init_hash_peer(ngx_stream_session_t *s, + ngx_stream_upstream_srv_conf_t *us) +{ + ngx_stream_upstream_hash_srv_conf_t *hcf; + ngx_stream_upstream_hash_peer_data_t *hp; + + hp = ngx_palloc(s->connection->pool, + sizeof(ngx_stream_upstream_hash_peer_data_t)); + if (hp == NULL) { + return NGX_ERROR; + } + + s->upstream->peer.data = &hp->rrp; + + if (ngx_stream_upstream_init_round_robin_peer(s, us) != NGX_OK) { + return NGX_ERROR; + } + + s->upstream->peer.get = ngx_stream_upstream_get_hash_peer; + + hcf = ngx_stream_conf_upstream_srv_conf(us, + ngx_stream_upstream_hash_module); + + hp->key = s->connection->addr_text; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "upstream hash key:\"%V\"", &hp->key); + + hp->conf = hcf; + hp->tries = 0; + hp->rehash = 0; + hp->hash = 0; + hp->get_rr_peer = ngx_stream_upstream_get_round_robin_peer; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) +{ + ngx_stream_upstream_hash_peer_data_t *hp = data; + + time_t now; + u_char buf[NGX_INT_T_LEN]; + size_t size; + uint32_t hash; + ngx_int_t w; + uintptr_t m; + ngx_uint_t n, p; + ngx_stream_upstream_rr_peer_t *peer; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "get hash peer, try: %ui", pc->tries); + + ngx_stream_upstream_rr_peers_wlock(hp->rrp.peers); + + if (hp->tries > 20 || hp->rrp.peers->single) { + ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers); + return hp->get_rr_peer(pc, &hp->rrp); + } + + now = ngx_time(); + + pc->connection = NULL; + + for ( ;; ) { + + /* + * Hash expression is compatible with Cache::Memcached: + * ((crc32([REHASH] KEY) >> 16) & 0x7fff) + PREV_HASH + * with REHASH omitted at the first iteration. + */ + + ngx_crc32_init(hash); + + if (hp->rehash > 0) { + size = ngx_sprintf(buf, "%ui", hp->rehash) - buf; + ngx_crc32_update(&hash, buf, size); + } + + ngx_crc32_update(&hash, hp->key.data, hp->key.len); + ngx_crc32_final(hash); + + hash = (hash >> 16) & 0x7fff; + + hp->hash += hash; + hp->rehash++; + + w = hp->hash % hp->rrp.peers->total_weight; + peer = hp->rrp.peers->peer; + p = 0; + + while (w >= peer->weight) { + w -= peer->weight; + peer = peer->next; + p++; + } + + n = p / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); + + if (hp->rrp.tried[n] & m) { + goto next; + } + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "get hash peer, value:%uD, peer:%ui", hp->hash, p); + + if (peer->down) { + goto next; + } + + if (peer->max_fails + && peer->fails >= peer->max_fails + && now - peer->checked <= peer->fail_timeout) + { + goto next; + } + + break; + + next: + + if (++hp->tries > 20) { + ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers); + return hp->get_rr_peer(pc, &hp->rrp); + } + } + + hp->rrp.current = peer; + + pc->sockaddr = peer->sockaddr; + pc->socklen = peer->socklen; + pc->name = &peer->name; + + peer->conns++; + + if (now - peer->checked > peer->fail_timeout) { + peer->checked = now; + } + + ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers); + + hp->rrp.tried[n] |= m; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_upstream_init_chash(ngx_conf_t *cf, + ngx_stream_upstream_srv_conf_t *us) +{ + u_char *host, *port, c; + size_t host_len, port_len, size; + uint32_t hash, base_hash; + ngx_str_t *server; + ngx_uint_t npoints, i, j; + ngx_stream_upstream_rr_peer_t *peer; + ngx_stream_upstream_rr_peers_t *peers; + ngx_stream_upstream_chash_points_t *points; + ngx_stream_upstream_hash_srv_conf_t *hcf; + union { + uint32_t value; + u_char byte[4]; + } prev_hash; + + if (ngx_stream_upstream_init_round_robin(cf, us) != NGX_OK) { + return NGX_ERROR; + } + + us->peer.init = ngx_stream_upstream_init_chash_peer; + + peers = us->peer.data; + npoints = peers->total_weight * 160; + + size = sizeof(ngx_stream_upstream_chash_points_t) + + sizeof(ngx_stream_upstream_chash_point_t) * (npoints - 1); + + points = ngx_palloc(cf->pool, size); + if (points == NULL) { + return NGX_ERROR; + } + + points->number = 0; + + for (peer = peers->peer; peer; peer = peer->next) { + server = &peer->server; + + /* + * Hash expression is compatible with Cache::Memcached::Fast: + * crc32(HOST \0 PORT PREV_HASH). + */ + + if (server->len >= 5 + && ngx_strncasecmp(server->data, (u_char *) "unix:", 5) == 0) + { + host = server->data + 5; + host_len = server->len - 5; + port = NULL; + port_len = 0; + goto done; + } + + for (j = 0; j < server->len; j++) { + c = server->data[server->len - j - 1]; + + if (c == ':') { + host = server->data; + host_len = server->len - j - 1; + port = server->data + server->len - j; + port_len = j; + goto done; + } + + if (c < '0' || c > '9') { + break; + } + } + + host = server->data; + host_len = server->len; + port = NULL; + port_len = 0; + + done: + + ngx_crc32_init(base_hash); + ngx_crc32_update(&base_hash, host, host_len); + ngx_crc32_update(&base_hash, (u_char *) "", 1); + ngx_crc32_update(&base_hash, port, port_len); + + prev_hash.value = 0; + npoints = peer->weight * 160; + + for (j = 0; j < npoints; j++) { + hash = base_hash; + + ngx_crc32_update(&hash, prev_hash.byte, 4); + ngx_crc32_final(hash); + + points->point[points->number].hash = hash; + points->point[points->number].server = server; + points->number++; + +#if (NGX_HAVE_LITTLE_ENDIAN) + prev_hash.value = hash; +#else + prev_hash.byte[0] = (u_char) (hash & 0xff); + prev_hash.byte[1] = (u_char) ((hash >> 8) & 0xff); + prev_hash.byte[2] = (u_char) ((hash >> 16) & 0xff); + prev_hash.byte[3] = (u_char) ((hash >> 24) & 0xff); +#endif + } + } + + ngx_qsort(points->point, + points->number, + sizeof(ngx_stream_upstream_chash_point_t), + ngx_stream_upstream_chash_cmp_points); + + for (i = 0, j = 1; j < points->number; j++) { + if (points->point[i].hash != points->point[j].hash) { + points->point[++i] = points->point[j]; + } + } + + points->number = i + 1; + + hcf = ngx_stream_conf_upstream_srv_conf(us, + ngx_stream_upstream_hash_module); + hcf->points = points; + + return NGX_OK; +} + + +static int ngx_libc_cdecl +ngx_stream_upstream_chash_cmp_points(const void *one, const void *two) +{ + ngx_stream_upstream_chash_point_t *first = + (ngx_stream_upstream_chash_point_t *) one; + ngx_stream_upstream_chash_point_t *second = + (ngx_stream_upstream_chash_point_t *) two; + + if (first->hash < second->hash) { + return -1; + + } else if (first->hash > second->hash) { + return 1; + + } else { + return 0; + } +} + + +static ngx_uint_t +ngx_stream_upstream_find_chash_point(ngx_stream_upstream_chash_points_t *points, + uint32_t hash) +{ + ngx_uint_t i, j, k; + ngx_stream_upstream_chash_point_t *point; + + /* find first point >= hash */ + + point = &points->point[0]; + + i = 0; + j = points->number; + + while (i < j) { + k = (i + j) / 2; + + if (hash > point[k].hash) { + i = k + 1; + + } else if (hash < point[k].hash) { + j = k; + + } else { + return k; + } + } + + return i; +} + + +static ngx_int_t +ngx_stream_upstream_init_chash_peer(ngx_stream_session_t *s, + ngx_stream_upstream_srv_conf_t *us) +{ + uint32_t hash; + ngx_stream_upstream_hash_srv_conf_t *hcf; + ngx_stream_upstream_hash_peer_data_t *hp; + + if (ngx_stream_upstream_init_hash_peer(s, us) != NGX_OK) { + return NGX_ERROR; + } + + s->upstream->peer.get = ngx_stream_upstream_get_chash_peer; + + hp = s->upstream->peer.data; + hcf = ngx_stream_conf_upstream_srv_conf(us, + ngx_stream_upstream_hash_module); + + hash = ngx_crc32_long(hp->key.data, hp->key.len); + + ngx_stream_upstream_rr_peers_rlock(hp->rrp.peers); + + hp->hash = ngx_stream_upstream_find_chash_point(hcf->points, hash); + + ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers); + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) +{ + ngx_stream_upstream_hash_peer_data_t *hp = data; + + time_t now; + intptr_t m; + ngx_str_t *server; + ngx_int_t total; + ngx_uint_t i, n, best_i; + ngx_stream_upstream_rr_peer_t *peer, *best; + ngx_stream_upstream_chash_point_t *point; + ngx_stream_upstream_chash_points_t *points; + ngx_stream_upstream_hash_srv_conf_t *hcf; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "get consistent hash peer, try: %ui", pc->tries); + + ngx_stream_upstream_rr_peers_wlock(hp->rrp.peers); + + pc->connection = NULL; + + now = ngx_time(); + hcf = hp->conf; + + points = hcf->points; + point = &points->point[0]; + + for ( ;; ) { + server = point[hp->hash % points->number].server; + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "consistent hash peer:%uD, server:\"%V\"", + hp->hash, server); + + best = NULL; + best_i = 0; + total = 0; + + for (peer = hp->rrp.peers->peer, i = 0; + peer; + peer = peer->next, i++) + { + + n = i / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); + + if (hp->rrp.tried[n] & m) { + continue; + } + + if (peer->down) { + continue; + } + + if (peer->server.len != server->len + || ngx_strncmp(peer->server.data, server->data, server->len) + != 0) + { + continue; + } + + if (peer->max_fails + && peer->fails >= peer->max_fails + && now - peer->checked <= peer->fail_timeout) + { + continue; + } + + peer->current_weight += peer->effective_weight; + total += peer->effective_weight; + + if (peer->effective_weight < peer->weight) { + peer->effective_weight++; + } + + if (best == NULL || peer->current_weight > best->current_weight) { + best = peer; + best_i = i; + } + } + + if (best) { + best->current_weight -= total; + break; + } + + hp->hash++; + hp->tries++; + + if (hp->tries >= points->number) { + ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers); + return NGX_BUSY; + } + } + + hp->rrp.current = best; + + pc->sockaddr = best->sockaddr; + pc->socklen = best->socklen; + pc->name = &best->name; + + best->conns++; + + if (now - best->checked > best->fail_timeout) { + best->checked = now; + } + + ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers); + + n = best_i / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << best_i % (8 * sizeof(uintptr_t)); + + hp->rrp.tried[n] |= m; + + return NGX_OK; +} + + +static void * +ngx_stream_upstream_hash_create_conf(ngx_conf_t *cf) +{ + ngx_stream_upstream_hash_srv_conf_t *conf; + + conf = ngx_palloc(cf->pool, sizeof(ngx_stream_upstream_hash_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + conf->points = NULL; + + return conf; +} + + +static char * +ngx_stream_upstream_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t *value; + ngx_stream_upstream_srv_conf_t *uscf; + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "$remote_addr")) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unsupported hash key \"%V\", use $remote_addr", + &value[1]); + return NGX_CONF_ERROR; + } + + uscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_upstream_module); + + if (uscf->peer.init_upstream) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "load balancing method redefined"); + } + + uscf->flags = NGX_STREAM_UPSTREAM_CREATE + |NGX_STREAM_UPSTREAM_WEIGHT + |NGX_STREAM_UPSTREAM_MAX_FAILS + |NGX_STREAM_UPSTREAM_FAIL_TIMEOUT + |NGX_STREAM_UPSTREAM_DOWN; + + if (cf->args->nelts == 2) { + uscf->peer.init_upstream = ngx_stream_upstream_init_hash; + + } else if (ngx_strcmp(value[2].data, "consistent") == 0) { + uscf->peer.init_upstream = ngx_stream_upstream_init_chash; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} diff --git a/src/stream/ngx_stream_upstream_least_conn_module.c b/src/stream/ngx_stream_upstream_least_conn_module.c new file mode 100644 index 0000000..eae4b17 --- /dev/null +++ b/src/stream/ngx_stream_upstream_least_conn_module.c @@ -0,0 +1,305 @@ + +/* + * Copyright (C) Maxim Dounin + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +static ngx_int_t ngx_stream_upstream_init_least_conn_peer( + ngx_stream_session_t *s, ngx_stream_upstream_srv_conf_t *us); +static ngx_int_t ngx_stream_upstream_get_least_conn_peer( + ngx_peer_connection_t *pc, void *data); +static char *ngx_stream_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_command_t ngx_stream_upstream_least_conn_commands[] = { + + { ngx_string("least_conn"), + NGX_STREAM_UPS_CONF|NGX_CONF_NOARGS, + ngx_stream_upstream_least_conn, + 0, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_upstream_least_conn_module_ctx = { + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_upstream_least_conn_module = { + NGX_MODULE_V1, + &ngx_stream_upstream_least_conn_module_ctx, /* module context */ + ngx_stream_upstream_least_conn_commands, /* module directives */ + NGX_STREAM_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_stream_upstream_init_least_conn(ngx_conf_t *cf, + ngx_stream_upstream_srv_conf_t *us) +{ + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, cf->log, 0, + "init least conn"); + + if (ngx_stream_upstream_init_round_robin(cf, us) != NGX_OK) { + return NGX_ERROR; + } + + us->peer.init = ngx_stream_upstream_init_least_conn_peer; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_upstream_init_least_conn_peer(ngx_stream_session_t *s, + ngx_stream_upstream_srv_conf_t *us) +{ + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "init least conn peer"); + + if (ngx_stream_upstream_init_round_robin_peer(s, us) != NGX_OK) { + return NGX_ERROR; + } + + s->upstream->peer.get = ngx_stream_upstream_get_least_conn_peer; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) +{ + ngx_stream_upstream_rr_peer_data_t *rrp = data; + + time_t now; + uintptr_t m; + ngx_int_t rc, total; + ngx_uint_t i, n, p, many; + ngx_stream_upstream_rr_peer_t *peer, *best; + ngx_stream_upstream_rr_peers_t *peers; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "get least conn peer, try: %ui", pc->tries); + + if (rrp->peers->single) { + return ngx_stream_upstream_get_round_robin_peer(pc, rrp); + } + + pc->connection = NULL; + + now = ngx_time(); + + peers = rrp->peers; + + ngx_stream_upstream_rr_peers_wlock(peers); + + best = NULL; + total = 0; + +#if (NGX_SUPPRESS_WARN) + many = 0; + p = 0; +#endif + + for (peer = peers->peer, i = 0; + peer; + peer = peer->next, i++) + { + + n = i / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); + + if (rrp->tried[n] & m) { + continue; + } + + if (peer->down) { + continue; + } + + if (peer->max_fails + && peer->fails >= peer->max_fails + && now - peer->checked <= peer->fail_timeout) + { + continue; + } + + /* + * select peer with least number of connections; if there are + * multiple peers with the same number of connections, select + * based on round-robin + */ + + if (best == NULL + || peer->conns * best->weight < best->conns * peer->weight) + { + best = peer; + many = 0; + p = i; + + } else if (peer->conns * best->weight == best->conns * peer->weight) { + many = 1; + } + } + + if (best == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "get least conn peer, no peer found"); + + goto failed; + } + + if (many) { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "get least conn peer, many"); + + for (peer = best, i = p; + peer; + peer = peer->next, i++) + { + n = i / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); + + if (rrp->tried[n] & m) { + continue; + } + + if (peer->down) { + continue; + } + + if (peer->conns * best->weight != best->conns * peer->weight) { + continue; + } + + if (peer->max_fails + && peer->fails >= peer->max_fails + && now - peer->checked <= peer->fail_timeout) + { + continue; + } + + peer->current_weight += peer->effective_weight; + total += peer->effective_weight; + + if (peer->effective_weight < peer->weight) { + peer->effective_weight++; + } + + if (peer->current_weight > best->current_weight) { + best = peer; + p = i; + } + } + } + + best->current_weight -= total; + + if (now - best->checked > best->fail_timeout) { + best->checked = now; + } + + pc->sockaddr = best->sockaddr; + pc->socklen = best->socklen; + pc->name = &best->name; + + best->conns++; + + rrp->current = best; + + n = p / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); + + rrp->tried[n] |= m; + + ngx_stream_upstream_rr_peers_unlock(peers); + + return NGX_OK; + +failed: + + if (peers->next) { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "get least conn peer, backup servers"); + + rrp->peers = peers->next; + + n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1)) + / (8 * sizeof(uintptr_t)); + + for (i = 0; i < n; i++) { + rrp->tried[i] = 0; + } + + ngx_stream_upstream_rr_peers_unlock(peers); + + rc = ngx_stream_upstream_get_least_conn_peer(pc, rrp); + + if (rc != NGX_BUSY) { + return rc; + } + + ngx_stream_upstream_rr_peers_wlock(peers); + } + + /* all peers failed, mark them as live for quick recovery */ + + for (peer = peers->peer; peer; peer = peer->next) { + peer->fails = 0; + } + + ngx_stream_upstream_rr_peers_unlock(peers); + + pc->name = peers->name; + + return NGX_BUSY; +} + + +static char * +ngx_stream_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_upstream_srv_conf_t *uscf; + + uscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_upstream_module); + + if (uscf->peer.init_upstream) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "load balancing method redefined"); + } + + uscf->peer.init_upstream = ngx_stream_upstream_init_least_conn; + + uscf->flags = NGX_STREAM_UPSTREAM_CREATE + |NGX_STREAM_UPSTREAM_WEIGHT + |NGX_STREAM_UPSTREAM_MAX_FAILS + |NGX_STREAM_UPSTREAM_FAIL_TIMEOUT + |NGX_STREAM_UPSTREAM_DOWN + |NGX_STREAM_UPSTREAM_BACKUP; + + return NGX_CONF_OK; +} diff --git a/src/stream/ngx_stream_upstream_round_robin.c b/src/stream/ngx_stream_upstream_round_robin.c new file mode 100644 index 0000000..efedb28 --- /dev/null +++ b/src/stream/ngx_stream_upstream_round_robin.c @@ -0,0 +1,702 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +#define ngx_stream_upstream_tries(p) ((p)->number \ + + ((p)->next ? (p)->next->number : 0)) + + +static ngx_stream_upstream_rr_peer_t *ngx_stream_upstream_get_peer( + ngx_stream_upstream_rr_peer_data_t *rrp); + +#if (NGX_STREAM_SSL) + +static ngx_int_t ngx_stream_upstream_set_round_robin_peer_session( + ngx_peer_connection_t *pc, void *data); +static void ngx_stream_upstream_save_round_robin_peer_session( + ngx_peer_connection_t *pc, void *data); + +#endif + + +ngx_int_t +ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, + ngx_stream_upstream_srv_conf_t *us) +{ + ngx_url_t u; + ngx_uint_t i, j, n, w; + ngx_stream_upstream_server_t *server; + ngx_stream_upstream_rr_peer_t *peer, **peerp; + ngx_stream_upstream_rr_peers_t *peers, *backup; + + us->peer.init = ngx_stream_upstream_init_round_robin_peer; + + if (us->servers) { + server = us->servers->elts; + + n = 0; + w = 0; + + for (i = 0; i < us->servers->nelts; i++) { + if (server[i].backup) { + continue; + } + + n += server[i].naddrs; + w += server[i].naddrs * server[i].weight; + } + + 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_stream_upstream_rr_peers_t)); + if (peers == NULL) { + return NGX_ERROR; + } + + peer = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_rr_peer_t) * n); + if (peer == NULL) { + return NGX_ERROR; + } + + peers->single = (n == 1); + peers->number = n; + peers->weighted = (w != n); + peers->total_weight = w; + peers->name = &us->host; + + n = 0; + peerp = &peers->peer; + + for (i = 0; i < us->servers->nelts; i++) { + if (server[i].backup) { + continue; + } + + for (j = 0; j < server[i].naddrs; j++) { + peer[n].sockaddr = server[i].addrs[j].sockaddr; + peer[n].socklen = server[i].addrs[j].socklen; + peer[n].name = server[i].addrs[j].name; + peer[n].weight = server[i].weight; + peer[n].effective_weight = server[i].weight; + peer[n].current_weight = 0; + peer[n].max_fails = server[i].max_fails; + peer[n].fail_timeout = server[i].fail_timeout; + peer[n].down = server[i].down; + peer[n].server = server[i].name; + + *peerp = &peer[n]; + peerp = &peer[n].next; + n++; + } + } + + us->peer.data = peers; + + /* backup servers */ + + n = 0; + w = 0; + + for (i = 0; i < us->servers->nelts; i++) { + if (!server[i].backup) { + continue; + } + + n += server[i].naddrs; + w += server[i].naddrs * server[i].weight; + } + + if (n == 0) { + return NGX_OK; + } + + backup = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_rr_peers_t)); + if (backup == NULL) { + return NGX_ERROR; + } + + peer = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_rr_peer_t) * n); + if (peer == NULL) { + return NGX_ERROR; + } + + peers->single = 0; + backup->single = 0; + backup->number = n; + backup->weighted = (w != n); + backup->total_weight = w; + backup->name = &us->host; + + n = 0; + peerp = &backup->peer; + + for (i = 0; i < us->servers->nelts; i++) { + if (!server[i].backup) { + continue; + } + + for (j = 0; j < server[i].naddrs; j++) { + peer[n].sockaddr = server[i].addrs[j].sockaddr; + peer[n].socklen = server[i].addrs[j].socklen; + peer[n].name = server[i].addrs[j].name; + peer[n].weight = server[i].weight; + peer[n].effective_weight = server[i].weight; + peer[n].current_weight = 0; + peer[n].max_fails = server[i].max_fails; + peer[n].fail_timeout = server[i].fail_timeout; + peer[n].down = server[i].down; + peer[n].server = server[i].name; + + *peerp = &peer[n]; + peerp = &peer[n].next; + n++; + } + } + + peers->next = backup; + + return NGX_OK; + } + + + /* an upstream implicitly defined by proxy_pass, etc. */ + + if (us->port == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no port in upstream \"%V\" in %s:%ui", + &us->host, us->file_name, us->line); + return NGX_ERROR; + } + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.host = us->host; + u.port = us->port; + + if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) { + if (u.err) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "%s in upstream \"%V\" in %s:%ui", + u.err, &us->host, us->file_name, us->line); + } + + return NGX_ERROR; + } + + n = u.naddrs; + + peers = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_rr_peers_t)); + if (peers == NULL) { + return NGX_ERROR; + } + + peer = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_rr_peer_t) * n); + if (peer == NULL) { + return NGX_ERROR; + } + + peers->single = (n == 1); + peers->number = n; + peers->weighted = 0; + peers->total_weight = n; + peers->name = &us->host; + + peerp = &peers->peer; + + for (i = 0; i < u.naddrs; i++) { + peer[i].sockaddr = u.addrs[i].sockaddr; + peer[i].socklen = u.addrs[i].socklen; + peer[i].name = u.addrs[i].name; + peer[i].weight = 1; + peer[i].effective_weight = 1; + peer[i].current_weight = 0; + peer[i].max_fails = 1; + peer[i].fail_timeout = 10; + *peerp = &peer[i]; + peerp = &peer[i].next; + } + + us->peer.data = peers; + + /* implicitly defined upstream has no backup servers */ + + return NGX_OK; +} + + +ngx_int_t +ngx_stream_upstream_init_round_robin_peer(ngx_stream_session_t *s, + ngx_stream_upstream_srv_conf_t *us) +{ + ngx_uint_t n; + ngx_stream_upstream_rr_peer_data_t *rrp; + + rrp = s->upstream->peer.data; + + if (rrp == NULL) { + rrp = ngx_palloc(s->connection->pool, + sizeof(ngx_stream_upstream_rr_peer_data_t)); + if (rrp == NULL) { + return NGX_ERROR; + } + + s->upstream->peer.data = rrp; + } + + rrp->peers = us->peer.data; + rrp->current = NULL; + + n = rrp->peers->number; + + if (rrp->peers->next && rrp->peers->next->number > n) { + n = rrp->peers->next->number; + } + + if (n <= 8 * sizeof(uintptr_t)) { + rrp->tried = &rrp->data; + rrp->data = 0; + + } else { + n = (n + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t)); + + rrp->tried = ngx_pcalloc(s->connection->pool, n * sizeof(uintptr_t)); + if (rrp->tried == NULL) { + return NGX_ERROR; + } + } + + s->upstream->peer.get = ngx_stream_upstream_get_round_robin_peer; + s->upstream->peer.free = ngx_stream_upstream_free_round_robin_peer; + s->upstream->peer.tries = ngx_stream_upstream_tries(rrp->peers); +#if (NGX_STREAM_SSL) + s->upstream->peer.set_session = + ngx_stream_upstream_set_round_robin_peer_session; + s->upstream->peer.save_session = + ngx_stream_upstream_save_round_robin_peer_session; +#endif + + return NGX_OK; +} + + +ngx_int_t +ngx_stream_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) +{ + ngx_stream_upstream_rr_peer_data_t *rrp = data; + + ngx_int_t rc; + ngx_uint_t i, n; + ngx_stream_upstream_rr_peer_t *peer; + ngx_stream_upstream_rr_peers_t *peers; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "get rr peer, try: %ui", pc->tries); + + pc->connection = NULL; + + peers = rrp->peers; + ngx_stream_upstream_rr_peers_wlock(peers); + + if (peers->single) { + peer = peers->peer; + + if (peer->down) { + goto failed; + } + + rrp->current = peer; + + } else { + + /* there are several peers */ + + peer = ngx_stream_upstream_get_peer(rrp); + + if (peer == NULL) { + goto failed; + } + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "get rr peer, current: %p %i", + peer, peer->current_weight); + } + + pc->sockaddr = peer->sockaddr; + pc->socklen = peer->socklen; + pc->name = &peer->name; + + peer->conns++; + + ngx_stream_upstream_rr_peers_unlock(peers); + + return NGX_OK; + +failed: + + if (peers->next) { + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, "backup servers"); + + rrp->peers = peers->next; + + n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1)) + / (8 * sizeof(uintptr_t)); + + for (i = 0; i < n; i++) { + rrp->tried[i] = 0; + } + + ngx_stream_upstream_rr_peers_unlock(peers); + + rc = ngx_stream_upstream_get_round_robin_peer(pc, rrp); + + if (rc != NGX_BUSY) { + return rc; + } + + ngx_stream_upstream_rr_peers_wlock(peers); + } + + /* all peers failed, mark them as live for quick recovery */ + + for (peer = peers->peer; peer; peer = peer->next) { + peer->fails = 0; + } + + ngx_stream_upstream_rr_peers_unlock(peers); + + pc->name = peers->name; + + return NGX_BUSY; +} + + +static ngx_stream_upstream_rr_peer_t * +ngx_stream_upstream_get_peer(ngx_stream_upstream_rr_peer_data_t *rrp) +{ + time_t now; + uintptr_t m; + ngx_int_t total; + ngx_uint_t i, n, p; + ngx_stream_upstream_rr_peer_t *peer, *best; + + now = ngx_time(); + + best = NULL; + total = 0; + +#if (NGX_SUPPRESS_WARN) + p = 0; +#endif + + for (peer = rrp->peers->peer, i = 0; + peer; + peer = peer->next, i++) + { + + n = i / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); + + if (rrp->tried[n] & m) { + continue; + } + + if (peer->down) { + continue; + } + + if (peer->max_fails + && peer->fails >= peer->max_fails + && now - peer->checked <= peer->fail_timeout) + { + continue; + } + + peer->current_weight += peer->effective_weight; + total += peer->effective_weight; + + if (peer->effective_weight < peer->weight) { + peer->effective_weight++; + } + + if (best == NULL || peer->current_weight > best->current_weight) { + best = peer; + p = i; + } + } + + if (best == NULL) { + return NULL; + } + + rrp->current = best; + + n = p / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); + + rrp->tried[n] |= m; + + best->current_weight -= total; + + if (now - best->checked > best->fail_timeout) { + best->checked = now; + } + + return best; +} + + +void +ngx_stream_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data, + ngx_uint_t state) +{ + ngx_stream_upstream_rr_peer_data_t *rrp = data; + + time_t now; + ngx_stream_upstream_rr_peer_t *peer; + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "free rr peer %ui %ui", pc->tries, state); + + peer = rrp->current; + + ngx_stream_upstream_rr_peers_rlock(rrp->peers); + ngx_stream_upstream_rr_peer_lock(rrp->peers, peer); + + if (rrp->peers->single) { + peer->conns--; + + ngx_stream_upstream_rr_peer_unlock(rrp->peers, peer); + ngx_stream_upstream_rr_peers_unlock(rrp->peers); + + pc->tries = 0; + return; + } + + if (state & NGX_PEER_FAILED) { + now = ngx_time(); + + peer->fails++; + peer->accessed = now; + peer->checked = now; + + if (peer->max_fails) { + peer->effective_weight -= peer->weight / peer->max_fails; + + if (peer->fails >= peer->max_fails) { + ngx_log_error(NGX_LOG_WARN, pc->log, 0, + "upstream server temporarily disabled"); + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "free rr peer failed: %p %i", + peer, peer->effective_weight); + + if (peer->effective_weight < 0) { + peer->effective_weight = 0; + } + + } else { + + /* mark peer live if check passed */ + + if (peer->accessed < peer->checked) { + peer->fails = 0; + } + } + + peer->conns--; + + ngx_stream_upstream_rr_peer_unlock(rrp->peers, peer); + ngx_stream_upstream_rr_peers_unlock(rrp->peers); + + if (pc->tries) { + pc->tries--; + } +} + + +#if (NGX_STREAM_SSL) + +static ngx_int_t +ngx_stream_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc, + void *data) +{ + ngx_stream_upstream_rr_peer_data_t *rrp = data; + + ngx_int_t rc; + ngx_ssl_session_t *ssl_session; + ngx_stream_upstream_rr_peer_t *peer; +#if (NGX_STREAM_UPSTREAM_ZONE) + int len; +#if OPENSSL_VERSION_NUMBER >= 0x0090707fL + const +#endif + u_char *p; + ngx_stream_upstream_rr_peers_t *peers; + u_char buf[NGX_SSL_MAX_SESSION_SIZE]; +#endif + + peer = rrp->current; + +#if (NGX_STREAM_UPSTREAM_ZONE) + peers = rrp->peers; + + if (peers->shpool) { + ngx_stream_upstream_rr_peers_rlock(peers); + ngx_stream_upstream_rr_peer_lock(peers, peer); + + if (peer->ssl_session == NULL) { + ngx_stream_upstream_rr_peer_unlock(peers, peer); + ngx_stream_upstream_rr_peers_unlock(peers); + return NGX_OK; + } + + len = peer->ssl_session_len; + + ngx_memcpy(buf, peer->ssl_session, len); + + ngx_stream_upstream_rr_peer_unlock(peers, peer); + ngx_stream_upstream_rr_peers_unlock(peers); + + p = buf; + ssl_session = d2i_SSL_SESSION(NULL, &p, len); + + rc = ngx_ssl_set_session(pc->connection, ssl_session); + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "set session: %p", ssl_session); + + ngx_ssl_free_session(ssl_session); + + return rc; + } +#endif + + ssl_session = peer->ssl_session; + + rc = ngx_ssl_set_session(pc->connection, ssl_session); + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "set session: %p", ssl_session); + + return rc; +} + + +static void +ngx_stream_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc, + void *data) +{ + ngx_stream_upstream_rr_peer_data_t *rrp = data; + + ngx_ssl_session_t *old_ssl_session, *ssl_session; + ngx_stream_upstream_rr_peer_t *peer; +#if (NGX_STREAM_UPSTREAM_ZONE) + int len; + u_char *p; + ngx_stream_upstream_rr_peers_t *peers; + u_char buf[NGX_SSL_MAX_SESSION_SIZE]; +#endif + +#if (NGX_STREAM_UPSTREAM_ZONE) + peers = rrp->peers; + + if (peers->shpool) { + + ssl_session = SSL_get0_session(pc->connection->ssl->connection); + + if (ssl_session == NULL) { + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "save session: %p", ssl_session); + + len = i2d_SSL_SESSION(ssl_session, NULL); + + /* do not cache too big session */ + + if (len > NGX_SSL_MAX_SESSION_SIZE) { + return; + } + + p = buf; + (void) i2d_SSL_SESSION(ssl_session, &p); + + peer = rrp->current; + + ngx_stream_upstream_rr_peers_rlock(peers); + ngx_stream_upstream_rr_peer_lock(peers, peer); + + if (len > peer->ssl_session_len) { + ngx_shmtx_lock(&peers->shpool->mutex); + + if (peer->ssl_session) { + ngx_slab_free_locked(peers->shpool, peer->ssl_session); + } + + peer->ssl_session = ngx_slab_alloc_locked(peers->shpool, len); + + ngx_shmtx_unlock(&peers->shpool->mutex); + + if (peer->ssl_session == NULL) { + peer->ssl_session_len = 0; + + ngx_stream_upstream_rr_peer_unlock(peers, peer); + ngx_stream_upstream_rr_peers_unlock(peers); + return; + } + + peer->ssl_session_len = len; + } + + ngx_memcpy(peer->ssl_session, buf, len); + + ngx_stream_upstream_rr_peer_unlock(peers, peer); + ngx_stream_upstream_rr_peers_unlock(peers); + + return; + } +#endif + + ssl_session = ngx_ssl_get_session(pc->connection); + + if (ssl_session == NULL) { + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "save session: %p", ssl_session); + + peer = rrp->current; + + old_ssl_session = peer->ssl_session; + peer->ssl_session = ssl_session; + + if (old_ssl_session) { + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "old session: %p", old_ssl_session); + + /* TODO: may block */ + + ngx_ssl_free_session(old_ssl_session); + } +} + +#endif diff --git a/src/stream/ngx_stream_upstream_round_robin.h b/src/stream/ngx_stream_upstream_round_robin.h new file mode 100644 index 0000000..83fd8b5 --- /dev/null +++ b/src/stream/ngx_stream_upstream_round_robin.h @@ -0,0 +1,138 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_STREAM_UPSTREAM_ROUND_ROBIN_H_INCLUDED_ +#define _NGX_STREAM_UPSTREAM_ROUND_ROBIN_H_INCLUDED_ + + +#include +#include +#include + + +typedef struct ngx_stream_upstream_rr_peer_s ngx_stream_upstream_rr_peer_t; + +struct ngx_stream_upstream_rr_peer_s { + struct sockaddr *sockaddr; + socklen_t socklen; + ngx_str_t name; + ngx_str_t server; + + ngx_int_t current_weight; + ngx_int_t effective_weight; + ngx_int_t weight; + + ngx_uint_t conns; + + ngx_uint_t fails; + time_t accessed; + time_t checked; + + ngx_uint_t max_fails; + time_t fail_timeout; + + ngx_uint_t down; /* unsigned down:1; */ + +#if (NGX_STREAM_SSL) + void *ssl_session; + int ssl_session_len; +#endif + + ngx_stream_upstream_rr_peer_t *next; + +#if (NGX_STREAM_UPSTREAM_ZONE) + ngx_atomic_t lock; +#endif +}; + + +typedef struct ngx_stream_upstream_rr_peers_s ngx_stream_upstream_rr_peers_t; + +struct ngx_stream_upstream_rr_peers_s { + ngx_uint_t number; + +#if (NGX_STREAM_UPSTREAM_ZONE) + ngx_slab_pool_t *shpool; + ngx_atomic_t rwlock; +#endif + + ngx_uint_t total_weight; + + unsigned single:1; + unsigned weighted:1; + + ngx_str_t *name; + + ngx_stream_upstream_rr_peers_t *next; + + ngx_stream_upstream_rr_peer_t *peer; +}; + + +#if (NGX_STREAM_UPSTREAM_ZONE) + +#define ngx_stream_upstream_rr_peers_rlock(peers) \ + \ + if (peers->shpool) { \ + ngx_rwlock_rlock(&peers->rwlock); \ + } + +#define ngx_stream_upstream_rr_peers_wlock(peers) \ + \ + if (peers->shpool) { \ + ngx_rwlock_wlock(&peers->rwlock); \ + } + +#define ngx_stream_upstream_rr_peers_unlock(peers) \ + \ + if (peers->shpool) { \ + ngx_rwlock_unlock(&peers->rwlock); \ + } + + +#define ngx_stream_upstream_rr_peer_lock(peers, peer) \ + \ + if (peers->shpool) { \ + ngx_rwlock_wlock(&peer->lock); \ + } + +#define ngx_stream_upstream_rr_peer_unlock(peers, peer) \ + \ + if (peers->shpool) { \ + ngx_rwlock_unlock(&peer->lock); \ + } + +#else + +#define ngx_stream_upstream_rr_peers_rlock(peers) +#define ngx_stream_upstream_rr_peers_wlock(peers) +#define ngx_stream_upstream_rr_peers_unlock(peers) +#define ngx_stream_upstream_rr_peer_lock(peers, peer) +#define ngx_stream_upstream_rr_peer_unlock(peers, peer) + +#endif + + +typedef struct { + ngx_stream_upstream_rr_peers_t *peers; + ngx_stream_upstream_rr_peer_t *current; + uintptr_t *tried; + uintptr_t data; +} ngx_stream_upstream_rr_peer_data_t; + + +ngx_int_t ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, + ngx_stream_upstream_srv_conf_t *us); +ngx_int_t ngx_stream_upstream_init_round_robin_peer(ngx_stream_session_t *s, + ngx_stream_upstream_srv_conf_t *us); +ngx_int_t ngx_stream_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, + void *data); +void ngx_stream_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, + void *data, ngx_uint_t state); + + +#endif /* _NGX_STREAM_UPSTREAM_ROUND_ROBIN_H_INCLUDED_ */ diff --git a/src/stream/ngx_stream_upstream_zone_module.c b/src/stream/ngx_stream_upstream_zone_module.c new file mode 100644 index 0000000..95a778f --- /dev/null +++ b/src/stream/ngx_stream_upstream_zone_module.c @@ -0,0 +1,221 @@ + +/* + * Copyright (C) Ruslan Ermilov + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +static char *ngx_stream_upstream_zone(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_stream_upstream_init_zone(ngx_shm_zone_t *shm_zone, + void *data); +static ngx_int_t ngx_stream_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, + ngx_stream_upstream_srv_conf_t *uscf); + + +static ngx_command_t ngx_stream_upstream_zone_commands[] = { + + { ngx_string("zone"), + NGX_STREAM_UPS_CONF|NGX_CONF_TAKE12, + ngx_stream_upstream_zone, + 0, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_upstream_zone_module_ctx = { + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_upstream_zone_module = { + NGX_MODULE_V1, + &ngx_stream_upstream_zone_module_ctx, /* module context */ + ngx_stream_upstream_zone_commands, /* module directives */ + NGX_STREAM_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 char * +ngx_stream_upstream_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ssize_t size; + ngx_str_t *value; + ngx_stream_upstream_srv_conf_t *uscf; + ngx_stream_upstream_main_conf_t *umcf; + + uscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_upstream_module); + umcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_upstream_module); + + value = cf->args->elts; + + if (!value[1].len) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid zone name \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 3) { + size = ngx_parse_size(&value[2]); + + if (size == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid zone size \"%V\"", &value[2]); + 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[1]); + return NGX_CONF_ERROR; + } + + } else { + size = 0; + } + + uscf->shm_zone = ngx_shared_memory_add(cf, &value[1], size, + &ngx_stream_upstream_module); + if (uscf->shm_zone == NULL) { + return NGX_CONF_ERROR; + } + + uscf->shm_zone->init = ngx_stream_upstream_init_zone; + uscf->shm_zone->data = umcf; + + uscf->shm_zone->noreuse = 1; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_stream_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data) +{ + size_t len; + ngx_uint_t i; + ngx_slab_pool_t *shpool; + ngx_stream_upstream_srv_conf_t *uscf, **uscfp; + ngx_stream_upstream_main_conf_t *umcf; + + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + + if (shm_zone->shm.exists) { + return NGX_ERROR; + } + + len = sizeof(" in upstream 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 upstream zone \"%V\"%Z", + &shm_zone->shm.name); + + + /* copy peers to shared memory */ + + umcf = shm_zone->data; + uscfp = umcf->upstreams.elts; + + for (i = 0; i < umcf->upstreams.nelts; i++) { + uscf = uscfp[i]; + + if (uscf->shm_zone != shm_zone) { + continue; + } + + if (ngx_stream_upstream_zone_copy_peers(shpool, uscf) != NGX_OK) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, + ngx_stream_upstream_srv_conf_t *uscf) +{ + ngx_stream_upstream_rr_peer_t *peer, **peerp; + ngx_stream_upstream_rr_peers_t *peers, *backup; + + peers = ngx_slab_alloc(shpool, sizeof(ngx_stream_upstream_rr_peers_t)); + if (peers == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(peers, uscf->peer.data, sizeof(ngx_stream_upstream_rr_peers_t)); + + peers->shpool = shpool; + + for (peerp = &peers->peer; *peerp; peerp = &peer->next) { + /* pool is unlocked */ + peer = ngx_slab_calloc_locked(shpool, + sizeof(ngx_stream_upstream_rr_peer_t)); + if (peer == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(peer, *peerp, sizeof(ngx_stream_upstream_rr_peer_t)); + + *peerp = peer; + } + + if (peers->next == NULL) { + goto done; + } + + backup = ngx_slab_alloc(shpool, sizeof(ngx_stream_upstream_rr_peers_t)); + if (backup == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(backup, peers->next, sizeof(ngx_stream_upstream_rr_peers_t)); + + backup->shpool = shpool; + + for (peerp = &backup->peer; *peerp; peerp = &peer->next) { + /* pool is unlocked */ + peer = ngx_slab_calloc_locked(shpool, + sizeof(ngx_stream_upstream_rr_peer_t)); + if (peer == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(peer, *peerp, sizeof(ngx_stream_upstream_rr_peer_t)); + + *peerp = peer; + } + + peers->next = backup; + +done: + + uscf->peer.data = peers; + + return NGX_OK; +} From 8e7e40b988d3f195f2174755538a15910084ce2c Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 11 Jun 2015 14:44:12 +0300 Subject: [PATCH 027/651] New upstream release, 1.9.1 --- debian/changelog | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 4a35984..340b913 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.6.2-6) UNRELEASED; urgency=medium +nginx (1.9.1-1) UNRELEASED; urgency=medium [ Michael Lustfield ] * debian/conf/nginx.conf: @@ -37,6 +37,9 @@ nginx (1.6.2-6) UNRELEASED; urgency=medium + Changed debian/index.html -> html/index.html. This installs the package maintained version of this file as opposed to our out of date version. + [ Christos Trochalakis ] + * New upstream release. Switching to mainline version. (Closes: #777677) + -- Michael Lustfield Tue, 07 Apr 2015 18:57:45 -0500 nginx (1.6.2-5) unstable; urgency=medium From 7d77b1195b8ecc82aaf837b592093e58484169b0 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 11 Jun 2015 14:18:42 +0300 Subject: [PATCH 028/651] Don't ship ngx-conf just yet Let's test it a bit first and discuss the api it exposes. --- debian/changelog | 2 +- debian/nginx-common.install | 1 - debian/nginx-common.manpages | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 340b913..ec1d032 100644 --- a/debian/changelog +++ b/debian/changelog @@ -30,7 +30,7 @@ nginx (1.9.1-1) UNRELEASED; urgency=medium * debian/modules/nginx-lua/*: + Updated module version. (Closes: #762494) * debian/ngx-conf/* - + Added configuration utility. (Closes: #652108) + + Added configuration utility, not shipped yet. (Closes: #652108) * debian/nginx-common.manpages: + Replaced man page with upstream maintained version. (Closes: #781345) * debian/nginx-common.install: diff --git a/debian/nginx-common.install b/debian/nginx-common.install index eea0c94..a114903 100644 --- a/debian/nginx-common.install +++ b/debian/nginx-common.install @@ -3,4 +3,3 @@ debian/ufw/nginx etc/ufw/applications.d html/index.html usr/share/nginx/html/ debian/vim/nginx.yaml usr/share/vim/registry contrib/vim/* usr/share/vim/addons -debian/ngx-conf/ngx-conf usr/sbin/ngx-conf diff --git a/debian/nginx-common.manpages b/debian/nginx-common.manpages index faaf162..3a789d7 100644 --- a/debian/nginx-common.manpages +++ b/debian/nginx-common.manpages @@ -1,2 +1 @@ man/nginx.8 -debian/ngx-conf/ngx-conf.1 From 6e41b4e4c35833c0d4369c01c9989eda9191caa4 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 11 Jun 2015 15:58:41 +0300 Subject: [PATCH 029/651] Build upstream manpages before shipping Complements Mike's commit. Manpages should be build before shipping. As a side effect, it's better to ship them together with the nginx binary. --- debian/changelog | 2 ++ debian/nginx-common.manpages | 1 - debian/nginx-extras.manpages | 1 + debian/nginx-full.manpages | 1 + debian/nginx-light.manpages | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) delete mode 100644 debian/nginx-common.manpages create mode 100644 debian/nginx-extras.manpages create mode 100644 debian/nginx-full.manpages create mode 100644 debian/nginx-light.manpages diff --git a/debian/changelog b/debian/changelog index ec1d032..9326268 100644 --- a/debian/changelog +++ b/debian/changelog @@ -39,6 +39,8 @@ nginx (1.9.1-1) UNRELEASED; urgency=medium [ Christos Trochalakis ] * New upstream release. Switching to mainline version. (Closes: #777677) + * debian/nginx-common.manpages: + + Build & ship manpages with binary packages. -- Michael Lustfield Tue, 07 Apr 2015 18:57:45 -0500 diff --git a/debian/nginx-common.manpages b/debian/nginx-common.manpages deleted file mode 100644 index 3a789d7..0000000 --- a/debian/nginx-common.manpages +++ /dev/null @@ -1 +0,0 @@ -man/nginx.8 diff --git a/debian/nginx-extras.manpages b/debian/nginx-extras.manpages new file mode 100644 index 0000000..6dd6a30 --- /dev/null +++ b/debian/nginx-extras.manpages @@ -0,0 +1 @@ +debian/build-extras/objs/nginx.8 diff --git a/debian/nginx-full.manpages b/debian/nginx-full.manpages new file mode 100644 index 0000000..28267c2 --- /dev/null +++ b/debian/nginx-full.manpages @@ -0,0 +1 @@ +debian/build-full/objs/nginx.8 diff --git a/debian/nginx-light.manpages b/debian/nginx-light.manpages new file mode 100644 index 0000000..06143d4 --- /dev/null +++ b/debian/nginx-light.manpages @@ -0,0 +1 @@ +debian/build-light/objs/nginx.8 From 8bea90a55d9001b3d6e4456289db88b07b31b44b Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 11 Jun 2015 15:02:07 +0300 Subject: [PATCH 030/651] debian/rules: http_limit_zone has been renamed to http_limit_conn Fixes building failure. --- debian/changelog | 2 ++ debian/rules | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 9326268..da2ab75 100644 --- a/debian/changelog +++ b/debian/changelog @@ -41,6 +41,8 @@ nginx (1.9.1-1) UNRELEASED; urgency=medium * New upstream release. Switching to mainline version. (Closes: #777677) * debian/nginx-common.manpages: + Build & ship manpages with binary packages. + * debian/rules: + + Adjust configure flags for limit_zone module (renamed to limit_conn). -- Michael Lustfield Tue, 07 Apr 2015 18:57:45 -0500 diff --git a/debian/rules b/debian/rules index 48f81d9..93e6db6 100755 --- a/debian/rules +++ b/debian/rules @@ -55,7 +55,7 @@ light_configure_flags := \ --without-http_browser_module \ --without-http_geo_module \ --without-http_limit_req_module \ - --without-http_limit_zone_module \ + --without-http_limit_conn_module \ --without-http_memcached_module \ --without-http_referer_module \ --without-http_scgi_module \ From 9b8414bbc8f46edfcec0933682c9961ac0a58cb0 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 11 Jun 2015 15:15:02 +0300 Subject: [PATCH 031/651] debian/modules/nginx-lua: Backport 1.9.x compilation fix Backport fix fixing 1.9.x compilation. The fix will be included in v0.9.16. https://github.com/openresty/lua-nginx-module/commit/f4e1311 --- debian/changelog | 2 ++ debian/modules/README.Modules-versions | 2 +- debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c | 8 ++++++++ debian/modules/nginx-lua/src/ngx_http_lua_timer.c | 8 ++++++++ debian/modules/nginx-lua/util/build2.sh | 1 - 5 files changed, 19 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index da2ab75..0554358 100644 --- a/debian/changelog +++ b/debian/changelog @@ -43,6 +43,8 @@ nginx (1.9.1-1) UNRELEASED; urgency=medium + Build & ship manpages with binary packages. * debian/rules: + Adjust configure flags for limit_zone module (renamed to limit_conn). + * debian/modules/nginx-lua: + + Backport upstream's f4e1311 fixing build failure with mainline nginx. -- Michael Lustfield Tue, 07 Apr 2015 18:57:45 -0500 diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index c95c897..a5c7563 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -22,7 +22,7 @@ README for Modules versions nginx-lua Homepage: https://github.com/openresty/lua-nginx-module - Version: v0.9.15 + Version: v0.9.15 + f4e1311 nginx-upstream-fair Homepage: https://github.com/gnosek/nginx-upstream-fair diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c b/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c index 6b5292d..bd03a24 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c @@ -227,8 +227,16 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) #if defined(nginx_version) && nginx_version >= 1003014 +# if nginx_version >= 1009000 + + ngx_set_connection_log(r->connection, clcf->error_log); + +# else + ngx_http_set_connection_log(r->connection, clcf->error_log); +# endif + #else c->log->file = clcf->error_log->file; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c index c0d66d6..a358fd6 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c @@ -350,8 +350,16 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) #if defined(nginx_version) && nginx_version >= 1003014 +# if nginx_version >= 1009000 + + ngx_set_connection_log(r->connection, clcf->error_log); + +# else + ngx_http_set_connection_log(r->connection, clcf->error_log); +# endif + #else c->log->file = clcf->error_log->file; diff --git a/debian/modules/nginx-lua/util/build2.sh b/debian/modules/nginx-lua/util/build2.sh index c426035..bccf4b4 100755 --- a/debian/modules/nginx-lua/util/build2.sh +++ b/debian/modules/nginx-lua/util/build2.sh @@ -49,7 +49,6 @@ time ngx-build $force $version \ --with-http_gunzip_module \ --with-select_module \ --with-poll_module \ - --with-rtsig_module \ $opts \ --with-debug From 6a6628bd93c2185a9e4d8abe8e7a716aa5cd8097 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 11 Jun 2015 14:36:01 +0300 Subject: [PATCH 032/651] Switch to libgd-dev now that jessie is released --- debian/changelog | 2 ++ debian/control | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 0554358..5aabd75 100644 --- a/debian/changelog +++ b/debian/changelog @@ -45,6 +45,8 @@ nginx (1.9.1-1) UNRELEASED; urgency=medium + Adjust configure flags for limit_zone module (renamed to limit_conn). * debian/modules/nginx-lua: + Backport upstream's f4e1311 fixing build failure with mainline nginx. + * debian/control: + + Depend on libgd-dev now that jessie is released. -- Michael Lustfield Tue, 07 Apr 2015 18:57:45 -0500 diff --git a/debian/control b/debian/control index 0a33572..e544ca8 100644 --- a/debian/control +++ b/debian/control @@ -13,7 +13,7 @@ Build-Depends: autotools-dev, dh-systemd (>= 1.5), dpkg-dev (>= 1.15.5), libexpat-dev, - libgd2-dev | libgd2-noxpm-dev, + libgd-dev, libgeoip-dev, libluajit-5.1-dev [i386 amd64 kfreebsd-i386 armel armhf powerpc powerpcspe mips mipsel] | liblua5.1-0-dev, libmhash-dev, From f4860d82df6b89a9bb0e66856e520cede7a3ba8a Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 11 Jun 2015 14:41:15 +0300 Subject: [PATCH 033/651] debian/watch: Search mainline versions for now --- debian/watch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/watch b/debian/watch index c1cdf74..2cb0678 100644 --- a/debian/watch +++ b/debian/watch @@ -1,3 +1,3 @@ version=3 opts=pgpsigurlmangle=s/$/.asc/ \ -http://nginx.org/download/nginx-(\d\.[02468]\.\d+)\.tar\.gz +http://nginx.org/download/nginx-(\d\.\d+\.\d+)\.tar\.gz From 9844dfdd8ab423539e558e2fcbe0f816654b99f8 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 12 Jun 2015 15:37:51 +0300 Subject: [PATCH 034/651] Update NEWS entry version --- debian/nginx-common.NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/nginx-common.NEWS b/debian/nginx-common.NEWS index 8eeeb58..edd750f 100644 --- a/debian/nginx-common.NEWS +++ b/debian/nginx-common.NEWS @@ -1,4 +1,4 @@ -nginx-common (1.6.3-1) unstable; urgency=medium +nginx-common (1.9.1-1) unstable; urgency=medium Starting with this release, we have enabled PIE build features which allows Address Space Layout Randomization. This is a hardening feature that From f1f0066de571217880fa1f33756e4039f1ad4f38 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 12 Jun 2015 15:44:14 +0300 Subject: [PATCH 035/651] Release 1.9.1-1 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 5aabd75..a48d86f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.9.1-1) UNRELEASED; urgency=medium +nginx (1.9.1-1) unstable; urgency=medium [ Michael Lustfield ] * debian/conf/nginx.conf: @@ -48,7 +48,7 @@ nginx (1.9.1-1) UNRELEASED; urgency=medium * debian/control: + Depend on libgd-dev now that jessie is released. - -- Michael Lustfield Tue, 07 Apr 2015 18:57:45 -0500 + -- Christos Trochalakis Fri, 12 Jun 2015 15:42:49 +0300 nginx (1.6.2-5) unstable; urgency=medium From 0ddf1ccfc049c7cc11f84c69b97dcf15d92ea941 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Mon, 15 Jun 2015 22:16:37 -0500 Subject: [PATCH 036/651] Cleaning up init script and fixed a bug with exit status --- debian/changelog | 8 +++ debian/nginx-common.nginx.init | 99 ++++++++++++++-------------------- 2 files changed, 47 insertions(+), 60 deletions(-) diff --git a/debian/changelog b/debian/changelog index a48d86f..0982eae 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +nginx (1.9.1-2) UNRELEASED; urgency=medium + + * debian/nginx-common.nginx.init: + + Init script now returns the proper exit status. (Closes: #788573) + + Cleaned up the init script to have consistent naming/structure. + + -- Michael Lustfield Mon, 15 Jun 2015 22:14:19 -0500 + nginx (1.9.1-1) unstable; urgency=medium [ Michael Lustfield ] diff --git a/debian/nginx-common.nginx.init b/debian/nginx-common.nginx.init index f20d0c7..c5bf8d9 100644 --- a/debian/nginx-common.nginx.init +++ b/debian/nginx-common.nginx.init @@ -29,23 +29,19 @@ test -x $DAEMON || exit 0 # Try to extract nginx pidfile PID=$(cat /etc/nginx/nginx.conf | grep -Ev '^\s*#' | awk 'BEGIN { RS="[;{}]" } { if ($1 == "pid") print $2 }' | head -n1) -if [ -z "$PID" ] -then +if [ -z "$PID" ]; then PID=/run/nginx.pid fi -# Check if the ULIMIT is set in /etc/default/nginx if [ -n "$ULIMIT" ]; then - # Set the ulimits + # Set ulimit if it is set in /etc/default/nginx ulimit $ULIMIT fi -# -# Function that starts the daemon/service -# -do_start() -{ - # Return +start_nginx() { + # Start the daemon/service + # + # Returns: # 0 if daemon has been started # 1 if daemon was already running # 2 if daemon could not be started @@ -56,15 +52,14 @@ do_start() || return 2 } -test_nginx_config() { +test_config() { + # Test the nginx configuration $DAEMON -t $DAEMON_OPTS >/dev/null 2>&1 } -# -# Function that stops the daemon/service -# -do_stop() -{ +stop_nginx() { + # Stops the daemon/service + # # Return # 0 if daemon has been stopped # 1 if daemon was already stopped @@ -72,34 +67,25 @@ do_stop() # other if a failure occurred start-stop-daemon --stop --quiet --retry=$STOP_SCHEDULE --pidfile $PID --name $NAME RETVAL="$?" - sleep 1 return "$RETVAL" } -# -# Function that sends a SIGHUP to the daemon/service -# -do_reload() { +reload_nginx() { + # Function that sends a SIGHUP to the daemon/service start-stop-daemon --stop --signal HUP --quiet --pidfile $PID --name $NAME return 0 } -# -# Rotate log files -# -do_rotate() { +rotate_logs() { + # Rotate log files start-stop-daemon --stop --signal USR1 --quiet --pidfile $PID --name $NAME return 0 } -# -# Online upgrade nginx executable -# -# "Upgrading Executable on the Fly" -# http://nginx.org/en/docs/control.html -# -do_upgrade() { +upgrade_nginx() { + # Online upgrade nginx executable + # # Return # 0 if nginx has been successfully upgraded # 1 if nginx is not running @@ -127,34 +113,34 @@ do_upgrade() { case "$1" in start) - [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" - do_start + log_daemon_msg "Starting $DESC" "$NAME" + start_nginx case "$?" in - 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; - 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + 0|1) log_end_msg 0 ;; + 2) log_end_msg 1 ;; esac ;; stop) - [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" - do_stop + log_daemon_msg "Stopping $DESC" "$NAME" + stop_nginx case "$?" in - 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; - 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + 0|1) log_end_msg 0 ;; + 2) log_end_msg 1 ;; esac ;; restart) log_daemon_msg "Restarting $DESC" "$NAME" # Check configuration before stopping nginx - if ! test_nginx_config; then + if ! test_config; then log_end_msg 1 # Configuration error - exit 0 + exit $? fi - do_stop + stop_nginx case "$?" in 0|1) - do_start + start_nginx case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running @@ -170,36 +156,31 @@ case "$1" in reload|force-reload) log_daemon_msg "Reloading $DESC configuration" "$NAME" - # Check configuration before reload nginx - # - # This is not entirely correct since the on-disk nginx binary - # may differ from the in-memory one, but that's not common. - # We prefer to check the configuration and return an error - # to the administrator. - if ! test_nginx_config; then + # Check configuration before stopping nginx + if ! test_config; then log_end_msg 1 # Configuration error - exit 0 + exit $? fi - do_reload + reload_nginx log_end_msg $? ;; configtest|testconfig) log_daemon_msg "Testing $DESC configuration" - test_nginx_config + test_config log_end_msg $? ;; status) - status_of_proc -p $PID "$DAEMON" "$NAME" && exit 0 || exit $? + status_of_proc -p $PID "$DAEMON" "$NAME" ;; upgrade) log_daemon_msg "Upgrading binary" "$NAME" - do_upgrade - log_end_msg 0 + upgrade_nginx + log_end_msg $? ;; rotate) log_daemon_msg "Re-opening $DESC log files" "$NAME" - do_rotate + rotate_logs log_end_msg $? ;; *) @@ -207,5 +188,3 @@ case "$1" in exit 3 ;; esac - -: From ac2d55e8d2e1dd3c5a5521640cde8f0cacb2a38b Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 16 Jun 2015 19:17:14 +0300 Subject: [PATCH 037/651] initscript: Fix exit status We need to explicitly `exit $?` since we don't use `set -e` --- debian/nginx-common.nginx.init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/nginx-common.nginx.init b/debian/nginx-common.nginx.init index c5bf8d9..8c8841a 100644 --- a/debian/nginx-common.nginx.init +++ b/debian/nginx-common.nginx.init @@ -171,7 +171,7 @@ case "$1" in log_end_msg $? ;; status) - status_of_proc -p $PID "$DAEMON" "$NAME" + status_of_proc -p $PID "$DAEMON" "$NAME" && exit 0 || exit $? ;; upgrade) log_daemon_msg "Upgrading binary" "$NAME" From 8550544cb4ab80a41261eba1ce964605e50ee527 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 17 Jun 2015 11:18:53 +0300 Subject: [PATCH 038/651] initscript: Add some comments/hints --- debian/nginx-common.nginx.init | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/nginx-common.nginx.init b/debian/nginx-common.nginx.init index 8c8841a..db10b7d 100644 --- a/debian/nginx-common.nginx.init +++ b/debian/nginx-common.nginx.init @@ -85,6 +85,7 @@ rotate_logs() { upgrade_nginx() { # Online upgrade nginx executable + # http://nginx.org/en/docs/control.html # # Return # 0 if nginx has been successfully upgraded @@ -157,6 +158,11 @@ case "$1" in log_daemon_msg "Reloading $DESC configuration" "$NAME" # Check configuration before stopping nginx + # + # This is not entirely correct since the on-disk nginx binary + # may differ from the in-memory one, but that's not common. + # We prefer to check the configuration and return an error + # to the administrator. if ! test_config; then log_end_msg 1 # Configuration error exit $? From eac12fe22e55c204eec89422b58d84a6d5bb390f Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 17 Jun 2015 11:21:32 +0300 Subject: [PATCH 039/651] Imported Upstream version 1.9.2 --- CHANGES | 40 +- CHANGES.ru | 31 +- auto/cc/gcc | 2 +- auto/install | 4 - auto/lib/openssl/conf | 48 ++ auto/make | 8 +- auto/modules | 5 + auto/options | 4 + auto/sources | 6 +- conf/fastcgi.conf | 1 + conf/fastcgi_params | 1 + conf/scgi_params | 1 + conf/uwsgi_params | 1 + man/nginx.8 | 8 +- src/core/nginx.c | 30 +- src/core/nginx.h | 4 +- src/core/ngx_conf_file.c | 47 +- src/core/ngx_conf_file.h | 7 + src/core/ngx_core.h | 1 + src/core/ngx_cycle.c | 8 + src/core/ngx_cycle.h | 2 + src/core/ngx_log.h | 15 +- .../ngx_parse_time.c} | 3 +- src/core/ngx_parse_time.h | 22 + src/core/ngx_proxy_protocol.c | 51 +- src/core/ngx_proxy_protocol.h | 4 +- src/event/ngx_event.c | 3 +- src/event/ngx_event_openssl_stapling.c | 68 ++- src/event/ngx_event_pipe.c | 2 +- src/http/modules/ngx_http_dav_module.c | 2 +- .../modules/ngx_http_headers_filter_module.c | 2 +- .../ngx_http_not_modified_filter_module.c | 4 +- .../modules/ngx_http_range_filter_module.c | 2 +- .../ngx_http_upstream_keepalive_module.c | 81 ++-- src/http/ngx_http.h | 5 - src/http/ngx_http_core_module.c | 4 +- src/http/ngx_http_request.c | 4 +- src/http/ngx_http_spdy.c | 2 +- src/http/ngx_http_upstream.c | 6 +- src/mail/ngx_mail.c | 71 ++- src/mail/ngx_mail.h | 34 +- src/mail/ngx_mail_core_module.c | 28 +- src/os/unix/ngx_files.h | 1 + src/stream/ngx_stream.c | 89 ++-- src/stream/ngx_stream.h | 40 +- src/stream/ngx_stream_access_module.c | 451 ++++++++++++++++++ src/stream/ngx_stream_core_module.c | 30 +- src/stream/ngx_stream_handler.c | 37 +- src/stream/ngx_stream_proxy_module.c | 178 ++++++- src/stream/ngx_stream_ssl_module.c | 2 + src/stream/ngx_stream_upstream.c | 2 + src/stream/ngx_stream_upstream.h | 2 + src/stream/ngx_stream_upstream_hash_module.c | 2 + .../ngx_stream_upstream_least_conn_module.c | 2 + src/stream/ngx_stream_upstream_zone_module.c | 2 + 55 files changed, 1257 insertions(+), 253 deletions(-) rename src/{http/ngx_http_parse_time.c => core/ngx_parse_time.c} (98%) create mode 100644 src/core/ngx_parse_time.h create mode 100644 src/stream/ngx_stream_access_module.c diff --git a/CHANGES b/CHANGES index abb5e29..f4d77d7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,28 @@ +Changes with nginx 1.9.2 16 Jun 2015 + + *) Feature: the "backlog" parameter of the "listen" directives of the + mail proxy and stream modules. + + *) Feature: the "allow" and "deny" directives in the stream module. + + *) Feature: the "proxy_bind" directive in the stream module. + + *) Feature: the "proxy_protocol" directive in the stream module. + + *) Feature: the -T switch. + + *) Feature: the REQUEST_SCHEME parameter added to the fastcgi.conf, + fastcgi_params, scgi_params, and uwsgi_params standard configuration + files. + + *) Bugfix: the "reuseport" parameter of the "listen" directive of the + stream module did not work. + + *) Bugfix: OCSP stapling might return an expired OCSP response in some + cases. + + Changes with nginx 1.9.1 26 May 2015 *) Change: now SSLv3 protocol is disabled by default. @@ -1467,7 +1491,7 @@ Changes with nginx 1.1.11 12 Dec 2011 Changes with nginx 1.1.10 30 Nov 2011 - *) Bugfix: a segmentation fault occured in a worker process if AIO was + *) Bugfix: a segmentation fault occurred in a worker process if AIO was used on Linux; the bug had appeared in 1.1.9. @@ -1744,7 +1768,7 @@ Changes with nginx 1.1.0 01 Aug 2011 and proxies to an HTTPS backend. Thanks to Maxim Dounin. - *) Bugfix: in parameter validaiton of a "proxy_pass" directive with + *) Bugfix: in parameter validation of a "proxy_pass" directive with variables. Thanks to Lanshun Zhou. @@ -4509,7 +4533,7 @@ Changes with nginx 0.5.22 29 May 2007 Changes with nginx 0.5.21 28 May 2007 *) Bugfix: if server has more than about ten locations, then regex - locations might be choosen not in that order as they were specified. + locations might be chosen not in that order as they were specified. *) Bugfix: a worker process may got caught in an endless loop on 64-bit platform, if the 33-rd or next in succession backend has failed. @@ -4595,7 +4619,7 @@ Changes with nginx 0.5.17 02 Apr 2007 *) Bugfix: in the HTTPS protocol in the "proxy_pass" directive. - *) Bugfix: in some cases non-cachable variables (such as $uri variable) + *) Bugfix: in some cases non-cacheable variables (such as $uri variable) returned old cached value. @@ -4620,7 +4644,7 @@ Changes with nginx 0.5.16 26 Mar 2007 Changes with nginx 0.5.15 19 Mar 2007 *) Feature: the mail proxy supports authenticated SMTP proxying and the - "smtp_auth", "smtp_capablities", and "xclient" directives. + "smtp_auth", "smtp_capabilities", and "xclient" directives. Thanks to Anton Yuzhaninov and Maxim Dounin. *) Feature: now the keep-alive connections are closed just after @@ -5721,7 +5745,7 @@ Changes with nginx 0.3.21 16 Jan 2006 *) Feature: the ngx_http_perl_module. - *) Change: the "valid_referers" directive allows the referreres without + *) Change: the "valid_referers" directive allows the referrers without URI part. @@ -5821,7 +5845,7 @@ Changes with nginx 0.3.15 07 Dec 2005 *) Feature: the "so_keepalive" directive in IMAP/POP3 proxy. *) Bugfix: if there are unclosed connection nginx now calls abort() only - on gracefull quit and active "debug_points" directive. + on graceful quit and active "debug_points" directive. Changes with nginx 0.3.14 05 Dec 2005 @@ -6362,7 +6386,7 @@ Changes with nginx 0.1.37 23 Jun 2005 *) Bugfix: the responses may be transferred not completely, if many parts or the big parts were included by SSI. - *) Bugfix: if all backends had returned the 404 reponse and the + *) Bugfix: if all backends had returned the 404 response and the "http_404" parameter of the "proxy_next_upstream" or "fastcgi_next_upstream" directives was used, then nginx started to request all backends again. diff --git a/CHANGES.ru b/CHANGES.ru index b70c132..ac40495 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,28 @@ +Изменения в nginx 1.9.2 16.06.2015 + + *) Добавление: параметр backlog директивы listen в почтовом + прокси-сервере и модуле stream. + + *) Добавление: директивы allow и deny в модуле stream. + + *) Добавление: директива proxy_bind в модуле stream. + + *) Добавление: директива proxy_protocol в модуле stream. + + *) Добавление: ключ -T. + + *) Добавление: параметр REQUEST_SCHEME добавлен в стандартные + конфигурационные файлы fastcgi.conf, fastcgi_params, scgi_params и + uwsgi_params. + + *) Исправление: параметр reuseport директивы listen в модуле stream не + работал. + + *) Исправление: OCSP stapling в некоторых случаях мог вернуть устаревший + OCSP-ответ. + + Изменения в nginx 1.9.1 26.05.2015 *) Изменение: теперь протокол SSLv3 по умолчанию запрещён. @@ -83,7 +107,7 @@ прокси-сервере. Спасибо Sven Peter, Franck Levionnois и Filipe Da Silva. - *) Добавление: уменьшение времени запуска при использовании дирекивы + *) Добавление: уменьшение времени запуска при использовании директивы "hash ... consistent" в блоке upstream. Спасибо Wai Keen Woon. @@ -4721,7 +4745,8 @@ Изменения в nginx 0.5.15 19.03.2007 *) Добавление: почтовый прокси-сервер поддерживает аутентифицированное - SMTP-проксирование и директивы smtp_auth, smtp_capablities и xclient. + SMTP-проксирование и директивы smtp_auth, smtp_capabilities и + xclient. Спасибо Антону Южанинову и Максиму Дунину. *) Добавление: теперь keep-alive соединения закрываются сразу же по @@ -5926,7 +5951,7 @@ *) Добавление: директива so_keepalive в IMAP/POP3 прокси. *) Исправление: nginx теперь вызывает abort() при обнаружении незакрытых - соединений только при планом выходе и включённой директиве + соединений только при плавном выходе и включённой директиве debug_points. diff --git a/auto/cc/gcc b/auto/cc/gcc index 727f11e..c9101fe 100644 --- a/auto/cc/gcc +++ b/auto/cc/gcc @@ -153,7 +153,7 @@ CFLAGS="$CFLAGS -Wall -Wpointer-arith" case "$NGX_GCC_VER" in - 3.* | 4.* ) + [3-5].*) # we have a lot of the unused function arguments CFLAGS="$CFLAGS -Wno-unused-parameter" # 4.2.1 shows the warning in wrong places diff --git a/auto/install b/auto/install index 254f9bc..f7f686c 100644 --- a/auto/install +++ b/auto/install @@ -20,10 +20,6 @@ case ".$NGX_SBIN_PATH" in ./*) ;; - .) - NGX_SBIN_PATH=$NGX_PREFIX/sbin/nginx - ;; - *) NGX_SBIN_PATH=$NGX_PREFIX/$NGX_SBIN_PATH ;; diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf index a65815f..bca2050 100644 --- a/auto/lib/openssl/conf +++ b/auto/lib/openssl/conf @@ -55,6 +55,54 @@ else ngx_feature_test="SSL_library_init()" . auto/feature + if [ $ngx_found = no ]; then + + # FreeBSD port + + ngx_feature="OpenSSL library in /usr/local/" + ngx_feature_path="/usr/local/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lssl -lcrypto" + else + ngx_feature_libs="-L/usr/local/lib -lssl -lcrypto" + fi + + . auto/feature + fi + + if [ $ngx_found = no ]; then + + # NetBSD port + + ngx_feature="OpenSSL library in /usr/pkg/" + ngx_feature_path="/usr/pkg/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lssl -lcrypto" + else + ngx_feature_libs="-L/usr/pkg/lib -lssl -lcrypto" + fi + + . auto/feature + fi + + if [ $ngx_found = no ]; then + + # MacPorts + + ngx_feature="OpenSSL library in /opt/local/" + ngx_feature_path="/opt/local/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lssl -lcrypto" + else + ngx_feature_libs="-L/opt/local/lib -lssl -lcrypto" + fi + + . auto/feature + fi + if [ $ngx_found = yes ]; then have=NGX_SSL . auto/have CORE_LIBS="$CORE_LIBS $ngx_feature_libs $NGX_LIBDL" diff --git a/auto/make b/auto/make index 98c2e3b..78d0422 100644 --- a/auto/make +++ b/auto/make @@ -50,7 +50,7 @@ END ngx_all_srcs="$CORE_SRCS" -# the core dependences and include paths +# the core dependencies and include paths ngx_deps=`echo $CORE_DEPS $NGX_AUTO_CONFIG_H $NGX_PCH \ | sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont\1/g" \ @@ -70,7 +70,7 @@ CORE_INCS = $ngx_include_opt$ngx_incs END -# the http dependences and include paths +# the http dependencies and include paths if [ $HTTP = YES ]; then @@ -96,7 +96,7 @@ END fi -# the mail dependences and include paths +# the mail dependencies and include paths if [ $MAIL = YES ]; then @@ -122,7 +122,7 @@ END fi -# the stream dependences and include paths +# the stream dependencies and include paths if [ $STREAM = YES ]; then diff --git a/auto/modules b/auto/modules index de3dc4a..82b8bca 100644 --- a/auto/modules +++ b/auto/modules @@ -514,6 +514,11 @@ if [ $STREAM = YES ]; then STREAM_SRCS="$STREAM_SRCS $STREAM_SSL_SRCS" fi + if [ $STREAM_ACCESS = YES ]; then + modules="$modules $STREAM_ACCESS_MODULE" + STREAM_SRCS="$STREAM_SRCS $STREAM_ACCESS_SRCS" + fi + if [ $STREAM_UPSTREAM_HASH = YES ]; then modules="$modules $STREAM_UPSTREAM_HASH_MODULE" STREAM_SRCS="$STREAM_SRCS $STREAM_UPSTREAM_HASH_SRCS" diff --git a/auto/options b/auto/options index e3a7ede..febbc27 100644 --- a/auto/options +++ b/auto/options @@ -113,6 +113,7 @@ MAIL_SMTP=YES STREAM=NO STREAM_SSL=NO +STREAM_ACCESS=YES STREAM_UPSTREAM_HASH=YES STREAM_UPSTREAM_LEAST_CONN=YES STREAM_UPSTREAM_ZONE=YES @@ -282,6 +283,7 @@ use the \"--with-mail_ssl_module\" option instead" --with-stream) STREAM=YES ;; --with-stream_ssl_module) STREAM_SSL=YES ;; + --without-stream_access_module) STREAM_ACCESS=NO ;; --without-stream_upstream_hash_module) STREAM_UPSTREAM_HASH=NO ;; --without-stream_upstream_least_conn_module) @@ -450,6 +452,7 @@ cat << END --with-stream enable TCP proxy module --with-stream_ssl_module enable ngx_stream_ssl_module + --without-stream_access_module disable ngx_stream_access_module --without-stream_upstream_hash_module disable ngx_stream_upstream_hash_module --without-stream_upstream_least_conn_module @@ -522,6 +525,7 @@ if [ ".$NGX_PLATFORM" = ".win32" ]; then fi +NGX_SBIN_PATH=${NGX_SBIN_PATH:-sbin/nginx} NGX_CONF_PATH=${NGX_CONF_PATH:-conf/nginx.conf} NGX_CONF_PREFIX=`dirname $NGX_CONF_PATH` NGX_PID_PATH=${NGX_PID_PATH:-logs/nginx.pid} diff --git a/auto/sources b/auto/sources index 156db56..44fba51 100644 --- a/auto/sources +++ b/auto/sources @@ -19,6 +19,7 @@ CORE_DEPS="src/core/nginx.h \ src/core/ngx_queue.h \ src/core/ngx_string.h \ src/core/ngx_parse.h \ + src/core/ngx_parse_time.h \ src/core/ngx_inet.h \ src/core/ngx_file.h \ src/core/ngx_crc.h \ @@ -53,6 +54,7 @@ CORE_SRCS="src/core/nginx.c \ src/core/ngx_output_chain.c \ src/core/ngx_string.c \ src/core/ngx_parse.c \ + src/core/ngx_parse_time.c \ src/core/ngx_inet.c \ src/core/ngx_file.c \ src/core/ngx_crc32.c \ @@ -303,7 +305,6 @@ HTTP_SRCS="src/http/ngx_http.c \ src/http/ngx_http_script.c \ src/http/ngx_http_upstream.c \ src/http/ngx_http_upstream_round_robin.c \ - src/http/ngx_http_parse_time.c \ src/http/modules/ngx_http_static_module.c \ src/http/modules/ngx_http_index_module.c \ src/http/modules/ngx_http_chunked_filter_module.c \ @@ -567,6 +568,9 @@ STREAM_SSL_MODULE="ngx_stream_ssl_module" STREAM_SSL_DEPS="src/stream/ngx_stream_ssl_module.h" STREAM_SSL_SRCS="src/stream/ngx_stream_ssl_module.c" +STREAM_ACCESS_MODULE=ngx_stream_access_module +STREAM_ACCESS_SRCS=src/stream/ngx_stream_access_module.c + STREAM_UPSTREAM_HASH_MODULE=ngx_stream_upstream_hash_module STREAM_UPSTREAM_HASH_SRCS=src/stream/ngx_stream_upstream_hash_module.c diff --git a/conf/fastcgi.conf b/conf/fastcgi.conf index ac9ff92..091738c 100644 --- a/conf/fastcgi.conf +++ b/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 REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; diff --git a/conf/fastcgi_params b/conf/fastcgi_params index 71e2c2e..28decb9 100644 --- a/conf/fastcgi_params +++ b/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 REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; diff --git a/conf/scgi_params b/conf/scgi_params index 47348ca..6d4ce4f 100644 --- a/conf/scgi_params +++ b/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 REQUEST_SCHEME $scheme; scgi_param HTTPS $https if_not_empty; scgi_param REMOTE_ADDR $remote_addr; diff --git a/conf/uwsgi_params b/conf/uwsgi_params index f539451..09c732c 100644 --- a/conf/uwsgi_params +++ b/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 REQUEST_SCHEME $scheme; uwsgi_param HTTPS $https if_not_empty; uwsgi_param REMOTE_ADDR $remote_addr; diff --git a/man/nginx.8 b/man/nginx.8 index f119a23..1f4dc89 100644 --- a/man/nginx.8 +++ b/man/nginx.8 @@ -25,7 +25,7 @@ .\" SUCH DAMAGE. .\" .\" -.Dd March 6, 2012 +.Dd June 16, 2015 .Dt NGINX 8 .Os .Sh NAME @@ -33,7 +33,7 @@ .Nd "HTTP and reverse proxy server, mail proxy server" .Sh SYNOPSIS .Nm -.Op Fl ?hqtVv +.Op Fl ?hqTtVv .Op Fl c Ar file .Op Fl g Ar directives .Op Fl p Ar prefix @@ -87,6 +87,10 @@ Do not run, just test the configuration file. .Nm checks the configuration file syntax and then tries to open files referenced in the configuration file. +.It Fl T +Same as +.Fl t , +but additionally dump configuration files to standard output. .It Fl V Print the .Nm diff --git a/src/core/nginx.c b/src/core/nginx.c index 231a3da..3213527 100644 --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -176,9 +176,11 @@ static char **ngx_os_environ; int ngx_cdecl main(int argc, char *const *argv) { - ngx_int_t i; + ngx_buf_t *b; ngx_log_t *log; + ngx_uint_t i; ngx_cycle_t *cycle, init_cycle; + ngx_conf_dump_t *cd; ngx_core_conf_t *ccf; ngx_debug_init(); @@ -196,7 +198,7 @@ main(int argc, char *const *argv) if (ngx_show_help) { ngx_write_stderr( - "Usage: nginx [-?hvVtq] [-s signal] [-c filename] " + "Usage: nginx [-?hvVtTq] [-s signal] [-c filename] " "[-p prefix] [-g directives]" NGX_LINEFEED NGX_LINEFEED "Options:" NGX_LINEFEED @@ -205,6 +207,8 @@ main(int argc, char *const *argv) " -V : show version and configure options then exit" NGX_LINEFEED " -t : test configuration and exit" NGX_LINEFEED + " -T : test configuration, dump it and exit" + NGX_LINEFEED " -q : suppress non-error messages " "during configuration testing" NGX_LINEFEED " -s signal : send signal to a master process: " @@ -333,6 +337,23 @@ main(int argc, char *const *argv) cycle->conf_file.data); } + if (ngx_dump_config) { + cd = cycle->config_dump.elts; + + for (i = 0; i < cycle->config_dump.nelts; i++) { + + ngx_write_stdout("# configuration file "); + (void) ngx_write_fd(ngx_stdout, cd[i].name.data, + cd[i].name.len); + ngx_write_stdout(":" NGX_LINEFEED); + + b = cd[i].buffer; + + (void) ngx_write_fd(ngx_stdout, b->pos, b->last - b->pos); + ngx_write_stdout(NGX_LINEFEED); + } + } + return 0; } @@ -689,6 +710,11 @@ ngx_get_options(int argc, char *const *argv) ngx_test_config = 1; break; + case 'T': + ngx_test_config = 1; + ngx_dump_config = 1; + break; + case 'q': ngx_quiet_mode = 1; break; diff --git a/src/core/nginx.h b/src/core/nginx.h index ec818e0..4c9cf35 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1009001 -#define NGINX_VERSION "1.9.1" +#define nginx_version 1009002 +#define NGINX_VERSION "1.9.2" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c index ec3c1fa..1c3238c 100644 --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -101,10 +101,13 @@ char * ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) { char *rv; + u_char *p; + off_t size; ngx_fd_t fd; ngx_int_t rc; - ngx_buf_t buf; + ngx_buf_t buf, *tbuf; ngx_conf_file_t *prev, conf_file; + ngx_conf_dump_t *cd; enum { parse_file = 0, parse_block, @@ -158,6 +161,39 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) type = parse_file; + if (ngx_dump_config +#if (NGX_DEBUG) + || 1 +#endif + ) + { + p = ngx_pstrdup(cf->cycle->pool, filename); + if (p == NULL) { + goto failed; + } + + size = ngx_file_size(&cf->conf_file->file.info); + + tbuf = ngx_create_temp_buf(cf->cycle->pool, (size_t) size); + if (tbuf == NULL) { + goto failed; + } + + cd = ngx_array_push(&cf->cycle->config_dump); + if (cd == NULL) { + goto failed; + } + + cd->name.len = filename->len; + cd->name.data = p; + cd->buffer = tbuf; + + cf->conf_file->dump = tbuf; + + } else { + cf->conf_file->dump = NULL; + } + } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) { type = parse_block; @@ -437,7 +473,7 @@ ngx_conf_read_token(ngx_conf_t *cf) ngx_uint_t found, need_space, last_space, sharp_comment, variable; ngx_uint_t quoted, s_quoted, d_quoted, start_line; ngx_str_t *word; - ngx_buf_t *b; + ngx_buf_t *b, *dump; found = 0; need_space = 0; @@ -450,6 +486,7 @@ ngx_conf_read_token(ngx_conf_t *cf) cf->args->nelts = 0; b = cf->conf_file->buffer; + dump = cf->conf_file->dump; start = b->pos; start_line = cf->conf_file->line; @@ -531,6 +568,10 @@ ngx_conf_read_token(ngx_conf_t *cf) b->pos = b->start + len; b->last = b->pos + n; start = b->start; + + if (dump) { + dump->last = ngx_cpymem(dump->last, b->pos, size); + } } ch = *b->pos++; @@ -680,7 +721,7 @@ ngx_conf_read_token(ngx_conf_t *cf) return NGX_ERROR; } - word->data = ngx_pnalloc(cf->pool, b->pos - start + 1); + word->data = ngx_pnalloc(cf->pool, b->pos - 1 - start + 1); if (word->data == NULL) { return NGX_ERROR; } diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h index d73a6c8..ee44306 100644 --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -146,10 +146,17 @@ typedef struct { typedef struct { ngx_file_t file; ngx_buf_t *buffer; + ngx_buf_t *dump; ngx_uint_t line; } ngx_conf_file_t; +typedef struct { + ngx_str_t name; + ngx_buf_t *buffer; +} ngx_conf_dump_t; + + typedef char *(*ngx_conf_handler_pt)(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h index a279c81..6b31705 100644 --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -54,6 +54,7 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c); #include #include #include +#include #include #include #include diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c index b358f3d..ad4bf92 100644 --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -24,6 +24,7 @@ static ngx_pool_t *ngx_temp_pool; static ngx_event_t ngx_cleaner_event; ngx_uint_t ngx_test_config; +ngx_uint_t ngx_dump_config; ngx_uint_t ngx_quiet_mode; @@ -124,6 +125,13 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) cycle->paths.pool = pool; + if (ngx_array_init(&cycle->config_dump, pool, 1, sizeof(ngx_conf_dump_t)) + != NGX_OK) + { + ngx_destroy_pool(pool); + return NULL; + } + if (old_cycle->open_files.part.nelts) { n = old_cycle->open_files.part.nelts; for (part = old_cycle->open_files.part.next; part; part = part->next) { diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h index c601ea1..b77c109 100644 --- a/src/core/ngx_cycle.h +++ b/src/core/ngx_cycle.h @@ -52,6 +52,7 @@ struct ngx_cycle_s { ngx_array_t listening; ngx_array_t paths; + ngx_array_t config_dump; ngx_list_t open_files; ngx_list_t shared_memory; @@ -124,6 +125,7 @@ extern volatile ngx_cycle_t *ngx_cycle; extern ngx_array_t ngx_old_cycles; extern ngx_module_t ngx_core_module; extern ngx_uint_t ngx_test_config; +extern ngx_uint_t ngx_dump_config; extern ngx_uint_t ngx_quiet_mode; diff --git a/src/core/ngx_log.h b/src/core/ngx_log.h index cb80b5f..618d3ad 100644 --- a/src/core/ngx_log.h +++ b/src/core/ngx_log.h @@ -111,7 +111,7 @@ void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, /*********************************/ -#else /* NO VARIADIC MACROS */ +#else /* no variadic macros */ #define NGX_HAVE_VARIADIC_MACROS 0 @@ -123,7 +123,7 @@ void ngx_cdecl ngx_log_debug_core(ngx_log_t *log, ngx_err_t err, const char *fmt, ...); -#endif /* VARIADIC MACROS */ +#endif /* variadic macros */ /*********************************/ @@ -166,7 +166,7 @@ void ngx_cdecl ngx_log_debug_core(ngx_log_t *log, ngx_err_t err, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) -#else /* NO VARIADIC MACROS */ +#else /* no variadic macros */ #define ngx_log_debug0(level, log, err, fmt) \ if ((log)->log_level & level) \ @@ -211,7 +211,7 @@ void ngx_cdecl ngx_log_debug_core(ngx_log_t *log, ngx_err_t err, #endif -#else /* NO NGX_DEBUG */ +#else /* !NGX_DEBUG */ #define ngx_log_debug0(level, log, err, fmt) #define ngx_log_debug1(level, log, err, fmt, arg1) @@ -255,6 +255,13 @@ ngx_write_stderr(char *text) } +static ngx_inline void +ngx_write_stdout(char *text) +{ + (void) ngx_write_fd(ngx_stdout, text, ngx_strlen(text)); +} + + extern ngx_module_t ngx_errlog_module; extern ngx_uint_t ngx_use_stderr; diff --git a/src/http/ngx_http_parse_time.c b/src/core/ngx_parse_time.c similarity index 98% rename from src/http/ngx_http_parse_time.c rename to src/core/ngx_parse_time.c index 985af31..831cc71 100644 --- a/src/http/ngx_http_parse_time.c +++ b/src/core/ngx_parse_time.c @@ -7,13 +7,12 @@ #include #include -#include static ngx_uint_t mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; time_t -ngx_http_parse_time(u_char *value, size_t len) +ngx_parse_http_time(u_char *value, size_t len) { u_char *p, *end; ngx_int_t month; diff --git a/src/core/ngx_parse_time.h b/src/core/ngx_parse_time.h new file mode 100644 index 0000000..aa542eb --- /dev/null +++ b/src/core/ngx_parse_time.h @@ -0,0 +1,22 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_PARSE_TIME_H_INCLUDED_ +#define _NGX_PARSE_TIME_H_INCLUDED_ + + +#include +#include + + +time_t ngx_parse_http_time(u_char *value, size_t len); + +/* compatibility */ +#define ngx_http_parse_time(value, len) ngx_parse_http_time(value, len) + + +#endif /* _NGX_PARSE_TIME_H_INCLUDED_ */ diff --git a/src/core/ngx_proxy_protocol.c b/src/core/ngx_proxy_protocol.c index 59ef010..f347e7f 100644 --- a/src/core/ngx_proxy_protocol.c +++ b/src/core/ngx_proxy_protocol.c @@ -10,7 +10,7 @@ u_char * -ngx_proxy_protocol_parse(ngx_connection_t *c, u_char *buf, u_char *last) +ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last) { size_t len; u_char ch, *p, *addr; @@ -89,3 +89,52 @@ invalid: return NULL; } + + +u_char * +ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *last) +{ + ngx_uint_t port, lport; + + if (last - buf < NGX_PROXY_PROTOCOL_MAX_HEADER) { + return NULL; + } + + if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { + return NULL; + } + + switch (c->sockaddr->sa_family) { + + case AF_INET: + buf = ngx_cpymem(buf, "PROXY TCP4 ", sizeof("PROXY TCP4 ") - 1); + + port = ntohs(((struct sockaddr_in *) c->sockaddr)->sin_port); + lport = ntohs(((struct sockaddr_in *) c->local_sockaddr)->sin_port); + + break; + +#if (NGX_HAVE_INET6) + case AF_INET6: + buf = ngx_cpymem(buf, "PROXY TCP6 ", sizeof("PROXY TCP6 ") - 1); + + port = ntohs(((struct sockaddr_in6 *) c->sockaddr)->sin6_port); + lport = ntohs(((struct sockaddr_in6 *) c->local_sockaddr)->sin6_port); + + break; +#endif + + default: + return ngx_cpymem(buf, "PROXY UNKNOWN" CRLF, + sizeof("PROXY UNKNOWN" CRLF) - 1); + } + + buf += ngx_sock_ntop(c->sockaddr, c->socklen, buf, last - buf, 0); + + *buf++ = ' '; + + buf += ngx_sock_ntop(c->local_sockaddr, c->local_socklen, buf, last - buf, + 0); + + return ngx_slprintf(buf, last, " %ui %ui" CRLF, port, lport); +} diff --git a/src/core/ngx_proxy_protocol.h b/src/core/ngx_proxy_protocol.h index 4f39125..fb848f6 100644 --- a/src/core/ngx_proxy_protocol.h +++ b/src/core/ngx_proxy_protocol.h @@ -16,7 +16,9 @@ #define NGX_PROXY_PROTOCOL_MAX_HEADER 107 -u_char *ngx_proxy_protocol_parse(ngx_connection_t *c, u_char *buf, +u_char *ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, + u_char *last); +u_char *ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *last); diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index 34a07e4..b8e0607 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -927,8 +927,9 @@ ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) *cf = pcf; - if (rv != NGX_CONF_OK) + if (rv != NGX_CONF_OK) { return rv; + } for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_EVENT_MODULE) { diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c index c39598f..03ff540 100644 --- a/src/event/ngx_event_openssl_stapling.c +++ b/src/event/ngx_event_openssl_stapling.c @@ -32,6 +32,7 @@ typedef struct { X509 *issuer; time_t valid; + time_t refresh; unsigned verify:1; unsigned loading:1; @@ -93,6 +94,8 @@ static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, static void ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple); static void ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx); +static time_t ngx_ssl_stapling_time(ASN1_GENERALIZEDTIME *asn1time); + static void ngx_ssl_stapling_cleanup(void *data); static ngx_ssl_ocsp_ctx_t *ngx_ssl_ocsp_start(void); @@ -462,7 +465,9 @@ ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data) staple = data; rc = SSL_TLSEXT_ERR_NOACK; - if (staple->staple.len) { + if (staple->staple.len + && staple->valid >= ngx_time()) + { /* we have to copy ocsp response as OpenSSL will free it by itself */ p = OPENSSL_malloc(staple->staple.len); @@ -490,7 +495,7 @@ ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple) ngx_ssl_ocsp_ctx_t *ctx; if (staple->host.len == 0 - || staple->loading || staple->valid >= ngx_time()) + || staple->loading || staple->refresh >= ngx_time()) { return; } @@ -532,6 +537,7 @@ ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx) u_char *p; int n; size_t len; + time_t now, valid; ngx_str_t response; X509_STORE *store; STACK_OF(X509) *chain; @@ -542,6 +548,7 @@ ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx) ASN1_GENERALIZEDTIME *thisupdate, *nextupdate; staple = ctx->data; + now = ngx_time(); ocsp = NULL; basic = NULL; id = NULL; @@ -629,17 +636,28 @@ ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx) goto error; } + valid = ngx_ssl_stapling_time(nextupdate); + if (valid == (time_t) NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, ctx->log, 0, + "invalid nextUpdate time in certificate status"); + goto error; + } + OCSP_CERTID_free(id); OCSP_BASICRESP_free(basic); OCSP_RESPONSE_free(ocsp); + id = NULL; + basic = NULL; + ocsp = NULL; + /* copy the response to memory not in ctx->pool */ response.len = len; response.data = ngx_alloc(response.len, ctx->log); if (response.data == NULL) { - goto done; + goto error; } ngx_memcpy(response.data, ctx->response->pos, response.len); @@ -653,11 +671,15 @@ ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx) } staple->staple = response; + staple->valid = valid; -done: + /* + * refresh before the response expires, + * but not earlier than in 5 minutes, and at least in an hour + */ staple->loading = 0; - staple->valid = ngx_time() + 3600; /* ssl_stapling_valid */ + staple->refresh = ngx_max(ngx_min(valid - 300, now + 3600), now + 300); ngx_ssl_ocsp_done(ctx); return; @@ -665,7 +687,7 @@ done: error: staple->loading = 0; - staple->valid = ngx_time() + 300; /* ssl_stapling_err_valid */ + staple->refresh = now + 300; if (id) { OCSP_CERTID_free(id); @@ -683,6 +705,40 @@ error: } +static time_t +ngx_ssl_stapling_time(ASN1_GENERALIZEDTIME *asn1time) +{ + u_char *value; + size_t len; + time_t time; + BIO *bio; + + /* + * OpenSSL doesn't provide a way to convert ASN1_GENERALIZEDTIME + * into time_t. To do this, we use ASN1_GENERALIZEDTIME_print(), + * which uses the "MMM DD HH:MM:SS YYYY [GMT]" format (e.g., + * "Feb 3 00:55:52 2015 GMT"), and parse the result. + */ + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) { + return NGX_ERROR; + } + + /* fake weekday prepended to match C asctime() format */ + + BIO_write(bio, "Tue ", sizeof("Tue ") - 1); + ASN1_GENERALIZEDTIME_print(bio, asn1time); + len = BIO_get_mem_data(bio, &value); + + time = ngx_parse_http_time(value, len); + + BIO_free(bio); + + return time; +} + + static void ngx_ssl_stapling_cleanup(void *data) { diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c index 8ba247f..2d0e7d3 100644 --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -22,8 +22,8 @@ static ngx_int_t ngx_event_pipe_drain_chains(ngx_event_pipe_t *p); ngx_int_t ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write) { - u_int flags; ngx_int_t rc; + ngx_uint_t flags; ngx_event_t *rev, *wev; for ( ;; ) { diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c index 529aba5..b9fadd0 100644 --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -255,7 +255,7 @@ ngx_http_dav_put_handler(ngx_http_request_t *r) ext.log = r->connection->log; if (r->headers_in.date) { - date = ngx_http_parse_time(r->headers_in.date->value.data, + date = ngx_parse_http_time(r->headers_in.date->value.data, r->headers_in.date->value.len); if (date != NGX_ERROR) { diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c index a356814..985e5b3 100644 --- a/src/http/modules/ngx_http_headers_filter_module.c +++ b/src/http/modules/ngx_http_headers_filter_module.c @@ -498,7 +498,7 @@ ngx_http_set_last_modified(ngx_http_request_t *r, ngx_http_header_val_t *hv, } r->headers_out.last_modified_time = - (value->len) ? ngx_http_parse_time(value->data, value->len) : -1; + (value->len) ? ngx_parse_http_time(value->data, value->len) : -1; return NGX_OK; } diff --git a/src/http/modules/ngx_http_not_modified_filter_module.c b/src/http/modules/ngx_http_not_modified_filter_module.c index acc94de..032ba96 100644 --- a/src/http/modules/ngx_http_not_modified_filter_module.c +++ b/src/http/modules/ngx_http_not_modified_filter_module.c @@ -118,7 +118,7 @@ ngx_http_test_if_unmodified(ngx_http_request_t *r) return 0; } - iums = ngx_http_parse_time(r->headers_in.if_unmodified_since->value.data, + iums = ngx_parse_http_time(r->headers_in.if_unmodified_since->value.data, r->headers_in.if_unmodified_since->value.len); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -148,7 +148,7 @@ ngx_http_test_if_modified(ngx_http_request_t *r) return 1; } - ims = ngx_http_parse_time(r->headers_in.if_modified_since->value.data, + ims = ngx_parse_http_time(r->headers_in.if_modified_since->value.data, r->headers_in.if_modified_since->value.len); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index bb9a42c..952da75 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -204,7 +204,7 @@ ngx_http_range_header_filter(ngx_http_request_t *r) goto next_filter; } - if_range_time = ngx_http_parse_time(if_range->data, if_range->len); + if_range_time = ngx_parse_http_time(if_range->data, if_range->len); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http ir:%d lm:%d", diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c b/src/http/modules/ngx_http_upstream_keepalive_module.c index 4e005fc..768881e 100644 --- a/src/http/modules/ngx_http_upstream_keepalive_module.c +++ b/src/http/modules/ngx_http_upstream_keepalive_module.c @@ -22,6 +22,18 @@ typedef struct { } ngx_http_upstream_keepalive_srv_conf_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; + + typedef struct { ngx_http_upstream_keepalive_srv_conf_t *conf; @@ -40,18 +52,6 @@ typedef struct { } 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, @@ -63,7 +63,6 @@ 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); @@ -244,24 +243,28 @@ ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc, void *data) 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->sent = 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; + goto found; } } return NGX_OK; + +found: + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "get keepalive peer: using connection %p", c); + + c->idle = 0; + c->sent = 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; } @@ -322,9 +325,10 @@ ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data, item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue); } - item->connection = c; ngx_queue_insert_head(&kp->conf->cache, q); + item->connection = c; + pc->connection = NULL; if (c->read->timer_set) { @@ -470,10 +474,9 @@ ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf) * * conf->original_init_upstream = NULL; * conf->original_init_peer = NULL; + * conf->max_cached = 0; */ - conf->max_cached = 1; - return conf; } @@ -487,18 +490,10 @@ ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_int_t n; ngx_str_t *value; - uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); - - if (kcf->original_init_upstream) { + if (kcf->max_cached) { return "is duplicate"; } - 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; @@ -514,5 +509,13 @@ ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) kcf->max_cached = n; + uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_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; + return NGX_CONF_OK; } diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index b1e5fae..844f502 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -148,11 +148,6 @@ ngx_int_t ngx_http_filter_finalize_request(ngx_http_request_t *r, void ngx_http_clean_header(ngx_http_request_t *r); -time_t ngx_http_parse_time(u_char *value, size_t len); -size_t ngx_http_get_time(char *buf, time_t t); - - - ngx_int_t ngx_http_discard_request_body(ngx_http_request_t *r); void ngx_http_discarded_request_body_handler(ngx_http_request_t *r); void ngx_http_block_reading(ngx_http_request_t *r); diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index f525526..d423d8b 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -2195,7 +2195,7 @@ ngx_http_gzip_ok(ngx_http_request_t *r) return NGX_DECLINED; } - expires = ngx_http_parse_time(e->value.data, e->value.len); + expires = ngx_parse_http_time(e->value.data, e->value.len); if (expires == NGX_ERROR) { return NGX_DECLINED; } @@ -2203,7 +2203,7 @@ ngx_http_gzip_ok(ngx_http_request_t *r) d = r->headers_out.date; if (d) { - date = ngx_http_parse_time(d->value.data, d->value.len); + date = ngx_parse_http_time(d->value.data, d->value.len); if (date == NGX_ERROR) { return NGX_DECLINED; } diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 2669b52..cd5f302 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -467,7 +467,7 @@ ngx_http_wait_request_handler(ngx_event_t *rev) if (hc->proxy_protocol) { hc->proxy_protocol = 0; - p = ngx_proxy_protocol_parse(c, b->pos, b->last); + p = ngx_proxy_protocol_read(c, b->pos, b->last); if (p == NULL) { ngx_http_close_connection(c); @@ -675,7 +675,7 @@ ngx_http_ssl_handshake(ngx_event_t *rev) if (hc->proxy_protocol) { hc->proxy_protocol = 0; - p = ngx_proxy_protocol_parse(c, buf, buf + n); + p = ngx_proxy_protocol_read(c, buf, buf + n); if (p == NULL) { ngx_http_close_connection(c); diff --git a/src/http/ngx_http_spdy.c b/src/http/ngx_http_spdy.c index 6bb79b8..21c5217 100644 --- a/src/http/ngx_http_spdy.c +++ b/src/http/ngx_http_spdy.c @@ -866,7 +866,7 @@ ngx_http_spdy_proxy_protocol(ngx_http_spdy_connection_t *sc, u_char *pos, log = sc->connection->log; log->action = "reading PROXY protocol"; - pos = ngx_proxy_protocol_parse(sc->connection, pos, end); + pos = ngx_proxy_protocol_read(sc->connection, pos, end); log->action = "processing SPDY"; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 47b574e..4b0332a 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -3731,7 +3731,7 @@ ngx_http_upstream_store(ngx_http_request_t *r, ngx_http_upstream_t *u) if (u->headers_in.last_modified) { - lm = ngx_http_parse_time(u->headers_in.last_modified->value.data, + lm = ngx_parse_http_time(u->headers_in.last_modified->value.data, u->headers_in.last_modified->value.len); if (lm != NGX_ERROR) { @@ -4128,7 +4128,7 @@ ngx_http_upstream_process_last_modified(ngx_http_request_t *r, #if (NGX_HTTP_CACHE) if (u->cacheable) { - u->headers_in.last_modified_time = ngx_http_parse_time(h->value.data, + u->headers_in.last_modified_time = ngx_parse_http_time(h->value.data, h->value.len); } @@ -4292,7 +4292,7 @@ ngx_http_upstream_process_expires(ngx_http_request_t *r, ngx_table_elt_t *h, return NGX_OK; } - expires = ngx_http_parse_time(h->value.data, h->value.len); + expires = ngx_parse_http_time(h->value.data, h->value.len); if (expires == NGX_ERROR || expires < ngx_time()) { u->cacheable = 0; diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c index f10f08c..38664bc 100644 --- a/src/mail/ngx_mail.c +++ b/src/mail/ngx_mail.c @@ -238,13 +238,13 @@ ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports, struct sockaddr_in6 *sin6; #endif - sa = (struct sockaddr *) &listen->sockaddr; + sa = &listen->u.sockaddr; switch (sa->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: - sin6 = (struct sockaddr_in6 *) sa; + sin6 = &listen->u.sockaddr_in6; p = sin6->sin6_port; break; #endif @@ -256,7 +256,7 @@ ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports, #endif default: /* AF_INET */ - sin = (struct sockaddr_in *) sa; + sin = &listen->u.sockaddr_in; p = sin->sin_port; break; } @@ -296,23 +296,7 @@ found: return NGX_ERROR; } - addr->sockaddr = (struct sockaddr *) &listen->sockaddr; - addr->socklen = listen->socklen; - 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 -#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) - addr->ipv6only = listen->ipv6only; -#endif + addr->opt = *listen; return NGX_OK; } @@ -342,8 +326,8 @@ ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) * to the "*:port" only and ignore the other bindings */ - if (addr[last - 1].wildcard) { - addr[last - 1].bind = 1; + if (addr[last - 1].opt.wildcard) { + addr[last - 1].opt.bind = 1; bind_wildcard = 1; } else { @@ -354,12 +338,13 @@ ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) while (i < last) { - if (bind_wildcard && !addr[i].bind) { + if (bind_wildcard && !addr[i].opt.bind) { i++; continue; } - ls = ngx_create_listening(cf, addr[i].sockaddr, addr[i].socklen); + ls = ngx_create_listening(cf, &addr[i].opt.u.sockaddr, + addr[i].opt.socklen); if (ls == NULL) { return NGX_CONF_ERROR; } @@ -368,21 +353,23 @@ ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) ls->handler = ngx_mail_init_connection; ls->pool_size = 256; - cscf = addr->ctx->srv_conf[ngx_mail_core_module.ctx_index]; + cscf = addr->opt.ctx->srv_conf[ngx_mail_core_module.ctx_index]; ls->logp = cscf->error_log; ls->log.data = &ls->addr_text; ls->log.handler = ngx_accept_log_error; - ls->keepalive = addr[i].so_keepalive; + ls->backlog = addr[i].opt.backlog; + + ls->keepalive = addr[i].opt.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; + ls->keepidle = addr[i].opt.tcp_keepidle; + ls->keepintvl = addr[i].opt.tcp_keepintvl; + ls->keepcnt = addr[i].opt.tcp_keepcnt; #endif #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) - ls->ipv6only = addr[i].ipv6only; + ls->ipv6only = addr[i].opt.ipv6only; #endif mport = ngx_palloc(cf->pool, sizeof(ngx_mail_port_t)); @@ -439,15 +426,15 @@ ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport, for (i = 0; i < mport->naddrs; i++) { - sin = (struct sockaddr_in *) addr[i].sockaddr; + sin = &addr[i].opt.u.sockaddr_in; addrs[i].addr = sin->sin_addr.s_addr; - addrs[i].conf.ctx = addr[i].ctx; + addrs[i].conf.ctx = addr[i].opt.ctx; #if (NGX_MAIL_SSL) - addrs[i].conf.ssl = addr[i].ssl; + addrs[i].conf.ssl = addr[i].opt.ssl; #endif - len = ngx_sock_ntop(addr[i].sockaddr, addr[i].socklen, buf, + len = ngx_sock_ntop(&addr[i].opt.u.sockaddr, addr[i].opt.socklen, buf, NGX_SOCKADDR_STRLEN, 1); p = ngx_pnalloc(cf->pool, len); @@ -488,15 +475,15 @@ ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport, for (i = 0; i < mport->naddrs; i++) { - sin6 = (struct sockaddr_in6 *) addr[i].sockaddr; + sin6 = &addr[i].opt.u.sockaddr_in6; addrs6[i].addr6 = sin6->sin6_addr; - addrs6[i].conf.ctx = addr[i].ctx; + addrs6[i].conf.ctx = addr[i].opt.ctx; #if (NGX_MAIL_SSL) - addrs6[i].conf.ssl = addr[i].ssl; + addrs6[i].conf.ssl = addr[i].opt.ssl; #endif - len = ngx_sock_ntop(addr[i].sockaddr, addr[i].socklen, buf, + len = ngx_sock_ntop(&addr[i].opt.u.sockaddr, addr[i].opt.socklen, buf, NGX_SOCKADDR_STRLEN, 1); p = ngx_pnalloc(cf->pool, len); @@ -524,22 +511,22 @@ ngx_mail_cmp_conf_addrs(const void *one, const void *two) first = (ngx_mail_conf_addr_t *) one; second = (ngx_mail_conf_addr_t *) two; - if (first->wildcard) { + if (first->opt.wildcard) { /* a wildcard must be the last resort, shift it to the end */ return 1; } - if (second->wildcard) { + if (second->opt.wildcard) { /* a wildcard must be the last resort, shift it to the end */ return -1; } - if (first->bind && !second->bind) { + if (first->opt.bind && !second->opt.bind) { /* shift explicit bind()ed addresses to the start */ return -1; } - if (!first->bind && second->bind) { + if (!first->opt.bind && second->opt.bind) { /* shift explicit bind()ed addresses to the start */ return 1; } diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index dd8a23a..07d0cb6 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -27,7 +27,18 @@ typedef struct { typedef struct { - u_char sockaddr[NGX_SOCKADDRLEN]; + union { + struct sockaddr sockaddr; + struct sockaddr_in sockaddr_in; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 sockaddr_in6; +#endif +#if (NGX_HAVE_UNIX_DOMAIN) + struct sockaddr_un sockaddr_un; +#endif + u_char sockaddr_data[NGX_SOCKADDRLEN]; + } u; + socklen_t socklen; /* server ctx */ @@ -47,6 +58,7 @@ typedef struct { int tcp_keepintvl; int tcp_keepcnt; #endif + int backlog; } ngx_mail_listen_t; @@ -89,25 +101,7 @@ typedef struct { typedef struct { - struct sockaddr *sockaddr; - socklen_t socklen; - - ngx_mail_conf_ctx_t *ctx; - - unsigned bind:1; - unsigned wildcard:1; -#if (NGX_MAIL_SSL) - unsigned ssl:1; -#endif -#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) - unsigned ipv6only:1; -#endif - unsigned so_keepalive:2; -#if (NGX_HAVE_KEEPALIVE_TUNABLE) - int tcp_keepidle; - int tcp_keepintvl; - int tcp_keepcnt; -#endif + ngx_mail_listen_t opt; } ngx_mail_conf_addr_t; diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index ab455b8..271afc4 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -325,7 +325,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) for (i = 0; i < cmcf->listen.nelts; i++) { - sa = (struct sockaddr *) ls[i].sockaddr; + sa = &ls[i].u.sockaddr; if (sa->sa_family != u.family) { continue; @@ -337,7 +337,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) case AF_INET6: off = offsetof(struct sockaddr_in6, sin6_addr); len = 16; - sin6 = (struct sockaddr_in6 *) sa; + sin6 = &ls[i].u.sockaddr_in6; port = ntohs(sin6->sin6_port); break; #endif @@ -353,12 +353,14 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) default: /* AF_INET */ off = offsetof(struct sockaddr_in, sin_addr); len = 4; - sin = (struct sockaddr_in *) sa; + sin = &ls[i].u.sockaddr_in; port = ntohs(sin->sin_port); break; } - if (ngx_memcmp(ls[i].sockaddr + off, u.sockaddr + off, len) != 0) { + if (ngx_memcmp(ls[i].u.sockaddr_data + off, u.sockaddr + off, len) + != 0) + { continue; } @@ -378,9 +380,10 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_memzero(ls, sizeof(ngx_mail_listen_t)); - ngx_memcpy(ls->sockaddr, u.sockaddr, u.socklen); + ngx_memcpy(&ls->u.sockaddr, u.sockaddr, u.socklen); ls->socklen = u.socklen; + ls->backlog = NGX_LISTEN_BACKLOG; ls->wildcard = u.wildcard; ls->ctx = cf->ctx; @@ -416,12 +419,25 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } + if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) { + ls->backlog = ngx_atoi(value[i].data + 8, value[i].len - 8); + ls->bind = 1; + + if (ls->backlog == NGX_ERROR || ls->backlog == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid backlog \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + continue; + } + if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) { #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) struct sockaddr *sa; u_char buf[NGX_SOCKADDR_STRLEN]; - sa = (struct sockaddr *) ls->sockaddr; + sa = &ls->u.sockaddr; if (sa->sa_family == AF_INET6) { diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h index b6990bc..6081b00 100644 --- a/src/os/unix/ngx_files.h +++ b/src/os/unix/ngx_files.h @@ -368,6 +368,7 @@ size_t ngx_fs_bsize(u_char *name); #endif +#define ngx_stdout STDOUT_FILENO #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/src/stream/ngx_stream.c b/src/stream/ngx_stream.c index 1c5e7a8..3dce35a 100644 --- a/src/stream/ngx_stream.c +++ b/src/stream/ngx_stream.c @@ -204,6 +204,20 @@ ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_STREAM_MODULE) { + continue; + } + + module = ngx_modules[m]->ctx; + + if (module->postconfiguration) { + if (module->postconfiguration(cf) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + } + *cf = pcf; @@ -239,13 +253,13 @@ ngx_stream_add_ports(ngx_conf_t *cf, ngx_array_t *ports, struct sockaddr_in6 *sin6; #endif - sa = (struct sockaddr *) &listen->sockaddr; + sa = &listen->u.sockaddr; switch (sa->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: - sin6 = (struct sockaddr_in6 *) sa; + sin6 = &listen->u.sockaddr_in6; p = sin6->sin6_port; break; #endif @@ -257,7 +271,7 @@ ngx_stream_add_ports(ngx_conf_t *cf, ngx_array_t *ports, #endif default: /* AF_INET */ - sin = (struct sockaddr_in *) sa; + sin = &listen->u.sockaddr_in; p = sin->sin_port; break; } @@ -297,23 +311,7 @@ found: return NGX_ERROR; } - addr->sockaddr = (struct sockaddr *) &listen->sockaddr; - addr->socklen = listen->socklen; - 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_STREAM_SSL) - addr->ssl = listen->ssl; -#endif -#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) - addr->ipv6only = listen->ipv6only; -#endif + addr->opt = *listen; return NGX_OK; } @@ -343,8 +341,8 @@ ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) * to the "*:port" only and ignore the other bindings */ - if (addr[last - 1].wildcard) { - addr[last - 1].bind = 1; + if (addr[last - 1].opt.wildcard) { + addr[last - 1].opt.bind = 1; bind_wildcard = 1; } else { @@ -355,12 +353,13 @@ ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) while (i < last) { - if (bind_wildcard && !addr[i].bind) { + if (bind_wildcard && !addr[i].opt.bind) { i++; continue; } - ls = ngx_create_listening(cf, addr[i].sockaddr, addr[i].socklen); + ls = ngx_create_listening(cf, &addr[i].opt.u.sockaddr, + addr[i].opt.socklen); if (ls == NULL) { return NGX_CONF_ERROR; } @@ -369,21 +368,27 @@ ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) ls->handler = ngx_stream_init_connection; ls->pool_size = 256; - cscf = addr->ctx->srv_conf[ngx_stream_core_module.ctx_index]; + cscf = addr->opt.ctx->srv_conf[ngx_stream_core_module.ctx_index]; ls->logp = cscf->error_log; ls->log.data = &ls->addr_text; ls->log.handler = ngx_accept_log_error; - ls->keepalive = addr[i].so_keepalive; + ls->backlog = addr[i].opt.backlog; + + ls->keepalive = addr[i].opt.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; + ls->keepidle = addr[i].opt.tcp_keepidle; + ls->keepintvl = addr[i].opt.tcp_keepintvl; + ls->keepcnt = addr[i].opt.tcp_keepcnt; #endif #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) - ls->ipv6only = addr[i].ipv6only; + ls->ipv6only = addr[i].opt.ipv6only; +#endif + +#if (NGX_HAVE_REUSEPORT) + ls->reuseport = addr[i].opt.reuseport; #endif stport = ngx_palloc(cf->pool, sizeof(ngx_stream_port_t)); @@ -444,15 +449,15 @@ ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *stport, for (i = 0; i < stport->naddrs; i++) { - sin = (struct sockaddr_in *) addr[i].sockaddr; + sin = &addr[i].opt.u.sockaddr_in; addrs[i].addr = sin->sin_addr.s_addr; - addrs[i].conf.ctx = addr[i].ctx; + addrs[i].conf.ctx = addr[i].opt.ctx; #if (NGX_STREAM_SSL) - addrs[i].conf.ssl = addr[i].ssl; + addrs[i].conf.ssl = addr[i].opt.ssl; #endif - len = ngx_sock_ntop(addr[i].sockaddr, addr[i].socklen, buf, + len = ngx_sock_ntop(&addr[i].opt.u.sockaddr, addr[i].opt.socklen, buf, NGX_SOCKADDR_STRLEN, 1); p = ngx_pnalloc(cf->pool, len); @@ -493,15 +498,15 @@ ngx_stream_add_addrs6(ngx_conf_t *cf, ngx_stream_port_t *stport, for (i = 0; i < stport->naddrs; i++) { - sin6 = (struct sockaddr_in6 *) addr[i].sockaddr; + sin6 = &addr[i].opt.u.sockaddr_in6; addrs6[i].addr6 = sin6->sin6_addr; - addrs6[i].conf.ctx = addr[i].ctx; + addrs6[i].conf.ctx = addr[i].opt.ctx; #if (NGX_STREAM_SSL) - addrs6[i].conf.ssl = addr[i].ssl; + addrs6[i].conf.ssl = addr[i].opt.ssl; #endif - len = ngx_sock_ntop(addr[i].sockaddr, addr[i].socklen, buf, + len = ngx_sock_ntop(&addr[i].opt.u.sockaddr, addr[i].opt.socklen, buf, NGX_SOCKADDR_STRLEN, 1); p = ngx_pnalloc(cf->pool, len); @@ -529,22 +534,22 @@ ngx_stream_cmp_conf_addrs(const void *one, const void *two) first = (ngx_stream_conf_addr_t *) one; second = (ngx_stream_conf_addr_t *) two; - if (first->wildcard) { + if (first->opt.wildcard) { /* a wildcard must be the last resort, shift it to the end */ return 1; } - if (second->wildcard) { + if (second->opt.wildcard) { /* a wildcard must be the last resort, shift it to the end */ return -1; } - if (first->bind && !second->bind) { + if (first->opt.bind && !second->opt.bind) { /* shift explicit bind()ed addresses to the start */ return -1; } - if (!first->bind && second->bind) { + if (!first->opt.bind && second->opt.bind) { /* shift explicit bind()ed addresses to the start */ return 1; } diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h index a10f68f..b0eb7d4 100644 --- a/src/stream/ngx_stream.h +++ b/src/stream/ngx_stream.h @@ -31,7 +31,18 @@ typedef struct { typedef struct { - u_char sockaddr[NGX_SOCKADDRLEN]; + union { + struct sockaddr sockaddr; + struct sockaddr_in sockaddr_in; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 sockaddr_in6; +#endif +#if (NGX_HAVE_UNIX_DOMAIN) + struct sockaddr_un sockaddr_un; +#endif + u_char sockaddr_data[NGX_SOCKADDRLEN]; + } u; + socklen_t socklen; /* server ctx */ @@ -54,6 +65,7 @@ typedef struct { int tcp_keepintvl; int tcp_keepcnt; #endif + int backlog; } ngx_stream_listen_t; @@ -96,31 +108,17 @@ typedef struct { typedef struct { - struct sockaddr *sockaddr; - socklen_t socklen; - - ngx_stream_conf_ctx_t *ctx; - - unsigned bind:1; - unsigned wildcard:1; -#if (NGX_STREAM_SSL) - unsigned ssl:1; -#endif -#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) - unsigned ipv6only:1; -#endif - unsigned so_keepalive:2; -#if (NGX_HAVE_KEEPALIVE_TUNABLE) - int tcp_keepidle; - int tcp_keepintvl; - int tcp_keepcnt; -#endif + ngx_stream_listen_t opt; } ngx_stream_conf_addr_t; +typedef ngx_int_t (*ngx_stream_access_pt)(ngx_stream_session_t *s); + + typedef struct { ngx_array_t servers; /* ngx_stream_core_srv_conf_t */ ngx_array_t listen; /* ngx_stream_listen_t */ + ngx_stream_access_pt access_handler; } ngx_stream_core_main_conf_t; @@ -154,6 +152,8 @@ struct ngx_stream_session_s { typedef struct { + ngx_int_t (*postconfiguration)(ngx_conf_t *cf); + void *(*create_main_conf)(ngx_conf_t *cf); char *(*init_main_conf)(ngx_conf_t *cf, void *conf); diff --git a/src/stream/ngx_stream_access_module.c b/src/stream/ngx_stream_access_module.c new file mode 100644 index 0000000..64869d2 --- /dev/null +++ b/src/stream/ngx_stream_access_module.c @@ -0,0 +1,451 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + in_addr_t mask; + in_addr_t addr; + ngx_uint_t deny; /* unsigned deny:1; */ +} ngx_stream_access_rule_t; + +#if (NGX_HAVE_INET6) + +typedef struct { + struct in6_addr addr; + struct in6_addr mask; + ngx_uint_t deny; /* unsigned deny:1; */ +} ngx_stream_access_rule6_t; + +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + +typedef struct { + ngx_uint_t deny; /* unsigned deny:1; */ +} ngx_stream_access_rule_un_t; + +#endif + +typedef struct { + ngx_array_t *rules; /* array of ngx_stream_access_rule_t */ +#if (NGX_HAVE_INET6) + ngx_array_t *rules6; /* array of ngx_stream_access_rule6_t */ +#endif +#if (NGX_HAVE_UNIX_DOMAIN) + ngx_array_t *rules_un; /* array of ngx_stream_access_rule_un_t */ +#endif +} ngx_stream_access_srv_conf_t; + + +static ngx_int_t ngx_stream_access_handler(ngx_stream_session_t *s); +static ngx_int_t ngx_stream_access_inet(ngx_stream_session_t *s, + ngx_stream_access_srv_conf_t *ascf, in_addr_t addr); +#if (NGX_HAVE_INET6) +static ngx_int_t ngx_stream_access_inet6(ngx_stream_session_t *s, + ngx_stream_access_srv_conf_t *ascf, u_char *p); +#endif +#if (NGX_HAVE_UNIX_DOMAIN) +static ngx_int_t ngx_stream_access_unix(ngx_stream_session_t *s, + ngx_stream_access_srv_conf_t *ascf); +#endif +static ngx_int_t ngx_stream_access_found(ngx_stream_session_t *s, + ngx_uint_t deny); +static char *ngx_stream_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void *ngx_stream_access_create_srv_conf(ngx_conf_t *cf); +static char *ngx_stream_access_merge_srv_conf(ngx_conf_t *cf, + void *parent, void *child); +static ngx_int_t ngx_stream_access_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_stream_access_commands[] = { + + { ngx_string("allow"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_stream_access_rule, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("deny"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_stream_access_rule, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + + +static ngx_stream_module_t ngx_stream_access_module_ctx = { + ngx_stream_access_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_stream_access_create_srv_conf, /* create server configuration */ + ngx_stream_access_merge_srv_conf /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_access_module = { + NGX_MODULE_V1, + &ngx_stream_access_module_ctx, /* module context */ + ngx_stream_access_commands, /* module directives */ + NGX_STREAM_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_stream_access_handler(ngx_stream_session_t *s) +{ + struct sockaddr_in *sin; + ngx_stream_access_srv_conf_t *ascf; +#if (NGX_HAVE_INET6) + u_char *p; + in_addr_t addr; + struct sockaddr_in6 *sin6; +#endif + + ascf = ngx_stream_get_module_srv_conf(s, ngx_stream_access_module); + + switch (s->connection->sockaddr->sa_family) { + + case AF_INET: + if (ascf->rules) { + sin = (struct sockaddr_in *) s->connection->sockaddr; + return ngx_stream_access_inet(s, ascf, sin->sin_addr.s_addr); + } + break; + +#if (NGX_HAVE_INET6) + + case AF_INET6: + sin6 = (struct sockaddr_in6 *) s->connection->sockaddr; + p = sin6->sin6_addr.s6_addr; + + if (ascf->rules && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + addr = p[12] << 24; + addr += p[13] << 16; + addr += p[14] << 8; + addr += p[15]; + return ngx_stream_access_inet(s, ascf, htonl(addr)); + } + + if (ascf->rules6) { + return ngx_stream_access_inet6(s, ascf, p); + } + + break; + +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + + case AF_UNIX: + if (ascf->rules_un) { + return ngx_stream_access_unix(s, ascf); + } + + break; + +#endif + } + + return NGX_DECLINED; +} + + +static ngx_int_t +ngx_stream_access_inet(ngx_stream_session_t *s, + ngx_stream_access_srv_conf_t *ascf, in_addr_t addr) +{ + ngx_uint_t i; + ngx_stream_access_rule_t *rule; + + rule = ascf->rules->elts; + for (i = 0; i < ascf->rules->nelts; i++) { + + ngx_log_debug3(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "access: %08XD %08XD %08XD", + addr, rule[i].mask, rule[i].addr); + + if ((addr & rule[i].mask) == rule[i].addr) { + return ngx_stream_access_found(s, rule[i].deny); + } + } + + return NGX_DECLINED; +} + + +#if (NGX_HAVE_INET6) + +static ngx_int_t +ngx_stream_access_inet6(ngx_stream_session_t *s, + ngx_stream_access_srv_conf_t *ascf, u_char *p) +{ + ngx_uint_t n; + ngx_uint_t i; + ngx_stream_access_rule6_t *rule6; + + rule6 = ascf->rules6->elts; + for (i = 0; i < ascf->rules6->nelts; i++) { + +#if (NGX_DEBUG) + { + size_t cl, ml, al; + u_char ct[NGX_INET6_ADDRSTRLEN]; + u_char mt[NGX_INET6_ADDRSTRLEN]; + u_char at[NGX_INET6_ADDRSTRLEN]; + + cl = ngx_inet6_ntop(p, ct, NGX_INET6_ADDRSTRLEN); + ml = ngx_inet6_ntop(rule6[i].mask.s6_addr, mt, NGX_INET6_ADDRSTRLEN); + al = ngx_inet6_ntop(rule6[i].addr.s6_addr, at, NGX_INET6_ADDRSTRLEN); + + ngx_log_debug6(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "access: %*s %*s %*s", cl, ct, ml, mt, al, at); + } +#endif + + for (n = 0; n < 16; n++) { + if ((p[n] & rule6[i].mask.s6_addr[n]) != rule6[i].addr.s6_addr[n]) { + goto next; + } + } + + return ngx_stream_access_found(s, rule6[i].deny); + + next: + continue; + } + + return NGX_DECLINED; +} + +#endif + + +#if (NGX_HAVE_UNIX_DOMAIN) + +static ngx_int_t +ngx_stream_access_unix(ngx_stream_session_t *s, + ngx_stream_access_srv_conf_t *ascf) +{ + ngx_uint_t i; + ngx_stream_access_rule_un_t *rule_un; + + rule_un = ascf->rules_un->elts; + for (i = 0; i < ascf->rules_un->nelts; i++) { + + /* TODO: check path */ + if (1) { + return ngx_stream_access_found(s, rule_un[i].deny); + } + } + + return NGX_DECLINED; +} + +#endif + + +static ngx_int_t +ngx_stream_access_found(ngx_stream_session_t *s, ngx_uint_t deny) +{ + if (deny) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "access forbidden by rule"); + return NGX_ABORT; + } + + return NGX_OK; +} + + +static char * +ngx_stream_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_access_srv_conf_t *ascf = conf; + + ngx_int_t rc; + ngx_uint_t all; + ngx_str_t *value; + ngx_cidr_t cidr; + ngx_stream_access_rule_t *rule; +#if (NGX_HAVE_INET6) + ngx_stream_access_rule6_t *rule6; +#endif +#if (NGX_HAVE_UNIX_DOMAIN) + ngx_stream_access_rule_un_t *rule_un; +#endif + + ngx_memzero(&cidr, sizeof(ngx_cidr_t)); + + value = cf->args->elts; + + all = (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0); + + if (!all) { + +#if (NGX_HAVE_UNIX_DOMAIN) + + if (value[1].len == 5 && ngx_strcmp(value[1].data, "unix:") == 0) { + cidr.family = AF_UNIX; + rc = NGX_OK; + + } else { + rc = ngx_ptocidr(&value[1], &cidr); + } + +#else + rc = ngx_ptocidr(&value[1], &cidr); +#endif + + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", &value[1]); + } + } + + if (cidr.family == AF_INET || all) { + + if (ascf->rules == NULL) { + ascf->rules = ngx_array_create(cf->pool, 4, + sizeof(ngx_stream_access_rule_t)); + if (ascf->rules == NULL) { + return NGX_CONF_ERROR; + } + } + + rule = ngx_array_push(ascf->rules); + if (rule == NULL) { + return NGX_CONF_ERROR; + } + + rule->mask = cidr.u.in.mask; + rule->addr = cidr.u.in.addr; + rule->deny = (value[0].data[0] == 'd') ? 1 : 0; + } + +#if (NGX_HAVE_INET6) + if (cidr.family == AF_INET6 || all) { + + if (ascf->rules6 == NULL) { + ascf->rules6 = ngx_array_create(cf->pool, 4, + sizeof(ngx_stream_access_rule6_t)); + if (ascf->rules6 == NULL) { + return NGX_CONF_ERROR; + } + } + + rule6 = ngx_array_push(ascf->rules6); + if (rule6 == NULL) { + return NGX_CONF_ERROR; + } + + rule6->mask = cidr.u.in6.mask; + rule6->addr = cidr.u.in6.addr; + rule6->deny = (value[0].data[0] == 'd') ? 1 : 0; + } +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + if (cidr.family == AF_UNIX || all) { + + if (ascf->rules_un == NULL) { + ascf->rules_un = ngx_array_create(cf->pool, 1, + sizeof(ngx_stream_access_rule_un_t)); + if (ascf->rules_un == NULL) { + return NGX_CONF_ERROR; + } + } + + rule_un = ngx_array_push(ascf->rules_un); + if (rule_un == NULL) { + return NGX_CONF_ERROR; + } + + rule_un->deny = (value[0].data[0] == 'd') ? 1 : 0; + } +#endif + + return NGX_CONF_OK; +} + + +static void * +ngx_stream_access_create_srv_conf(ngx_conf_t *cf) +{ + ngx_stream_access_srv_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_access_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + return conf; +} + + +static char * +ngx_stream_access_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_stream_access_srv_conf_t *prev = parent; + ngx_stream_access_srv_conf_t *conf = child; + + if (conf->rules == NULL +#if (NGX_HAVE_INET6) + && conf->rules6 == NULL +#endif +#if (NGX_HAVE_UNIX_DOMAIN) + && conf->rules_un == NULL +#endif + ) { + conf->rules = prev->rules; +#if (NGX_HAVE_INET6) + conf->rules6 = prev->rules6; +#endif +#if (NGX_HAVE_UNIX_DOMAIN) + conf->rules_un = prev->rules_un; +#endif + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_stream_access_init(ngx_conf_t *cf) +{ + ngx_stream_core_main_conf_t *cmcf; + + cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); + cmcf->access_handler = ngx_stream_access_handler; + + return NGX_OK; +} diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c index c8d8e66..246f55c 100644 --- a/src/stream/ngx_stream_core_module.c +++ b/src/stream/ngx_stream_core_module.c @@ -50,6 +50,8 @@ static ngx_command_t ngx_stream_core_commands[] = { static ngx_stream_module_t ngx_stream_core_module_ctx = { + NULL, /* postconfiguration */ + ngx_stream_core_create_main_conf, /* create main configuration */ NULL, /* init main configuration */ @@ -272,7 +274,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) for (i = 0; i < cmcf->listen.nelts; i++) { - sa = (struct sockaddr *) ls[i].sockaddr; + sa = &ls[i].u.sockaddr; if (sa->sa_family != u.family) { continue; @@ -284,7 +286,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) case AF_INET6: off = offsetof(struct sockaddr_in6, sin6_addr); len = 16; - sin6 = (struct sockaddr_in6 *) sa; + sin6 = &ls[i].u.sockaddr_in6; port = sin6->sin6_port; break; #endif @@ -300,12 +302,14 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) default: /* AF_INET */ off = offsetof(struct sockaddr_in, sin_addr); len = 4; - sin = (struct sockaddr_in *) sa; + sin = &ls[i].u.sockaddr_in; port = sin->sin_port; break; } - if (ngx_memcmp(ls[i].sockaddr + off, u.sockaddr + off, len) != 0) { + if (ngx_memcmp(ls[i].u.sockaddr_data + off, u.sockaddr + off, len) + != 0) + { continue; } @@ -325,9 +329,10 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_memzero(ls, sizeof(ngx_stream_listen_t)); - ngx_memcpy(ls->sockaddr, u.sockaddr, u.socklen); + ngx_memcpy(&ls->u.sockaddr, u.sockaddr, u.socklen); ls->socklen = u.socklen; + ls->backlog = NGX_LISTEN_BACKLOG; ls->wildcard = u.wildcard; ls->ctx = cf->ctx; @@ -342,12 +347,25 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } + if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) { + ls->backlog = ngx_atoi(value[i].data + 8, value[i].len - 8); + ls->bind = 1; + + if (ls->backlog == NGX_ERROR || ls->backlog == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid backlog \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + continue; + } + if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) { #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) struct sockaddr *sa; u_char buf[NGX_SOCKADDR_STRLEN]; - sa = (struct sockaddr *) ls->sockaddr; + sa = &ls->u.sockaddr; if (sa->sa_family == AF_INET6) { diff --git a/src/stream/ngx_stream_handler.c b/src/stream/ngx_stream_handler.c index 2be5183..e4538b2 100644 --- a/src/stream/ngx_stream_handler.c +++ b/src/stream/ngx_stream_handler.c @@ -23,20 +23,22 @@ static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c); void ngx_stream_init_connection(ngx_connection_t *c) { - u_char text[NGX_SOCKADDR_STRLEN]; - size_t len; - ngx_uint_t i; - struct sockaddr *sa; - ngx_stream_port_t *port; - struct sockaddr_in *sin; - ngx_stream_in_addr_t *addr; - ngx_stream_session_t *s; - ngx_stream_addr_conf_t *addr_conf; + u_char text[NGX_SOCKADDR_STRLEN]; + size_t len; + ngx_int_t rc; + ngx_uint_t i; + struct sockaddr *sa; + ngx_stream_port_t *port; + struct sockaddr_in *sin; + ngx_stream_in_addr_t *addr; + ngx_stream_session_t *s; + ngx_stream_addr_conf_t *addr_conf; #if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; - ngx_stream_in6_addr_t *addr6; + struct sockaddr_in6 *sin6; + ngx_stream_in6_addr_t *addr6; #endif - ngx_stream_core_srv_conf_t *cscf; + ngx_stream_core_srv_conf_t *cscf; + ngx_stream_core_main_conf_t *cmcf; /* find the server configuration for the address:port */ @@ -143,6 +145,17 @@ ngx_stream_init_connection(ngx_connection_t *c) c->log->action = "initializing connection"; c->log_error = NGX_ERROR_INFO; + cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); + + if (cmcf->access_handler) { + rc = cmcf->access_handler(s); + + if (rc != NGX_OK && rc != NGX_DECLINED) { + ngx_stream_close_connection(c); + return; + } + } + #if (NGX_STREAM_SSL) { ngx_stream_ssl_conf_t *sslcf; diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index a34b7ce..8c88505 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -21,6 +21,8 @@ typedef struct { size_t upstream_buf_size; ngx_uint_t next_upstream_tries; ngx_flag_t next_upstream; + ngx_flag_t proxy_protocol; + ngx_addr_t *local; #if (NGX_STREAM_SSL) ngx_flag_t ssl_enable; @@ -64,6 +66,9 @@ static char *ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child); static char *ngx_stream_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_stream_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s); #if (NGX_STREAM_SSL) @@ -97,6 +102,13 @@ static ngx_command_t ngx_stream_proxy_commands[] = { 0, NULL }, + { ngx_string("proxy_bind"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_stream_proxy_bind, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + { ngx_string("proxy_connect_timeout"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -146,6 +158,13 @@ static ngx_command_t ngx_stream_proxy_commands[] = { offsetof(ngx_stream_proxy_srv_conf_t, next_upstream_timeout), NULL }, + { ngx_string("proxy_protocol"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, proxy_protocol), + NULL }, + #if (NGX_STREAM_SSL) { ngx_string("proxy_ssl"), @@ -246,6 +265,8 @@ static ngx_command_t ngx_stream_proxy_commands[] = { static ngx_stream_module_t ngx_stream_proxy_module_ctx = { + NULL, /* postconfiguration */ + NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -299,6 +320,8 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) u->peer.log = c->log; u->peer.log_error = NGX_ERROR_ERR; + u->peer.local = pscf->local; + uscf = pscf->upstream; if (uscf->peer.init(s, uscf) != NGX_OK) { @@ -314,6 +337,8 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) u->peer.tries = pscf->next_upstream_tries; } + u->proxy_protocol = pscf->proxy_protocol; + p = ngx_pnalloc(c->pool, pscf->downstream_buf_size); if (p == NULL) { ngx_stream_proxy_finalize(s, NGX_ERROR); @@ -328,6 +353,29 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) c->write->handler = ngx_stream_proxy_downstream_handler; c->read->handler = ngx_stream_proxy_downstream_handler; + if (u->proxy_protocol +#if (NGX_STREAM_SSL) + && pscf->ssl == NULL +#endif + && pscf->downstream_buf_size >= NGX_PROXY_PROTOCOL_MAX_HEADER + ) + { + /* optimization for a typical case */ + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream proxy send PROXY protocol header"); + + p = ngx_proxy_protocol_write(c, u->downstream_buf.last, + u->downstream_buf.end); + if (p == NULL) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + u->downstream_buf.last = p; + u->proxy_protocol = 0; + } + if (ngx_stream_proxy_process(s, 0, 0) != NGX_OK) { return; } @@ -403,10 +451,18 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) ngx_stream_upstream_t *u; ngx_stream_proxy_srv_conf_t *pscf; - pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); - u = s->upstream; + if (u->proxy_protocol) { + if (ngx_stream_proxy_send_proxy_protocol(s) != NGX_OK) { + return; + } + + u->proxy_protocol = 0; + } + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + pc = u->peer.connection; #if (NGX_STREAM_SSL) @@ -460,6 +516,76 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) } +static ngx_int_t +ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s) +{ + u_char *p; + ssize_t n, size; + ngx_connection_t *c, *pc; + ngx_stream_upstream_t *u; + ngx_stream_proxy_srv_conf_t *pscf; + u_char buf[NGX_PROXY_PROTOCOL_MAX_HEADER]; + + c = s->connection; + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream proxy send PROXY protocol header"); + + p = ngx_proxy_protocol_write(c, buf, buf + NGX_PROXY_PROTOCOL_MAX_HEADER); + if (p == NULL) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return NGX_ERROR; + } + + u = s->upstream; + + pc = u->peer.connection; + + size = p - buf; + + n = pc->send(pc, buf, size); + + if (n == NGX_AGAIN) { + if (ngx_handle_write_event(pc->write, 0) != NGX_OK) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return NGX_ERROR; + } + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + + ngx_add_timer(pc->write, pscf->timeout); + + pc->write->handler = ngx_stream_proxy_connect_handler; + + return NGX_AGAIN; + } + + if (n == NGX_ERROR) { + ngx_stream_proxy_finalize(s, NGX_DECLINED); + return NGX_ERROR; + } + + if (n != size) { + + /* + * PROXY protocol specification: + * The sender must always ensure that the header + * is sent at once, so that the transport layer + * maintains atomicity along the path to the receiver. + */ + + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "could not send PROXY protocol header at once"); + + ngx_stream_proxy_finalize(s, NGX_DECLINED); + + return NGX_ERROR; + } + + return NGX_OK; +} + + #if (NGX_STREAM_SSL) static char * @@ -1091,6 +1217,8 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) conf->upstream_buf_size = NGX_CONF_UNSET_SIZE; conf->next_upstream_tries = NGX_CONF_UNSET_UINT; conf->next_upstream = NGX_CONF_UNSET; + conf->proxy_protocol = NGX_CONF_UNSET; + conf->local = NGX_CONF_UNSET_PTR; #if (NGX_STREAM_SSL) conf->ssl_enable = NGX_CONF_UNSET; @@ -1131,6 +1259,10 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->next_upstream, prev->next_upstream, 1); + ngx_conf_merge_value(conf->proxy_protocol, prev->proxy_protocol, 0); + + ngx_conf_merge_ptr_value(conf->local, prev->local, NULL); + #if (NGX_STREAM_SSL) ngx_conf_merge_value(conf->ssl_enable, prev->ssl_enable, 0); @@ -1288,3 +1420,45 @@ ngx_stream_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_OK; } + + +static char * +ngx_stream_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_proxy_srv_conf_t *pscf = conf; + + ngx_int_t rc; + ngx_str_t *value; + + if (pscf->local != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "off") == 0) { + pscf->local = NULL; + return NGX_CONF_OK; + } + + pscf->local = ngx_palloc(cf->pool, sizeof(ngx_addr_t)); + if (pscf->local == NULL) { + return NGX_CONF_ERROR; + } + + rc = ngx_parse_addr(cf->pool, pscf->local, value[1].data, value[1].len); + + switch (rc) { + case NGX_OK: + pscf->local->name = value[1]; + return NGX_CONF_OK; + + case NGX_DECLINED: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid address \"%V\"", &value[1]); + /* fall through */ + + default: + return NGX_CONF_ERROR; + } +} diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index 4b27a1e..97a0fa9 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -132,6 +132,8 @@ static ngx_command_t ngx_stream_ssl_commands[] = { static ngx_stream_module_t ngx_stream_ssl_module_ctx = { + NULL, /* postconfiguration */ + NULL, /* create main configuration */ NULL, /* init main configuration */ diff --git a/src/stream/ngx_stream_upstream.c b/src/stream/ngx_stream_upstream.c index a991f8a..f21e17d 100644 --- a/src/stream/ngx_stream_upstream.c +++ b/src/stream/ngx_stream_upstream.c @@ -39,6 +39,8 @@ static ngx_command_t ngx_stream_upstream_commands[] = { static ngx_stream_module_t ngx_stream_upstream_module_ctx = { + NULL, /* postconfiguration */ + ngx_stream_upstream_create_main_conf, /* create main configuration */ ngx_stream_upstream_init_main_conf, /* init main configuration */ diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h index 83353ed..56325da 100644 --- a/src/stream/ngx_stream_upstream.h +++ b/src/stream/ngx_stream_upstream.h @@ -86,6 +86,8 @@ typedef struct { #if (NGX_STREAM_SSL) ngx_str_t ssl_name; #endif + ngx_uint_t proxy_protocol; + /* unsigned proxy_protocol:1; */ } ngx_stream_upstream_t; diff --git a/src/stream/ngx_stream_upstream_hash_module.c b/src/stream/ngx_stream_upstream_hash_module.c index 88e7414..56ff7d6 100644 --- a/src/stream/ngx_stream_upstream_hash_module.c +++ b/src/stream/ngx_stream_upstream_hash_module.c @@ -76,6 +76,8 @@ static ngx_command_t ngx_stream_upstream_hash_commands[] = { static ngx_stream_module_t ngx_stream_upstream_hash_module_ctx = { + NULL, /* postconfiguration */ + NULL, /* create main configuration */ NULL, /* init main configuration */ diff --git a/src/stream/ngx_stream_upstream_least_conn_module.c b/src/stream/ngx_stream_upstream_least_conn_module.c index eae4b17..677da45 100644 --- a/src/stream/ngx_stream_upstream_least_conn_module.c +++ b/src/stream/ngx_stream_upstream_least_conn_module.c @@ -32,6 +32,8 @@ static ngx_command_t ngx_stream_upstream_least_conn_commands[] = { static ngx_stream_module_t ngx_stream_upstream_least_conn_module_ctx = { + NULL, /* postconfiguration */ + NULL, /* create main configuration */ NULL, /* init main configuration */ diff --git a/src/stream/ngx_stream_upstream_zone_module.c b/src/stream/ngx_stream_upstream_zone_module.c index 95a778f..6025aee 100644 --- a/src/stream/ngx_stream_upstream_zone_module.c +++ b/src/stream/ngx_stream_upstream_zone_module.c @@ -32,6 +32,8 @@ static ngx_command_t ngx_stream_upstream_zone_commands[] = { static ngx_stream_module_t ngx_stream_upstream_zone_module_ctx = { + NULL, /* postconfiguration */ + NULL, /* create main configuration */ NULL, /* init main configuration */ From 782a6ed9fe8b22b624d539fed1493489a5b27fee Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 17 Jun 2015 11:27:01 +0300 Subject: [PATCH 040/651] New upstream release (1.9.2) --- debian/changelog | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 0982eae..da7838e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,9 +1,13 @@ -nginx (1.9.1-2) UNRELEASED; urgency=medium +nginx (1.9.2-1) UNRELEASED; urgency=medium + [ Michael Lustfield ] * debian/nginx-common.nginx.init: + Init script now returns the proper exit status. (Closes: #788573) + Cleaned up the init script to have consistent naming/structure. + [ Christos Trochalakis ] + * New upstream Release. + -- Michael Lustfield Mon, 15 Jun 2015 22:14:19 -0500 nginx (1.9.1-1) unstable; urgency=medium From 632421e0e5e2e2ad743a90aecf54a4d7a394f301 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 17 Jun 2015 11:27:21 +0300 Subject: [PATCH 041/651] debian/rules: Add stream module for nginx-full & nginx-extras --- debian/changelog | 2 ++ debian/control | 6 +++--- debian/rules | 4 ++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index da7838e..cf33bc5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -7,6 +7,8 @@ nginx (1.9.2-1) UNRELEASED; urgency=medium [ Christos Trochalakis ] * New upstream Release. + * debian/rules: + + Add stream module to nginx-full & nginx-extras. -- Michael Lustfield Mon, 15 Jun 2015 22:14:19 -0500 diff --git a/debian/control b/debian/control index e544ca8..7427e44 100644 --- a/debian/control +++ b/debian/control @@ -100,7 +100,7 @@ Description: nginx web/proxy server (standard version) . OPTIONAL HTTP MODULES: Addition, Auth Request, Charset, WebDAV, GeoIP, Gunzip, Gzip, Gzip Precompression, Headers, Image Filter, Index, Log, Real IP, Spdy, - SSI, SSL, Stub Status, Substitution, Upstream, User ID, XSLT. + SSI, SSL, Stream, Stub Status, Substitution, Upstream, User ID, XSLT. . MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. . @@ -186,8 +186,8 @@ Description: nginx web/proxy server (extended version) . OPTIONAL HTTP MODULES: Addition, Auth Request, Charset, WebDAV, FLV, GeoIP, Gunzip, Gzip, Gzip Precompression, Headers, Image Filter, Index, Log, MP4, - Embedded Perl, Random Index, Real IP, Secure Link, Spdy, SSI, SSL, Stub - Status, Substitution, Upstream, User ID, XSLT. + Embedded Perl, Random Index, Real IP, Secure Link, Spdy, SSI, SSL, Stream, + Stub Status, Substitution, Upstream, User ID, XSLT. . MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. . diff --git a/debian/rules b/debian/rules index 93e6db6..9775b97 100755 --- a/debian/rules +++ b/debian/rules @@ -76,6 +76,8 @@ full_configure_flags := \ --with-http_spdy_module \ --with-http_sub_module \ --with-http_xslt_module \ + --with-stream \ + --with-stream_ssl_module \ --with-mail \ --with-mail_ssl_module \ --add-module=$(MODULESDIR)/nginx-auth-pam \ @@ -102,6 +104,8 @@ extras_configure_flags := \ --with-http_xslt_module \ --with-mail \ --with-mail_ssl_module \ + --with-stream \ + --with-stream_ssl_module \ --add-module=$(MODULESDIR)/headers-more-nginx-module \ --add-module=$(MODULESDIR)/nginx-auth-pam \ --add-module=$(MODULESDIR)/nginx-cache-purge \ From edc91aa9dc0722a9e3977edadec15474b356a5ab Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Sun, 21 Jun 2015 20:43:39 +0300 Subject: [PATCH 042/651] Add thread pool support to nginx-full & nginx-extras 9531e5e7 was backported for lua-nginx-module v0.9.16rc1 breaking compilation when thread pool was enabled. --- debian/changelog | 4 ++++ debian/control | 5 +++-- .../modules/nginx-lua/src/ngx_http_lua_socket_udp.c | 11 ----------- debian/rules | 2 ++ 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/debian/changelog b/debian/changelog index cf33bc5..a3a80bd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,10 @@ nginx (1.9.2-1) UNRELEASED; urgency=medium * New upstream Release. * debian/rules: + Add stream module to nginx-full & nginx-extras. + + Add thread pool support to nginx-full & nginx-extras. + * debian/modules/nginx-lua: + + Backport upstream's 9531e5e7 fixing build failure when thread pool + support is enabled. -- Michael Lustfield Mon, 15 Jun 2015 22:14:19 -0500 diff --git a/debian/control b/debian/control index 7427e44..6acfbab 100644 --- a/debian/control +++ b/debian/control @@ -100,7 +100,8 @@ Description: nginx web/proxy server (standard version) . OPTIONAL HTTP MODULES: Addition, Auth Request, Charset, WebDAV, GeoIP, Gunzip, Gzip, Gzip Precompression, Headers, Image Filter, Index, Log, Real IP, Spdy, - SSI, SSL, Stream, Stub Status, Substitution, Upstream, User ID, XSLT. + SSI, SSL, Stream, Stub Status, Substitution, Thread Pool, Upstream, User ID, + XSLT. . MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. . @@ -187,7 +188,7 @@ Description: nginx web/proxy server (extended version) OPTIONAL HTTP MODULES: Addition, Auth Request, Charset, WebDAV, FLV, GeoIP, Gunzip, Gzip, Gzip Precompression, Headers, Image Filter, Index, Log, MP4, Embedded Perl, Random Index, Real IP, Secure Link, Spdy, SSI, SSL, Stream, - Stub Status, Substitution, Upstream, User ID, XSLT. + Stub Status, Substitution, Thread Pool, Upstream, User ID, XSLT. . MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. . diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c b/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c index 6410b1e..6c846f5 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c @@ -1400,17 +1400,6 @@ ngx_http_lua_udp_connect(ngx_udp_connection_t *uc) c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); -#if (NGX_THREADS) - - /* TODO: lock event when call completion handler */ - - rev->lock = &c->lock; - wev->lock = &c->lock; - rev->own_lock = &c->lock; - wev->own_lock = &c->lock; - -#endif - #if (NGX_HTTP_LUA_HAVE_SO_PASSCRED) if (uc->sockaddr->sa_family == AF_UNIX) { struct sockaddr addr; diff --git a/debian/rules b/debian/rules index 9775b97..34223d8 100755 --- a/debian/rules +++ b/debian/rules @@ -80,6 +80,7 @@ full_configure_flags := \ --with-stream_ssl_module \ --with-mail \ --with-mail_ssl_module \ + --with-threads \ --add-module=$(MODULESDIR)/nginx-auth-pam \ --add-module=$(MODULESDIR)/nginx-dav-ext-module \ --add-module=$(MODULESDIR)/nginx-echo \ @@ -106,6 +107,7 @@ extras_configure_flags := \ --with-mail_ssl_module \ --with-stream \ --with-stream_ssl_module \ + --with-threads \ --add-module=$(MODULESDIR)/headers-more-nginx-module \ --add-module=$(MODULESDIR)/nginx-auth-pam \ --add-module=$(MODULESDIR)/nginx-cache-purge \ From 1715cb7c592e845eae80bbaacedf3f7101958ac0 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Sun, 21 Jun 2015 21:29:40 +0300 Subject: [PATCH 043/651] Add a reference for the backported lua patch to README.Modules-versions --- debian/modules/README.Modules-versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index a5c7563..86ea160 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -22,7 +22,7 @@ README for Modules versions nginx-lua Homepage: https://github.com/openresty/lua-nginx-module - Version: v0.9.15 + f4e1311 + Version: v0.9.15 + f4e1311 + 9531e5e7 nginx-upstream-fair Homepage: https://github.com/gnosek/nginx-upstream-fair From 6717510c8107782e8aef9fc9eb6d3b07d8e6c7f0 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 22 Jun 2015 10:16:31 +0300 Subject: [PATCH 044/651] Release 1.9.2-1 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index a3a80bd..79f6584 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.9.2-1) UNRELEASED; urgency=medium +nginx (1.9.2-1) unstable; urgency=medium [ Michael Lustfield ] * debian/nginx-common.nginx.init: @@ -14,7 +14,7 @@ nginx (1.9.2-1) UNRELEASED; urgency=medium + Backport upstream's 9531e5e7 fixing build failure when thread pool support is enabled. - -- Michael Lustfield Mon, 15 Jun 2015 22:14:19 -0500 + -- Christos Trochalakis Mon, 22 Jun 2015 10:16:19 +0300 nginx (1.9.1-1) unstable; urgency=medium From 1979c23fea257b22c89f46459001f98abf654a8d Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 22 Jun 2015 13:02:45 +0300 Subject: [PATCH 045/651] Remove XS-Testsuite header --- debian/changelog | 9 +++++++++ debian/control | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 79f6584..98e7d61 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +nginx (1.9.2-2) UNRELEASED; urgency=medium + + [ Christos Trochalakis] + * debian/control: + + Remove XS-Testsuite header, it is now automatically added when + `debian/tests/control` is present. + + -- Christos Trochalakis Mon, 22 Jun 2015 13:01:07 +0300 + nginx (1.9.2-1) unstable; urgency=medium [ Michael Lustfield ] diff --git a/debian/control b/debian/control index 6acfbab..b3bfcc3 100644 --- a/debian/control +++ b/debian/control @@ -28,7 +28,6 @@ Standards-Version: 3.9.6.0 Homepage: http://nginx.net Vcs-Git: git://anonscm.debian.org/collab-maint/nginx.git Vcs-Browser: http://anonscm.debian.org/gitweb/?p=collab-maint/nginx.git;a=summary -XS-Testsuite: autopkgtest Package: nginx Architecture: all From 5a275f894952d9429d6332b08c15dc4195c6228f Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 1 Jul 2015 17:09:41 +0300 Subject: [PATCH 046/651] Update nginx-lua to v0.9.16 --- debian/changelog | 2 + debian/modules/README.Modules-versions | 2 +- debian/modules/nginx-lua/.gitmodules | 3 - debian/modules/nginx-lua/README.markdown | 71 ++++++--- debian/modules/nginx-lua/config | 78 +++++++--- .../modules/nginx-lua/doc/HttpLuaModule.wiki | 56 +++++-- .../nginx-lua/src/api/ngx_http_lua_api.h | 6 +- debian/modules/nginx-lua/src/ddebug.h | 1 + .../src/ngx_http_lua_capturefilter.c | 1 + .../nginx-lua/src/ngx_http_lua_common.h | 14 +- .../nginx-lua/src/ngx_http_lua_control.c | 8 +- .../nginx-lua/src/ngx_http_lua_directive.c | 2 +- .../nginx-lua/src/ngx_http_lua_directive.h | 30 ++-- .../nginx-lua/src/ngx_http_lua_headers.c | 12 +- .../nginx-lua/src/ngx_http_lua_initworkerby.c | 2 +- .../modules/nginx-lua/src/ngx_http_lua_misc.c | 14 +- .../nginx-lua/src/ngx_http_lua_output.c | 4 +- .../nginx-lua/src/ngx_http_lua_output.h | 2 +- .../nginx-lua/src/ngx_http_lua_regex.c | 4 +- .../nginx-lua/src/ngx_http_lua_req_body.c | 4 +- .../nginx-lua/src/ngx_http_lua_script.c | 2 +- .../nginx-lua/src/ngx_http_lua_socket_tcp.c | 13 +- .../nginx-lua/src/ngx_http_lua_string.c | 74 ++++++++- .../nginx-lua/src/ngx_http_lua_timer.c | 2 +- .../modules/nginx-lua/src/ngx_http_lua_util.c | 39 +++-- .../modules/nginx-lua/src/ngx_http_lua_util.h | 22 +-- debian/modules/nginx-lua/t/013-base64.t | 51 ++++++- debian/modules/nginx-lua/t/014-bugs.t | 2 +- debian/modules/nginx-lua/t/016-resp-header.t | 28 +++- debian/modules/nginx-lua/t/020-subrequest.t | 41 ++++- .../nginx-lua/t/023-rewrite/req-body.t | 101 ++++++++++++- .../nginx-lua/t/023-rewrite/uthread-exec.t | 3 - .../nginx-lua/t/023-rewrite/uthread-exit.t | 7 - .../t/023-rewrite/uthread-redirect.t | 2 - .../modules/nginx-lua/t/024-access/req-body.t | 98 +++++++++++- .../nginx-lua/t/024-access/uthread-exec.t | 2 - .../nginx-lua/t/024-access/uthread-exit.t | 6 - .../nginx-lua/t/024-access/uthread-redirect.t | 2 - debian/modules/nginx-lua/t/028-req-header.t | 28 +++- debian/modules/nginx-lua/t/030-uri-args.t | 102 +++++++++---- debian/modules/nginx-lua/t/044-req-body.t | 133 ++++++++++++++++- debian/modules/nginx-lua/t/055-subreq-vars.t | 4 +- debian/modules/nginx-lua/t/086-init-by.t | 29 +++- debian/modules/nginx-lua/t/094-uthread-exit.t | 6 - debian/modules/nginx-lua/t/095-uthread-exec.t | 2 - .../nginx-lua/t/096-uthread-redirect.t | 2 - .../modules/nginx-lua/t/097-uthread-rewrite.t | 2 - .../nginx-lua/t/118-use-default-type.t | 19 +++ debian/modules/nginx-lua/t/123-lua-path.t | 8 + .../nginx-lua/t/131-duplex-req-socket.t | 141 ++++++++++++++++++ debian/modules/nginx-lua/util/build2.sh | 2 +- 51 files changed, 1061 insertions(+), 228 deletions(-) delete mode 100644 debian/modules/nginx-lua/.gitmodules create mode 100644 debian/modules/nginx-lua/t/131-duplex-req-socket.t diff --git a/debian/changelog b/debian/changelog index 98e7d61..b604ec5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,8 @@ nginx (1.9.2-2) UNRELEASED; urgency=medium * debian/control: + Remove XS-Testsuite header, it is now automatically added when `debian/tests/control` is present. + * debian/modules/nginx-lua: + + Update nginx-lua to v0.9.16 and drop our backported patches. -- Christos Trochalakis Mon, 22 Jun 2015 13:01:07 +0300 diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index 86ea160..435eaab 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -22,7 +22,7 @@ README for Modules versions nginx-lua Homepage: https://github.com/openresty/lua-nginx-module - Version: v0.9.15 + f4e1311 + 9531e5e7 + Version: v0.9.16 nginx-upstream-fair Homepage: https://github.com/gnosek/nginx-upstream-fair diff --git a/debian/modules/nginx-lua/.gitmodules b/debian/modules/nginx-lua/.gitmodules deleted file mode 100644 index db339a7..0000000 --- a/debian/modules/nginx-lua/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "deps/ngx_devel_kit"] - path = deps/ngx_devel_kit - url = git://github.com/simpl/ngx_devel_kit.git diff --git a/debian/modules/nginx-lua/README.markdown b/debian/modules/nginx-lua/README.markdown index 70c60dd..248c47f 100644 --- a/debian/modules/nginx-lua/README.markdown +++ b/debian/modules/nginx-lua/README.markdown @@ -13,6 +13,7 @@ ngx_lua - Embed the power of Lua into Nginx Table of Contents ================= +* [Name](#name) * [Status](#status) * [Version](#version) * [Synopsis](#synopsis) @@ -38,9 +39,10 @@ Table of Contents * [Lua Variable Scope](#lua-variable-scope) * [Locations Configured by Subrequest Directives of Other Modules](#locations-configured-by-subrequest-directives-of-other-modules) * [Cosockets Not Available Everywhere](#cosockets-not-available-everywhere) - * [Special PCRE Sequences](#special-pcre-sequences) + * [Special Escaping Sequences](#special-escaping-sequences) * [Mixing with SSI Not Supported](#mixing-with-ssi-not-supported) * [SPDY Mode Not Fully Supported](#spdy-mode-not-fully-supported) + * [Missing data on short circuited requests](#missing-data-on-short-circuited-requests) * [TODO](#todo) * [Changes](#changes) * [Test Suite](#test-suite) @@ -48,6 +50,8 @@ Table of Contents * [See Also](#see-also) * [Directives](#directives) * [Nginx API for Lua](#nginx-api-for-lua) +* [Obsolete Sections](#obsolete-sections) + * [Special PCRE Sequences](#special-pcre-sequences) Status ====== @@ -57,7 +61,7 @@ Production ready. Version ======= -This document describes ngx_lua [v0.9.15](https://github.com/openresty/lua-nginx-module/tags) released on 18 February 2015. +This document describes ngx_lua [v0.9.16](https://github.com/openresty/lua-nginx-module/tags) released on 22 June 2015. Synopsis ======== @@ -108,7 +112,7 @@ Synopsis content_by_lua "ngx.say('Hello,world!')"; } - location /nginx_var { + location /nginx_var { # MIME type determined by default_type: default_type 'text/plain'; @@ -710,7 +714,7 @@ This tool will guarantee that local variables in the Lua module functions are al Locations Configured by Subrequest Directives of Other Modules -------------------------------------------------------------- -The [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) directives cannot capture locations that include the [echo_location](http://github.com/openresty/echo-nginx-module#echo_location), [echo_location_async](http://github.com/openresty/echo-nginx-module#echo_location_async), [echo_subrequest](http://github.com/openresty/echo-nginx-module#echo_subrequest), or [echo_subrequest_async](http://github.com/openresty/echo-nginx-module#echo_subrequest_async) directives. +The [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) directives cannot capture locations that include the [add_before_body](http://nginx.org/en/docs/http/ngx_http_addition_module.html#add_before_body), [add_after_body](http://nginx.org/en/docs/http/ngx_http_addition_module.html#add_after_body), [auth_request](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html#auth_request), [echo_location](http://github.com/openresty/echo-nginx-module#echo_location), [echo_location_async](http://github.com/openresty/echo-nginx-module#echo_location_async), [echo_subrequest](http://github.com/openresty/echo-nginx-module#echo_subrequest), or [echo_subrequest_async](http://github.com/openresty/echo-nginx-module#echo_subrequest_async) directives. ```nginx @@ -747,8 +751,8 @@ There exists a work-around, however, when the original context does *not* need t [Back to TOC](#table-of-contents) -Special PCRE Sequences ----------------------- +Special Escaping Sequences +-------------------------- PCRE sequences such as `\d`, `\s`, or `\w`, require special attention because in string literals, the backslash character, `\`, is stripped out by both the Lua language parser and by the Nginx config file parser before processing. So the following snippet will not work as expected: ```nginx @@ -853,6 +857,27 @@ Certain Lua APIs provided by ngx_lua do not work in Nginx's SPDY mode yet: [ngx. [Back to TOC](#table-of-contents) +Missing data on short circuited requests +---------------------------------------- + +Nginx may terminate a request early with (at least): + +* 400 (Bad Request) +* 405 (Not Allowed) +* 408 (Request Timeout) +* 414 (Request URI Too Large) +* 494 (Request Headers Too Large) +* 499 (Client Closed Request) +* 500 (Internal Server Error) +* 501 (Not Implemented) + +This means that phases that normally run are skipped, such as the rewrite or +access phase. This also means that later phases that are run regardless, e.g. +[log_by_lua](#log_by_lua), will not have access to information that is normally set in those +phases. + +[Back to TOC](#table-of-contents) + TODO ==== @@ -1976,7 +2001,7 @@ lua_need_request_body **default:** *off* -**context:** *main | server | location* +**context:** *http, server, location, location if* **phase:** *depends on usage* @@ -2766,7 +2791,6 @@ Consider the following example, location /test { rewrite_by_lua ' - ngx.say("foo = ", ngx.ctx.foo) ngx.ctx.foo = 76 '; access_by_lua ' @@ -2782,7 +2806,6 @@ Then `GET /test` will yield the output ```bash - foo = nil 79 ``` @@ -4276,7 +4299,7 @@ which is equivalent to ```lua - return ngx.redirect("http://localhost:1984/foo", ngx.HTTP_MOVED_TEMPORARILY) + return ngx.redirect("/foo", ngx.HTTP_MOVED_TEMPORARILY) ``` Redirecting arbitrary external URLs is also supported, for example: @@ -4669,11 +4692,13 @@ This method was introduced in the `v0.5.0rc29`. ngx.encode_base64 ----------------- -**syntax:** *newstr = ngx.encode_base64(str)* +**syntax:** *newstr = ngx.encode_base64(str, no_padding?)* **context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** -Encode `str` to a base64 digest. +Encodes `str` to a base64 digest. + +Since the `0.9.16` release, an optional boolean-typed `no_padding` argument can be specified to control whether the base64 padding should be appended to the resulting digest (default to `false`, i.e., with padding enabled). This enables streaming base64 digest calculation by (data chunks) though it would be the caller's responsibility to append an appropriate padding at the end of data stream. [Back to TOC](#nginx-api-for-lua) @@ -5092,7 +5117,7 @@ The `ctx` table argument combined with the `a` regex modifier can be used to con Note that, the `options` argument is not optional when the `ctx` argument is specified and that the empty Lua string (`""`) must be used as placeholder for `options` if no meaningful regex options are required. -This method requires the PCRE library enabled in Nginx. ([Known Issue With Special PCRE Sequences](#special-pcre-sequences)). +This method requires the PCRE library enabled in Nginx. ([Known Issue With Special Escaping Sequences](#special-escaping-sequences)). To confirm that PCRE JIT is enabled, activate the Nginx debug log by adding the `--with-debug` option to Nginx or ngx_openresty's `./configure` script. Then, enable the "debug" error log level in `error_log` directive. The following message will be generated if PCRE JIT is enabled: @@ -5232,7 +5257,7 @@ The optional `options` argument takes exactly the same semantics as the [ngx.re. The current implementation requires that the iterator returned should only be used in a single request. That is, one should *not* assign it to a variable belonging to persistent namespace like a Lua package. -This method requires the PCRE library enabled in Nginx. ([Known Issue With Special PCRE Sequences](#special-pcre-sequences)). +This method requires the PCRE library enabled in Nginx. ([Known Issue With Special Escaping Sequences](#special-escaping-sequences)). This feature was first introduced in the `v0.2.1rc12` release. @@ -5298,7 +5323,7 @@ When the `replace` argument is of type "function", then it will be invoked with The dollar sign characters in the return value of the `replace` function argument are not special at all. -This method requires the PCRE library enabled in Nginx. ([Known Issue With Special PCRE Sequences](#special-pcre-sequences)). +This method requires the PCRE library enabled in Nginx. ([Known Issue With Special Escaping Sequences](#special-escaping-sequences)). This feature was first introduced in the `v0.2.1rc13` release. @@ -5336,7 +5361,7 @@ Here is some examples: -- n == 2 ``` -This method requires the PCRE library enabled in Nginx. ([Known Issue With Special PCRE Sequences](#special-pcre-sequences)). +This method requires the PCRE library enabled in Nginx. ([Known Issue With Special Escaping Sequences](#special-escaping-sequences)). This feature was first introduced in the `v0.2.1rc15` release. @@ -6950,5 +6975,17 @@ This API was first usable in the context of [init_by_lua*](#init_by_lua) since t This API was first enabled in the `v0.6.0` release. - [Back to TOC](#nginx-api-for-lua) + +Obsolete Sections +================= + +This section is just holding obsolete documentation sections that have been either renamed or removed so that existing links over the web are still valid. + +[Back to TOC](#table-of-contents) + +Special PCRE Sequences +---------------------- + +This section has been renamed to [Special Escaping Sequences](#special-escaping-sequences). + diff --git a/debian/modules/nginx-lua/config b/debian/modules/nginx-lua/config index 1cb9fd3..28b4078 100644 --- a/debian/modules/nginx-lua/config +++ b/debian/modules/nginx-lua/config @@ -8,27 +8,35 @@ ngx_feature_test="#if LUA_VERSION_NUM != 501 # error unsupported Lua language version #endif (void) luaL_newstate();" +ngx_lua_opt_I= +ngx_lua_opt_L= if [ -n "$LUAJIT_INC" -o -n "$LUAJIT_LIB" ]; then - # explicitly set Lua lib path - ngx_feature="LuaJIT library in $LUAJIT_LIB and $LUAJIT_INC (specified by the LUAJIT_LIB and LUAJIT_INC env)" + # explicitly set LuaJIT paths + + # attempt to link with -ldl, static linking on Linux requires it. + ngx_feature="LuaJIT library in $LUAJIT_LIB and $LUAJIT_INC (specified by the LUAJIT_LIB and LUAJIT_INC env, with -ldl)" ngx_feature_path="$LUAJIT_INC" + ngx_lua_opt_I="-I$LUAJIT_INC" + ngx_lua_opt_L="-L$LUAJIT_LIB" if [ $NGX_RPATH = YES ]; then - ngx_feature_libs="-R$LUAJIT_LIB -L$LUAJIT_LIB -lluajit-5.1 -lm" + ngx_feature_libs="-R$LUAJIT_LIB $ngx_lua_opt_L -lluajit-5.1 -lm -ldl" else - ngx_feature_libs="-L$LUAJIT_LIB -lluajit-5.1 -lm" + ngx_feature_libs="$ngx_lua_opt_L -lluajit-5.1 -lm -ldl" fi . auto/feature if [ $ngx_found = no ]; then - # retry with -ldl, static linking on Linux requires it. - ngx_feature="LuaJIT library in $LUAJIT_LIB and $LUAJIT_INC (specified by the LUAJIT_LIB and LUAJIT_INC env, with -ldl)" + # retry without -ldl + ngx_feature="LuaJIT library in $LUAJIT_LIB and $LUAJIT_INC (specified by the LUAJIT_LIB and LUAJIT_INC env)" ngx_feature_path="$LUAJIT_INC" + ngx_lua_opt_I="-I$LUAJIT_INC" + ngx_lua_opt_L="-L$LUAJIT_LIB" if [ $NGX_RPATH = YES ]; then - ngx_feature_libs="-R$LUAJIT_LIB -L$LUAJIT_LIB -lluajit-5.1 -lm -ldl" + ngx_feature_libs="-R$LUAJIT_LIB $ngx_lua_opt_L -lluajit-5.1 -lm" else - ngx_feature_libs="-L$LUAJIT_LIB -lluajit-5.1 -lm -ldl" + ngx_feature_libs="$ngx_lua_opt_L -lluajit-5.1 -lm" fi . auto/feature @@ -59,17 +67,34 @@ END esac else if [ -n "$LUA_INC" -o -n "$LUA_LIB" ]; then - # explicitly set Lua lib path + # explicitly set Lua paths ngx_feature="Lua library in $LUA_LIB and $LUA_INC (specified by the LUA_LIB and LUA_INC env)" ngx_feature_path="$LUA_INC" + ngx_lua_opt_I="-I$LUA_INC" + ngx_lua_opt_L="-L$LUA_LIB" if [ $NGX_RPATH = YES ]; then - ngx_feature_libs="-R$LUA_LIB -L$LUA_LIB -llua -lm" + ngx_feature_libs="-R$LUA_LIB $ngx_lua_opt_L -llua -lm -ldl" else - ngx_feature_libs="-L$LUA_LIB -llua -lm" + ngx_feature_libs="$ngx_lua_opt_L -llua -lm -ldl" fi . auto/feature + if [ $ngx_found = no ]; then + # retry without -ldl + + ngx_feature_path="$LUA_INC" + ngx_lua_opt_I="-I$LUA_INC" + ngx_lua_opt_L="-L$LUA_LIB" + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R$LUA_LIB $ngx_lua_opt_L -llua -lm" + else + ngx_feature_libs="$ngx_lua_opt_L -llua -lm" + fi + + . auto/feature + fi + if [ $ngx_found = no ]; then cat << END $0: error: ngx_http_lua_module requires the Lua or LuaJIT library and LUA_LIB is defined as $LUA_LIB and LUA_INC (path for lua.h) is $LUA_INC, but we cannot find standard Lua there. @@ -167,19 +192,7 @@ END fi if [ $ngx_found = no ]; then - # Gentoo with LuaJIT-2.0 - ngx_feature="LuaJIT library in /usr/" - ngx_feature_path="/usr/include/luajit-2.0" - if [ $NGX_RPATH = YES ]; then - ngx_feature_libs="-R/usr/lib -L/usr/lib -lm -lluajit-5.1" - else - ngx_feature_libs="-L/usr/lib -lm -lluajit-5.1" - fi - . auto/feature - fi - - if [ $ngx_found = no ]; then - # Gentoo with LuaJIT-2.0, retry with -ldl + # Gentoo with LuaJIT-2.0, try with -ldl ngx_feature="LuaJIT library in /usr/" ngx_feature_path="/usr/include/luajit-2.0" if [ $NGX_RPATH = YES ]; then @@ -189,10 +202,27 @@ END fi . auto/feature fi + + if [ $ngx_found = no ]; then + # Gentoo with LuaJIT 2.0 + ngx_feature="LuaJIT library in /usr/" + ngx_feature_path="/usr/include/luajit-2.0" + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/lib -L/usr/lib -lm -lluajit-5.1" + else + ngx_feature_libs="-L/usr/lib -lm -lluajit-5.1" + fi + . auto/feature + fi fi fi if [ $ngx_found = yes ]; then + # this is a hack to persuade nginx's build system to favor + # the paths set by our user environments: + CFLAGS="$ngx_lua_opt_I $CFLAGS" + NGX_LD_OPT="$ngx_lua_opt_L $NGX_LD_OPT" + CORE_INCS="$CORE_INCS $ngx_feature_path" CORE_LIBS="$CORE_LIBS $ngx_feature_libs" else diff --git a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki index cfaa680..7e72449 100644 --- a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki @@ -1,4 +1,4 @@ -= Name = += Name = ngx_lua - Embed the power of Lua into Nginx @@ -10,7 +10,7 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.9.15] released on 18 February 2015. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.9.16] released on 22 June 2015. = Synopsis = @@ -59,7 +59,7 @@ This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/t content_by_lua "ngx.say('Hello,world!')"; } - location /nginx_var { + location /nginx_var { # MIME type determined by default_type: default_type 'text/plain'; @@ -579,7 +579,7 @@ The output says that the line 1489 of file lib/foo/bar.lua writes t This tool will guarantee that local variables in the Lua module functions are all declared with the local keyword, otherwise a runtime exception will be thrown. It prevents undesirable race conditions while accessing such variables. See [[#Data_Sharing_within_an_Nginx_Worker|Data Sharing within an Nginx Worker]] for the reasons behind this. == Locations Configured by Subrequest Directives of Other Modules == -The [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] directives cannot capture locations that include the [[HttpEchoModule#echo_location|echo_location]], [[HttpEchoModule#echo_location_async|echo_location_async]], [[HttpEchoModule#echo_subrequest|echo_subrequest]], or [[HttpEchoModule#echo_subrequest_async|echo_subrequest_async]] directives. +The [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] directives cannot capture locations that include the [[HttpAdditionModule#add_before_body|add_before_body]], [[HttpAdditionModule#add_after_body|add_after_body]], [http://nginx.org/en/docs/http/ngx_http_auth_request_module.html#auth_request auth_request], [[HttpEchoModule#echo_location|echo_location]], [[HttpEchoModule#echo_location_async|echo_location_async]], [[HttpEchoModule#echo_subrequest|echo_subrequest]], or [[HttpEchoModule#echo_subrequest_async|echo_subrequest_async]] directives. location /foo { @@ -609,7 +609,7 @@ The cosockets are currently also disabled in the [[#init_by_lua|init_by_lua*]] a There exists a work-around, however, when the original context does *not* need to wait for the cosocket results. That is, creating a 0-delay timer via the [[#ngx.timer.at|ngx.timer.at]] API and do the cosocket results in the timer handler, which runs asynchronously as to the original context creating the timer. -== Special PCRE Sequences == +== Special Escaping Sequences == PCRE sequences such as \d, \s, or \w, require special attention because in string literals, the backslash character, \, is stripped out by both the Lua language parser and by the Nginx config file parser before processing. So the following snippet will not work as expected: @@ -700,6 +700,24 @@ Mixing SSI with ngx_lua in the same Nginx request is not supported at all. Just Certain Lua APIs provided by ngx_lua do not work in Nginx's SPDY mode yet: [[#ngx.location.capture|ngx.location.capture]], [[#ngx.location.capture_multi|ngx.location.capture_multi]], and [[#ngx.req.socket|ngx.req.socket]]. +== Missing data on short circuited requests == + +Nginx may terminate a request early with (at least): + +* 400 (Bad Request) +* 405 (Not Allowed) +* 408 (Request Timeout) +* 414 (Request URI Too Large) +* 494 (Request Headers Too Large) +* 499 (Client Closed Request) +* 500 (Internal Server Error) +* 501 (Not Implemented) + +This means that phases that normally run are skipped, such as the rewrite or +access phase. This also means that later phases that are run regardless, e.g. +[[#log_by_lua|log_by_lua]], will not have access to information that is normally set in those +phases. + = TODO = * add *_by_lua_block directives for existing *_by_lua directives so that we put literal Lua code directly in curly braces instead of an nginx literal string. For example, @@ -1662,7 +1680,7 @@ This directive was first introduced in the v0.5.0rc31 release. '''default:''' ''off'' -'''context:''' ''main | server | location'' +'''context:''' ''http, server, location, location if'' '''phase:''' ''depends on usage'' @@ -2220,7 +2238,6 @@ Consider the following example, location /test { rewrite_by_lua ' - ngx.say("foo = ", ngx.ctx.foo) ngx.ctx.foo = 76 '; access_by_lua ' @@ -2235,7 +2252,6 @@ Consider the following example, Then GET /test will yield the output - foo = nil 79 @@ -3557,7 +3573,7 @@ Here is an example assuming the current server name is localhost an which is equivalent to - return ngx.redirect("http://localhost:1984/foo", ngx.HTTP_MOVED_TEMPORARILY) + return ngx.redirect("/foo", ngx.HTTP_MOVED_TEMPORARILY) Redirecting arbitrary external URLs is also supported, for example: @@ -3889,11 +3905,13 @@ Removing the max_args cap is strongly discouraged. This method was introduced in the v0.5.0rc29. == ngx.encode_base64 == -'''syntax:''' ''newstr = ngx.encode_base64(str)'' +'''syntax:''' ''newstr = ngx.encode_base64(str, no_padding?)'' '''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' -Encode str to a base64 digest. +Encodes str to a base64 digest. + +Since the 0.9.16 release, an optional boolean-typed no_padding argument can be specified to control whether the base64 padding should be appended to the resulting digest (default to false, i.e., with padding enabled). This enables streaming base64 digest calculation by (data chunks) though it would be the caller's responsibility to append an appropriate padding at the end of data stream. == ngx.decode_base64 == '''syntax:''' ''newstr = ngx.decode_base64(str)'' @@ -4242,7 +4260,7 @@ The ctx table argument combined with the a regex modif Note that, the options argument is not optional when the ctx argument is specified and that the empty Lua string ("") must be used as placeholder for options if no meaningful regex options are required. -This method requires the PCRE library enabled in Nginx. ([[#Special PCRE Sequences|Known Issue With Special PCRE Sequences]]). +This method requires the PCRE library enabled in Nginx. ([[#Special Escaping Sequences|Known Issue With Special Escaping Sequences]]). To confirm that PCRE JIT is enabled, activate the Nginx debug log by adding the --with-debug option to Nginx or ngx_openresty's ./configure script. Then, enable the "debug" error log level in error_log directive. The following message will be generated if PCRE JIT is enabled: @@ -4372,7 +4390,7 @@ The optional options argument takes exactly the same semantics as t The current implementation requires that the iterator returned should only be used in a single request. That is, one should ''not'' assign it to a variable belonging to persistent namespace like a Lua package. -This method requires the PCRE library enabled in Nginx. ([[#Special PCRE Sequences|Known Issue With Special PCRE Sequences]]). +This method requires the PCRE library enabled in Nginx. ([[#Special Escaping Sequences|Known Issue With Special Escaping Sequences]]). This feature was first introduced in the v0.2.1rc12 release. @@ -4431,7 +4449,7 @@ When the replace argument is of type "function", then it will be in The dollar sign characters in the return value of the replace function argument are not special at all. -This method requires the PCRE library enabled in Nginx. ([[#Special PCRE Sequences|Known Issue With Special PCRE Sequences]]). +This method requires the PCRE library enabled in Nginx. ([[#Special Escaping Sequences|Known Issue With Special Escaping Sequences]]). This feature was first introduced in the v0.2.1rc13 release. @@ -4464,7 +4482,7 @@ Here is some examples: -- n == 2 -This method requires the PCRE library enabled in Nginx. ([[#Special PCRE Sequences|Known Issue With Special PCRE Sequences]]). +This method requires the PCRE library enabled in Nginx. ([[#Special Escaping Sequences|Known Issue With Special Escaping Sequences]]). This feature was first introduced in the v0.2.1rc15 release. @@ -5896,3 +5914,11 @@ This API was first usable in the context of [[#init_by_lua|init_by_lua*]] since This API was first enabled in the v0.6.0 release. += Obsolete Sections = + +This section is just holding obsolete documentation sections that have been either renamed or removed so that existing links over the web are still valid. + +== Special PCRE Sequences == + +This section has been renamed to [[#Special Escaping Sequences|Special Escaping Sequences]]. + diff --git a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h index 3700c1f..c9e3e66 100644 --- a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 9015 +#define ngx_http_lua_version 9016 typedef struct { @@ -34,9 +34,9 @@ typedef struct { } ngx_http_lua_value_t; -lua_State * ngx_http_lua_get_global_state(ngx_conf_t *cf); +lua_State *ngx_http_lua_get_global_state(ngx_conf_t *cf); -ngx_http_request_t * ngx_http_lua_get_request(lua_State *L); +ngx_http_request_t *ngx_http_lua_get_request(lua_State *L); ngx_int_t ngx_http_lua_add_package_preload(ngx_conf_t *cf, const char *package, lua_CFunction func); diff --git a/debian/modules/nginx-lua/src/ddebug.h b/debian/modules/nginx-lua/src/ddebug.h index 7965252..d0f3d1b 100644 --- a/debian/modules/nginx-lua/src/ddebug.h +++ b/debian/modules/nginx-lua/src/ddebug.h @@ -8,6 +8,7 @@ #define _DDEBUG_H_INCLUDED_ +#include #include #include diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_capturefilter.c b/debian/modules/nginx-lua/src/ngx_http_lua_capturefilter.c index 23925f8..5fe5f60 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_capturefilter.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_capturefilter.c @@ -97,6 +97,7 @@ ngx_http_lua_capture_header_filter(ngx_http_request_t *r) /* force subrequest response body buffer in memory */ r->filter_need_in_memory = 1; r->header_sent = 1; + ctx->header_sent = 1; if (r->method == NGX_HTTP_HEAD) { r->header_only = 1; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_common.h b/debian/modules/nginx-lua/src/ngx_http_lua_common.h index ff1c0bc..582815c 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_common.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_common.h @@ -194,7 +194,7 @@ typedef struct { inline script/script file path */ - u_char *rewrite_src_key; /* cached key for rewrite_src */ + u_char *rewrite_src_key; /* cached key for rewrite_src */ u_char *access_chunkname; ngx_http_complex_value_t access_src; /* access_by_lua @@ -382,8 +382,9 @@ typedef struct ngx_http_lua_ctx_s { ngx_int_t exit_code; - ngx_http_lua_co_ctx_t *downstream_co_ctx; /* co ctx for the coroutine - reading the request body */ + void *downstream; /* can be either + ngx_http_lua_socket_tcp_upstream_t + or ngx_http_lua_co_ctx_t */ ngx_uint_t index; /* index of the current subrequest in its parent @@ -434,6 +435,13 @@ typedef struct ngx_http_lua_ctx_s { unsigned no_abort:1; /* prohibit "world abortion" via ngx.exit() and etc */ + unsigned header_sent:1; /* r->header_sent is not sufficient for + * this because special header filters + * like ngx_image_filter may intercept + * the header. so we should always test + * both flags. see the test case in + * t/020-subrequest.t */ + unsigned seen_last_in_filter:1; /* used by body_filter_by_lua* */ unsigned seen_last_for_subreq:1; /* used by body capture filter */ unsigned writing_raw_req_socket:1; /* used by raw downstream diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_control.c b/debian/modules/nginx-lua/src/ngx_http_lua_control.c index 95a8227..6105edd 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_control.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_control.c @@ -170,7 +170,7 @@ ngx_http_lua_ngx_exec(lua_State *L) } } - if (r->header_sent) { + if (r->header_sent || ctx->header_sent) { return luaL_error(L, "attempt to call ngx.exec after " "sending out response headers"); } @@ -235,7 +235,7 @@ ngx_http_lua_ngx_redirect(lua_State *L) ngx_http_lua_check_if_abortable(L, ctx); - if (r->header_sent) { + if (r->header_sent || ctx->header_sent) { return luaL_error(L, "attempt to call ngx.redirect after sending out " "the headers"); } @@ -325,7 +325,7 @@ ngx_http_lua_ngx_exit(lua_State *L) return luaL_error(L, "attempt to abort with pending subrequests"); } - if (r->header_sent + if ((r->header_sent || ctx->header_sent) && rc >= NGX_HTTP_SPECIAL_RESPONSE && rc != NGX_HTTP_REQUEST_TIME_OUT && rc != NGX_HTTP_CLIENT_CLOSED_REQUEST @@ -450,7 +450,7 @@ ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, u_char *err, return NGX_ERROR; } - if (r->header_sent + if ((r->header_sent || ctx->header_sent) && status >= NGX_HTTP_SPECIAL_RESPONSE && status != NGX_HTTP_REQUEST_TIME_OUT && status != NGX_HTTP_CLIENT_CLOSED_REQUEST diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c b/debian/modules/nginx-lua/src/ngx_http_lua_directive.c index a83136c..dc9a12c 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_directive.c @@ -33,7 +33,7 @@ static ngx_int_t ngx_http_lua_set_by_lua_init(ngx_http_request_t *r); #endif -static u_char * ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, +static u_char *ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_directive.h b/debian/modules/nginx-lua/src/ngx_http_lua_directive.h index 151849b..5d5540c 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_directive.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_directive.h @@ -12,33 +12,33 @@ #include "ngx_http_lua_common.h" -char * ngx_http_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -char * ngx_http_lua_package_cpath(ngx_conf_t *cf, ngx_command_t *cmd, +char *ngx_http_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_lua_package_cpath(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -char * ngx_http_lua_package_path(ngx_conf_t *cf, ngx_command_t *cmd, +char *ngx_http_lua_package_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -char * ngx_http_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, +char *ngx_http_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -char * ngx_http_lua_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, +char *ngx_http_lua_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -char * ngx_http_lua_access_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, +char *ngx_http_lua_access_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -char * ngx_http_lua_log_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, +char *ngx_http_lua_log_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -char * ngx_http_lua_header_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, +char *ngx_http_lua_header_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -char * ngx_http_lua_body_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, +char *ngx_http_lua_body_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -char * ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, +char *ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -char * ngx_http_lua_init_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, +char *ngx_http_lua_init_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -char * ngx_http_lua_code_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_lua_code_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); #if defined(NDK) && NDK -char * ngx_http_lua_set_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -char * ngx_http_lua_set_by_lua_file(ngx_conf_t *cf, ngx_command_t *cmd, +char *ngx_http_lua_set_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_lua_set_by_lua_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); ngx_int_t ngx_http_lua_filter_set_by_lua_inline(ngx_http_request_t *r, ngx_str_t *val, ngx_http_variable_value_t *v, void *data); @@ -47,7 +47,7 @@ ngx_int_t ngx_http_lua_filter_set_by_lua_file(ngx_http_request_t *r, #endif -char * ngx_http_lua_rewrite_no_postpone(ngx_conf_t *cf, ngx_command_t *cmd, +char *ngx_http_lua_rewrite_no_postpone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers.c b/debian/modules/nginx-lua/src/ngx_http_lua_headers.c index c186864..5f8e59a 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headers.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headers.c @@ -488,7 +488,7 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) #if 1 if (r->headers_out.content_type.len) { - lua_pushliteral(L, "Content-Type"); + lua_pushliteral(L, "content-type"); lua_pushlstring(L, (char *) r->headers_out.content_type.data, r->headers_out.content_type.len); lua_rawset(L, -3); @@ -497,12 +497,12 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) if (r->headers_out.content_length == NULL && r->headers_out.content_length_n >= 0) { - lua_pushliteral(L, "Content-Length"); + lua_pushliteral(L, "content-length"); lua_pushfstring(L, "%d", (int) r->headers_out.content_length_n); lua_rawset(L, -3); } - lua_pushliteral(L, "Connection"); + lua_pushliteral(L, "connection"); if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) { lua_pushliteral(L, "upgrade"); @@ -515,7 +515,7 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) lua_rawset(L, -3); if (r->chunked) { - lua_pushliteral(L, "Transfer-Encoding"); + lua_pushliteral(L, "transfer-encoding"); lua_pushliteral(L, "chunked"); lua_rawset(L, -3); } @@ -658,7 +658,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) ngx_http_lua_check_fake_request(L, r); - if (r->header_sent) { + if (r->header_sent || ctx->header_sent) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to " "set ngx.header.HEADER after sending out " "response headers"); @@ -1086,7 +1086,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } - if (r->header_sent) { + if (r->header_sent || ctx->header_sent) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to " "set ngx.header.HEADER after sending out " "response headers"); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c b/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c index bd03a24..6aa1a33 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c @@ -14,7 +14,7 @@ #include "ngx_http_lua_util.h" -static u_char * ngx_http_lua_log_init_worker_error(ngx_log_t *log, +static u_char *ngx_http_lua_log_init_worker_error(ngx_log_t *log, u_char *buf, size_t len); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_misc.c b/debian/modules/nginx-lua/src/ngx_http_lua_misc.c index 0d9e7b6..4990e26 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_misc.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_misc.c @@ -40,10 +40,18 @@ ngx_http_lua_ngx_get(lua_State *L) ngx_http_request_t *r; u_char *p; size_t len; + ngx_http_lua_ctx_t *ctx; r = ngx_http_lua_get_req(L); if (r == NULL) { - return luaL_error(L, "no request object found"); + lua_pushnil(L); + return 1; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + lua_pushnil(L); + return 1; } p = (u_char *) luaL_checklstring(L, -1, &len); @@ -90,9 +98,9 @@ ngx_http_lua_ngx_get(lua_State *L) { ngx_http_lua_check_fake_request(L, r); - dd("headers sent: %d", r->header_sent); + dd("headers sent: %d", r->header_sent || ctx->header_sent); - lua_pushboolean(L, r->header_sent ? 1 : 0); + lua_pushboolean(L, r->header_sent || ctx->header_sent); return 1; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_output.c b/debian/modules/nginx-lua/src/ngx_http_lua_output.c index a3feb7d..2062e5a 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_output.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_output.c @@ -510,7 +510,7 @@ ngx_http_lua_ngx_flush(lua_State *L) } #if 1 - if (!r->header_sent) { + if (!r->header_sent && !ctx->header_sent) { lua_pushnil(L); lua_pushliteral(L, "nothing to flush"); return 2; @@ -690,7 +690,7 @@ ngx_http_lua_ngx_send_headers(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); - if (!r->header_sent) { + if (!r->header_sent && !ctx->header_sent) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua send headers"); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_output.h b/debian/modules/nginx-lua/src/ngx_http_lua_output.h index 5d4975e..109a4b4 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_output.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_output.h @@ -17,7 +17,7 @@ void ngx_http_lua_inject_output_api(lua_State *L); size_t ngx_http_lua_calc_strlen_in_table(lua_State *L, int index, int arg_i, unsigned strict); -u_char * ngx_http_lua_copy_str_in_table(lua_State *L, int index, u_char *dst); +u_char *ngx_http_lua_copy_str_in_table(lua_State *L, int index, u_char *dst); ngx_int_t ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c b/debian/modules/nginx-lua/src/ngx_http_lua_regex.c index fd2d017..1ecfd70 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_regex.c @@ -2303,9 +2303,9 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, (int) pos, cap, ovecsize, ws, sizeof(ws)/sizeof(ws[0]), exec_opts); -#else /* LUA_HAVE_PCRE_DFA */ +#else - return PCRE_ERROR_INTERNAL; + return PCRE_ERROR_BADOPTION; #endif /* LUA_HAVE_PCRE_DFA */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c b/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c index 0810c32..af90245 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c @@ -142,7 +142,7 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) "interruptions"); ctx->waiting_more_body = 1; - ctx->downstream_co_ctx = coctx; + ctx->downstream = coctx; ngx_http_lua_cleanup_pending_operation(coctx); coctx->cleanup = ngx_http_lua_req_body_cleanup; @@ -176,7 +176,7 @@ ngx_http_lua_req_body_post_read(ngx_http_request_t *r) if (ctx->waiting_more_body) { ctx->waiting_more_body = 0; - coctx = ctx->downstream_co_ctx; + coctx = ctx->downstream; ctx->cur_co_ctx = coctx; coctx->cleanup = NULL; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_script.c b/debian/modules/nginx-lua/src/ngx_http_lua_script.c index 228e3a8..24be601 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_script.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_script.c @@ -13,7 +13,7 @@ #include "ngx_http_lua_script.h" -static void * ngx_http_lua_script_add_code(ngx_array_t *codes, size_t size); +static void *ngx_http_lua_script_add_code(ngx_array_t *codes, size_t size); static size_t ngx_http_lua_script_copy_len_code( ngx_http_lua_script_engine_t *e); static void ngx_http_lua_script_copy_code(ngx_http_lua_script_engine_t *e); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c index e825308..804c854 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c @@ -1842,7 +1842,7 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) dd("setting data to %p, coctx:%p", u, coctx); if (u->raw_downstream || u->body_downstream) { - ctx->downstream_co_ctx = coctx; + ctx->downstream = u; } return lua_yield(L, 0); @@ -3722,7 +3722,7 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) dd("setting data to %p", u); if (u->raw_downstream || u->body_downstream) { - ctx->downstream_co_ctx = coctx; + ctx->downstream = u; } return lua_yield(L, 0); @@ -4143,6 +4143,8 @@ ngx_http_lua_req_socket(lua_State *L) r->header_sent = 1; } + ctx->header_sent = 1; + dd("ctx acquired raw req socket: %d", ctx->acquired_raw_req_socket); if (ctx->acquired_raw_req_socket) { @@ -4265,7 +4267,7 @@ ngx_http_lua_req_socket(lua_State *L) dd("setting data to %p", u); coctx->data = u; - ctx->downstream_co_ctx = coctx; + ctx->downstream = u; if (c->read->timer_set) { ngx_del_timer(c->read); @@ -4286,7 +4288,6 @@ static void ngx_http_lua_req_socket_rev_handler(ngx_http_request_t *r) { ngx_http_lua_ctx_t *ctx; - ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_socket_tcp_upstream_t *u; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -4297,9 +4298,7 @@ ngx_http_lua_req_socket_rev_handler(ngx_http_request_t *r) return; } - coctx = ctx->downstream_co_ctx; - u = coctx->data; - + u = ctx->downstream; if (u) { u->read_event_handler(r, u); } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_string.c b/debian/modules/nginx-lua/src/ngx_http_lua_string.c index 52877bb..750d95e 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_string.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_string.c @@ -450,13 +450,68 @@ ngx_http_lua_ngx_decode_base64(lua_State *L) } +static void +ngx_http_lua_encode_base64(ngx_str_t *dst, ngx_str_t *src, int no_padding) +{ + u_char *d, *s; + size_t len; + static u_char basis[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + len = src->len; + s = src->data; + d = dst->data; + + while (len > 2) { + *d++ = basis[(s[0] >> 2) & 0x3f]; + *d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)]; + *d++ = basis[((s[1] & 0x0f) << 2) | (s[2] >> 6)]; + *d++ = basis[s[2] & 0x3f]; + + s += 3; + len -= 3; + } + + if (len) { + *d++ = basis[(s[0] >> 2) & 0x3f]; + + if (len == 1) { + *d++ = basis[(s[0] & 3) << 4]; + if (!no_padding) { + *d++ = '='; + } + + } else { + *d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)]; + *d++ = basis[(s[1] & 0x0f) << 2]; + } + + if (!no_padding) { + *d++ = '='; + } + } + + dst->len = d - dst->data; +} + + +static size_t +ngx_http_lua_base64_encoded_length(size_t n, int no_padding) +{ + return no_padding ? (n * 8 + 5) / 6 : ngx_base64_encoded_length(n); +} + + static int ngx_http_lua_ngx_encode_base64(lua_State *L) { + int n; + int no_padding = 0; ngx_str_t p, src; - if (lua_gettop(L) != 1) { - return luaL_error(L, "expecting one argument"); + n = lua_gettop(L); + if (n != 1 && n != 2) { + return luaL_error(L, "expecting one or two arguments"); } if (lua_isnil(L, 1)) { @@ -467,11 +522,17 @@ ngx_http_lua_ngx_encode_base64(lua_State *L) src.data = (u_char *) luaL_checklstring(L, 1, &src.len); } - p.len = ngx_base64_encoded_length(src.len); + if (n == 2) { + /* get the 2nd optional argument */ + luaL_checktype(L, 2, LUA_TBOOLEAN); + no_padding = lua_toboolean(L, 2); + } + + p.len = ngx_http_lua_base64_encoded_length(src.len, no_padding); p.data = lua_newuserdata(L, p.len); - ngx_encode_base64(&p, &src); + ngx_http_lua_encode_base64(&p, &src, no_padding); lua_pushlstring(L, (char *) p.data, p.len); @@ -639,7 +700,8 @@ ngx_http_lua_ffi_sha1_bin(const u_char *src, size_t len, u_char *dst) size_t -ngx_http_lua_ffi_encode_base64(const u_char *src, size_t slen, u_char *dst) +ngx_http_lua_ffi_encode_base64(const u_char *src, size_t slen, u_char *dst, + int no_padding) { ngx_str_t in, out; @@ -648,7 +710,7 @@ ngx_http_lua_ffi_encode_base64(const u_char *src, size_t slen, u_char *dst) out.data = dst; - ngx_encode_base64(&out, &in); + ngx_http_lua_encode_base64(&out, &in, no_padding); return out.len; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c index a358fd6..49230f4 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c @@ -41,7 +41,7 @@ typedef struct { static int ngx_http_lua_ngx_timer_at(lua_State *L); static void ngx_http_lua_timer_handler(ngx_event_t *ev); -static u_char * ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, +static u_char *ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, size_t len); static void ngx_http_lua_abort_pending_timers(ngx_event_t *ev); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.c b/debian/modules/nginx-lua/src/ngx_http_lua_util.c index 879608b..65916be 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_util.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_util.c @@ -117,7 +117,7 @@ static ngx_int_t ngx_http_lua_flush_pending_output(ngx_http_request_t *r, static ngx_int_t ngx_http_lua_process_flushing_coroutines(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); -static lua_State * ngx_http_lua_new_state(lua_State *parent_vm, +static lua_State *ngx_http_lua_new_state(lua_State *parent_vm, ngx_cycle_t *cycle, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log); static int ngx_http_lua_get_raw_phase_context(lua_State *L); @@ -410,7 +410,9 @@ ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, { ngx_int_t rc; - if (!r->header_sent) { + dd("send header if needed: %d", r->header_sent || ctx->header_sent); + + if (!r->header_sent && !ctx->header_sent) { if (r->headers_out.status == 0) { r->headers_out.status = NGX_HTTP_OK; } @@ -427,6 +429,7 @@ ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, if (!ctx->buffering) { dd("sending headers"); rc = ngx_http_send_header(r); + ctx->header_sent = 1; return rc; } } @@ -460,6 +463,7 @@ ngx_http_lua_send_chain_link(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, if (llcf->http10_buffering && !ctx->buffering && !r->header_sent + && !ctx->header_sent && r->http_version < NGX_HTTP_VERSION_11 && r->headers_out.content_length_n < 0) { @@ -483,6 +487,16 @@ ngx_http_lua_send_chain_link(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, } if (in == NULL) { + dd("last buf to be sent"); + +#if 1 + if (!r->request_body && r == r->main) { + if (ngx_http_discard_request_body(r) != NGX_OK) { + return NGX_ERROR; + } + } +#endif + if (ctx->buffering) { rc = ngx_http_lua_send_http10_headers(r, ctx); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { @@ -613,7 +627,7 @@ ngx_http_lua_send_http10_headers(ngx_http_request_t *r, ngx_chain_t *cl; ngx_int_t rc; - if (r->header_sent) { + if (r->header_sent || ctx->header_sent) { return NGX_OK; } @@ -639,6 +653,7 @@ ngx_http_lua_send_http10_headers(ngx_http_request_t *r, send: rc = ngx_http_send_header(r); + ctx->header_sent = 1; return rc; } @@ -1398,14 +1413,14 @@ user_co_done: ngx_http_lua_request_cleanup(ctx, 0); - dd("headers sent? %d", r->header_sent ? 1 : 0); + dd("headers sent? %d", r->header_sent || ctx->header_sent); if (ctx->no_abort) { ctx->no_abort = 0; return NGX_ERROR; } - return r->header_sent ? NGX_ERROR : + return (r->header_sent || ctx->header_sent) ? NGX_ERROR : NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -1460,7 +1475,8 @@ no_parent: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua handler aborted: " "user coroutine has no parent"); - return r->header_sent ? NGX_ERROR : NGX_HTTP_INTERNAL_SERVER_ERROR; + return (r->header_sent || ctx->header_sent) ? + NGX_ERROR : NGX_HTTP_INTERNAL_SERVER_ERROR; done: @@ -1484,7 +1500,6 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) ngx_event_t *wev; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; - ngx_http_lua_co_ctx_t *coctx; ngx_http_core_loc_conf_t *clcf; ngx_http_lua_socket_tcp_upstream_t *u; @@ -1535,12 +1550,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) if (ctx->writing_raw_req_socket) { ctx->writing_raw_req_socket = 0; - coctx = ctx->downstream_co_ctx; - if (coctx == NULL) { - return NGX_ERROR; - } - - u = coctx->data; + u = ctx->downstream; if (u == NULL) { return NGX_ERROR; } @@ -2204,6 +2214,7 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, #if 1 if (!r->header_sent + && !ctx->header_sent && r->headers_out.status == 0 && ctx->exit_code >= NGX_HTTP_OK) { @@ -2257,7 +2268,7 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, } #if 1 - if (r->header_sent + if ((r->header_sent || ctx->header_sent) && ctx->exit_code > NGX_OK && ctx->exit_code != NGX_HTTP_REQUEST_TIME_OUT && ctx->exit_code != NGX_HTTP_CLIENT_CLOSED_REQUEST diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.h b/debian/modules/nginx-lua/src/ngx_http_lua_util.h index 3dfb819..42ba07e 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_util.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_util.h @@ -126,14 +126,14 @@ ngx_http_lua_ffi_check_context(ngx_http_lua_ctx_t *ctx, unsigned flags, } -lua_State * ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, +lua_State *ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, ngx_pool_t *pool, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log, ngx_pool_cleanup_t **pcln); -lua_State * ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *l, +lua_State *ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *l, int *ref); -u_char * ngx_http_lua_rebase_path(ngx_pool_t *pool, u_char *src, size_t len); +u_char *ngx_http_lua_rebase_path(ngx_pool_t *pool, u_char *src, size_t len); ngx_int_t ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); @@ -161,7 +161,7 @@ ngx_int_t ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ngx_int_t ngx_http_lua_wev_handler(ngx_http_request_t *r); -u_char * ngx_http_lua_digest_hex(u_char *dest, const u_char *buf, +u_char *ngx_http_lua_digest_hex(u_char *dest, const u_char *buf, int buf_len); void ngx_http_lua_set_multi_value_table(lua_State *L, int index); @@ -180,17 +180,17 @@ void ngx_http_lua_process_args_option(ngx_http_request_t *r, ngx_int_t ngx_http_lua_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log); -ngx_chain_t * ngx_http_lua_chain_get_free_buf(ngx_log_t *log, ngx_pool_t *p, +ngx_chain_t *ngx_http_lua_chain_get_free_buf(ngx_log_t *log, ngx_pool_t *p, ngx_chain_t **free, size_t len); void ngx_http_lua_create_new_globals_table(lua_State *L, int narr, int nrec); int ngx_http_lua_traceback(lua_State *L); -ngx_http_lua_co_ctx_t * ngx_http_lua_get_co_ctx(lua_State *L, +ngx_http_lua_co_ctx_t *ngx_http_lua_get_co_ctx(lua_State *L, ngx_http_lua_ctx_t *ctx); -ngx_http_lua_co_ctx_t * ngx_http_lua_create_co_ctx(ngx_http_request_t *r, +ngx_http_lua_co_ctx_t *ngx_http_lua_create_co_ctx(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); ngx_int_t ngx_http_lua_run_posted_threads(ngx_connection_t *c, lua_State *L, @@ -221,9 +221,9 @@ void ngx_http_lua_release_ngx_ctx_table(ngx_log_t *log, lua_State *L, void ngx_http_lua_cleanup_vm(void *data); -ngx_connection_t * ngx_http_lua_create_fake_connection(ngx_pool_t *pool); +ngx_connection_t *ngx_http_lua_create_fake_connection(ngx_pool_t *pool); -ngx_http_request_t * ngx_http_lua_create_fake_request(ngx_connection_t *c); +ngx_http_request_t *ngx_http_lua_create_fake_request(ngx_connection_t *c); ngx_int_t ngx_http_lua_report(ngx_log_t *log, lua_State *L, int status, const char *prefix); @@ -379,7 +379,9 @@ ngx_http_lua_set_content_type(ngx_http_request_t *r) ngx_http_lua_loc_conf_t *llcf; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - if (llcf->use_default_type) { + if (llcf->use_default_type + && r->headers_out.status != NGX_HTTP_NOT_MODIFIED) + { return ngx_http_set_content_type(r); } diff --git a/debian/modules/nginx-lua/t/013-base64.t b/debian/modules/nginx-lua/t/013-base64.t index 1c5ada9..95db9a1 100644 --- a/debian/modules/nginx-lua/t/013-base64.t +++ b/debian/modules/nginx-lua/t/013-base64.t @@ -9,7 +9,7 @@ log_level('warn'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 3); +plan tests => repeat_each() * (blocks() * 2 + 4); #no_diff(); #no_long_string(); @@ -196,3 +196,52 @@ nil --- no_error_log [error] + + +=== TEST 15: base64 encode without padding (explicit true to no_padding) +--- config + location = /t { + content_by_lua 'ngx.say(ngx.encode_base64("hello", true))'; + } +--- request +GET /t +--- response_body +aGVsbG8 + + + +=== TEST 16: base64 encode short string +--- config + location = /t { + content_by_lua 'ngx.say(ngx.encode_base64("w"))'; + } +--- request +GET /t +--- response_body +dw== + + + +=== TEST 17: base64 encode short string with padding (explicit false to no_padding) +--- config + location = /t { + content_by_lua 'ngx.say(ngx.encode_base64("w", false))'; + } +--- request +GET /t +--- response_body +dw== + + + +=== TEST 18: base64 encode with wrong 2nd parameter +--- config + location = /t { + content_by_lua 'ngx.say(ngx.encode_base64("w", 0))'; + } +--- request +GET /t +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log eval +qr/bad argument \#2 to 'encode_base64' \(boolean expected, got number\)|\[error\] .*? boolean argument only/ diff --git a/debian/modules/nginx-lua/t/014-bugs.t b/debian/modules/nginx-lua/t/014-bugs.t index 1042b29..6461783 100644 --- a/debian/modules/nginx-lua/t/014-bugs.t +++ b/debian/modules/nginx-lua/t/014-bugs.t @@ -784,7 +784,7 @@ See more details here: http://mailman.nginx.org/pipermail/nginx-devel/2013-Janua --- no_error_log [alert] --- error_log eval -qr/send\(\) failed \(\d+: Connection refused\) while resolving/ +qr/(?:send|recv)\(\) failed \(\d+: Connection refused\) while resolving/ diff --git a/debian/modules/nginx-lua/t/016-resp-header.t b/debian/modules/nginx-lua/t/016-resp-header.t index f119fb9..38765dc 100644 --- a/debian/modules/nginx-lua/t/016-resp-header.t +++ b/debian/modules/nginx-lua/t/016-resp-header.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 26); +plan tests => repeat_each() * (blocks() * 3 + 34); #no_diff(); no_long_string(); @@ -839,8 +839,11 @@ Hello results.content_type = "anything" results.somehing_else = "hi" - for k, v in pairs(results) do - ngx.say(k .. ": " .. v) + local arr = {} + for k in pairs(results) do table.insert(arr, k) end + table.sort(arr) + for i, k in ipairs(arr) do + ngx.say(k .. ": " .. results[k]) end '; } @@ -850,9 +853,9 @@ GET /read Content-Type: text/my-plain --- response_body +content_type: anything somehing_else: hi something: hello -content_type: anything --- no_error_log [error] @@ -1234,6 +1237,8 @@ bar: baz header_filter_by_lua ' local hs = ngx.resp.get_headers() print("my Content-Type: ", hs["Content-Type"]) + print("my content-type: ", hs["content-type"]) + print("my content_type: ", hs["content_type"]) '; } --- request @@ -1245,6 +1250,8 @@ hi [alert] --- error_log my Content-Type: text/plain +my content-type: text/plain +my content_type: text/plain @@ -1259,6 +1266,8 @@ my Content-Type: text/plain header_filter_by_lua ' local hs = ngx.resp.get_headers() print("my Content-Length: ", hs["Content-Length"]) + print("my content-length: ", hs["content-length"]) + print("my content_length: ", hs.content_length) '; } --- request @@ -1270,6 +1279,8 @@ hi [alert] --- error_log my Content-Length: 3 +my content-length: 3 +my content_length: 3 @@ -1284,6 +1295,7 @@ my Content-Length: 3 header_filter_by_lua ' local hs = ngx.resp.get_headers() print("my Connection: ", hs["Connection"]) + print("my connection: ", hs["connection"]) '; } --- request @@ -1295,6 +1307,7 @@ hi [alert] --- error_log my Connection: close +my connection: close @@ -1309,6 +1322,8 @@ my Connection: close body_filter_by_lua ' local hs = ngx.resp.get_headers() print("my Transfer-Encoding: ", hs["Transfer-Encoding"]) + print("my transfer-encoding: ", hs["transfer-encoding"]) + print("my transfer_encoding: ", hs.transfer_encoding) '; } --- request @@ -1320,6 +1335,7 @@ hi [alert] --- error_log my Transfer-Encoding: chunked +my transfer-encoding: chunked @@ -1334,6 +1350,8 @@ my Transfer-Encoding: chunked body_filter_by_lua ' local hs = ngx.resp.get_headers() print("my Transfer-Encoding: ", hs["Transfer-Encoding"]) + print("my transfer-encoding: ", hs["transfer-encoding"]) + print("my transfer_encoding: ", hs.transfer_encoding) '; } --- request @@ -1345,6 +1363,8 @@ hi [alert] --- error_log my Transfer-Encoding: nil +my transfer-encoding: nil +my transfer_encoding: nil diff --git a/debian/modules/nginx-lua/t/020-subrequest.t b/debian/modules/nginx-lua/t/020-subrequest.t index e36d1f4..e3357be 100644 --- a/debian/modules/nginx-lua/t/020-subrequest.t +++ b/debian/modules/nginx-lua/t/020-subrequest.t @@ -10,7 +10,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 21); +plan tests => repeat_each() * (blocks() * 3 + 22); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; @@ -2758,3 +2758,42 @@ $ --- no_error_log [error] + + +=== TEST 74: image_filter + ngx.location.capture +ngx_http_image_filter_module's header filter intercepts +the header filter chain so the r->header_sent flag won't +get set right after the header filter chain is first invoked. + +--- config + +location = /back { + empty_gif; +} + +location = /t { + image_filter rotate 90; + + content_by_lua ' + local res = ngx.location.capture("/back") + for k, v in pairs(res.header) do + ngx.header[k] = v + end + ngx.status = res.status + ngx.print(res.body) + '; +} + +--- request +GET /t +--- response_body_like: . +--- stap +F(ngx_http_image_header_filter) { + println("image header filter") +} +--- stap_out +image header filter + +--- no_error_log +[error] + diff --git a/debian/modules/nginx-lua/t/023-rewrite/req-body.t b/debian/modules/nginx-lua/t/023-rewrite/req-body.t index dec093a..c085c0f 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/req-body.t +++ b/debian/modules/nginx-lua/t/023-rewrite/req-body.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 1); +plan tests => repeat_each() * (blocks() * 4 + 5); #no_diff(); #no_long_string(); @@ -100,6 +100,9 @@ hello, world --- response_body hello, world sub: foo +--- no_error_log +[error] +[alert] @@ -123,3 +126,99 @@ Expect: 100-Continue [error] http finalize request: 500, "/test?" a:1, c:0 + + +=== TEST 6: not discard body (exit 200) +--- config + location = /foo { + rewrite_by_lua ' + -- ngx.req.discard_body() + ngx.say("body: ", ngx.var.request_body) + ngx.exit(200) + '; + } + location = /bar { + content_by_lua ' + ngx.req.read_body() + ngx.say("body: ", ngx.var.request_body) + '; + } +--- pipelined_requests eval +["POST /foo +hello, world", +"POST /bar +hiya, world"] +--- response_body eval +["body: nil\n", +"body: hiya, world\n", +] +--- error_code eval +[200, 200] +--- no_error_log +[error] +[alert] + + + +=== TEST 7: not discard body (exit 201) +--- config + location = /foo { + rewrite_by_lua ' + -- ngx.req.discard_body() + ngx.say("body: ", ngx.var.request_body) + ngx.exit(201) + '; + } + location = /bar { + content_by_lua ' + ngx.req.read_body() + ngx.say("body: ", ngx.var.request_body) + '; + } +--- pipelined_requests eval +["POST /foo +hello, world", +"POST /bar +hiya, world"] +--- response_body eval +["body: nil\n", +"body: hiya, world\n", +] +--- error_code eval +[200, 200] +--- no_error_log +[error] +[alert] + + + +=== TEST 8: not discard body (exit 302) +--- config + location = /foo { + rewrite_by_lua ' + -- ngx.req.discard_body() + -- ngx.say("body: ", ngx.var.request_body) + ngx.redirect("/blah") + '; + } + location = /bar { + content_by_lua ' + ngx.req.read_body() + ngx.say("body: ", ngx.var.request_body) + '; + } +--- pipelined_requests eval +["POST /foo +hello, world", +"POST /bar +hiya, world"] +--- response_body eval +[qr/302 Found/, +"body: hiya, world\n", +] +--- error_code eval +[302, 200] +--- no_error_log +[error] +[alert] + diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-exec.t b/debian/modules/nginx-lua/t/023-rewrite/uthread-exec.t index 6b4e650..d929670 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/uthread-exec.t +++ b/debian/modules/nginx-lua/t/023-rewrite/uthread-exec.t @@ -292,8 +292,6 @@ hello foo } --- request POST /lua ---- more_headers -Content-Length: 1024 --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; @@ -346,4 +344,3 @@ free request end --- error_log attempt to abort with pending subrequests - diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-exit.t b/debian/modules/nginx-lua/t/023-rewrite/uthread-exit.t index 750573d..f17c9c3 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/uthread-exit.t +++ b/debian/modules/nginx-lua/t/023-rewrite/uthread-exit.t @@ -1102,8 +1102,6 @@ after } --- request POST /lua ---- more_headers -Content-Length: 1024 --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; @@ -1184,8 +1182,6 @@ attempt to abort with pending subrequests } --- request POST /lua ---- more_headers -Content-Length: 1024 --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; @@ -1276,8 +1272,6 @@ attempt to abort with pending subrequests } --- request POST /lua ---- more_headers -Content-Length: 1024 --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; @@ -1336,4 +1330,3 @@ free request end --- error_log attempt to abort with pending subrequests - diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t b/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t index 9d440bb..6d4f0a1 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t +++ b/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t @@ -50,8 +50,6 @@ __DATA__ } --- request POST /lua ---- more_headers -Content-Length: 1024 --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; diff --git a/debian/modules/nginx-lua/t/024-access/req-body.t b/debian/modules/nginx-lua/t/024-access/req-body.t index e26a79c..4d8eb78 100644 --- a/debian/modules/nginx-lua/t/024-access/req-body.t +++ b/debian/modules/nginx-lua/t/024-access/req-body.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 1); +plan tests => repeat_each() * (blocks() * 2 + 19); #no_diff(); #no_long_string(); @@ -123,3 +123,99 @@ Expect: 100-Continue [error] http finalize request: 500, "/test?" a:1, c:0 + + +=== TEST 6: not discard body (exit 200) +--- config + location = /foo { + access_by_lua ' + -- ngx.req.discard_body() + ngx.say("body: ", ngx.var.request_body) + ngx.exit(200) + '; + } + location = /bar { + content_by_lua ' + ngx.req.read_body() + ngx.say("body: ", ngx.var.request_body) + '; + } +--- pipelined_requests eval +["POST /foo +hello, world", +"POST /bar +hiya, world"] +--- response_body eval +["body: nil\n", +"body: hiya, world\n", +] +--- error_code eval +[200, 200] +--- no_error_log +[error] +[alert] + + + +=== TEST 7: not discard body (exit 201) +--- config + location = /foo { + access_by_lua ' + -- ngx.req.discard_body() + ngx.say("body: ", ngx.var.request_body) + ngx.exit(201) + '; + } + location = /bar { + content_by_lua ' + ngx.req.read_body() + ngx.say("body: ", ngx.var.request_body) + '; + } +--- pipelined_requests eval +["POST /foo +hello, world", +"POST /bar +hiya, world"] +--- response_body eval +["body: nil\n", +"body: hiya, world\n", +] +--- error_code eval +[200, 200] +--- no_error_log +[error] +[alert] + + + +=== TEST 8: not discard body (exit 302) +--- config + location = /foo { + access_by_lua ' + -- ngx.req.discard_body() + -- ngx.say("body: ", ngx.var.request_body) + ngx.redirect("/blah") + '; + } + location = /bar { + content_by_lua ' + ngx.req.read_body() + ngx.say("body: ", ngx.var.request_body) + '; + } +--- pipelined_requests eval +["POST /foo +hello, world", +"POST /bar +hiya, world"] +--- response_body eval +[qr/302 Found/, +"body: hiya, world\n", +] +--- error_code eval +[302, 200] +--- no_error_log +[error] +[alert] + diff --git a/debian/modules/nginx-lua/t/024-access/uthread-exec.t b/debian/modules/nginx-lua/t/024-access/uthread-exec.t index f050cf0..b8d01e0 100644 --- a/debian/modules/nginx-lua/t/024-access/uthread-exec.t +++ b/debian/modules/nginx-lua/t/024-access/uthread-exec.t @@ -293,8 +293,6 @@ hello foo } --- request POST /lua ---- more_headers -Content-Length: 1024 --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; diff --git a/debian/modules/nginx-lua/t/024-access/uthread-exit.t b/debian/modules/nginx-lua/t/024-access/uthread-exit.t index 1d0f878..a843d3b 100644 --- a/debian/modules/nginx-lua/t/024-access/uthread-exit.t +++ b/debian/modules/nginx-lua/t/024-access/uthread-exit.t @@ -1084,8 +1084,6 @@ after } --- request POST /lua ---- more_headers -Content-Length: 1024 --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; @@ -1166,8 +1164,6 @@ attempt to abort with pending subrequests } --- request POST /lua ---- more_headers -Content-Length: 1024 --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; @@ -1258,8 +1254,6 @@ attempt to abort with pending subrequests } --- request POST /lua ---- more_headers -Content-Length: 1024 --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; diff --git a/debian/modules/nginx-lua/t/024-access/uthread-redirect.t b/debian/modules/nginx-lua/t/024-access/uthread-redirect.t index 918fa83..620fcc0 100644 --- a/debian/modules/nginx-lua/t/024-access/uthread-redirect.t +++ b/debian/modules/nginx-lua/t/024-access/uthread-redirect.t @@ -50,8 +50,6 @@ __DATA__ } --- request POST /lua ---- more_headers -Content-Length: 1024 --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; diff --git a/debian/modules/nginx-lua/t/028-req-header.t b/debian/modules/nginx-lua/t/028-req-header.t index d940e13..1d18c39 100644 --- a/debian/modules/nginx-lua/t/028-req-header.t +++ b/debian/modules/nginx-lua/t/028-req-header.t @@ -744,8 +744,14 @@ Foo22: foo22\r location /t { content_by_lua ' local h = {} + local arr = {} for k, v in pairs(ngx.req.get_headers(nil, true)) do - ngx.say(k, ": ", v) + h[k] = v + table.insert(arr, k) + end + table.sort(arr) + for i, k in ipairs(arr) do + ngx.say(k, ": ", h[k]) end '; } @@ -755,10 +761,10 @@ GET /t My-Foo: bar Bar: baz --- response_body -Host: localhost Bar: baz -My-Foo: bar Connection: close +Host: localhost +My-Foo: bar @@ -1049,9 +1055,15 @@ foo-21: 21\r location /t { content_by_lua ' -- get ALL the raw headers (0 == no limit, not recommended) - local headers = ngx.req.get_headers(0, true) - for k, v in pairs(headers) do - ngx.say{ k, ": ", v} + local h = {} + local arr = {} + for k, v in pairs(ngx.req.get_headers(0, true)) do + h[k] = v + table.insert(arr, k) + end + table.sort(arr) + for i, k in ipairs(arr) do + ngx.say(k, ": ", h[k]) end '; } @@ -1061,10 +1073,10 @@ GET /t My-Foo: bar Bar: baz --- response_body -Host: localhost Bar: baz -My-Foo: bar Connection: close +Host: localhost +My-Foo: bar --- no_error_log [error] diff --git a/debian/modules/nginx-lua/t/030-uri-args.t b/debian/modules/nginx-lua/t/030-uri-args.t index be6b9e4..83b3842 100644 --- a/debian/modules/nginx-lua/t/030-uri-args.t +++ b/debian/modules/nginx-lua/t/030-uri-args.t @@ -655,7 +655,12 @@ args: --- request GET /lua --- response_body_like -^args:(?:a=9&a=2&b=3|b=3&a=9&a=2)$ +(?x) ^args: + (?= .*? \b a=9 \b ) # 3 chars + (?= .*? \b a=2 \b ) # 3 chars + (?= .*? \b b=3 \b ) # 3 chars + (?= (?: [^&]+ & ){2} [^&]+ $ ) # requires exactly 2 &'s + (?= .{11} $ ) # requires for total 11 chars (exactly) in the string @@ -700,8 +705,13 @@ args: foo=3 } --- request GET /lua ---- response_body -foo=3&bar=32&bar +--- response_body_like +(?x) ^ + (?= .*? \b bar=32 \b ) # 6 chars + (?= .*? \b bar (?!=) \b ) # 3 chars + (?= .*? \b foo=3 \b ) # 5 chars + (?= (?: [^&]+ & ){2} [^&]+ $ ) # requires exactly 2 &'s + (?= .{16} $ ) # requires for total 16 chars (exactly) in the string --- no_error_log [error] @@ -1129,7 +1139,12 @@ b = foo content_by_lua ' local s = "f+f=bar&B=foo" args = ngx.decode_args(s) + local arr = {} for k, v in pairs(args) do + table.insert(arr, k) + end + table.sort(arr) + for i, k in ipairs(arr) do ngx.say("key: ", k) end ngx.say("s = ", s) @@ -1138,8 +1153,8 @@ b = foo --- request GET /lua --- response_body -key: f f key: B +key: f f s = f+f=bar&B=foo --- no_error_log [error] @@ -1170,8 +1185,13 @@ s = f+f=bar&B=foo for _, command in pairs(commands) do --command = ngx.unescape_uri(command) local request_args = ngx.decode_args(command, 0) - for key, value in pairs(request_args) do - ngx.say(key, ": ", value) + local arr = {} + for k, v in pairs(request_args) do + table.insert(arr, k) + end + table.sort(arr) + for i, k in ipairs(arr) do + ngx.say(k, ": ", request_args[k]) end ngx.say(" ===============") end @@ -1181,20 +1201,20 @@ s = f+f=bar&B=foo POST /t method=zadd&key=User%3A1227713%3Alikes%3Atwitters&arg1=1356514698&arg2=780984852||method=zadd&key=User%3A1227713%3Alikes%3Atwitters&arg1=1356514698&arg2=780984852||method=zadd&key=User%3A1227713%3Alikes%3Atwitters&arg1=1356514698&arg2=780984852 --- response_body -arg2: 780984852 -method: zadd -key: User:1227713:likes:twitters arg1: 1356514698 +arg2: 780984852 +key: User:1227713:likes:twitters +method: zadd =============== -arg2: 780984852 -method: zadd -key: User:1227713:likes:twitters arg1: 1356514698 +arg2: 780984852 +key: User:1227713:likes:twitters +method: zadd =============== -arg2: 780984852 -method: zadd -key: User:1227713:likes:twitters arg1: 1356514698 +arg2: 780984852 +key: User:1227713:likes:twitters +method: zadd =============== --- no_error_log [error] @@ -1244,8 +1264,14 @@ rewrite or internal redirection cycle while processing "/jump" } --- request GET /lua ---- response_body -foo=3&a=32&a&bar=5 +--- response_body_like +(?x) ^ + (?= .*? \b a=32 \b ) # 4 chars + (?= .*? \b a (?=&|$) \b ) # 1 chars + (?= .*? \b foo=3 \b ) # 5 chars + (?= .*? \b bar=5 \b ) # 5 chars + (?= (?: [^&]+ & ){3} [^&]+ $ ) # requires exactly 3 &'s + (?= .{18} $ ) # requires for total 18 chars (exactly) in the string --- no_error_log [error] @@ -1262,8 +1288,13 @@ foo=3&a=32&a&bar=5 } --- request GET /lua ---- response_body -foo=3&a=32&bar=5 +--- response_body_like +(?x) ^ + (?= .*? \b a=32 \b ) # 4 chars + (?= .*? \b foo=3 \b ) # 5 chars + (?= .*? \b bar=5 \b ) # 5 chars + (?= (?: [^&]+ & ){2} [^&]+ $ ) # requires exactly 2 &'s + (?= .{16} $ ) # requires for total 16 chars (exactly) in the string --- no_error_log [error] @@ -1280,8 +1311,13 @@ foo=3&a=32&bar=5 } --- request GET /lua ---- response_body -foo=3&a%20b=32&bar=5 +--- response_body_like +(?x) ^ + (?= .*? \b a%20b=32 \b ) # 8 chars + (?= .*? \b foo=3 \b ) # 5 chars + (?= .*? \b bar=5 \b ) # 5 chars + (?= (?: [^&]+ & ){2} [^&]+ $ ) # requires exactly 2 &'s + (?= .{20} $ ) # requires for total 20 chars (exactly) in the string --- no_error_log [error] @@ -1298,8 +1334,14 @@ foo=3&a%20b=32&bar=5 } --- request GET /lua ---- response_body -foo=3&a%20b=32&a%20b&bar=5 +--- response_body_like +(?x) ^ + (?= .*? \b a%20b=32 \b ) # 8 chars + (?= .*? \b a%20b (?!=) \b ) # 5 chars + (?= .*? \b foo=3 \b ) # 5 chars + (?= .*? \b bar=5 \b ) # 5 chars + (?= (?: [^&]+ & ){3} [^&]+ $ ) # requires exactly 3 &'s + (?= .{26} $ ) # requires for total 26 chars (exactly) in the string --- no_error_log [error] @@ -1320,8 +1362,14 @@ foo=3&a%20b=32&a%20b&bar=5 } --- request GET /foo?world ---- response_body -HTTP/1.0 a=3&b=5&b&b=6 +--- response_body_like +(?x) ^HTTP/1.0 \s + (?= .*? \b a=3 \b ) # 3 chars + (?= .*? \b b=5 \b ) # 3 chars + (?= .*? \b b (?!=) \b ) # 1 chars + (?= .*? \b b=6 \b ) # 3 chars + (?= (?: [^&]+ & ){3} [^&]+ $ ) # requires exactly 3 &'s + (?= .{13} $ ) # requires for total 13 chars (exactly) in the string @@ -1340,6 +1388,6 @@ HTTP/1.0 a=3&b=5&b&b=6 } --- request GET /foo?world ---- response_body -HTTP/1.0 a=3&b +--- response_body_like +^HTTP/1.0 (a=3&b|b&a=3)$ diff --git a/debian/modules/nginx-lua/t/044-req-body.t b/debian/modules/nginx-lua/t/044-req-body.t index 8c309a0..0246265 100644 --- a/debian/modules/nginx-lua/t/044-req-body.t +++ b/debian/modules/nginx-lua/t/044-req-body.t @@ -8,7 +8,7 @@ log_level('warn'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 35); +plan tests => repeat_each() * (blocks() * 4 + 51); #no_diff(); no_long_string(); @@ -140,7 +140,7 @@ hiya, world"] -=== TEST 6: not discard body +=== TEST 6: not discard body (content_by_lua falls through) --- config location = /foo { content_by_lua ' @@ -161,9 +161,10 @@ hello, world", hiya, world"] --- response_body eval ["body: nil\n", -qr/400 Bad Request/] +"body: hiya, world\n", +] --- error_code eval -[200, 400] +[200, 200] --- no_error_log [error] [alert] @@ -1482,3 +1483,127 @@ Will you change this world? [error] [alert] + + +=== TEST 45: not discard body (content_by_lua exit 200) +--- config + location = /foo { + content_by_lua ' + -- ngx.req.discard_body() + ngx.say("body: ", ngx.var.request_body) + ngx.exit(200) + '; + } + location = /bar { + content_by_lua ' + ngx.req.read_body() + ngx.say("body: ", ngx.var.request_body) + '; + } +--- pipelined_requests eval +["POST /foo +hello, world", +"POST /bar +hiya, world"] +--- response_body eval +["body: nil\n", +"body: hiya, world\n", +] +--- error_code eval +[200, 200] +--- no_error_log +[error] +[alert] + + + +=== TEST 46: not discard body (content_by_lua exit 201) +--- config + location = /foo { + content_by_lua ' + -- ngx.req.discard_body() + ngx.say("body: ", ngx.var.request_body) + ngx.exit(201) + '; + } + location = /bar { + content_by_lua ' + ngx.req.read_body() + ngx.say("body: ", ngx.var.request_body) + '; + } +--- pipelined_requests eval +["POST /foo +hello, world", +"POST /bar +hiya, world"] +--- response_body eval +["body: nil\n", +"body: hiya, world\n", +] +--- error_code eval +[200, 200] +--- no_error_log +[error] +[alert] + + + +=== TEST 47: not discard body (content_by_lua exit 302) +--- config + location = /foo { + content_by_lua ' + -- ngx.req.discard_body() + -- ngx.say("body: ", ngx.var.request_body) + ngx.redirect("/blah") + '; + } + location = /bar { + content_by_lua ' + ngx.req.read_body() + ngx.say("body: ", ngx.var.request_body) + '; + } +--- pipelined_requests eval +["POST /foo +hello, world", +"POST /bar +hiya, world"] +--- response_body eval +[qr/302 Found/, +"body: hiya, world\n", +] +--- error_code eval +[302, 200] +--- no_error_log +[error] +[alert] + + + +=== TEST 48: not discard body (custom error page) +--- config + error_page 404 = /err; + + location = /foo { + content_by_lua ' + ngx.exit(404) + '; + } + location = /err { + content_by_lua 'ngx.say("error")'; + } +--- pipelined_requests eval +["POST /foo +hello, world", +"POST /foo +hiya, world"] +--- response_body eval +["error\n", +"error\n", +] +--- error_code eval +[404, 404] +--- no_error_log +[error] +[alert] diff --git a/debian/modules/nginx-lua/t/055-subreq-vars.t b/debian/modules/nginx-lua/t/055-subreq-vars.t index 6f5da2b..e2b0658 100644 --- a/debian/modules/nginx-lua/t/055-subreq-vars.t +++ b/debian/modules/nginx-lua/t/055-subreq-vars.t @@ -65,8 +65,8 @@ M(http-subrequest-start) { --- request GET /lua --- response_body_like: 500 Internal Server Error ---- error_log chop -variable "dog" cannot be assigned a value (maybe you forgot to define it first?) +--- error_log eval +qr/variable "(dog|cat)" cannot be assigned a value \(maybe you forgot to define it first\?\)/ --- error_code: 500 diff --git a/debian/modules/nginx-lua/t/086-init-by.t b/debian/modules/nginx-lua/t/086-init-by.t index c77f7f9..f9ed12c 100644 --- a/debian/modules/nginx-lua/t/086-init-by.t +++ b/debian/modules/nginx-lua/t/086-init-by.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 2); +plan tests => repeat_each() * (blocks() * 3 + 3); #no_diff(); #no_long_string(); @@ -278,3 +278,30 @@ baz = 78 [error] Failed to resume our co: + + +=== TEST 11: access a field in the ngx. table +--- http_config + init_by_lua ' + print("INIT 1: foo = ", ngx.foo) + ngx.foo = 3 + print("INIT 2: foo = ", ngx.foo) + '; +--- config + location /t { + echo ok; + } +--- request +GET /t +--- response_body +ok +--- no_error_log +[error] +--- grep_error_log eval: qr/INIT \d+: foo = \S+/ +--- grep_error_log_out eval +[ +"INIT 1: foo = nil +INIT 2: foo = 3 +", +"", +] diff --git a/debian/modules/nginx-lua/t/094-uthread-exit.t b/debian/modules/nginx-lua/t/094-uthread-exit.t index 6d69620..1bd970c 100644 --- a/debian/modules/nginx-lua/t/094-uthread-exit.t +++ b/debian/modules/nginx-lua/t/094-uthread-exit.t @@ -1081,8 +1081,6 @@ after } --- request POST /lua ---- more_headers -Content-Length: 1024 --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; @@ -1162,8 +1160,6 @@ attempt to abort with pending subrequests } --- request POST /lua ---- more_headers -Content-Length: 1024 --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; @@ -1254,8 +1250,6 @@ attempt to abort with pending subrequests } --- request POST /lua ---- more_headers -Content-Length: 1024 --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; diff --git a/debian/modules/nginx-lua/t/095-uthread-exec.t b/debian/modules/nginx-lua/t/095-uthread-exec.t index 7cb8cbd..2309fbe 100644 --- a/debian/modules/nginx-lua/t/095-uthread-exec.t +++ b/debian/modules/nginx-lua/t/095-uthread-exec.t @@ -289,8 +289,6 @@ hello foo } --- request POST /lua ---- more_headers -Content-Length: 1024 --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; diff --git a/debian/modules/nginx-lua/t/096-uthread-redirect.t b/debian/modules/nginx-lua/t/096-uthread-redirect.t index f435dc3..177e071 100644 --- a/debian/modules/nginx-lua/t/096-uthread-redirect.t +++ b/debian/modules/nginx-lua/t/096-uthread-redirect.t @@ -50,8 +50,6 @@ __DATA__ } --- request POST /lua ---- more_headers -Content-Length: 1024 --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; diff --git a/debian/modules/nginx-lua/t/097-uthread-rewrite.t b/debian/modules/nginx-lua/t/097-uthread-rewrite.t index 9912dd3..bf88864 100644 --- a/debian/modules/nginx-lua/t/097-uthread-rewrite.t +++ b/debian/modules/nginx-lua/t/097-uthread-rewrite.t @@ -288,8 +288,6 @@ hello foo } --- request POST /lua ---- more_headers -Content-Length: 1024 --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; diff --git a/debian/modules/nginx-lua/t/118-use-default-type.t b/debian/modules/nginx-lua/t/118-use-default-type.t index a348f87..fd77cff 100644 --- a/debian/modules/nginx-lua/t/118-use-default-type.t +++ b/debian/modules/nginx-lua/t/118-use-default-type.t @@ -120,3 +120,22 @@ hello --- no_error_log [error] + + +=== TEST 6: lua_use_default_type on does not set content type on 304 +--- config + lua_use_default_type on; + location /lua { + default_type text/plain; + content_by_lua ' + ngx.status = ngx.HTTP_NOT_MODIFIED + '; + } +--- request +GET /lua +--- response_body +--- response_headers +!Content-Type +--- no_error_log +[error] +--- error_code: 304 diff --git a/debian/modules/nginx-lua/t/123-lua-path.t b/debian/modules/nginx-lua/t/123-lua-path.t index 38a44f2..964b48b 100644 --- a/debian/modules/nginx-lua/t/123-lua-path.t +++ b/debian/modules/nginx-lua/t/123-lua-path.t @@ -24,6 +24,10 @@ run_tests(); __DATA__ === TEST 1: LUA_PATH & LUA_CPATH env (code cache on) +--- main_config +env LUA_PATH; +env LUA_CPATH; + --- config location /lua { content_by_lua ' @@ -43,6 +47,10 @@ GET /lua === TEST 2: LUA_PATH & LUA_CPATH env (code cache off) +--- main_config +env LUA_PATH; +env LUA_CPATH; + --- config lua_code_cache off; location /lua { diff --git a/debian/modules/nginx-lua/t/131-duplex-req-socket.t b/debian/modules/nginx-lua/t/131-duplex-req-socket.t new file mode 100644 index 0000000..5d698b9 --- /dev/null +++ b/debian/modules/nginx-lua/t/131-duplex-req-socket.t @@ -0,0 +1,141 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +BEGIN { + if (!defined $ENV{LD_PRELOAD}) { + $ENV{LD_PRELOAD} = ''; + } + + if ($ENV{LD_PRELOAD} !~ /\bmockeagain\.so\b/) { + $ENV{LD_PRELOAD} = "mockeagain.so $ENV{LD_PRELOAD}"; + } + + if ($ENV{MOCKEAGAIN} eq 'r') { + $ENV{MOCKEAGAIN} = 'rw'; + + } else { + $ENV{MOCKEAGAIN} = 'w'; + } + + $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; + $ENV{MOCKEAGAIN_WRITE_TIMEOUT_PATTERN} = 'slow'; +} + +use Test::Nginx::Socket::Lua; + +log_level('debug'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 2); + +run_tests(); + +__DATA__ + +=== TEST 1: raw downstream cosocket used in two different threads. See issue #481 +--- config + lua_socket_read_timeout 1ms; + lua_socket_send_timeout 1s; + lua_socket_log_errors off; + + location /t { + content_by_lua ' + local function reader(req_socket) + -- First we receive in a blocking fashion so that ctx->downstream_co_ctx will be changed + local data, err, partial = req_socket:receive(1) + if err ~= "timeout" then + ngx.log(ngx.ERR, "Did not get timeout in the receiving thread!") + return + end + + -- Now, sleep so that coctx->data is changed to sleep handler + ngx.sleep(1) + end + + local function writer(req_socket) + -- send in a slow manner with a low timeout, so that the timeout handler will be + local bytes, err = req_socket:send("slow!!!") + if err ~= "timeout" then + return error("Did not get timeout in the sending thread!") + end + end + + local req_socket, err = ngx.req.socket(true) + if req_socket == nil then + ngx.status = 500 + return error("Unable to get request socket:" .. (err or "nil")) + end + + local writer_thread = ngx.thread.spawn(writer, req_socket) + local reader_thread = ngx.thread.spawn(reader, req_socket) + + ngx.thread.wait(writer_thread) + ngx.thread.wait(reader_thread) + print("The two threads finished") +'; + } +--- request +POST /t +--- more_headers +Content-Length: 1 +--- no_error_log +[error] +--- error_log: The two threads finished +--- wait: 0.1 +--- ignore_response +--- timeout: 10 + + + +=== TEST 2: normal downstream cosocket used in two different threads. See issue #481 +--- config + lua_socket_read_timeout 1ms; + lua_socket_send_timeout 1s; + lua_socket_log_errors off; + send_timeout 1s; + + location /t { + content_by_lua ' + local function reader(req_socket) + -- First we receive in a blocking fashion so that ctx->downstream_co_ctx will be changed + local data, err, partial = req_socket:receive(1) + if err ~= "timeout" then + ngx.log(ngx.ERR, "Did not get timeout in the receiving thread!") + return + end + + -- Now, sleep so that coctx->data is changed to sleep handler + ngx.sleep(1) + end + + local function writer(req_socket) + -- send in a slow manner with a low timeout, so that the timeout handler will be + ngx.sleep(0.3) + ngx.say("slow!!!") + ngx.flush(true) + end + + local req_socket, err = ngx.req.socket() + if req_socket == nil then + ngx.status = 500 + return error("Unable to get request socket:" .. (err or "nil")) + end + + local writer_thread = ngx.thread.spawn(writer, req_socket) + local reader_thread = ngx.thread.spawn(reader, req_socket) + + ngx.thread.wait(writer_thread) + ngx.thread.wait(reader_thread) + print("The two threads finished") +'; + } +--- request +POST /t +--- more_headers +Content-Length: 1 +--- no_error_log +[error] +--- error_log: The two threads finished +--- wait: 0.1 +--- ignore_response +--- timeout: 10 diff --git a/debian/modules/nginx-lua/util/build2.sh b/debian/modules/nginx-lua/util/build2.sh index bccf4b4..21caf1f 100755 --- a/debian/modules/nginx-lua/util/build2.sh +++ b/debian/modules/nginx-lua/util/build2.sh @@ -29,9 +29,9 @@ time ngx-build $force $version \ --with-http_spdy_module \ --without-mail_pop3_module \ --without-mail_imap_module \ + --with-http_image_filter_module \ --without-mail_smtp_module \ --without-http_upstream_ip_hash_module \ - --without-http_empty_gif_module \ --without-http_memcached_module \ --without-http_auth_basic_module \ --without-http_userid_module \ From 81f1a374e11b346b2c9a8f59b1461193271e9694 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 9 Jul 2015 11:00:06 +0300 Subject: [PATCH 047/651] Sync cgi configs with upstream --- debian/changelog | 2 ++ debian/conf/fastcgi.conf | 1 + debian/conf/fastcgi_params | 1 + debian/conf/scgi_params | 1 + debian/conf/uwsgi_params | 1 + 5 files changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index b604ec5..8b1d439 100644 --- a/debian/changelog +++ b/debian/changelog @@ -6,6 +6,8 @@ nginx (1.9.2-2) UNRELEASED; urgency=medium `debian/tests/control` is present. * debian/modules/nginx-lua: + Update nginx-lua to v0.9.16 and drop our backported patches. + * debian/conf/*: + + Add REQUEST_SCHEME to fcgi, wsgi and scgi configs (sync with upstream). -- Christos Trochalakis Mon, 22 Jun 2015 13:01:07 +0300 diff --git a/debian/conf/fastcgi.conf b/debian/conf/fastcgi.conf index ac9ff92..091738c 100644 --- a/debian/conf/fastcgi.conf +++ b/debian/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 REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; diff --git a/debian/conf/fastcgi_params b/debian/conf/fastcgi_params index 71e2c2e..28decb9 100644 --- a/debian/conf/fastcgi_params +++ b/debian/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 REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; diff --git a/debian/conf/scgi_params b/debian/conf/scgi_params index 47348ca..6d4ce4f 100644 --- a/debian/conf/scgi_params +++ b/debian/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 REQUEST_SCHEME $scheme; scgi_param HTTPS $https if_not_empty; scgi_param REMOTE_ADDR $remote_addr; diff --git a/debian/conf/uwsgi_params b/debian/conf/uwsgi_params index f539451..09c732c 100644 --- a/debian/conf/uwsgi_params +++ b/debian/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 REQUEST_SCHEME $scheme; uwsgi_param HTTPS $https if_not_empty; uwsgi_param REMOTE_ADDR $remote_addr; From 5ad6a9e00fbb7e92b3622ee7d0d09515ec57a06f Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 14 Jul 2015 20:20:51 +0300 Subject: [PATCH 048/651] Imported Upstream version 1.9.3 --- CHANGES | 27 + CHANGES.ru | 25 + auto/modules | 5 + auto/options | 4 + auto/sources | 3 + auto/unix | 9 +- configure | 2 +- src/core/nginx.h | 4 +- src/core/ngx_resolver.c | 20 + src/event/ngx_event_openssl_stapling.c | 16 +- .../modules/ngx_http_upstream_zone_module.c | 43 +- src/http/ngx_http.c | 4 + src/http/ngx_http_upstream_round_robin.h | 1 + src/mail/ngx_mail.c | 4 + src/stream/ngx_stream.c | 4 + src/stream/ngx_stream.h | 1 + src/stream/ngx_stream_handler.c | 9 + src/stream/ngx_stream_limit_conn_module.c | 632 ++++++++++++++++++ src/stream/ngx_stream_proxy_module.c | 170 +++-- src/stream/ngx_stream_ssl_module.c | 2 + src/stream/ngx_stream_upstream.h | 5 +- src/stream/ngx_stream_upstream_round_robin.h | 1 + src/stream/ngx_stream_upstream_zone_module.c | 43 +- 23 files changed, 952 insertions(+), 82 deletions(-) create mode 100644 src/stream/ngx_stream_limit_conn_module.c diff --git a/CHANGES b/CHANGES index f4d77d7..01130f8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,31 @@ +Changes with nginx 1.9.3 14 Jul 2015 + + *) Change: duplicate "http", "mail", and "stream" blocks are now + disallowed. + + *) Feature: connection limiting in the stream module. + + *) Feature: data rate limiting in the stream module. + + *) Bugfix: the "zone" directive inside the "upstream" block did not work + on Windows. + + *) Bugfix: compatibility with LibreSSL in the stream module. + Thanks to Piotr Sikora. + + *) Bugfix: in the "--builddir" configure parameter. + Thanks to Piotr Sikora. + + *) Bugfix: the "ssl_stapling_file" directive did not work; the bug had + appeared in 1.9.2. + Thanks to Faidon Liambotis and Brandon Black. + + *) Bugfix: a segmentation fault might occur in a worker process if the + "ssl_stapling" directive was used; the bug had appeared in 1.9.2. + Thanks to Matthew Baldwin. + + Changes with nginx 1.9.2 16 Jun 2015 *) Feature: the "backlog" parameter of the "listen" directives of the diff --git a/CHANGES.ru b/CHANGES.ru index ac40495..25dfd22 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,29 @@ +Изменения в nginx 1.9.3 14.07.2015 + + *) Изменение: дублирующиеся блоки http, mail и stream теперь запрещены. + + *) Добавление: ограничение количества соединений в модуле stream. + + *) Добавление: органичение скорости в модуле stream. + + *) Исправление: директива zone в блоке upstream не работала на Windows. + + *) Исправление: совместимость с LibreSSL в модуле stream. + Спасибо Piotr Sikora. + + *) Исправление: в параметре --builddir в configure. + Спасибо Piotr Sikora. + + *) Исправление: директива ssl_stapling_file не работала; ошибка + появилась в 1.9.2. + Спасибо Faidon Liambotis и Brandon Black. + + *) Исправление: при использовании директивы ssl_stapling в рабочем + процессе мог произойти segmentation fault; ошибка появилась в 1.9.2. + Спасибо Matthew Baldwin. + + Изменения в nginx 1.9.2 16.06.2015 *) Добавление: параметр backlog директивы listen в почтовом diff --git a/auto/modules b/auto/modules index 82b8bca..60a060d 100644 --- a/auto/modules +++ b/auto/modules @@ -514,6 +514,11 @@ if [ $STREAM = YES ]; then STREAM_SRCS="$STREAM_SRCS $STREAM_SSL_SRCS" fi + if [ $STREAM_LIMIT_CONN = YES ]; then + modules="$modules $STREAM_LIMIT_CONN_MODULE" + STREAM_SRCS="$STREAM_SRCS $STREAM_LIMIT_CONN_SRCS" + fi + if [ $STREAM_ACCESS = YES ]; then modules="$modules $STREAM_ACCESS_MODULE" STREAM_SRCS="$STREAM_SRCS $STREAM_ACCESS_SRCS" diff --git a/auto/options b/auto/options index febbc27..e70d1a0 100644 --- a/auto/options +++ b/auto/options @@ -113,6 +113,7 @@ MAIL_SMTP=YES STREAM=NO STREAM_SSL=NO +STREAM_LIMIT_CONN=YES STREAM_ACCESS=YES STREAM_UPSTREAM_HASH=YES STREAM_UPSTREAM_LEAST_CONN=YES @@ -283,6 +284,8 @@ use the \"--with-mail_ssl_module\" option instead" --with-stream) STREAM=YES ;; --with-stream_ssl_module) STREAM_SSL=YES ;; + --without-stream_limit_conn_module) + STREAM_LIMIT_CONN=NO ;; --without-stream_access_module) STREAM_ACCESS=NO ;; --without-stream_upstream_hash_module) STREAM_UPSTREAM_HASH=NO ;; @@ -452,6 +455,7 @@ cat << END --with-stream enable TCP proxy module --with-stream_ssl_module enable ngx_stream_ssl_module + --without-stream_limit_conn_module disable ngx_stream_limit_conn_module --without-stream_access_module disable ngx_stream_access_module --without-stream_upstream_hash_module disable ngx_stream_upstream_hash_module diff --git a/auto/sources b/auto/sources index 44fba51..3d89e2d 100644 --- a/auto/sources +++ b/auto/sources @@ -568,6 +568,9 @@ STREAM_SSL_MODULE="ngx_stream_ssl_module" STREAM_SSL_DEPS="src/stream/ngx_stream_ssl_module.h" STREAM_SSL_SRCS="src/stream/ngx_stream_ssl_module.c" +STREAM_LIMIT_CONN_MODULE=ngx_stream_limit_conn_module +STREAM_LIMIT_CONN_SRCS=src/stream/ngx_stream_limit_conn_module.c + STREAM_ACCESS_MODULE=ngx_stream_access_module STREAM_ACCESS_SRCS=src/stream/ngx_stream_access_module.c diff --git a/auto/unix b/auto/unix index 595f905..b7b7a25 100755 --- a/auto/unix +++ b/auto/unix @@ -505,14 +505,7 @@ ngx_param=NGX_PTR_SIZE; ngx_value=$ngx_size; . auto/types/value # POSIX types -case "$NGX_AUTO_CONFIG_H" in - /*) - NGX_INCLUDE_AUTO_CONFIG_H="#include \"$NGX_AUTO_CONFIG_H\"" - ;; - *) - NGX_INCLUDE_AUTO_CONFIG_H="#include \"../$NGX_AUTO_CONFIG_H\"" - ;; -esac +NGX_INCLUDE_AUTO_CONFIG_H="#include \"ngx_auto_config.h\"" ngx_type="uint64_t"; ngx_types="u_int64_t"; . auto/types/typedef diff --git a/configure b/configure index 617d992..ceff15e 100755 --- a/configure +++ b/configure @@ -11,7 +11,7 @@ export LC_ALL . auto/init . auto/sources -test -d $NGX_OBJS || mkdir $NGX_OBJS +test -d $NGX_OBJS || mkdir -p $NGX_OBJS echo > $NGX_AUTO_HEADERS_H echo > $NGX_AUTOCONF_ERR diff --git a/src/core/nginx.h b/src/core/nginx.h index 4c9cf35..dfb90ea 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1009002 -#define NGINX_VERSION "1.9.2" +#define nginx_version 1009003 +#define NGINX_VERSION "1.9.3" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index caa2b51..7013885 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -71,6 +71,7 @@ static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, static void ngx_resolver_resend_handler(ngx_event_t *ev); static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue); +static ngx_uint_t ngx_resolver_resend_empty(ngx_resolver_t *r); static void ngx_resolver_read_response(ngx_event_t *rev); static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n); @@ -463,6 +464,10 @@ done: ngx_resolver_free_locked(r, ctx); /* unlock alloc mutex */ + + if (r->event->timer_set && ngx_resolver_resend_empty(r)) { + ngx_del_timer(r->event); + } } @@ -1016,6 +1021,10 @@ done: ngx_resolver_free_locked(r, ctx); /* unlock alloc mutex */ + + if (r->event->timer_set && ngx_resolver_resend_empty(r)) { + ngx_del_timer(r->event); + } } @@ -1225,6 +1234,17 @@ ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue) } +static ngx_uint_t +ngx_resolver_resend_empty(ngx_resolver_t *r) +{ + return ngx_queue_empty(&r->name_resend_queue) +#if (NGX_HAVE_INET6) + && ngx_queue_empty(&r->addr6_resend_queue) +#endif + && ngx_queue_empty(&r->addr_resend_queue); +} + + static void ngx_resolver_read_response(ngx_event_t *rev) { diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c index 03ff540..fa77678 100644 --- a/src/event/ngx_event_openssl_stapling.c +++ b/src/event/ngx_event_openssl_stapling.c @@ -245,6 +245,7 @@ ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) staple->staple.data = buf; staple->staple.len = len; + staple->valid = NGX_MAX_TIME_T_VALUE; return NGX_OK; @@ -636,11 +637,16 @@ ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx) goto error; } - valid = ngx_ssl_stapling_time(nextupdate); - if (valid == (time_t) NGX_ERROR) { - ngx_log_error(NGX_LOG_ERR, ctx->log, 0, - "invalid nextUpdate time in certificate status"); - goto error; + if (nextupdate) { + valid = ngx_ssl_stapling_time(nextupdate); + if (valid == (time_t) NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, ctx->log, 0, + "invalid nextUpdate time in certificate status"); + goto error; + } + + } else { + valid = NGX_MAX_TIME_T_VALUE; } OCSP_CERTID_free(id); diff --git a/src/http/modules/ngx_http_upstream_zone_module.c b/src/http/modules/ngx_http_upstream_zone_module.c index ea7c43b..7169c36 100644 --- a/src/http/modules/ngx_http_upstream_zone_module.c +++ b/src/http/modules/ngx_http_upstream_zone_module.c @@ -14,8 +14,8 @@ static char *ngx_http_upstream_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static ngx_int_t ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data); -static ngx_int_t ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, - ngx_http_upstream_srv_conf_t *uscf); +static ngx_http_upstream_rr_peers_t *ngx_http_upstream_zone_copy_peers( + ngx_slab_pool_t *shpool, ngx_http_upstream_srv_conf_t *uscf); static ngx_command_t ngx_http_upstream_zone_commands[] = { @@ -121,13 +121,29 @@ ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data) size_t len; ngx_uint_t i; ngx_slab_pool_t *shpool; + ngx_http_upstream_rr_peers_t *peers, **peersp; ngx_http_upstream_srv_conf_t *uscf, **uscfp; ngx_http_upstream_main_conf_t *umcf; shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + umcf = shm_zone->data; + uscfp = umcf->upstreams.elts; if (shm_zone->shm.exists) { - return NGX_ERROR; + peers = shpool->data; + + for (i = 0; i < umcf->upstreams.nelts; i++) { + uscf = uscfp[i]; + + if (uscf->shm_zone != shm_zone) { + continue; + } + + uscf->peer.data = peers; + peers = peers->zone_next; + } + + return NGX_OK; } len = sizeof(" in upstream zone \"\"") + shm_zone->shm.name.len; @@ -143,8 +159,7 @@ ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data) /* copy peers to shared memory */ - umcf = shm_zone->data; - uscfp = umcf->upstreams.elts; + peersp = (ngx_http_upstream_rr_peers_t **) &shpool->data; for (i = 0; i < umcf->upstreams.nelts; i++) { uscf = uscfp[i]; @@ -153,16 +168,20 @@ ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data) continue; } - if (ngx_http_upstream_zone_copy_peers(shpool, uscf) != NGX_OK) { + peers = ngx_http_upstream_zone_copy_peers(shpool, uscf); + if (peers == NULL) { return NGX_ERROR; } + + *peersp = peers; + peersp = &peers->zone_next; } return NGX_OK; } -static ngx_int_t +static ngx_http_upstream_rr_peers_t * ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_http_upstream_srv_conf_t *uscf) { @@ -171,7 +190,7 @@ ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, peers = ngx_slab_alloc(shpool, sizeof(ngx_http_upstream_rr_peers_t)); if (peers == NULL) { - return NGX_ERROR; + return NULL; } ngx_memcpy(peers, uscf->peer.data, sizeof(ngx_http_upstream_rr_peers_t)); @@ -183,7 +202,7 @@ ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, peer = ngx_slab_calloc_locked(shpool, sizeof(ngx_http_upstream_rr_peer_t)); if (peer == NULL) { - return NGX_ERROR; + return NULL; } ngx_memcpy(peer, *peerp, sizeof(ngx_http_upstream_rr_peer_t)); @@ -197,7 +216,7 @@ ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, backup = ngx_slab_alloc(shpool, sizeof(ngx_http_upstream_rr_peers_t)); if (backup == NULL) { - return NGX_ERROR; + return NULL; } ngx_memcpy(backup, peers->next, sizeof(ngx_http_upstream_rr_peers_t)); @@ -209,7 +228,7 @@ ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, peer = ngx_slab_calloc_locked(shpool, sizeof(ngx_http_upstream_rr_peer_t)); if (peer == NULL) { - return NGX_ERROR; + return NULL; } ngx_memcpy(peer, *peerp, sizeof(ngx_http_upstream_rr_peer_t)); @@ -223,5 +242,5 @@ done: uscf->peer.data = peers; - return NGX_OK; + return peers; } diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index 4642559..6b0a48f 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -128,6 +128,10 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_http_core_srv_conf_t **cscfp; ngx_http_core_main_conf_t *cmcf; + if (*(ngx_http_conf_ctx_t **) conf) { + return "is duplicate"; + } + /* the main http context */ ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h index 454515c..f2c573f 100644 --- a/src/http/ngx_http_upstream_round_robin.h +++ b/src/http/ngx_http_upstream_round_robin.h @@ -58,6 +58,7 @@ struct ngx_http_upstream_rr_peers_s { #if (NGX_HTTP_UPSTREAM_ZONE) ngx_slab_pool_t *shpool; ngx_atomic_t rwlock; + ngx_http_upstream_rr_peers_t *zone_next; #endif ngx_uint_t total_weight; diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c index 38664bc..962ae8b 100644 --- a/src/mail/ngx_mail.c +++ b/src/mail/ngx_mail.c @@ -76,6 +76,10 @@ ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_mail_core_srv_conf_t **cscfp; ngx_mail_core_main_conf_t *cmcf; + if (*(ngx_mail_conf_ctx_t **) conf) { + return "is duplicate"; + } + /* the main mail context */ ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t)); diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c index 3dce35a..f0aa532 100644 --- a/src/stream/ngx_stream.c +++ b/src/stream/ngx_stream.c @@ -76,6 +76,10 @@ ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_stream_core_srv_conf_t **cscfp; ngx_stream_core_main_conf_t *cmcf; + if (*(ngx_stream_conf_ctx_t **) conf) { + return "is duplicate"; + } + /* the main stream context */ ctx = ngx_pcalloc(cf->pool, sizeof(ngx_stream_conf_ctx_t)); diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h index b0eb7d4..266101c 100644 --- a/src/stream/ngx_stream.h +++ b/src/stream/ngx_stream.h @@ -118,6 +118,7 @@ typedef ngx_int_t (*ngx_stream_access_pt)(ngx_stream_session_t *s); typedef struct { ngx_array_t servers; /* ngx_stream_core_srv_conf_t */ ngx_array_t listen; /* ngx_stream_listen_t */ + ngx_stream_access_pt limit_conn_handler; ngx_stream_access_pt access_handler; } ngx_stream_core_main_conf_t; diff --git a/src/stream/ngx_stream_handler.c b/src/stream/ngx_stream_handler.c index e4538b2..7b635fa 100644 --- a/src/stream/ngx_stream_handler.c +++ b/src/stream/ngx_stream_handler.c @@ -147,6 +147,15 @@ ngx_stream_init_connection(ngx_connection_t *c) cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); + if (cmcf->limit_conn_handler) { + rc = cmcf->limit_conn_handler(s); + + if (rc != NGX_DECLINED) { + ngx_stream_close_connection(c); + return; + } + } + if (cmcf->access_handler) { rc = cmcf->access_handler(s); diff --git a/src/stream/ngx_stream_limit_conn_module.c b/src/stream/ngx_stream_limit_conn_module.c new file mode 100644 index 0000000..732b089 --- /dev/null +++ b/src/stream/ngx_stream_limit_conn_module.c @@ -0,0 +1,632 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + u_char color; + u_char len; + u_short conn; + u_char data[1]; +} ngx_stream_limit_conn_node_t; + + +typedef struct { + ngx_shm_zone_t *shm_zone; + ngx_rbtree_node_t *node; +} ngx_stream_limit_conn_cleanup_t; + + +typedef struct { + ngx_rbtree_t *rbtree; +} ngx_stream_limit_conn_ctx_t; + + +typedef struct { + ngx_shm_zone_t *shm_zone; + ngx_uint_t conn; +} ngx_stream_limit_conn_limit_t; + + +typedef struct { + ngx_array_t limits; + ngx_uint_t log_level; +} ngx_stream_limit_conn_conf_t; + + +static ngx_rbtree_node_t *ngx_stream_limit_conn_lookup(ngx_rbtree_t *rbtree, + ngx_str_t *key, uint32_t hash); +static void ngx_stream_limit_conn_cleanup(void *data); +static ngx_inline void ngx_stream_limit_conn_cleanup_all(ngx_pool_t *pool); + +static void *ngx_stream_limit_conn_create_conf(ngx_conf_t *cf); +static char *ngx_stream_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_stream_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_stream_limit_conn_init(ngx_conf_t *cf); + + +static ngx_conf_enum_t ngx_stream_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_stream_limit_conn_commands[] = { + + { ngx_string("limit_conn_zone"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE2, + ngx_stream_limit_conn_zone, + 0, + 0, + NULL }, + + { ngx_string("limit_conn"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE2, + ngx_stream_limit_conn, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("limit_conn_log_level"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_limit_conn_conf_t, log_level), + &ngx_stream_limit_conn_log_levels }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_limit_conn_module_ctx = { + ngx_stream_limit_conn_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_stream_limit_conn_create_conf, /* create server configuration */ + ngx_stream_limit_conn_merge_conf, /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_limit_conn_module = { + NGX_MODULE_V1, + &ngx_stream_limit_conn_module_ctx, /* module context */ + ngx_stream_limit_conn_commands, /* module directives */ + NGX_STREAM_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_stream_limit_conn_handler(ngx_stream_session_t *s) +{ + size_t n; + uint32_t hash; + ngx_str_t key; + ngx_uint_t i; + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *node; + ngx_pool_cleanup_t *cln; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + ngx_stream_limit_conn_ctx_t *ctx; + ngx_stream_limit_conn_node_t *lc; + ngx_stream_limit_conn_conf_t *lccf; + ngx_stream_limit_conn_limit_t *limits; + ngx_stream_limit_conn_cleanup_t *lccln; + + switch (s->connection->sockaddr->sa_family) { + + case AF_INET: + sin = (struct sockaddr_in *) s->connection->sockaddr; + + key.len = sizeof(in_addr_t); + key.data = (u_char *) &sin->sin_addr; + + break; + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) s->connection->sockaddr; + + key.len = sizeof(struct in6_addr); + key.data = sin6->sin6_addr.s6_addr; + + break; +#endif + + default: + return NGX_DECLINED; + } + + hash = ngx_crc32_short(key.data, key.len); + + lccf = ngx_stream_get_module_srv_conf(s, ngx_stream_limit_conn_module); + limits = lccf->limits.elts; + + for (i = 0; i < lccf->limits.nelts; i++) { + ctx = limits[i].shm_zone->data; + + shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr; + + ngx_shmtx_lock(&shpool->mutex); + + node = ngx_stream_limit_conn_lookup(ctx->rbtree, &key, hash); + + if (node == NULL) { + + n = offsetof(ngx_rbtree_node_t, color) + + offsetof(ngx_stream_limit_conn_node_t, data) + + key.len; + + node = ngx_slab_alloc_locked(shpool, n); + + if (node == NULL) { + ngx_shmtx_unlock(&shpool->mutex); + ngx_stream_limit_conn_cleanup_all(s->connection->pool); + return NGX_ABORT; + } + + lc = (ngx_stream_limit_conn_node_t *) &node->color; + + node->key = hash; + lc->len = (u_char) key.len; + lc->conn = 1; + ngx_memcpy(lc->data, key.data, key.len); + + ngx_rbtree_insert(ctx->rbtree, node); + + } else { + + lc = (ngx_stream_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, s->connection->log, 0, + "limiting connections by zone \"%V\"", + &limits[i].shm_zone->shm.name); + + ngx_stream_limit_conn_cleanup_all(s->connection->pool); + return NGX_ABORT; + } + + lc->conn++; + } + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "limit conn: %08XD %d", node->key, lc->conn); + + ngx_shmtx_unlock(&shpool->mutex); + + cln = ngx_pool_cleanup_add(s->connection->pool, + sizeof(ngx_stream_limit_conn_cleanup_t)); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_stream_limit_conn_cleanup; + lccln = cln->data; + + lccln->shm_zone = limits[i].shm_zone; + lccln->node = node; + } + + return NGX_DECLINED; +} + + +static void +ngx_stream_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_stream_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_stream_limit_conn_node_t *) &node->color; + lcnt = (ngx_stream_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_stream_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_str_t *key, + uint32_t hash) +{ + ngx_int_t rc; + ngx_rbtree_node_t *node, *sentinel; + ngx_stream_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_stream_limit_conn_node_t *) &node->color; + + rc = ngx_memn2cmp(key->data, lcn->data, key->len, (size_t) lcn->len); + + if (rc == 0) { + return node; + } + + node = (rc < 0) ? node->left : node->right; + } + + return NULL; +} + + +static void +ngx_stream_limit_conn_cleanup(void *data) +{ + ngx_stream_limit_conn_cleanup_t *lccln = data; + + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *node; + ngx_stream_limit_conn_ctx_t *ctx; + ngx_stream_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_stream_limit_conn_node_t *) &node->color; + + ngx_shmtx_lock(&shpool->mutex); + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, lccln->shm_zone->shm.log, 0, + "limit conn 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_stream_limit_conn_cleanup_all(ngx_pool_t *pool) +{ + ngx_pool_cleanup_t *cln; + + cln = pool->cleanup; + + while (cln && cln->handler == ngx_stream_limit_conn_cleanup) { + ngx_stream_limit_conn_cleanup(cln->data); + cln = cln->next; + } + + pool->cleanup = cln; +} + + +static ngx_int_t +ngx_stream_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data) +{ + ngx_stream_limit_conn_ctx_t *octx = data; + + size_t len; + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *sentinel; + ngx_stream_limit_conn_ctx_t *ctx; + + ctx = shm_zone->data; + + if (octx) { + 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_stream_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_stream_limit_conn_create_conf(ngx_conf_t *cf) +{ + ngx_stream_limit_conn_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_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_stream_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_stream_limit_conn_conf_t *prev = parent; + ngx_stream_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_stream_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_stream_limit_conn_ctx_t *ctx; + + value = cf->args->elts; + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_stream_limit_conn_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + size = 0; + name.len = 0; + + for (i = 2; 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; + } + + 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; + } + + shm_zone = ngx_shared_memory_add(cf, &name, size, + &ngx_stream_limit_conn_module); + if (shm_zone == NULL) { + return NGX_CONF_ERROR; + } + + if (shm_zone->data) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%V \"%V\" is already bound to key " + "\"$binary_remote_addr\"", + &cmd->name, &name); + return NGX_CONF_ERROR; + } + + if (ngx_strcmp(value[1].data, "$binary_remote_addr") != 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unsupported key \"%V\", use " + "$binary_remote_addr", &value[1]); + return NGX_CONF_ERROR; + } + + shm_zone->init = ngx_stream_limit_conn_init_zone; + shm_zone->data = ctx; + + return NGX_CONF_OK; +} + + +static char * +ngx_stream_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_shm_zone_t *shm_zone; + ngx_stream_limit_conn_conf_t *lccf = conf; + ngx_stream_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_stream_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_stream_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); + if (limit == NULL) { + return NGX_CONF_ERROR; + } + + limit->conn = n; + limit->shm_zone = shm_zone; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_stream_limit_conn_init(ngx_conf_t *cf) +{ + ngx_stream_core_main_conf_t *cmcf; + + cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); + + cmcf->limit_conn_handler = ngx_stream_limit_conn_handler; + + return NGX_OK; +} diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 8c88505..68af5a8 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -18,7 +18,9 @@ typedef struct { ngx_msec_t timeout; ngx_msec_t next_upstream_timeout; size_t downstream_buf_size; + size_t upload_rate; size_t upstream_buf_size; + size_t download_rate; ngx_uint_t next_upstream_tries; ngx_flag_t next_upstream; ngx_flag_t proxy_protocol; @@ -52,6 +54,8 @@ static void ngx_stream_proxy_connect(ngx_stream_session_t *s); static void ngx_stream_proxy_init_upstream(ngx_stream_session_t *s); static void ngx_stream_proxy_upstream_handler(ngx_event_t *ev); static void ngx_stream_proxy_downstream_handler(ngx_event_t *ev); +static void ngx_stream_proxy_process_connection(ngx_event_t *ev, + ngx_uint_t from_upstream); static void ngx_stream_proxy_connect_handler(ngx_event_t *ev); static ngx_int_t ngx_stream_proxy_test_connect(ngx_connection_t *c); static ngx_int_t ngx_stream_proxy_process(ngx_stream_session_t *s, @@ -130,6 +134,13 @@ static ngx_command_t ngx_stream_proxy_commands[] = { offsetof(ngx_stream_proxy_srv_conf_t, downstream_buf_size), NULL }, + { ngx_string("proxy_upload_rate"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, upload_rate), + NULL }, + { ngx_string("proxy_upstream_buffer"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, @@ -137,6 +148,13 @@ static ngx_command_t ngx_stream_proxy_commands[] = { offsetof(ngx_stream_proxy_srv_conf_t, upstream_buf_size), NULL }, + { ngx_string("proxy_download_rate"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, download_rate), + NULL }, + { ngx_string("proxy_next_upstream"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -338,6 +356,7 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) } u->proxy_protocol = pscf->proxy_protocol; + u->start_sec = ngx_time(); p = ngx_pnalloc(c->pool, pscf->downstream_buf_size); if (p == NULL) { @@ -505,6 +524,8 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) u->upstream_buf.pos = p; u->upstream_buf.last = p; + u->connected = 1; + pc->read->handler = ngx_stream_proxy_upstream_handler; pc->write->handler = ngx_stream_proxy_upstream_handler; @@ -815,48 +836,78 @@ done: static void ngx_stream_proxy_downstream_handler(ngx_event_t *ev) { - ngx_connection_t *c; - ngx_stream_session_t *s; - ngx_stream_upstream_t *u; - - c = ev->data; - s = c->data; - - if (ev->timedout) { - ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); - ngx_stream_proxy_finalize(s, NGX_DECLINED); - return; - } - - u = s->upstream; - - if (!ev->write) { - ngx_stream_proxy_process(s, 0, 0); - - } else if (u->upstream_buf.start) { - ngx_stream_proxy_process(s, 1, 1); - } + ngx_stream_proxy_process_connection(ev, ev->write); } static void ngx_stream_proxy_upstream_handler(ngx_event_t *ev) { - ngx_connection_t *c; - ngx_stream_session_t *s; - ngx_stream_upstream_t *u; + ngx_stream_proxy_process_connection(ev, !ev->write); +} + + +static void +ngx_stream_proxy_process_connection(ngx_event_t *ev, ngx_uint_t from_upstream) +{ + ngx_connection_t *c, *pc; + ngx_stream_session_t *s; + ngx_stream_upstream_t *u; + ngx_stream_proxy_srv_conf_t *pscf; c = ev->data; s = c->data; - u = s->upstream; - if (ev->write) { - ngx_stream_proxy_process(s, 0, 1); + if (ev->timedout) { - } else if (u->upstream_buf.start) { - ngx_stream_proxy_process(s, 1, 0); + if (ev->delayed) { + + ev->timedout = 0; + ev->delayed = 0; + + if (!ev->ready) { + if (ngx_handle_read_event(ev, 0) != NGX_OK) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + if (u->connected) { + pc = u->peer.connection; + + if (!c->read->delayed && !pc->read->delayed) { + pscf = ngx_stream_get_module_srv_conf(s, + ngx_stream_proxy_module); + ngx_add_timer(c->write, pscf->timeout); + } + } + + return; + } + + } else { + ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); + ngx_stream_proxy_finalize(s, NGX_DECLINED); + return; + } + + } else if (ev->delayed) { + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream connection delayed"); + + if (ngx_handle_read_event(ev, 0) != NGX_OK) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + } + + return; } + + if (from_upstream && !u->connected) { + return; + } + + ngx_stream_proxy_process(s, from_upstream, ev->write); } @@ -937,10 +988,12 @@ static ngx_int_t ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, ngx_uint_t do_write) { - size_t size; + off_t *received, limit; + size_t size, limit_rate; ssize_t n; ngx_buf_t *b; ngx_uint_t flags; + ngx_msec_t delay; ngx_connection_t *c, *pc, *src, *dst; ngx_log_handler_pt handler; ngx_stream_upstream_t *u; @@ -949,17 +1002,23 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, u = s->upstream; c = s->connection; - pc = u->upstream_buf.start ? u->peer.connection : NULL; + pc = u->connected ? u->peer.connection : NULL; + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); if (from_upstream) { src = pc; dst = c; b = &u->upstream_buf; + limit_rate = pscf->download_rate; + received = &u->received; } else { src = c; dst = pc; b = &u->downstream_buf; + limit_rate = pscf->upload_rate; + received = &s->received; } for ( ;; ) { @@ -990,7 +1049,23 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, size = b->end - b->last; - if (size && src->read->ready) { + if (size && src->read->ready && !src->read->delayed) { + + if (limit_rate) { + limit = (off_t) limit_rate * (ngx_time() - u->start_sec + 1) + - *received; + + if (limit <= 0) { + src->read->delayed = 1; + delay = (ngx_msec_t) (- limit * 1000 / limit_rate + 1); + ngx_add_timer(src->read, delay); + break; + } + + if ((off_t) size > limit) { + size = (size_t) limit; + } + } n = src->recv(src, b->last, size); @@ -999,15 +1074,19 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, } if (n > 0) { - if (from_upstream) { - u->received += n; + if (limit_rate) { + delay = (ngx_msec_t) (n * 1000 / limit_rate); - } else { - s->received += n; + if (delay > 0) { + src->read->delayed = 1; + ngx_add_timer(src->read, delay); + } } - do_write = 1; + *received += n; b->last += n; + do_write = 1; + continue; } @@ -1019,8 +1098,6 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, break; } - pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); - if (src->read->eof && (b->pos == b->last || (dst && dst->read->eof))) { handler = c->log->handler; c->log->handler = NULL; @@ -1051,7 +1128,12 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, return NGX_ERROR; } - ngx_add_timer(c->read, pscf->timeout); + if (!c->read->delayed && !pc->read->delayed) { + ngx_add_timer(c->write, pscf->timeout); + + } else if (c->write->timer_set) { + ngx_del_timer(c->write); + } } return NGX_OK; @@ -1214,7 +1296,9 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) conf->timeout = NGX_CONF_UNSET_MSEC; conf->next_upstream_timeout = NGX_CONF_UNSET_MSEC; conf->downstream_buf_size = NGX_CONF_UNSET_SIZE; + conf->upload_rate = NGX_CONF_UNSET_SIZE; conf->upstream_buf_size = NGX_CONF_UNSET_SIZE; + conf->download_rate = NGX_CONF_UNSET_SIZE; conf->next_upstream_tries = NGX_CONF_UNSET_UINT; conf->next_upstream = NGX_CONF_UNSET; conf->proxy_protocol = NGX_CONF_UNSET; @@ -1251,9 +1335,15 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_size_value(conf->downstream_buf_size, prev->downstream_buf_size, 16384); + ngx_conf_merge_size_value(conf->upload_rate, + prev->upload_rate, 0); + ngx_conf_merge_size_value(conf->upstream_buf_size, prev->upstream_buf_size, 16384); + ngx_conf_merge_size_value(conf->download_rate, + prev->download_rate, 0); + ngx_conf_merge_uint_value(conf->next_upstream_tries, prev->next_upstream_tries, 0); diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index 97a0fa9..7abd9e1 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -276,7 +276,9 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } +#ifndef LIBRESSL_VERSION_NUMBER SSL_CTX_set_tmp_rsa_callback(conf->ssl.ctx, ngx_ssl_rsa512_key_callback); +#endif if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { return NGX_CONF_ERROR; diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h index 56325da..80520c2 100644 --- a/src/stream/ngx_stream_upstream.h +++ b/src/stream/ngx_stream_upstream.h @@ -83,11 +83,12 @@ typedef struct { ngx_buf_t downstream_buf; ngx_buf_t upstream_buf; off_t received; + time_t start_sec; #if (NGX_STREAM_SSL) ngx_str_t ssl_name; #endif - ngx_uint_t proxy_protocol; - /* unsigned proxy_protocol:1; */ + unsigned connected:1; + unsigned proxy_protocol:1; } ngx_stream_upstream_t; diff --git a/src/stream/ngx_stream_upstream_round_robin.h b/src/stream/ngx_stream_upstream_round_robin.h index 83fd8b5..77ee0ab 100644 --- a/src/stream/ngx_stream_upstream_round_robin.h +++ b/src/stream/ngx_stream_upstream_round_robin.h @@ -58,6 +58,7 @@ struct ngx_stream_upstream_rr_peers_s { #if (NGX_STREAM_UPSTREAM_ZONE) ngx_slab_pool_t *shpool; ngx_atomic_t rwlock; + ngx_stream_upstream_rr_peers_t *zone_next; #endif ngx_uint_t total_weight; diff --git a/src/stream/ngx_stream_upstream_zone_module.c b/src/stream/ngx_stream_upstream_zone_module.c index 6025aee..87ddc03 100644 --- a/src/stream/ngx_stream_upstream_zone_module.c +++ b/src/stream/ngx_stream_upstream_zone_module.c @@ -14,8 +14,8 @@ static char *ngx_stream_upstream_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static ngx_int_t ngx_stream_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data); -static ngx_int_t ngx_stream_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, - ngx_stream_upstream_srv_conf_t *uscf); +static ngx_stream_upstream_rr_peers_t *ngx_stream_upstream_zone_copy_peers( + ngx_slab_pool_t *shpool, ngx_stream_upstream_srv_conf_t *uscf); static ngx_command_t ngx_stream_upstream_zone_commands[] = { @@ -117,13 +117,29 @@ ngx_stream_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data) size_t len; ngx_uint_t i; ngx_slab_pool_t *shpool; + ngx_stream_upstream_rr_peers_t *peers, **peersp; ngx_stream_upstream_srv_conf_t *uscf, **uscfp; ngx_stream_upstream_main_conf_t *umcf; shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + umcf = shm_zone->data; + uscfp = umcf->upstreams.elts; if (shm_zone->shm.exists) { - return NGX_ERROR; + peers = shpool->data; + + for (i = 0; i < umcf->upstreams.nelts; i++) { + uscf = uscfp[i]; + + if (uscf->shm_zone != shm_zone) { + continue; + } + + uscf->peer.data = peers; + peers = peers->zone_next; + } + + return NGX_OK; } len = sizeof(" in upstream zone \"\"") + shm_zone->shm.name.len; @@ -139,8 +155,7 @@ ngx_stream_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data) /* copy peers to shared memory */ - umcf = shm_zone->data; - uscfp = umcf->upstreams.elts; + peersp = (ngx_stream_upstream_rr_peers_t **) &shpool->data; for (i = 0; i < umcf->upstreams.nelts; i++) { uscf = uscfp[i]; @@ -149,16 +164,20 @@ ngx_stream_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data) continue; } - if (ngx_stream_upstream_zone_copy_peers(shpool, uscf) != NGX_OK) { + peers = ngx_stream_upstream_zone_copy_peers(shpool, uscf); + if (peers == NULL) { return NGX_ERROR; } + + *peersp = peers; + peersp = &peers->zone_next; } return NGX_OK; } -static ngx_int_t +static ngx_stream_upstream_rr_peers_t * ngx_stream_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_stream_upstream_srv_conf_t *uscf) { @@ -167,7 +186,7 @@ ngx_stream_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, peers = ngx_slab_alloc(shpool, sizeof(ngx_stream_upstream_rr_peers_t)); if (peers == NULL) { - return NGX_ERROR; + return NULL; } ngx_memcpy(peers, uscf->peer.data, sizeof(ngx_stream_upstream_rr_peers_t)); @@ -179,7 +198,7 @@ ngx_stream_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, peer = ngx_slab_calloc_locked(shpool, sizeof(ngx_stream_upstream_rr_peer_t)); if (peer == NULL) { - return NGX_ERROR; + return NULL; } ngx_memcpy(peer, *peerp, sizeof(ngx_stream_upstream_rr_peer_t)); @@ -193,7 +212,7 @@ ngx_stream_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, backup = ngx_slab_alloc(shpool, sizeof(ngx_stream_upstream_rr_peers_t)); if (backup == NULL) { - return NGX_ERROR; + return NULL; } ngx_memcpy(backup, peers->next, sizeof(ngx_stream_upstream_rr_peers_t)); @@ -205,7 +224,7 @@ ngx_stream_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, peer = ngx_slab_calloc_locked(shpool, sizeof(ngx_stream_upstream_rr_peer_t)); if (peer == NULL) { - return NGX_ERROR; + return NULL; } ngx_memcpy(peer, *peerp, sizeof(ngx_stream_upstream_rr_peer_t)); @@ -219,5 +238,5 @@ done: uscf->peer.data = peers; - return NGX_OK; + return peers; } From 93550c314f8dc7aecf972ca9373d86f2721e35a1 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 14 Jul 2015 20:25:16 +0300 Subject: [PATCH 049/651] Release 1.9.3-1 --- debian/changelog | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 8b1d439..8e64506 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,7 @@ -nginx (1.9.2-2) UNRELEASED; urgency=medium +nginx (1.9.3-1) unstable; urgency=medium [ Christos Trochalakis] + * New upstream Release. (Closes: #789924) * debian/control: + Remove XS-Testsuite header, it is now automatically added when `debian/tests/control` is present. @@ -9,7 +10,7 @@ nginx (1.9.2-2) UNRELEASED; urgency=medium * debian/conf/*: + Add REQUEST_SCHEME to fcgi, wsgi and scgi configs (sync with upstream). - -- Christos Trochalakis Mon, 22 Jun 2015 13:01:07 +0300 + -- Christos Trochalakis Tue, 14 Jul 2015 20:24:52 +0300 nginx (1.9.2-1) unstable; urgency=medium From fba932f24fa105edaf3b928e82acc55a9759ed61 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 24 Aug 2015 15:17:09 +0300 Subject: [PATCH 050/651] Imported Upstream version 1.9.4 --- CHANGES | 34 +- CHANGES.ru | 35 +- src/core/nginx.h | 4 +- src/core/ngx_connection.c | 46 +- src/core/ngx_connection.h | 1 + src/core/ngx_hash.c | 10 +- src/core/ngx_open_file_cache.c | 2 +- src/http/modules/ngx_http_fastcgi_module.c | 1 - src/http/modules/ngx_http_map_module.c | 10 +- src/http/modules/ngx_http_sub_filter_module.c | 569 ++++++++++++------ .../ngx_http_upstream_keepalive_module.c | 4 + .../modules/ngx_http_upstream_zone_module.c | 2 +- src/http/modules/perl/nginx.xs | 18 +- src/http/ngx_http_core_module.c | 10 +- src/mail/ngx_mail_core_module.c | 3 +- src/os/unix/ngx_process_cycle.c | 19 +- src/stream/ngx_stream.h | 1 + src/stream/ngx_stream_core_module.c | 13 +- src/stream/ngx_stream_handler.c | 23 +- src/stream/ngx_stream_proxy_module.c | 92 ++- src/stream/ngx_stream_upstream_zone_module.c | 2 +- 21 files changed, 631 insertions(+), 268 deletions(-) diff --git a/CHANGES b/CHANGES index 01130f8..120c31d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,36 @@ +Changes with nginx 1.9.4 18 Aug 2015 + + *) Change: the "proxy_downstream_buffer" and "proxy_upstream_buffer" + directives of the stream module are replaced with the + "proxy_buffer_size" directive. + + *) Feature: the "tcp_nodelay" directive in the stream module. + + *) Feature: multiple "sub_filter" directives can be used simultaneously. + + *) Feature: variables support in the search string of the "sub_filter" + directive. + + *) Workaround: configuration testing might fail under Linux OpenVZ. + Thanks to Gena Makhomed. + + *) Bugfix: old worker processes might hog CPU after reconfiguration with + a large number of worker_connections. + + *) Bugfix: a segmentation fault might occur in a worker process if the + "try_files" and "alias" directives were used inside a location given + by a regular expression; the bug had appeared in 1.7.1. + + *) Bugfix: the "try_files" directive inside a nested location given by a + regular expression worked incorrectly if the "alias" directive was + used in the outer location. + + *) Bugfix: in hash table initialization error handling. + + *) Bugfix: nginx could not be built with Visual Studio 2015. + + Changes with nginx 1.9.3 14 Jul 2015 *) Change: duplicate "http", "mail", and "stream" blocks are now @@ -57,7 +89,7 @@ Changes with nginx 1.9.1 26 May 2015 *) Change: some long deprecated directives are not supported anymore. *) Feature: the "reuseport" parameter of the "listen" directive. - Thanks to Sepherosa Ziehau and Yingqi Lu. + Thanks to Yingqi Lu at Intel and Sepherosa Ziehau. *) Feature: the $upstream_connect_time variable. diff --git a/CHANGES.ru b/CHANGES.ru index 25dfd22..09a0fe7 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,37 @@ +Изменения в nginx 1.9.4 18.08.2015 + + *) Изменение: директивы proxy_downstream_buffer и proxy_upstream_buffer + в модуле stream заменены директивой proxy_buffer_size. + + *) Добавление: директива tcp_nodelay в модуле stream. + + *) Добавление: теперь можно указать несколько директив sub_filter + одновременно. + + *) Добавление: директива sub_filter поддерживает переменные в строке + поиска. + + *) Изменение: тестирование конфигурации могло не работать под Linux + OpenVZ. + Спасибо Геннадию Махомеду. + + *) Исправление: после переконфигурации старые рабочие процессы могли + сильно нагружать процессор при больших значениях worker_connections. + + *) Исправление: при совместном использовании директив try_files и alias + внутри location'а, заданного регулярным выражением, в рабочем + процессе мог произойти segmentation fault; ошибка появилась в 1.7.1. + + *) Исправление: директива try_files внутри вложенного location'а, + заданного регулярным выражением, работала неправильно, если во + внешнем location'е использовалась директива alias. + + *) Исправление: в обработке ошибок при построении хэш-таблиц. + + *) Исправление: nginx не собирался с Visual Studio 2015. + + Изменения в nginx 1.9.3 14.07.2015 *) Изменение: дублирующиеся блоки http, mail и stream теперь запрещены. @@ -56,7 +89,7 @@ поддерживаются. *) Добавление: параметр reuseport директивы listen. - Спасибо Sepherosa Ziehau и Yingqi Lu. + Спасибо Yingqi Lu из Intel и Sepherosa Ziehau. *) Добавление: переменная $upstream_connect_time. diff --git a/src/core/nginx.h b/src/core/nginx.h index dfb90ea..a655f30 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1009003 -#define NGINX_VERSION "1.9.3" +#define nginx_version 1009004 +#define NGINX_VERSION "1.9.4" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 04a365a..9f2675b 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -567,9 +567,19 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) #endif if (listen(s, ls[i].backlog) == -1) { - ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - "listen() to %V, backlog %d failed", - &ls[i].addr_text, ls[i].backlog); + err = ngx_socket_errno; + + /* + * on OpenVZ after suspend/resume EADDRINUSE + * may be returned by listen() instead of bind(), see + * https://bugzilla.openvz.org/show_bug.cgi?id=2470 + */ + + if (err != NGX_EADDRINUSE || !ngx_test_config) { + ngx_log_error(NGX_LOG_EMERG, log, err, + "listen() to %V, backlog %d failed", + &ls[i].addr_text, ls[i].backlog); + } if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, @@ -577,7 +587,15 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) &ls[i].addr_text); } - return NGX_ERROR; + if (err != NGX_EADDRINUSE) { + return NGX_ERROR; + } + + if (!ngx_test_config) { + failed = 1; + } + + continue; } ls[i].listen = 1; @@ -1145,6 +1163,26 @@ ngx_drain_connections(void) } +void +ngx_close_idle_connections(ngx_cycle_t *cycle) +{ + ngx_uint_t i; + ngx_connection_t *c; + + c = cycle->connections; + + for (i = 0; i < cycle->connection_n; i++) { + + /* THREAD: lock */ + + if (c[i].fd != -1 && c[i].idle) { + c[i].close = 1; + c[i].read->handler(c[i].read); + } + } +} + + ngx_int_t ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s, ngx_uint_t port) diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index a49aa95..c3aca7f 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -215,6 +215,7 @@ ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle); void ngx_configure_listening_sockets(ngx_cycle_t *cycle); void ngx_close_listening_sockets(ngx_cycle_t *cycle); void ngx_close_connection(ngx_connection_t *c); +void ngx_close_idle_connections(ngx_cycle_t *cycle); ngx_int_t ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s, ngx_uint_t port); ngx_int_t ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text); diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c index e707c09..1a5d0be 100644 --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -257,11 +257,19 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) ngx_uint_t i, n, key, size, start, bucket_size; ngx_hash_elt_t *elt, **buckets; + if (hinit->max_size == 0) { + ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, + "could not build %s, you should " + "increase %s_max_size: %i", + hinit->name, hinit->name, hinit->max_size); + return NGX_ERROR; + } + for (n = 0; n < nelts; n++) { if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *)) { ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, - "could not build the %s, you should " + "could not build %s, you should " "increase %s_bucket_size: %i", hinit->name, hinit->name, hinit->bucket_size); return NGX_ERROR; diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c index 4df2134..f8bb2e3 100644 --- a/src/core/ngx_open_file_cache.c +++ b/src/core/ngx_open_file_cache.c @@ -128,7 +128,7 @@ ngx_open_file_cache_cleanup(void *data) if (cache->current) { ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "%ui items still leave in open file cache", + "%ui items still left in open file cache", cache->current); } diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index f3f78e8..668719f 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -1770,7 +1770,6 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) #if (NGX_HTTP_CACHE) if (f->large_stderr && r->cache) { - u_char *start; ssize_t len; ngx_http_fastcgi_header_t *fh; diff --git a/src/http/modules/ngx_http_map_module.c b/src/http/modules/ngx_http_map_module.c index 3245e04..2b80d0f 100644 --- a/src/http/modules/ngx_http_map_module.c +++ b/src/http/modules/ngx_http_map_module.c @@ -375,7 +375,7 @@ ngx_http_map_cmp_dns_wildcards(const void *one, const void *two) static char * ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) { - ngx_int_t rc, index; + ngx_int_t rv, index; ngx_str_t *value, name; ngx_uint_t i, key; ngx_http_map_conf_ctx_t *ctx; @@ -546,19 +546,19 @@ found: value[0].data++; } - rc = ngx_hash_add_key(&ctx->keys, &value[0], var, + rv = ngx_hash_add_key(&ctx->keys, &value[0], var, (ctx->hostnames) ? NGX_HASH_WILDCARD_KEY : 0); - if (rc == NGX_OK) { + if (rv == NGX_OK) { return NGX_CONF_OK; } - if (rc == NGX_DECLINED) { + if (rv == NGX_DECLINED) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid hostname or wildcard \"%V\"", &value[0]); } - if (rc == NGX_BUSY) { + if (rv == NGX_BUSY) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "conflicting parameter \"%V\"", &value[0]); } diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c index e6a34a7..0a4ff6d 100644 --- a/src/http/modules/ngx_http_sub_filter_module.c +++ b/src/http/modules/ngx_http_sub_filter_module.c @@ -11,8 +11,32 @@ typedef struct { - ngx_str_t match; + ngx_http_complex_value_t match; ngx_http_complex_value_t value; +} ngx_http_sub_pair_t; + + +typedef struct { + ngx_str_t match; + ngx_http_complex_value_t *value; +} ngx_http_sub_match_t; + + +typedef struct { + ngx_uint_t min_match_len; + ngx_uint_t max_match_len; + + u_char index[257]; + u_char shift[256]; +} ngx_http_sub_tables_t; + + +typedef struct { + ngx_uint_t dynamic; /* unsigned dynamic:1; */ + + ngx_array_t *pairs; + + ngx_http_sub_tables_t *tables; ngx_hash_t types; @@ -20,17 +44,11 @@ typedef struct { ngx_flag_t last_modified; ngx_array_t *types_keys; + ngx_array_t *matches; } ngx_http_sub_loc_conf_t; -typedef enum { - sub_start_state = 0, - sub_match_state, -} ngx_http_sub_state_e; - - typedef struct { - ngx_str_t match; ngx_str_t saved; ngx_str_t looked; @@ -48,12 +66,20 @@ typedef struct { ngx_chain_t *busy; ngx_chain_t *free; - ngx_str_t sub; + ngx_str_t *sub; + ngx_uint_t applied; - ngx_uint_t state; + ngx_int_t offset; + ngx_uint_t index; + + ngx_http_sub_tables_t *tables; + ngx_array_t *matches; } ngx_http_sub_ctx_t; +static ngx_uint_t ngx_http_sub_cmp_index; + + static ngx_int_t ngx_http_sub_output(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx); static ngx_int_t ngx_http_sub_parse(ngx_http_request_t *r, @@ -64,6 +90,9 @@ static char * ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, static void *ngx_http_sub_create_conf(ngx_conf_t *cf); static char *ngx_http_sub_merge_conf(ngx_conf_t *cf, void *parent, void *child); +static void ngx_http_sub_init_tables(ngx_http_sub_tables_t *tables, + ngx_http_sub_match_t *match, ngx_uint_t n); +static ngx_int_t ngx_http_sub_cmp_matches(const void *one, const void *two); static ngx_int_t ngx_http_sub_filter_init(ngx_conf_t *cf); @@ -139,12 +168,16 @@ static ngx_http_output_body_filter_pt ngx_http_next_body_filter; static ngx_int_t ngx_http_sub_header_filter(ngx_http_request_t *r) { - ngx_http_sub_ctx_t *ctx; + ngx_str_t *m; + ngx_uint_t i, j, n; + ngx_http_sub_ctx_t *ctx; + ngx_http_sub_pair_t *pairs; + ngx_http_sub_match_t *matches; ngx_http_sub_loc_conf_t *slcf; slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module); - if (slcf->match.len == 0 + if (slcf->pairs == NULL || r->headers_out.content_length_n == 0 || ngx_http_test_content_type(r, &slcf->types) == NULL) { @@ -156,19 +189,76 @@ ngx_http_sub_header_filter(ngx_http_request_t *r) return NGX_ERROR; } - ctx->saved.data = ngx_pnalloc(r->pool, slcf->match.len); - if (ctx->saved.data == NULL) { - return NGX_ERROR; - } + if (slcf->dynamic == 0) { + ctx->tables = slcf->tables; + ctx->matches = slcf->matches; - ctx->looked.data = ngx_pnalloc(r->pool, slcf->match.len); - if (ctx->looked.data == NULL) { - return NGX_ERROR; + } else { + pairs = slcf->pairs->elts; + n = slcf->pairs->nelts; + + matches = ngx_pcalloc(r->pool, sizeof(ngx_http_sub_match_t) * n); + if (matches == NULL) { + return NGX_ERROR; + } + + j = 0; + for (i = 0; i < n; i++) { + matches[j].value = &pairs[i].value; + + if (pairs[i].match.lengths == NULL) { + matches[j].match = pairs[i].match.value; + j++; + continue; + } + + m = &matches[j].match; + if (ngx_http_complex_value(r, &pairs[i].match, m) != NGX_OK) { + return NGX_ERROR; + } + + if (m->len == 0) { + continue; + } + + ngx_strlow(m->data, m->data, m->len); + j++; + } + + if (j == 0) { + return ngx_http_next_header_filter(r); + } + + ctx->matches = ngx_pnalloc(r->pool, sizeof(ngx_array_t)); + if (ctx->matches == NULL) { + return NGX_ERROR; + } + + ctx->matches->elts = matches; + ctx->matches->nelts = j; + + ctx->tables = ngx_pnalloc(r->pool, sizeof(ngx_http_sub_tables_t)); + if (ctx->tables == NULL) { + return NGX_ERROR; + } + + ngx_http_sub_init_tables(ctx->tables, ctx->matches->elts, + ctx->matches->nelts); } ngx_http_set_ctx(r, ctx, ngx_http_sub_filter_module); - ctx->match = slcf->match; + ctx->saved.data = ngx_pnalloc(r->pool, ctx->tables->max_match_len - 1); + if (ctx->saved.data == NULL) { + return NGX_ERROR; + } + + ctx->looked.data = ngx_pnalloc(r->pool, ctx->tables->max_match_len - 1); + if (ctx->looked.data == NULL) { + return NGX_ERROR; + } + + ctx->offset = ctx->tables->min_match_len - 1; ctx->last_out = &ctx->out; r->filter_need_in_memory = 1; @@ -194,8 +284,10 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_int_t rc; ngx_buf_t *b; + ngx_str_t *sub; ngx_chain_t *cl; ngx_http_sub_ctx_t *ctx; + ngx_http_sub_match_t *match; ngx_http_sub_loc_conf_t *slcf; ctx = ngx_http_get_module_ctx(r, ngx_http_sub_filter_module); @@ -242,18 +334,10 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ctx->pos = ctx->buf->pos; } - if (ctx->state == sub_start_state) { - ctx->copy_start = ctx->pos; - ctx->copy_end = ctx->pos; - } - b = NULL; while (ctx->pos < ctx->buf->last) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "saved: \"%V\" state: %d", &ctx->saved, ctx->state); - rc = ngx_http_sub_parse(r, ctx); ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -320,20 +404,6 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ctx->last_out = &cl->next; } - if (ctx->state == sub_start_state) { - ctx->copy_start = ctx->pos; - ctx->copy_end = ctx->pos; - - } else { - ctx->copy_start = NULL; - ctx->copy_end = NULL; - } - - if (ctx->looked.len > (size_t) (ctx->pos - ctx->buf->pos)) { - ctx->saved.len = ctx->looked.len - (ctx->pos - ctx->buf->pos); - ngx_memcpy(ctx->saved.data, ctx->looked.data, ctx->saved.len); - } - if (rc == NGX_AGAIN) { continue; } @@ -352,19 +422,30 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module); - if (ctx->sub.data == NULL) { + if (ctx->sub == NULL) { + ctx->sub = ngx_pcalloc(r->pool, sizeof(ngx_str_t) + * ctx->matches->nelts); + if (ctx->sub == NULL) { + return NGX_ERROR; + } + } - if (ngx_http_complex_value(r, &slcf->value, &ctx->sub) + sub = &ctx->sub[ctx->index]; + + if (sub->data == NULL) { + match = ctx->matches->elts; + + if (ngx_http_complex_value(r, match[ctx->index].value, sub) != NGX_OK) { return NGX_ERROR; } } - if (ctx->sub.len) { + if (sub->len) { b->memory = 1; - b->pos = ctx->sub.data; - b->last = ctx->sub.data + ctx->sub.len; + b->pos = sub->data; + b->last = sub->data + sub->len; } else { b->sync = 1; @@ -373,7 +454,8 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) *ctx->last_out = cl; ctx->last_out = &cl->next; - ctx->once = slcf->once; + ctx->index = 0; + ctx->once = slcf->once && (++ctx->applied == ctx->matches->nelts); continue; } @@ -428,9 +510,6 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) } ctx->buf = NULL; - - ctx->saved.len = ctx->looked.len; - ngx_memcpy(ctx->saved.data, ctx->looked.data, ctx->looked.len); } if (ctx->out == NULL && ctx->busy == NULL) { @@ -513,158 +592,142 @@ ngx_http_sub_output(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) static ngx_int_t ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) { - u_char *p, *last, *copy_end, ch, match; - size_t looked, i; - ngx_http_sub_state_e state; + u_char *p, *last, *pat, *pat_end, c; + ngx_str_t *m; + ngx_int_t offset, start, next, end, len, rc; + ngx_uint_t shift, i, j; + ngx_http_sub_match_t *match; + ngx_http_sub_tables_t *tables; + ngx_http_sub_loc_conf_t *slcf; + + slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module); + tables = ctx->tables; + + offset = ctx->offset; + end = ctx->buf->last - ctx->pos; if (ctx->once) { - ctx->copy_start = ctx->pos; - ctx->copy_end = ctx->buf->last; - ctx->pos = ctx->buf->last; - ctx->looked.len = 0; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "once"); - - return NGX_AGAIN; + /* sets start and next to end */ + offset = end + (ngx_int_t) tables->min_match_len - 1; + goto again; } - state = ctx->state; - looked = ctx->looked.len; - last = ctx->buf->last; - copy_end = ctx->copy_end; + while (offset < end) { - for (p = ctx->pos; p < last; p++) { + c = offset < 0 ? ctx->looked.data[ctx->looked.len + offset] + : ctx->pos[offset]; - ch = *p; - ch = ngx_tolower(ch); - - if (state == sub_start_state) { - - /* the tight loop */ - - match = ctx->match.data[0]; - - for ( ;; ) { - if (ch == match) { - - if (ctx->match.len == 1) { - ctx->pos = p + 1; - ctx->copy_end = p; - - return NGX_OK; - } - - copy_end = p; - ctx->looked.data[0] = *p; - looked = 1; - state = sub_match_state; - - goto match_started; - } - - if (++p == last) { - break; - } - - ch = *p; - ch = ngx_tolower(ch); - } - - ctx->state = state; - ctx->pos = p; - ctx->looked.len = looked; - ctx->copy_end = p; - - if (ctx->copy_start == NULL) { - ctx->copy_start = ctx->buf->pos; - } - - return NGX_AGAIN; - - match_started: + c = ngx_tolower(c); + shift = tables->shift[c]; + if (shift > 0) { + offset += shift; continue; } - /* state == sub_match_state */ + /* a potential match */ - if (ch == ctx->match.data[looked]) { - ctx->looked.data[looked] = *p; - looked++; + start = offset - (ngx_int_t) tables->min_match_len + 1; + match = ctx->matches->elts; - if (looked == ctx->match.len) { + i = ngx_max(tables->index[c], ctx->index); + j = tables->index[c + 1]; - ctx->state = sub_start_state; - ctx->pos = p + 1; - ctx->looked.len = 0; - ctx->saved.len = 0; - ctx->copy_end = copy_end; + while (i != j) { - if (ctx->copy_start == NULL && copy_end) { - ctx->copy_start = ctx->buf->pos; - } - - return NGX_OK; + if (slcf->once && ctx->sub && ctx->sub[i].data) { + goto next; } - } else { - /* - * check if there is another partial match in previously - * matched substring to catch cases like "aab" in "aaab" - */ + m = &match[i].match; - ctx->looked.data[looked] = *p; - looked++; + pat = m->data; + pat_end = m->data + m->len; - for (i = 1; i < looked; i++) { - if (ngx_strncasecmp(ctx->looked.data + i, - ctx->match.data, looked - i) - == 0) - { - break; - } - } - - if (i < looked) { - if (ctx->saved.len > i) { - ctx->saved.len = i; - } - - if ((size_t) (p + 1 - ctx->buf->pos) >= looked - i) { - copy_end = p + 1 - (looked - i); - } - - ngx_memmove(ctx->looked.data, ctx->looked.data + i, looked - i); - looked = looked - i; + if (start >= 0) { + p = ctx->pos + start; } else { - copy_end = p; - looked = 0; - state = sub_start_state; + last = ctx->looked.data + ctx->looked.len; + p = last + start; + + while (p < last && pat < pat_end) { + if (ngx_tolower(*p) != *pat) { + goto next; + } + + p++; + pat++; + } + + p = ctx->pos; } - if (ctx->saved.len) { + while (p < ctx->buf->last && pat < pat_end) { + if (ngx_tolower(*p) != *pat) { + goto next; + } + p++; - goto out; + pat++; } + + ctx->index = i; + + if (pat != pat_end) { + /* partial match */ + goto again; + } + + ctx->offset = offset + (ngx_int_t) m->len; + next = start + (ngx_int_t) m->len; + end = ngx_max(next, 0); + rc = NGX_OK; + + goto done; + + next: + + i++; } + + offset++; + ctx->index = 0; } - ctx->saved.len = 0; +again: -out: + ctx->offset = offset; + start = offset - (ngx_int_t) tables->min_match_len + 1; + next = start; + rc = NGX_AGAIN; - ctx->state = state; - ctx->pos = p; - ctx->looked.len = looked; +done: - ctx->copy_end = (state == sub_start_state) ? p : copy_end; + /* send [ - looked.len, start ] to client */ - if (ctx->copy_start == NULL && ctx->copy_end) { - ctx->copy_start = ctx->buf->pos; - } + ctx->saved.len = ctx->looked.len + ngx_min(start, 0); + ngx_memcpy(ctx->saved.data, ctx->looked.data, ctx->saved.len); - return NGX_AGAIN; + ctx->copy_start = ctx->pos; + ctx->copy_end = ctx->pos + ngx_max(start, 0); + + /* save [ next, end ] in looked */ + + len = ngx_min(next, 0); + p = ctx->looked.data; + p = ngx_movemem(p, p + ctx->looked.len + len, - len); + + len = ngx_max(next, 0); + p = ngx_cpymem(p, ctx->pos + len, end - len); + ctx->looked.len = p - ctx->looked.data; + + /* update position */ + + ctx->pos += end; + ctx->offset -= end; + + return rc; } @@ -674,23 +737,60 @@ ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_http_sub_loc_conf_t *slcf = conf; ngx_str_t *value; + ngx_http_sub_pair_t *pair; ngx_http_compile_complex_value_t ccv; - if (slcf->match.data) { - return "is duplicate"; - } - value = cf->args->elts; + if (value[1].len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty search pattern"); + return NGX_CONF_ERROR; + } + + if (slcf->pairs == NULL) { + slcf->pairs = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_sub_pair_t)); + if (slcf->pairs == NULL) { + return NGX_CONF_ERROR; + } + } + + if (slcf->pairs->nelts == 255) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "number of search patterns exceeds 255"); + return NGX_CONF_ERROR; + } + ngx_strlow(value[1].data, value[1].data, value[1].len); - slcf->match = value[1]; + pair = ngx_array_push(slcf->pairs); + if (pair == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &pair->match; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (ccv.complex_value->lengths != NULL) { + slcf->dynamic = 1; + + } else { + ngx_strlow(pair->match.value.data, pair->match.value.data, + pair->match.value.len); + } ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); ccv.cf = cf; ccv.value = &value[2]; - ccv.complex_value = &slcf->value; + ccv.complex_value = &pair->value; if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { return NGX_CONF_ERROR; @@ -713,9 +813,12 @@ ngx_http_sub_create_conf(ngx_conf_t *cf) /* * set by ngx_pcalloc(): * - * conf->match = { 0, NULL }; + * conf->dynamic = 0; + * conf->pairs = NULL; + * conf->tables = NULL; * conf->types = { NULL }; * conf->types_keys = NULL; + * conf->matches = NULL; */ slcf->once = NGX_CONF_UNSET; @@ -728,17 +831,15 @@ ngx_http_sub_create_conf(ngx_conf_t *cf) static char * ngx_http_sub_merge_conf(ngx_conf_t *cf, void *parent, void *child) { - ngx_http_sub_loc_conf_t *prev = parent; - ngx_http_sub_loc_conf_t *conf = child; + ngx_uint_t i, n; + ngx_http_sub_pair_t *pairs; + ngx_http_sub_match_t *matches; + ngx_http_sub_loc_conf_t *prev = parent; + ngx_http_sub_loc_conf_t *conf = child; ngx_conf_merge_value(conf->once, prev->once, 1); - ngx_conf_merge_str_value(conf->match, prev->match, ""); ngx_conf_merge_value(conf->last_modified, prev->last_modified, 0); - if (conf->value.value.data == NULL) { - conf->value = prev->value; - } - if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types, &prev->types_keys, &prev->types, ngx_http_html_default_types) @@ -747,10 +848,108 @@ ngx_http_sub_merge_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } + if (conf->pairs == NULL) { + conf->dynamic = prev->dynamic; + conf->pairs = prev->pairs; + conf->matches = prev->matches; + conf->tables = prev->tables; + + } else if (conf->dynamic == 0){ + pairs = conf->pairs->elts; + n = conf->pairs->nelts; + + matches = ngx_pnalloc(cf->pool, sizeof(ngx_http_sub_match_t) * n); + if (matches == NULL) { + return NGX_CONF_ERROR; + } + + for (i = 0; i < n; i++) { + matches[i].match = pairs[i].match.value; + matches[i].value = &pairs[i].value; + } + + conf->matches = ngx_pnalloc(cf->pool, sizeof(ngx_array_t)); + if (conf->matches == NULL) { + return NGX_CONF_ERROR; + } + + conf->matches->elts = matches; + conf->matches->nelts = n; + + conf->tables = ngx_palloc(cf->pool, sizeof(ngx_http_sub_tables_t)); + if (conf->tables == NULL) { + return NGX_CONF_ERROR; + } + + ngx_http_sub_init_tables(conf->tables, conf->matches->elts, + conf->matches->nelts); + } + return NGX_CONF_OK; } +static void +ngx_http_sub_init_tables(ngx_http_sub_tables_t *tables, + ngx_http_sub_match_t *match, ngx_uint_t n) +{ + u_char c; + ngx_uint_t i, j, min, max, ch; + + min = match[0].match.len; + max = match[0].match.len; + + for (i = 1; i < n; i++) { + min = ngx_min(min, match[i].match.len); + max = ngx_max(max, match[i].match.len); + } + + tables->min_match_len = min; + tables->max_match_len = max; + + ngx_http_sub_cmp_index = tables->min_match_len - 1; + ngx_sort(match, n, sizeof(ngx_http_sub_match_t), ngx_http_sub_cmp_matches); + + min = ngx_min(min, 255); + ngx_memset(tables->shift, min, 256); + + ch = 0; + + for (i = 0; i < n; i++) { + + for (j = 0; j < min; j++) { + c = match[i].match.data[tables->min_match_len - 1 - j]; + tables->shift[c] = ngx_min(tables->shift[c], (u_char) j); + } + + c = match[i].match.data[tables->min_match_len - 1]; + while (ch <= c) { + tables->index[ch++] = (u_char) i; + } + } + + while (ch < 257) { + tables->index[ch++] = (u_char) n; + } +} + + +static ngx_int_t +ngx_http_sub_cmp_matches(const void *one, const void *two) +{ + ngx_int_t c1, c2; + ngx_http_sub_match_t *first, *second; + + first = (ngx_http_sub_match_t *) one; + second = (ngx_http_sub_match_t *) two; + + c1 = first->match.data[ngx_http_sub_cmp_index]; + c2 = second->match.data[ngx_http_sub_cmp_index]; + + return c1 - c2; +} + + static ngx_int_t ngx_http_sub_filter_init(ngx_conf_t *cf) { diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c b/src/http/modules/ngx_http_upstream_keepalive_module.c index 768881e..51887b4 100644 --- a/src/http/modules/ngx_http_upstream_keepalive_module.c +++ b/src/http/modules/ngx_http_upstream_keepalive_module.c @@ -302,6 +302,10 @@ ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data, goto invalid; } + if (ngx_terminate || ngx_exiting) { + goto invalid; + } + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { goto invalid; } diff --git a/src/http/modules/ngx_http_upstream_zone_module.c b/src/http/modules/ngx_http_upstream_zone_module.c index 7169c36..7e5bd74 100644 --- a/src/http/modules/ngx_http_upstream_zone_module.c +++ b/src/http/modules/ngx_http_upstream_zone_module.c @@ -159,7 +159,7 @@ ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data) /* copy peers to shared memory */ - peersp = (ngx_http_upstream_rr_peers_t **) &shpool->data; + peersp = (ngx_http_upstream_rr_peers_t **) (void *) &shpool->data; for (i = 0; i < umcf->upstreams.nelts; i++) { uscf = uscfp[i]; diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs index 71f17a8..6716620 100644 --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -98,6 +98,9 @@ ngx_http_perl_output(ngx_http_request_t *r, ngx_buf_t *b) MODULE = nginx PACKAGE = nginx +PROTOTYPES: DISABLE + + void status(r, code) CODE: @@ -268,19 +271,16 @@ header_in(r, key) } #endif - if (hh->offset) { + ph = (ngx_table_elt_t **) ((char *) &r->headers_in + hh->offset); - ph = (ngx_table_elt_t **) ((char *) &r->headers_in + hh->offset); + if (*ph) { + ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len); - if (*ph) { - ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len); - - goto done; - } - - XSRETURN_UNDEF; + goto done; } + XSRETURN_UNDEF; + multi: /* Cookie, X-Forwarded-For */ diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index d423d8b..22400ca 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -1239,7 +1239,9 @@ ngx_http_core_try_files_phase(ngx_http_request_t *r, *e.pos = '\0'; - if (alias && ngx_strncmp(name, clcf->name.data, alias) == 0) { + if (alias && alias != NGX_MAX_SIZE_T_VALUE + && ngx_strncmp(name, r->uri.data, alias) == 0) + { ngx_memmove(name, name + alias, len - alias); path.len -= alias; } @@ -1322,6 +1324,8 @@ ngx_http_core_try_files_phase(ngx_http_request_t *r, } } else { + name = r->uri.data; + r->uri.len = alias + path.len; r->uri.data = ngx_pnalloc(r->pool, r->uri.len); if (r->uri.data == NULL) { @@ -1329,8 +1333,8 @@ ngx_http_core_try_files_phase(ngx_http_request_t *r, return NGX_OK; } - p = ngx_copy(r->uri.data, clcf->name.data, alias); - ngx_memcpy(p, name, path.len); + p = ngx_copy(r->uri.data, name, alias); + ngx_memcpy(p, path.data, path.len); } ngx_http_set_exten(r); diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index 271afc4..c219296 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -434,8 +434,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) { #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) - struct sockaddr *sa; - u_char buf[NGX_SOCKADDR_STRLEN]; + u_char buf[NGX_SOCKADDR_STRLEN]; sa = &ls->u.sockaddr; diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c index c69932e..5da0911 100644 --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -728,9 +728,6 @@ ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) { ngx_int_t worker = (intptr_t) data; - ngx_uint_t i; - ngx_connection_t *c; - ngx_process = NGX_PROCESS_WORKER; ngx_worker = worker; @@ -741,19 +738,6 @@ ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) for ( ;; ) { if (ngx_exiting) { - - c = cycle->connections; - - for (i = 0; i < cycle->connection_n; i++) { - - /* THREAD: lock */ - - if (c[i].fd != -1 && c[i].idle) { - c[i].close = 1; - c[i].read->handler(c[i].read); - } - } - ngx_event_cancel_timers(); if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel) @@ -781,8 +765,9 @@ ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) ngx_setproctitle("worker process is shutting down"); if (!ngx_exiting) { - ngx_close_listening_sockets(cycle); ngx_exiting = 1; + ngx_close_listening_sockets(cycle); + ngx_close_idle_connections(cycle); } } diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h index 266101c..21953e9 100644 --- a/src/stream/ngx_stream.h +++ b/src/stream/ngx_stream.h @@ -132,6 +132,7 @@ typedef struct { u_char *file_name; ngx_int_t line; ngx_log_t *error_log; + ngx_flag_t tcp_nodelay; } ngx_stream_core_srv_conf_t; diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c index 246f55c..4fe6818 100644 --- a/src/stream/ngx_stream_core_module.c +++ b/src/stream/ngx_stream_core_module.c @@ -45,6 +45,13 @@ static ngx_command_t ngx_stream_core_commands[] = { 0, NULL }, + { ngx_string("tcp_nodelay"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_core_srv_conf_t, tcp_nodelay), + NULL }, + ngx_null_command }; @@ -122,6 +129,7 @@ ngx_stream_core_create_srv_conf(ngx_conf_t *cf) cscf->file_name = cf->conf_file->file.name.data; cscf->line = cf->conf_file->line; + cscf->tcp_nodelay = NGX_CONF_UNSET; return cscf; } @@ -148,6 +156,8 @@ ngx_stream_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) } } + ngx_conf_merge_value(conf->tcp_nodelay, prev->tcp_nodelay, 1); + return NGX_CONF_OK; } @@ -362,8 +372,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) { #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) - struct sockaddr *sa; - u_char buf[NGX_SOCKADDR_STRLEN]; + u_char buf[NGX_SOCKADDR_STRLEN]; sa = &ls->u.sockaddr; diff --git a/src/stream/ngx_stream_handler.c b/src/stream/ngx_stream_handler.c index 7b635fa..b3edb68 100644 --- a/src/stream/ngx_stream_handler.c +++ b/src/stream/ngx_stream_handler.c @@ -23,6 +23,7 @@ static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c); void ngx_stream_init_connection(ngx_connection_t *c) { + int tcp_nodelay; u_char text[NGX_SOCKADDR_STRLEN]; size_t len; ngx_int_t rc; @@ -165,6 +166,24 @@ ngx_stream_init_connection(ngx_connection_t *c) } } + if (cscf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "tcp_nodelay"); + + tcp_nodelay = 1; + + if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, + (const void *) &tcp_nodelay, sizeof(int)) == -1) + { + ngx_connection_error(c, ngx_socket_errno, + "setsockopt(TCP_NODELAY) failed"); + ngx_stream_close_connection(c); + return; + } + + c->tcp_nodelay = NGX_TCP_NODELAY_SET; + } + + #if (NGX_STREAM_SSL) { ngx_stream_ssl_conf_t *sslcf; @@ -309,9 +328,11 @@ ngx_stream_log_error(ngx_log_t *log, u_char *buf, size_t len) p = ngx_snprintf(buf, len, ", client: %V, server: %V", &s->connection->addr_text, &s->connection->listening->addr_text); + len -= p - buf; + buf = p; if (s->log_handler) { - return s->log_handler(log, p, len); + p = s->log_handler(log, buf, len); } return p; diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 68af5a8..ea142e7 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -17,9 +17,8 @@ typedef struct { ngx_msec_t connect_timeout; ngx_msec_t timeout; ngx_msec_t next_upstream_timeout; - size_t downstream_buf_size; + size_t buffer_size; size_t upload_rate; - size_t upstream_buf_size; size_t download_rate; ngx_uint_t next_upstream_tries; ngx_flag_t next_upstream; @@ -97,6 +96,15 @@ static ngx_conf_bitmask_t ngx_stream_proxy_ssl_protocols[] = { #endif +static ngx_conf_deprecated_t ngx_conf_deprecated_proxy_downstream_buffer = { + ngx_conf_deprecated, "proxy_downstream_buffer", "proxy_buffer_size" +}; + +static ngx_conf_deprecated_t ngx_conf_deprecated_proxy_upstream_buffer = { + ngx_conf_deprecated, "proxy_upstream_buffer", "proxy_buffer_size" +}; + + static ngx_command_t ngx_stream_proxy_commands[] = { { ngx_string("proxy_pass"), @@ -127,12 +135,26 @@ static ngx_command_t ngx_stream_proxy_commands[] = { offsetof(ngx_stream_proxy_srv_conf_t, timeout), NULL }, + { ngx_string("proxy_buffer_size"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, buffer_size), + NULL }, + { ngx_string("proxy_downstream_buffer"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, downstream_buf_size), - NULL }, + offsetof(ngx_stream_proxy_srv_conf_t, buffer_size), + &ngx_conf_deprecated_proxy_downstream_buffer }, + + { ngx_string("proxy_upstream_buffer"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, buffer_size), + &ngx_conf_deprecated_proxy_upstream_buffer }, { ngx_string("proxy_upload_rate"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, @@ -141,13 +163,6 @@ static ngx_command_t ngx_stream_proxy_commands[] = { offsetof(ngx_stream_proxy_srv_conf_t, upload_rate), NULL }, - { ngx_string("proxy_upstream_buffer"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, upstream_buf_size), - NULL }, - { ngx_string("proxy_download_rate"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, @@ -358,14 +373,14 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) u->proxy_protocol = pscf->proxy_protocol; u->start_sec = ngx_time(); - p = ngx_pnalloc(c->pool, pscf->downstream_buf_size); + p = ngx_pnalloc(c->pool, pscf->buffer_size); if (p == NULL) { ngx_stream_proxy_finalize(s, NGX_ERROR); return; } u->downstream_buf.start = p; - u->downstream_buf.end = p + pscf->downstream_buf_size; + u->downstream_buf.end = p + pscf->buffer_size; u->downstream_buf.pos = p; u->downstream_buf.last = p; @@ -376,8 +391,7 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) #if (NGX_STREAM_SSL) && pscf->ssl == NULL #endif - && pscf->downstream_buf_size >= NGX_PROXY_PROTOCOL_MAX_HEADER - ) + && pscf->buffer_size >= NGX_PROXY_PROTOCOL_MAX_HEADER) { /* optimization for a typical case */ @@ -464,13 +478,35 @@ ngx_stream_proxy_connect(ngx_stream_session_t *s) static void ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) { + int tcp_nodelay; u_char *p; ngx_connection_t *c, *pc; ngx_log_handler_pt handler; ngx_stream_upstream_t *u; + ngx_stream_core_srv_conf_t *cscf; ngx_stream_proxy_srv_conf_t *pscf; u = s->upstream; + pc = u->peer.connection; + + cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); + + if (cscf->tcp_nodelay && pc->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, "tcp_nodelay"); + + tcp_nodelay = 1; + + if (setsockopt(pc->fd, IPPROTO_TCP, TCP_NODELAY, + (const void *) &tcp_nodelay, sizeof(int)) == -1) + { + ngx_connection_error(pc, ngx_socket_errno, + "setsockopt(TCP_NODELAY) failed"); + ngx_stream_proxy_next_upstream(s); + return; + } + + pc->tcp_nodelay = NGX_TCP_NODELAY_SET; + } if (u->proxy_protocol) { if (ngx_stream_proxy_send_proxy_protocol(s) != NGX_OK) { @@ -482,8 +518,6 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); - pc = u->peer.connection; - #if (NGX_STREAM_SSL) if (pscf->ssl && pc->ssl == NULL) { ngx_stream_proxy_ssl_init_connection(s); @@ -494,18 +528,18 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) c = s->connection; if (c->log->log_level >= NGX_LOG_INFO) { - ngx_str_t s; + ngx_str_t str; u_char addr[NGX_SOCKADDR_STRLEN]; - s.len = NGX_SOCKADDR_STRLEN; - s.data = addr; + str.len = NGX_SOCKADDR_STRLEN; + str.data = addr; - if (ngx_connection_local_sockaddr(pc, &s, 1) == NGX_OK) { + if (ngx_connection_local_sockaddr(pc, &str, 1) == NGX_OK) { handler = c->log->handler; c->log->handler = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "proxy %V connected to %V", - &s, u->peer.name); + &str, u->peer.name); c->log->handler = handler; } @@ -513,14 +547,14 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) c->log->action = "proxying connection"; - p = ngx_pnalloc(c->pool, pscf->upstream_buf_size); + p = ngx_pnalloc(c->pool, pscf->buffer_size); if (p == NULL) { ngx_stream_proxy_finalize(s, NGX_ERROR); return; } u->upstream_buf.start = p; - u->upstream_buf.end = p + pscf->upstream_buf_size; + u->upstream_buf.end = p + pscf->buffer_size; u->upstream_buf.pos = p; u->upstream_buf.last = p; @@ -1295,9 +1329,8 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) conf->connect_timeout = NGX_CONF_UNSET_MSEC; conf->timeout = NGX_CONF_UNSET_MSEC; conf->next_upstream_timeout = NGX_CONF_UNSET_MSEC; - conf->downstream_buf_size = NGX_CONF_UNSET_SIZE; + conf->buffer_size = NGX_CONF_UNSET_SIZE; conf->upload_rate = NGX_CONF_UNSET_SIZE; - conf->upstream_buf_size = NGX_CONF_UNSET_SIZE; conf->download_rate = NGX_CONF_UNSET_SIZE; conf->next_upstream_tries = NGX_CONF_UNSET_UINT; conf->next_upstream = NGX_CONF_UNSET; @@ -1332,15 +1365,12 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->next_upstream_timeout, prev->next_upstream_timeout, 0); - ngx_conf_merge_size_value(conf->downstream_buf_size, - prev->downstream_buf_size, 16384); + ngx_conf_merge_size_value(conf->buffer_size, + prev->buffer_size, 16384); ngx_conf_merge_size_value(conf->upload_rate, prev->upload_rate, 0); - ngx_conf_merge_size_value(conf->upstream_buf_size, - prev->upstream_buf_size, 16384); - ngx_conf_merge_size_value(conf->download_rate, prev->download_rate, 0); diff --git a/src/stream/ngx_stream_upstream_zone_module.c b/src/stream/ngx_stream_upstream_zone_module.c index 87ddc03..ffc9e8a 100644 --- a/src/stream/ngx_stream_upstream_zone_module.c +++ b/src/stream/ngx_stream_upstream_zone_module.c @@ -155,7 +155,7 @@ ngx_stream_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data) /* copy peers to shared memory */ - peersp = (ngx_stream_upstream_rr_peers_t **) &shpool->data; + peersp = (ngx_stream_upstream_rr_peers_t **) (void *) &shpool->data; for (i = 0; i < umcf->upstreams.nelts; i++) { uscf = uscfp[i]; From a26063750ff282f1ad214846d19d17326e06a0a8 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 24 Aug 2015 15:19:12 +0300 Subject: [PATCH 051/651] New upstream release (1.9.4) --- debian/changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index 8e64506..9cde120 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.9.4-1) UNRELEASED; urgency=medium + + [ Christos Trochalakis] + * New upstream release. + + -- Christos Trochalakis Mon, 24 Aug 2015 15:19:01 +0300 + nginx (1.9.3-1) unstable; urgency=medium [ Christos Trochalakis] From f539cc0a49a4a5046ff511ee9215efbe2f31f3cf Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 22 Jul 2015 10:46:53 +0300 Subject: [PATCH 052/651] Fix licence ordering --- debian/copyright | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/debian/copyright b/debian/copyright index 9b123d1..a386770 100644 --- a/debian/copyright +++ b/debian/copyright @@ -30,6 +30,16 @@ Files: contrib/geo2nginx.pl Copyright: 2005, Andrei Nigmatulin License: BSD-2-clause +Files: debian/* +Copyright: 2007-2009, Fabio Tranchitella + 2008, Jose Parrella + 2009-2014, Kartik Mistry + 2010-2014, Michael Lustfield + 2011 Dmitry E. Oboukhov + 2011-2013, Cyril Lavier + 2013-2014, Christos Trochalakis +License: BSD-2-clause + Files: debian/modules/headers-more-nginx-module/* Copyright: Copyright (c) 2009-2014, Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. Copyright (c) 2010-2013, Bernd Dorn @@ -89,16 +99,6 @@ Files: debian/modules/ngx_http_substitutions_filter_module/* Copyright: Copyright (C) 2014 by Weibin Yao License: BSD-2-clause -Files: debian/* -Copyright: 2007-2009, Fabio Tranchitella - 2008, Jose Parrella - 2009-2014, Kartik Mistry - 2010-2014, Michael Lustfield - 2011 Dmitry E. Oboukhov - 2011-2013, Cyril Lavier - 2013-2014, Christos Trochalakis -License: BSD-2-clause - License: BSD-2-clause All rights reserved. . From a9600e2b4d49f207a36128797b30280a1d0f80ec Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 6 Aug 2015 15:40:05 +0300 Subject: [PATCH 053/651] Update debian/copyright for nginx source --- debian/copyright | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/debian/copyright b/debian/copyright index a386770..0edb73b 100644 --- a/debian/copyright +++ b/debian/copyright @@ -7,23 +7,20 @@ Copyright: 2002-2014 Igor Sysoev 2011-2014 Nginx, Inc. Maxim Dounin Valentin V. Bartenev + Roman Arutyunyan + Ruslan Ermilov License: BSD-2-clause Files: src/core/ngx_murmurhash.c Copyright: Copyright (C) Austin Appleby License: BSD-2-clause -Files: src/core/ngx_proxy_protocol.h - src/core/ngx_proxy_protocol.c -Copyright: Copyright (C) Roman Arutyunyan - Copyright (C) Nginx, Inc. -License: BSD-2-clause - Files: src/http/modules/ngx_http_scgi_module.c src/http/modules/ngx_http_uwsgi_module.c Copyright: Copyright (C) Igor Sysoev Copyright (C) Nginx, Inc. - Copyright (C) Manlio Perillo (manlio.perillo@gmail.com) + 2009-2010 Unbit S.a.s. + 2008 Manlio Perillo (manlio.perillo@gmail.com) License: BSD-2-clause Files: contrib/geo2nginx.pl From a8ef8abc7b0ea981cd14705f39ed247e26f243dc Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 24 Aug 2015 15:57:08 +0300 Subject: [PATCH 054/651] Release 1.9.4-1 --- debian/changelog | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 9cde120..004eaa2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,9 +1,11 @@ -nginx (1.9.4-1) UNRELEASED; urgency=medium +nginx (1.9.4-1) unstable; urgency=medium [ Christos Trochalakis] * New upstream release. + * debian/copyright: + + Fix licence order. - -- Christos Trochalakis Mon, 24 Aug 2015 15:19:01 +0300 + -- Christos Trochalakis Mon, 24 Aug 2015 16:23:20 +0300 nginx (1.9.3-1) unstable; urgency=medium From 3efc8819263ce2868b629fe53df139603bd614ee Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 25 Sep 2015 14:02:47 +0300 Subject: [PATCH 055/651] Imported Upstream version 1.9.5 --- CHANGES | 30 + CHANGES.ru | 31 + auto/make | 2 +- auto/modules | 18 +- auto/options | 6 +- auto/sources | 18 +- src/core/nginx.h | 4 +- src/core/ngx_connection.h | 2 +- src/core/ngx_hash.c | 4 + src/http/modules/ngx_http_rewrite_module.c | 2 +- src/http/modules/ngx_http_ssl_module.c | 24 +- src/http/modules/ngx_http_sub_filter_module.c | 3 +- src/http/ngx_http.c | 31 +- src/http/ngx_http.h | 8 +- src/http/ngx_http_copy_filter_module.c | 2 +- src/http/ngx_http_core_module.c | 47 +- src/http/ngx_http_core_module.h | 8 +- src/http/ngx_http_file_cache.c | 21 +- src/http/ngx_http_request.c | 40 +- src/http/ngx_http_request.h | 9 +- src/http/ngx_http_request_body.c | 12 +- src/http/ngx_http_spdy.c | 3701 --------------- src/http/ngx_http_spdy.h | 261 -- src/http/ngx_http_spdy_filter_module.c | 1222 ----- src/http/ngx_http_spdy_module.c | 408 -- src/http/ngx_http_upstream.c | 33 +- src/http/v2/ngx_http_v2.c | 4036 +++++++++++++++++ src/http/v2/ngx_http_v2.h | 333 ++ src/http/v2/ngx_http_v2_filter_module.c | 1291 ++++++ src/http/v2/ngx_http_v2_huff_decode.c | 2714 +++++++++++ src/http/v2/ngx_http_v2_huff_encode.c | 10 + src/http/v2/ngx_http_v2_module.c | 469 ++ .../ngx_http_v2_module.h} | 19 +- src/http/v2/ngx_http_v2_table.c | 349 ++ src/os/unix/ngx_files.c | 13 +- 35 files changed, 9453 insertions(+), 5728 deletions(-) delete mode 100644 src/http/ngx_http_spdy.c delete mode 100644 src/http/ngx_http_spdy.h delete mode 100644 src/http/ngx_http_spdy_filter_module.c delete mode 100644 src/http/ngx_http_spdy_module.c create mode 100644 src/http/v2/ngx_http_v2.c create mode 100644 src/http/v2/ngx_http_v2.h create mode 100644 src/http/v2/ngx_http_v2_filter_module.c create mode 100644 src/http/v2/ngx_http_v2_huff_decode.c create mode 100644 src/http/v2/ngx_http_v2_huff_encode.c create mode 100644 src/http/v2/ngx_http_v2_module.c rename src/http/{ngx_http_spdy_module.h => v2/ngx_http_v2_module.h} (58%) create mode 100644 src/http/v2/ngx_http_v2_table.c diff --git a/CHANGES b/CHANGES index 120c31d..47d33a4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,34 @@ +Changes with nginx 1.9.5 22 Sep 2015 + + *) Feature: the ngx_http_v2_module (replaces ngx_http_spdy_module). + Thanks to Dropbox and Automattic for sponsoring this work. + + *) Change: now the "output_buffers" directive uses two buffers by + default. + + *) Change: now nginx limits subrequests recursion, not simultaneous + subrequests. + + *) Change: now nginx checks the whole cache key when returning a + response from cache. + Thanks to Gena Makhomed and Sergey Brester. + + *) Bugfix: "header already sent" alerts might appear in logs when using + cache; the bug had appeared in 1.7.5. + + *) Bugfix: "writev() failed (4: Interrupted system call)" errors might + appear in logs when using CephFS and the "timer_resolution" directive + on Linux. + + *) Bugfix: in invalid configurations handling. + Thanks to Markus Linnala. + + *) Bugfix: a segmentation fault occurred in a worker process if the + "sub_filter" directive was used at http level; the bug had appeared + in 1.9.4. + + Changes with nginx 1.9.4 18 Aug 2015 *) Change: the "proxy_downstream_buffer" and "proxy_upstream_buffer" diff --git a/CHANGES.ru b/CHANGES.ru index 09a0fe7..b95c33d 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,35 @@ +Изменения в nginx 1.9.5 22.09.2015 + + *) Добавление: модуль ngx_http_v2_module (заменяет модуль + ngx_http_spdy_module). + Спасибо Dropbox и Automattic за спонсирование разработки. + + *) Изменение: теперь по умолчанию директива output_buffers использует + два буфера. + + *) Изменение: теперь nginx ограничивает максимальную вложенность + подзапросов, а не количество одновременных подзапросов. + + *) Изменение: теперь при возврате ответов из кэша nginx проверяет ключ + полностью. + Спасибо Геннадию Махомеду и Сергею Брестеру. + + *) Исправление: при использовании кэша в логах могли появляться + сообщения "header already sent"; ошибка появилась в 1.7.5. + + *) Исправление: при использовании CephFS и директивы timer_resolution на + Linux в логах могли появляться сообщения "writev() failed (4: + Interrupted system call)". + + *) Исправление: в обработке ошибок конфигурации. + Спасибо Markus Linnala. + + *) Исправление: при использовании директивы sub_filter на уровне http в + рабочем процессе происходил segmentation fault; ошибка появилась в + 1.9.4. + + Изменения в nginx 1.9.4 18.08.2015 *) Изменение: директивы proxy_downstream_buffer и proxy_upstream_buffer diff --git a/auto/make b/auto/make index 78d0422..dca011c 100644 --- a/auto/make +++ b/auto/make @@ -7,7 +7,7 @@ echo "creating $NGX_MAKEFILE" mkdir -p $NGX_OBJS/src/core $NGX_OBJS/src/event $NGX_OBJS/src/event/modules \ $NGX_OBJS/src/os/unix $NGX_OBJS/src/os/win32 \ - $NGX_OBJS/src/http $NGX_OBJS/src/http/modules \ + $NGX_OBJS/src/http $NGX_OBJS/src/http/v2 $NGX_OBJS/src/http/modules \ $NGX_OBJS/src/http/modules/perl \ $NGX_OBJS/src/mail \ $NGX_OBJS/src/stream \ diff --git a/auto/modules b/auto/modules index 60a060d..5c734e1 100644 --- a/auto/modules +++ b/auto/modules @@ -94,7 +94,7 @@ fi # ngx_http_write_filter # ngx_http_header_filter # ngx_http_chunked_filter -# ngx_http_spdy_filter +# ngx_http_v2_filter # ngx_http_range_header_filter # ngx_http_gzip_filter # ngx_http_postpone_filter @@ -115,8 +115,8 @@ HTTP_FILTER_MODULES="$HTTP_WRITE_FILTER_MODULE \ $HTTP_HEADER_FILTER_MODULE \ $HTTP_CHUNKED_FILTER_MODULE" -if [ $HTTP_SPDY = YES ]; then - HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_SPDY_FILTER_MODULE" +if [ $HTTP_V2 = YES ]; then + HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_V2_FILTER_MODULE" fi HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_RANGE_HEADER_FILTER_MODULE" @@ -180,12 +180,12 @@ if [ $HTTP_USERID = YES ]; then fi -if [ $HTTP_SPDY = YES ]; then - have=NGX_HTTP_SPDY . auto/have - USE_ZLIB=YES - HTTP_MODULES="$HTTP_MODULES $HTTP_SPDY_MODULE" - HTTP_DEPS="$HTTP_DEPS $HTTP_SPDY_DEPS" - HTTP_SRCS="$HTTP_SRCS $HTTP_SPDY_SRCS" +if [ $HTTP_V2 = YES ]; then + have=NGX_HTTP_V2 . auto/have + HTTP_MODULES="$HTTP_MODULES $HTTP_V2_MODULE" + HTTP_INCS="$HTTP_INCS $HTTP_V2_INCS" + HTTP_DEPS="$HTTP_DEPS $HTTP_V2_DEPS" + HTTP_SRCS="$HTTP_SRCS $HTTP_V2_SRCS" fi HTTP_MODULES="$HTTP_MODULES $HTTP_STATIC_MODULE" diff --git a/auto/options b/auto/options index e70d1a0..efc8943 100644 --- a/auto/options +++ b/auto/options @@ -58,7 +58,7 @@ HTTP_CACHE=YES HTTP_CHARSET=YES HTTP_GZIP=YES HTTP_SSL=NO -HTTP_SPDY=NO +HTTP_V2=NO HTTP_SSI=YES HTTP_POSTPONE=NO HTTP_REALIP=NO @@ -210,7 +210,7 @@ do --http-scgi-temp-path=*) NGX_HTTP_SCGI_TEMP_PATH="$value" ;; --with-http_ssl_module) HTTP_SSL=YES ;; - --with-http_spdy_module) HTTP_SPDY=YES ;; + --with-http_v2_module) HTTP_V2=YES ;; --with-http_realip_module) HTTP_REALIP=YES ;; --with-http_addition_module) HTTP_ADDITION=YES ;; --with-http_xslt_module) HTTP_XSLT=YES ;; @@ -378,7 +378,7 @@ cat << END --with-ipv6 enable IPv6 support --with-http_ssl_module enable ngx_http_ssl_module - --with-http_spdy_module enable ngx_http_spdy_module + --with-http_v2_module enable ngx_http_v2_module --with-http_realip_module enable ngx_http_realip_module --with-http_addition_module enable ngx_http_addition_module --with-http_xslt_module enable ngx_http_xslt_module diff --git a/auto/sources b/auto/sources index 3d89e2d..2abbc60 100644 --- a/auto/sources +++ b/auto/sources @@ -317,13 +317,17 @@ HTTP_POSTPONE_FILTER_SRCS=src/http/ngx_http_postpone_filter_module.c HTTP_FILE_CACHE_SRCS=src/http/ngx_http_file_cache.c -HTTP_SPDY_MODULE=ngx_http_spdy_module -HTTP_SPDY_FILTER_MODULE=ngx_http_spdy_filter_module -HTTP_SPDY_DEPS="src/http/ngx_http_spdy.h \ - src/http/ngx_http_spdy_module.h" -HTTP_SPDY_SRCS="src/http/ngx_http_spdy.c \ - src/http/ngx_http_spdy_module.c \ - src/http/ngx_http_spdy_filter_module.c" +HTTP_V2_MODULE=ngx_http_v2_module +HTTP_V2_FILTER_MODULE=ngx_http_v2_filter_module +HTTP_V2_INCS="src/http/v2" +HTTP_V2_DEPS="src/http/v2/ngx_http_v2.h \ + src/http/v2/ngx_http_v2_module.h" +HTTP_V2_SRCS="src/http/v2/ngx_http_v2.c \ + src/http/v2/ngx_http_v2_table.c \ + src/http/v2/ngx_http_v2_huff_decode.c \ + src/http/v2/ngx_http_v2_huff_encode.c \ + src/http/v2/ngx_http_v2_module.c \ + src/http/v2/ngx_http_v2_filter_module.c" HTTP_CHARSET_FILTER_MODULE=ngx_http_charset_filter_module diff --git a/src/core/nginx.h b/src/core/nginx.h index a655f30..34a6a80 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1009004 -#define NGINX_VERSION "1.9.4" +#define nginx_version 1009005 +#define NGINX_VERSION "1.9.5" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index c3aca7f..977f028 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -118,7 +118,7 @@ typedef enum { #define NGX_LOWLEVEL_BUFFERED 0x0f #define NGX_SSL_BUFFERED 0x01 -#define NGX_SPDY_BUFFERED 0x02 +#define NGX_HTTP_V2_BUFFERED 0x02 struct ngx_connection_s { diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c index 1a5d0be..151e643 100644 --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -743,6 +743,10 @@ ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key, void *value, if (key->data[i] == '.' && key->data[i + 1] == '.') { return NGX_DECLINED; } + + if (key->data[i] == '\0') { + return NGX_DECLINED; + } } if (key->len > 1 && key->data[0] == '.') { diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c index f241196..754512f 100644 --- a/src/http/modules/ngx_http_rewrite_module.c +++ b/src/http/modules/ngx_http_rewrite_module.c @@ -612,7 +612,7 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) save = *cf; cf->ctx = ctx; - if (pclcf->name.len == 0) { + if (cf->cmd_type == NGX_HTTP_SRV_CONF) { if_code->loc_conf = NULL; cf->cmd_type = NGX_HTTP_SIF_CONF; diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index d6a1794..7b051ea 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -326,10 +326,10 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, #if (NGX_DEBUG) unsigned int i; #endif -#if (NGX_HTTP_SPDY) +#if (NGX_HTTP_V2) ngx_http_connection_t *hc; #endif -#if (NGX_HTTP_SPDY || NGX_DEBUG) +#if (NGX_HTTP_V2 || NGX_DEBUG) ngx_connection_t *c; c = ngx_ssl_get_connection(ssl_conn); @@ -342,12 +342,13 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, } #endif -#if (NGX_HTTP_SPDY) +#if (NGX_HTTP_V2) hc = c->data; - if (hc->addr_conf->spdy) { - srv = (unsigned char *) NGX_SPDY_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE; - srvlen = sizeof(NGX_SPDY_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1; + if (hc->addr_conf->http2) { + srv = + (unsigned char *) NGX_HTTP_V2_ALPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE; + srvlen = sizeof(NGX_HTTP_V2_ALPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1; } else #endif @@ -378,22 +379,23 @@ static int ngx_http_ssl_npn_advertised(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, unsigned int *outlen, void *arg) { -#if (NGX_HTTP_SPDY || NGX_DEBUG) +#if (NGX_HTTP_V2 || NGX_DEBUG) ngx_connection_t *c; c = ngx_ssl_get_connection(ssl_conn); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "SSL NPN advertised"); #endif -#if (NGX_HTTP_SPDY) +#if (NGX_HTTP_V2) { ngx_http_connection_t *hc; hc = c->data; - if (hc->addr_conf->spdy) { - *out = (unsigned char *) NGX_SPDY_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE; - *outlen = sizeof(NGX_SPDY_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1; + if (hc->addr_conf->http2) { + *out = + (unsigned char *) NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE; + *outlen = sizeof(NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1; return SSL_TLSEXT_ERR_OK; } diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c index 0a4ff6d..8ba75ed 100644 --- a/src/http/modules/ngx_http_sub_filter_module.c +++ b/src/http/modules/ngx_http_sub_filter_module.c @@ -853,8 +853,9 @@ ngx_http_sub_merge_conf(ngx_conf_t *cf, void *parent, void *child) conf->pairs = prev->pairs; conf->matches = prev->matches; conf->tables = prev->tables; + } - } else if (conf->dynamic == 0){ + if (conf->pairs && conf->dynamic == 0 && conf->tables == NULL) { pairs = conf->pairs->elts; n = conf->pairs->nelts; diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index 6b0a48f..d09e3f0 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1233,8 +1233,8 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, #if (NGX_HTTP_SSL) ngx_uint_t ssl; #endif -#if (NGX_HTTP_SPDY) - ngx_uint_t spdy; +#if (NGX_HTTP_V2) + ngx_uint_t http2; #endif /* @@ -1290,8 +1290,8 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, #if (NGX_HTTP_SSL) ssl = lsopt->ssl || addr[i].opt.ssl; #endif -#if (NGX_HTTP_SPDY) - spdy = lsopt->spdy || addr[i].opt.spdy; +#if (NGX_HTTP_V2) + http2 = lsopt->http2 || addr[i].opt.http2; #endif if (lsopt->set) { @@ -1324,8 +1324,8 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, #if (NGX_HTTP_SSL) addr[i].opt.ssl = ssl; #endif -#if (NGX_HTTP_SPDY) - addr[i].opt.spdy = spdy; +#if (NGX_HTTP_V2) + addr[i].opt.http2 = http2; #endif return NGX_OK; @@ -1357,14 +1357,17 @@ ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, } } -#if (NGX_HTTP_SPDY && NGX_HTTP_SSL \ +#if (NGX_HTTP_V2 && NGX_HTTP_SSL \ && !defined TLSEXT_TYPE_application_layer_protocol_negotiation \ && !defined TLSEXT_TYPE_next_proto_neg) - if (lsopt->spdy && lsopt->ssl) { + + if (lsopt->http2 && lsopt->ssl) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "nginx was built without OpenSSL ALPN or NPN " - "support, SPDY is not enabled for %s", lsopt->addr); + "nginx was built with OpenSSL that lacks ALPN " + "and NPN support, HTTP/2 is not enabled for %s", + lsopt->addr); } + #endif addr = ngx_array_push(&port->addrs); @@ -1856,8 +1859,8 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport, #if (NGX_HTTP_SSL) addrs[i].conf.ssl = addr[i].opt.ssl; #endif -#if (NGX_HTTP_SPDY) - addrs[i].conf.spdy = addr[i].opt.spdy; +#if (NGX_HTTP_V2) + addrs[i].conf.http2 = addr[i].opt.http2; #endif addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; @@ -1921,8 +1924,8 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport, #if (NGX_HTTP_SSL) addrs6[i].conf.ssl = addr[i].opt.ssl; #endif -#if (NGX_HTTP_SPDY) - addrs6[i].conf.spdy = addr[i].opt.spdy; +#if (NGX_HTTP_V2) + addrs6[i].conf.http2 = addr[i].opt.http2; #endif if (addr[i].hash.buckets == NULL diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index 844f502..19cb680 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -20,8 +20,8 @@ typedef struct ngx_http_file_cache_s ngx_http_file_cache_t; typedef struct ngx_http_log_ctx_s ngx_http_log_ctx_t; typedef struct ngx_http_chunked_s ngx_http_chunked_t; -#if (NGX_HTTP_SPDY) -typedef struct ngx_http_spdy_stream_s ngx_http_spdy_stream_t; +#if (NGX_HTTP_V2) +typedef struct ngx_http_v2_stream_s ngx_http_v2_stream_t; #endif typedef ngx_int_t (*ngx_http_header_handler_pt)(ngx_http_request_t *r, @@ -38,8 +38,8 @@ typedef u_char *(*ngx_http_log_handler_pt)(ngx_http_request_t *r, #include #include -#if (NGX_HTTP_SPDY) -#include +#if (NGX_HTTP_V2) +#include #endif #if (NGX_HTTP_CACHE) #include diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c index 0f908ad..c6d03ee 100644 --- a/src/http/ngx_http_copy_filter_module.c +++ b/src/http/ngx_http_copy_filter_module.c @@ -327,7 +327,7 @@ ngx_http_copy_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_copy_filter_conf_t *prev = parent; ngx_http_copy_filter_conf_t *conf = child; - ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 1, 32768); + ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 2, 32768); return NULL; } diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 22400ca..36f00f6 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -2132,13 +2132,6 @@ ngx_http_gzip_ok(ngx_http_request_t *r) return NGX_DECLINED; } -#if (NGX_HTTP_SPDY) - if (r->spdy_stream) { - r->gzip_ok = 1; - return NGX_OK; - } -#endif - ae = r->headers_in.accept_encoding; if (ae == NULL) { return NGX_DECLINED; @@ -2427,12 +2420,19 @@ ngx_http_subrequest(ngx_http_request_t *r, ngx_http_core_srv_conf_t *cscf; ngx_http_postponed_request_t *pr, *p; - r->main->subrequests--; - - if (r->main->subrequests == 0) { + if (r->subrequests == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "subrequests cycle while processing \"%V\"", uri); - r->main->subrequests = 1; + return NGX_ERROR; + } + + /* + * 1000 is reserved for other purposes. + */ + if (r->main->count >= 65535 - 1000) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + "request reference counter overflow " + "while processing \"%V\"", uri); return NGX_ERROR; } @@ -2473,8 +2473,8 @@ ngx_http_subrequest(ngx_http_request_t *r, sr->request_body = r->request_body; -#if (NGX_HTTP_SPDY) - sr->spdy_stream = r->spdy_stream; +#if (NGX_HTTP_V2) + sr->stream = r->stream; #endif sr->method = NGX_HTTP_GET; @@ -2537,6 +2537,7 @@ ngx_http_subrequest(ngx_http_request_t *r, sr->main_filter_need_in_memory = r->main_filter_need_in_memory; sr->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1; + sr->subrequests = r->subrequests - 1; tp = ngx_timeofday(); sr->start_sec = tp->sec; @@ -3188,7 +3189,7 @@ ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index]; - if (pclcf->name.len) { + if (cf->cmd_type == NGX_HTTP_LOC_CONF) { /* nested location */ @@ -4195,18 +4196,26 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } - if (ngx_strcmp(value[n].data, "spdy") == 0) { -#if (NGX_HTTP_SPDY) - lsopt.spdy = 1; + if (ngx_strcmp(value[n].data, "http2") == 0) { +#if (NGX_HTTP_V2) + lsopt.http2 = 1; continue; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the \"spdy\" parameter requires " - "ngx_http_spdy_module"); + "the \"http2\" parameter requires " + "ngx_http_v2_module"); return NGX_CONF_ERROR; #endif } + if (ngx_strcmp(value[n].data, "spdy") == 0) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "invalid parameter \"spdy\": " + "ngx_http_spdy_module was superseded " + "by ngx_http_v2_module"); + continue; + } + if (ngx_strncmp(value[n].data, "so_keepalive=", 13) == 0) { if (ngx_strcmp(&value[n].data[13], "on") == 0) { diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index e6be5ac..7dec9e1 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -79,8 +79,8 @@ typedef struct { #if (NGX_HTTP_SSL) unsigned ssl:1; #endif -#if (NGX_HTTP_SPDY) - unsigned spdy:1; +#if (NGX_HTTP_V2) + unsigned http2:1; #endif #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) unsigned ipv6only:1; @@ -248,8 +248,8 @@ struct ngx_http_addr_conf_s { #if (NGX_HTTP_SSL) unsigned ssl:1; #endif -#if (NGX_HTTP_SPDY) - unsigned spdy:1; +#if (NGX_HTTP_V2) + unsigned http2:1; #endif unsigned proxy_protocol:1; }; diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index fc14761..6633918 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -521,9 +521,12 @@ wakeup: static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c) { + u_char *p; time_t now; ssize_t n; + ngx_str_t *key; ngx_int_t rc; + ngx_uint_t i; ngx_http_file_cache_t *cache; ngx_http_file_cache_header_t *h; @@ -547,12 +550,27 @@ ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c) return NGX_DECLINED; } - if (h->crc32 != c->crc32) { + if (h->crc32 != c->crc32 || h->header_start != c->header_start) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, "cache file \"%s\" has md5 collision", c->file.name.data); return NGX_DECLINED; } + p = c->buf->pos + sizeof(ngx_http_file_cache_header_t) + + sizeof(ngx_http_file_cache_key); + + key = c->keys.elts; + for (i = 0; i < c->keys.nelts; i++) { + if (ngx_memcmp(p, key[i].data, key[i].len) != 0) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + "cache file \"%s\" has md5 collision", + c->file.name.data); + return NGX_DECLINED; + } + + p += key[i].len; + } + if ((size_t) h->body_start > c->body_start) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, "cache file \"%s\" has too long header", @@ -583,7 +601,6 @@ ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c) c->last_modified = h->last_modified; c->date = h->date; c->valid_msec = h->valid_msec; - c->header_start = h->header_start; c->body_start = h->body_start; c->etag.len = h->etag_len; c->etag.data = h->etag; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index cd5f302..9da972e 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -312,9 +312,9 @@ ngx_http_init_connection(ngx_connection_t *c) rev->handler = ngx_http_wait_request_handler; c->write->handler = ngx_http_empty_handler; -#if (NGX_HTTP_SPDY) - if (hc->addr_conf->spdy) { - rev->handler = ngx_http_spdy_init; +#if (NGX_HTTP_V2) + if (hc->addr_conf->http2) { + rev->handler = ngx_http_v2_init; } #endif @@ -764,13 +764,12 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c) c->ssl->no_wait_shutdown = 1; -#if (NGX_HTTP_SPDY \ +#if (NGX_HTTP_V2 \ && (defined TLSEXT_TYPE_application_layer_protocol_negotiation \ || defined TLSEXT_TYPE_next_proto_neg)) { - unsigned int len; - const unsigned char *data; - static const ngx_str_t spdy = ngx_string(NGX_SPDY_NPN_NEGOTIATED); + unsigned int len; + const unsigned char *data; #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation SSL_get0_alpn_selected(c->ssl->connection, &data, &len); @@ -785,8 +784,8 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c) SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len); #endif - if (len == spdy.len && ngx_strncmp(data, spdy.data, spdy.len) == 0) { - ngx_http_spdy_init(c->read); + if (len == 2 && data[0] == 'h' && data[1] == '2') { + ngx_http_v2_init(c->read); return; } } @@ -2338,7 +2337,6 @@ 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) { @@ -2500,8 +2498,8 @@ ngx_http_finalize_connection(ngx_http_request_t *r) { ngx_http_core_loc_conf_t *clcf; -#if (NGX_HTTP_SPDY) - if (r->spdy_stream) { +#if (NGX_HTTP_V2) + if (r->stream) { ngx_http_close_request(r, 0); return; } @@ -2566,8 +2564,8 @@ ngx_http_set_write_handler(ngx_http_request_t *r) ngx_http_test_reading; r->write_event_handler = ngx_http_writer; -#if (NGX_HTTP_SPDY) - if (r->spdy_stream) { +#if (NGX_HTTP_V2) + if (r->stream) { return NGX_OK; } #endif @@ -2657,8 +2655,8 @@ ngx_http_writer(ngx_http_request_t *r) if (r->buffered || r->postponed || (r == r->main && c->buffered)) { -#if (NGX_HTTP_SPDY) - if (r->spdy_stream) { +#if (NGX_HTTP_V2) + if (r->stream) { return; } #endif @@ -2725,9 +2723,9 @@ ngx_http_test_reading(ngx_http_request_t *r) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http test reading"); -#if (NGX_HTTP_SPDY) +#if (NGX_HTTP_V2) - if (r->spdy_stream) { + if (r->stream) { if (c->error) { err = 0; goto closed; @@ -3400,9 +3398,9 @@ ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc) return; } -#if (NGX_HTTP_SPDY) - if (r->spdy_stream) { - ngx_http_spdy_close_stream(r->spdy_stream, rc); +#if (NGX_HTTP_V2) + if (r->stream) { + ngx_http_v2_close_stream(r->stream, rc); return; } #endif diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 3954de3..967032a 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -10,7 +10,7 @@ #define NGX_HTTP_MAX_URI_CHANGES 10 -#define NGX_HTTP_MAX_SUBREQUESTS 200 +#define NGX_HTTP_MAX_SUBREQUESTS 50 /* must be 2^n */ #define NGX_HTTP_LC_HEADER_LEN 32 @@ -23,6 +23,7 @@ #define NGX_HTTP_VERSION_9 9 #define NGX_HTTP_VERSION_10 1000 #define NGX_HTTP_VERSION_11 1001 +#define NGX_HTTP_VERSION_20 2000 #define NGX_HTTP_UNKNOWN 0x0001 #define NGX_HTTP_GET 0x0002 @@ -431,16 +432,16 @@ struct ngx_http_request_s { ngx_uint_t err_status; ngx_http_connection_t *http_connection; -#if (NGX_HTTP_SPDY) - ngx_http_spdy_stream_t *spdy_stream; +#if (NGX_HTTP_V2) + ngx_http_v2_stream_t *stream; #endif ngx_http_log_handler_pt log_handler; ngx_http_cleanup_t *cleanup; + unsigned count:16; unsigned subrequests:8; - unsigned count:8; unsigned blocked:8; unsigned aio:1; diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c index 9c16984..77e92e3 100644 --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -40,10 +40,10 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, r->main->count++; -#if (NGX_HTTP_SPDY) - if (r->spdy_stream && r == r->main) { +#if (NGX_HTTP_V2) + if (r->stream && r == r->main) { r->request_body_no_buffering = 0; - rc = ngx_http_spdy_read_request_body(r, post_handler); + rc = ngx_http_v2_read_request_body(r, post_handler); goto done; } #endif @@ -570,9 +570,9 @@ ngx_http_discard_request_body(ngx_http_request_t *r) ngx_int_t rc; ngx_event_t *rev; -#if (NGX_HTTP_SPDY) - if (r->spdy_stream && r == r->main) { - r->spdy_stream->skip_data = NGX_SPDY_DATA_DISCARD; +#if (NGX_HTTP_V2) + if (r->stream && r == r->main) { + r->stream->skip_data = NGX_HTTP_V2_DATA_DISCARD; return NGX_OK; } #endif diff --git a/src/http/ngx_http_spdy.c b/src/http/ngx_http_spdy.c deleted file mode 100644 index 21c5217..0000000 --- a/src/http/ngx_http_spdy.c +++ /dev/null @@ -1,3701 +0,0 @@ - -/* - * Copyright (C) Nginx, Inc. - * Copyright (C) Valentin V. Bartenev - */ - - -#include -#include -#include -#include - -#include - - -#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) - -#define ngx_str5cmp(m, c0, c1, c2, c3, c4) \ - *(uint32_t *) m == (c3 << 24 | c2 << 16 | c1 << 8 | c0) \ - && m[4] == c4 - -#else - -#define ngx_str5cmp(m, c0, c1, c2, c3, c4) \ - m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 && m[4] == c4 - -#endif - - -#if (NGX_HAVE_NONALIGNED) - -#define ngx_spdy_frame_parse_uint16(p) ntohs(*(uint16_t *) (p)) -#define ngx_spdy_frame_parse_uint32(p) ntohl(*(uint32_t *) (p)) - -#else - -#define ngx_spdy_frame_parse_uint16(p) ((p)[0] << 8 | (p)[1]) -#define ngx_spdy_frame_parse_uint32(p) \ - ((p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3]) - -#endif - -#define ngx_spdy_frame_parse_sid(p) \ - (ngx_spdy_frame_parse_uint32(p) & 0x7fffffff) -#define ngx_spdy_frame_parse_delta(p) \ - (ngx_spdy_frame_parse_uint32(p) & 0x7fffffff) - - -#define ngx_spdy_ctl_frame_check(h) \ - (((h) & 0xffff0000) == ngx_spdy_ctl_frame_head(0)) -#define ngx_spdy_data_frame_check(h) \ - (!((h) & (uint32_t) NGX_SPDY_CTL_BIT << 31)) - -#define ngx_spdy_ctl_frame_type(h) ((h) & 0x0000ffff) -#define ngx_spdy_frame_flags(p) ((p) >> 24) -#define ngx_spdy_frame_length(p) ((p) & 0x00ffffff) -#define ngx_spdy_frame_id(p) ((p) & 0x00ffffff) - - -#define NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE 4096 -#define NGX_SPDY_CTL_FRAME_BUFFER_SIZE 16 - -#define NGX_SPDY_PROTOCOL_ERROR 1 -#define NGX_SPDY_INVALID_STREAM 2 -#define NGX_SPDY_REFUSED_STREAM 3 -#define NGX_SPDY_UNSUPPORTED_VERSION 4 -#define NGX_SPDY_CANCEL 5 -#define NGX_SPDY_INTERNAL_ERROR 6 -#define NGX_SPDY_FLOW_CONTROL_ERROR 7 -#define NGX_SPDY_STREAM_IN_USE 8 -#define NGX_SPDY_STREAM_ALREADY_CLOSED 9 -/* deprecated 10 */ -#define NGX_SPDY_FRAME_TOO_LARGE 11 - -#define NGX_SPDY_SETTINGS_MAX_STREAMS 4 -#define NGX_SPDY_SETTINGS_INIT_WINDOW 7 - -#define NGX_SPDY_SETTINGS_FLAG_PERSIST 0x01 -#define NGX_SPDY_SETTINGS_FLAG_PERSISTED 0x02 - -#define NGX_SPDY_MAX_WINDOW NGX_MAX_INT32_VALUE -#define NGX_SPDY_CONNECTION_WINDOW 65536 -#define NGX_SPDY_INIT_STREAM_WINDOW 65536 -#define NGX_SPDY_STREAM_WINDOW NGX_SPDY_MAX_WINDOW - -typedef struct { - ngx_uint_t hash; - u_char len; - u_char header[7]; - ngx_int_t (*handler)(ngx_http_request_t *r); -} ngx_http_spdy_request_header_t; - - -static void ngx_http_spdy_read_handler(ngx_event_t *rev); -static void ngx_http_spdy_write_handler(ngx_event_t *wev); -static void ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc); - -static u_char *ngx_http_spdy_proxy_protocol(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end); -static u_char *ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end); -static u_char *ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end); -static u_char *ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end); -static u_char *ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end); -static u_char *ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end); -static u_char *ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end); -static u_char *ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end); -static u_char *ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end); -static u_char *ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end); -static u_char *ngx_http_spdy_state_ping(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end); -static u_char *ngx_http_spdy_state_skip(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end); -static u_char *ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end); -static u_char *ngx_http_spdy_state_complete(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end); -static u_char *ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end, ngx_http_spdy_handler_pt handler); - -static u_char *ngx_http_spdy_state_inflate_error( - ngx_http_spdy_connection_t *sc, int rc); -static u_char *ngx_http_spdy_state_protocol_error( - ngx_http_spdy_connection_t *sc); -static u_char *ngx_http_spdy_state_internal_error( - ngx_http_spdy_connection_t *sc); - -static ngx_int_t ngx_http_spdy_send_window_update( - ngx_http_spdy_connection_t *sc, ngx_uint_t sid, ngx_uint_t delta); -static ngx_int_t ngx_http_spdy_send_rst_stream(ngx_http_spdy_connection_t *sc, - ngx_uint_t sid, ngx_uint_t status, ngx_uint_t priority); -static ngx_int_t ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc); -static ngx_int_t ngx_http_spdy_settings_frame_handler( - ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame); -static ngx_http_spdy_out_frame_t *ngx_http_spdy_get_ctl_frame( - ngx_http_spdy_connection_t *sc, size_t size, ngx_uint_t priority); -static ngx_int_t ngx_http_spdy_ctl_frame_handler( - ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame); - -static ngx_http_spdy_stream_t *ngx_http_spdy_create_stream( - ngx_http_spdy_connection_t *sc, ngx_uint_t id, ngx_uint_t priority); -static ngx_http_spdy_stream_t *ngx_http_spdy_get_stream_by_id( - ngx_http_spdy_connection_t *sc, ngx_uint_t sid); -#define ngx_http_spdy_streams_index_size(sscf) (sscf->streams_index_mask + 1) -#define ngx_http_spdy_stream_index(sscf, sid) \ - ((sid >> 1) & sscf->streams_index_mask) - -static ngx_int_t ngx_http_spdy_parse_header(ngx_http_request_t *r); -static ngx_int_t ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r); - -static ngx_int_t ngx_http_spdy_handle_request_header(ngx_http_request_t *r); -static ngx_int_t ngx_http_spdy_parse_method(ngx_http_request_t *r); -static ngx_int_t ngx_http_spdy_parse_scheme(ngx_http_request_t *r); -static ngx_int_t ngx_http_spdy_parse_host(ngx_http_request_t *r); -static ngx_int_t ngx_http_spdy_parse_path(ngx_http_request_t *r); -static ngx_int_t ngx_http_spdy_parse_version(ngx_http_request_t *r); - -static ngx_int_t ngx_http_spdy_construct_request_line(ngx_http_request_t *r); -static void ngx_http_spdy_run_request(ngx_http_request_t *r); -static ngx_int_t ngx_http_spdy_init_request_body(ngx_http_request_t *r); - -static ngx_int_t ngx_http_spdy_terminate_stream(ngx_http_spdy_connection_t *sc, - ngx_http_spdy_stream_t *stream, ngx_uint_t status); - -static void ngx_http_spdy_close_stream_handler(ngx_event_t *ev); - -static void ngx_http_spdy_handle_connection_handler(ngx_event_t *rev); -static void ngx_http_spdy_keepalive_handler(ngx_event_t *rev); -static void ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc, - ngx_int_t rc); - -static ngx_int_t ngx_http_spdy_adjust_windows(ngx_http_spdy_connection_t *sc, - ssize_t delta); - -static void ngx_http_spdy_pool_cleanup(void *data); - -static void *ngx_http_spdy_zalloc(void *opaque, u_int items, u_int size); -static void ngx_http_spdy_zfree(void *opaque, void *address); - - -static const u_char ngx_http_spdy_dict[] = { - 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, /* - - - - o p t i */ - 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, /* o n s - - - - h */ - 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, /* e a d - - - - p */ - 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, /* o s t - - - - p */ - 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, /* u t - - - - d e */ - 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, /* l e t e - - - - */ - 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, /* t r a c e - - - */ - 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, /* - a c c e p t - */ - 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, /* - - - a c c e p */ - 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, /* t - c h a r s e */ - 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, /* t - - - - a c c */ - 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, /* e p t - e n c o */ - 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, /* d i n g - - - - */ - 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, /* a c c e p t - l */ - 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, /* a n g u a g e - */ - 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, /* - - - a c c e p */ - 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, /* t - r a n g e s */ - 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, /* - - - - a g e - */ - 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, /* - - - a l l o w */ - 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, /* - - - - a u t h */ - 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, /* o r i z a t i o */ - 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, /* n - - - - c a c */ - 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, /* h e - c o n t r */ - 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, /* o l - - - - c o */ - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, /* n n e c t i o n */ - 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, /* - - - - c o n t */ - 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, /* e n t - b a s e */ - 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, /* - - - - c o n t */ - 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, /* e n t - e n c o */ - 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, /* d i n g - - - - */ - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, /* c o n t e n t - */ - 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, /* l a n g u a g e */ - 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, /* - - - - c o n t */ - 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, /* e n t - l e n g */ - 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, /* t h - - - - c o */ - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, /* n t e n t - l o */ - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, /* c a t i o n - - */ - 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, /* - - c o n t e n */ - 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, /* t - m d 5 - - - */ - 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, /* - c o n t e n t */ - 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, /* - r a n g e - - */ - 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, /* - - c o n t e n */ - 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, /* t - t y p e - - */ - 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, /* - - d a t e - - */ - 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, /* - - e t a g - - */ - 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, /* - - e x p e c t */ - 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, /* - - - - e x p i */ - 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, /* r e s - - - - f */ - 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, /* r o m - - - - h */ - 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, /* o s t - - - - i */ - 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, /* f - m a t c h - */ - 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, /* - - - i f - m o */ - 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, /* d i f i e d - s */ - 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, /* i n c e - - - - */ - 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, /* i f - n o n e - */ - 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, /* m a t c h - - - */ - 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, /* - i f - r a n g */ - 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, /* e - - - - i f - */ - 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, /* u n m o d i f i */ - 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, /* e d - s i n c e */ - 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, /* - - - - l a s t */ - 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, /* - m o d i f i e */ - 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, /* d - - - - l o c */ - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, /* a t i o n - - - */ - 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, /* - m a x - f o r */ - 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, /* w a r d s - - - */ - 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, /* - p r a g m a - */ - 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, /* - - - p r o x y */ - 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, /* - a u t h e n t */ - 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, /* i c a t e - - - */ - 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, /* - p r o x y - a */ - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, /* u t h o r i z a */ - 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, /* t i o n - - - - */ - 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, /* r a n g e - - - */ - 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, /* - r e f e r e r */ - 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, /* - - - - r e t r */ - 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, /* y - a f t e r - */ - 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, /* - - - s e r v e */ - 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, /* r - - - - t e - */ - 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, /* - - - t r a i l */ - 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, /* e r - - - - t r */ - 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, /* a n s f e r - e */ - 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, /* n c o d i n g - */ - 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, /* - - - u p g r a */ - 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, /* d e - - - - u s */ - 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, /* e r - a g e n t */ - 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, /* - - - - v a r y */ - 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, /* - - - - v i a - */ - 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, /* - - - w a r n i */ - 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, /* n g - - - - w w */ - 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, /* w - a u t h e n */ - 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, /* t i c a t e - - */ - 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, /* - - m e t h o d */ - 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, /* - - - - g e t - */ - 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, /* - - - s t a t u */ - 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, /* s - - - - 2 0 0 */ - 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, /* - O K - - - - v */ - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, /* e r s i o n - - */ - 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, /* - - H T T P - 1 */ - 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, /* - 1 - - - - u r */ - 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, /* l - - - - p u b */ - 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, /* l i c - - - - s */ - 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, /* e t - c o o k i */ - 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, /* e - - - - k e e */ - 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, /* p - a l i v e - */ - 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, /* - - - o r i g i */ - 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, /* n 1 0 0 1 0 1 2 */ - 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, /* 0 1 2 0 2 2 0 5 */ - 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, /* 2 0 6 3 0 0 3 0 */ - 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, /* 2 3 0 3 3 0 4 3 */ - 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, /* 0 5 3 0 6 3 0 7 */ - 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, /* 4 0 2 4 0 5 4 0 */ - 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, /* 6 4 0 7 4 0 8 4 */ - 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, /* 0 9 4 1 0 4 1 1 */ - 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, /* 4 1 2 4 1 3 4 1 */ - 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, /* 4 4 1 5 4 1 6 4 */ - 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, /* 1 7 5 0 2 5 0 4 */ - 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, /* 5 0 5 2 0 3 - N */ - 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, /* o n - A u t h o */ - 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, /* r i t a t i v e */ - 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, /* - I n f o r m a */ - 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, /* t i o n 2 0 4 - */ - 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, /* N o - C o n t e */ - 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, /* n t 3 0 1 - M o */ - 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, /* v e d - P e r m */ - 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, /* a n e n t l y 4 */ - 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, /* 0 0 - B a d - R */ - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, /* e q u e s t 4 0 */ - 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, /* 1 - U n a u t h */ - 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, /* o r i z e d 4 0 */ - 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, /* 3 - F o r b i d */ - 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, /* d e n 4 0 4 - N */ - 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, /* o t - F o u n d */ - 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, /* 5 0 0 - I n t e */ - 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, /* r n a l - S e r */ - 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, /* v e r - E r r o */ - 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, /* r 5 0 1 - N o t */ - 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, /* - I m p l e m e */ - 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, /* n t e d 5 0 3 - */ - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, /* S e r v i c e - */ - 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, /* U n a v a i l a */ - 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, /* b l e J a n - F */ - 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, /* e b - M a r - A */ - 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, /* p r - M a y - J */ - 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, /* u n - J u l - A */ - 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, /* u g - S e p t - */ - 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, /* O c t - N o v - */ - 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, /* D e c - 0 0 - 0 */ - 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, /* 0 - 0 0 - M o n */ - 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, /* - - T u e - - W */ - 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, /* e d - - T h u - */ - 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, /* - F r i - - S a */ - 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, /* t - - S u n - - */ - 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, /* G M T c h u n k */ - 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, /* e d - t e x t - */ - 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, /* h t m l - i m a */ - 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, /* g e - p n g - i */ - 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, /* m a g e - j p g */ - 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, /* - i m a g e - g */ - 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, /* i f - a p p l i */ - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, /* c a t i o n - x */ - 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, /* m l - a p p l i */ - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, /* c a t i o n - x */ - 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, /* h t m l - x m l */ - 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, /* - t e x t - p l */ - 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, /* a i n - t e x t */ - 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, /* - j a v a s c r */ - 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, /* i p t - p u b l */ - 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, /* i c p r i v a t */ - 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, /* e m a x - a g e */ - 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, /* - g z i p - d e */ - 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, /* f l a t e - s d */ - 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, /* c h c h a r s e */ - 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, /* t - u t f - 8 c */ - 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, /* h a r s e t - i */ - 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, /* s o - 8 8 5 9 - */ - 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, /* 1 - u t f - - - */ - 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e /* - e n q - 0 - */ -}; - - -static ngx_http_spdy_request_header_t ngx_http_spdy_request_headers[] = { - { 0, 6, "method", ngx_http_spdy_parse_method }, - { 0, 6, "scheme", ngx_http_spdy_parse_scheme }, - { 0, 4, "host", ngx_http_spdy_parse_host }, - { 0, 4, "path", ngx_http_spdy_parse_path }, - { 0, 7, "version", ngx_http_spdy_parse_version }, -}; - -#define NGX_SPDY_REQUEST_HEADERS \ - (sizeof(ngx_http_spdy_request_headers) \ - / sizeof(ngx_http_spdy_request_header_t)) - - -void -ngx_http_spdy_init(ngx_event_t *rev) -{ - int rc; - ngx_connection_t *c; - ngx_pool_cleanup_t *cln; - ngx_http_connection_t *hc; - ngx_http_spdy_srv_conf_t *sscf; - ngx_http_spdy_main_conf_t *smcf; - ngx_http_spdy_connection_t *sc; - - c = rev->data; - hc = c->data; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "init spdy request"); - - c->log->action = "processing SPDY"; - - smcf = ngx_http_get_module_main_conf(hc->conf_ctx, ngx_http_spdy_module); - - if (smcf->recv_buffer == NULL) { - smcf->recv_buffer = ngx_palloc(ngx_cycle->pool, smcf->recv_buffer_size); - if (smcf->recv_buffer == NULL) { - ngx_http_close_connection(c); - return; - } - } - - sc = ngx_pcalloc(c->pool, sizeof(ngx_http_spdy_connection_t)); - if (sc == NULL) { - ngx_http_close_connection(c); - return; - } - - sc->connection = c; - sc->http_connection = hc; - - sc->send_window = NGX_SPDY_CONNECTION_WINDOW; - sc->recv_window = NGX_SPDY_CONNECTION_WINDOW; - - sc->init_window = NGX_SPDY_INIT_STREAM_WINDOW; - - sc->handler = hc->proxy_protocol ? ngx_http_spdy_proxy_protocol - : ngx_http_spdy_state_head; - - sc->zstream_in.zalloc = ngx_http_spdy_zalloc; - sc->zstream_in.zfree = ngx_http_spdy_zfree; - sc->zstream_in.opaque = sc; - - rc = inflateInit(&sc->zstream_in); - if (rc != Z_OK) { - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "inflateInit() failed: %d", rc); - ngx_http_close_connection(c); - return; - } - - sc->zstream_out.zalloc = ngx_http_spdy_zalloc; - sc->zstream_out.zfree = ngx_http_spdy_zfree; - sc->zstream_out.opaque = sc; - - sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_spdy_module); - - rc = deflateInit2(&sc->zstream_out, (int) sscf->headers_comp, - Z_DEFLATED, 11, 4, Z_DEFAULT_STRATEGY); - - if (rc != Z_OK) { - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "deflateInit2() failed: %d", rc); - ngx_http_close_connection(c); - return; - } - - rc = deflateSetDictionary(&sc->zstream_out, ngx_http_spdy_dict, - sizeof(ngx_http_spdy_dict)); - if (rc != Z_OK) { - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "deflateSetDictionary() failed: %d", rc); - ngx_http_close_connection(c); - return; - } - - sc->pool = ngx_create_pool(sscf->pool_size, sc->connection->log); - if (sc->pool == NULL) { - ngx_http_close_connection(c); - return; - } - - cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_pool_cleanup_file_t)); - if (cln == NULL) { - ngx_http_close_connection(c); - return; - } - - cln->handler = ngx_http_spdy_pool_cleanup; - cln->data = sc; - - sc->streams_index = ngx_pcalloc(sc->pool, - ngx_http_spdy_streams_index_size(sscf) - * sizeof(ngx_http_spdy_stream_t *)); - if (sc->streams_index == NULL) { - ngx_http_close_connection(c); - return; - } - - if (ngx_http_spdy_send_settings(sc) == NGX_ERROR) { - ngx_http_close_connection(c); - return; - } - - if (ngx_http_spdy_send_window_update(sc, 0, NGX_SPDY_MAX_WINDOW - - sc->recv_window) - == NGX_ERROR) - { - ngx_http_close_connection(c); - return; - } - - sc->recv_window = NGX_SPDY_MAX_WINDOW; - - ngx_queue_init(&sc->waiting); - ngx_queue_init(&sc->posted); - - c->data = sc; - - rev->handler = ngx_http_spdy_read_handler; - c->write->handler = ngx_http_spdy_write_handler; - - ngx_http_spdy_read_handler(rev); -} - - -static void -ngx_http_spdy_read_handler(ngx_event_t *rev) -{ - u_char *p, *end; - size_t available; - ssize_t n; - ngx_connection_t *c; - ngx_http_spdy_main_conf_t *smcf; - ngx_http_spdy_connection_t *sc; - - c = rev->data; - sc = c->data; - - if (rev->timedout) { - ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); - ngx_http_spdy_finalize_connection(sc, NGX_HTTP_REQUEST_TIME_OUT); - return; - } - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy read handler"); - - sc->blocked = 1; - - smcf = ngx_http_get_module_main_conf(sc->http_connection->conf_ctx, - ngx_http_spdy_module); - - available = smcf->recv_buffer_size - 2 * NGX_SPDY_STATE_BUFFER_SIZE; - - do { - p = smcf->recv_buffer; - - ngx_memcpy(p, sc->buffer, NGX_SPDY_STATE_BUFFER_SIZE); - end = p + sc->buffer_used; - - n = c->recv(c, end, available); - - if (n == NGX_AGAIN) { - break; - } - - if (n == 0 && (sc->incomplete || sc->processing)) { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client prematurely closed connection"); - } - - if (n == 0 || n == NGX_ERROR) { - ngx_http_spdy_finalize_connection(sc, - NGX_HTTP_CLIENT_CLOSED_REQUEST); - return; - } - - end += n; - - sc->buffer_used = 0; - sc->incomplete = 0; - - do { - p = sc->handler(sc, p, end); - - if (p == NULL) { - return; - } - - } while (p != end); - - } while (rev->ready); - - if (ngx_handle_read_event(rev, 0) != NGX_OK) { - ngx_http_spdy_finalize_connection(sc, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - if (sc->last_out && ngx_http_spdy_send_output_queue(sc) == NGX_ERROR) { - ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST); - return; - } - - sc->blocked = 0; - - if (sc->processing) { - if (rev->timer_set) { - ngx_del_timer(rev); - } - return; - } - - ngx_http_spdy_handle_connection(sc); -} - - -static void -ngx_http_spdy_write_handler(ngx_event_t *wev) -{ - ngx_int_t rc; - ngx_queue_t *q; - ngx_connection_t *c; - ngx_http_spdy_stream_t *stream; - ngx_http_spdy_connection_t *sc; - - c = wev->data; - sc = c->data; - - if (wev->timedout) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "spdy write event timed out"); - ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST); - return; - } - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy write handler"); - - sc->blocked = 1; - - rc = ngx_http_spdy_send_output_queue(sc); - - if (rc == NGX_ERROR) { - ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST); - return; - } - - while (!ngx_queue_empty(&sc->posted)) { - q = ngx_queue_head(&sc->posted); - - ngx_queue_remove(q); - - stream = ngx_queue_data(q, ngx_http_spdy_stream_t, queue); - - stream->handled = 0; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "run spdy stream %ui", stream->id); - - wev = stream->request->connection->write; - wev->handler(wev); - } - - sc->blocked = 0; - - if (rc == NGX_AGAIN) { - return; - } - - ngx_http_spdy_handle_connection(sc); -} - - -ngx_int_t -ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc) -{ - int tcp_nodelay; - ngx_chain_t *cl; - ngx_event_t *wev; - ngx_connection_t *c; - ngx_http_core_loc_conf_t *clcf; - ngx_http_spdy_out_frame_t *out, *frame, *fn; - - c = sc->connection; - - if (c->error) { - return NGX_ERROR; - } - - wev = c->write; - - if (!wev->ready) { - return NGX_OK; - } - - cl = NULL; - out = NULL; - - for (frame = sc->last_out; frame; frame = fn) { - frame->last->next = cl; - cl = frame->first; - - fn = frame->next; - frame->next = out; - out = frame; - - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0, - "spdy frame out: %p sid:%ui prio:%ui bl:%d len:%uz", - out, out->stream ? out->stream->id : 0, out->priority, - out->blocked, out->length); - } - - cl = c->send_chain(c, cl, 0); - - if (cl == NGX_CHAIN_ERROR) { - goto error; - } - - clcf = ngx_http_get_module_loc_conf(sc->http_connection->conf_ctx, - ngx_http_core_module); - - if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { - goto error; - } - - if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) { - if (ngx_tcp_push(c->fd) == -1) { - ngx_connection_error(c, ngx_socket_errno, ngx_tcp_push_n " failed"); - goto error; - } - - c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; - tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0; - - } else { - tcp_nodelay = 1; - } - - if (tcp_nodelay - && clcf->tcp_nodelay - && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) - { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); - - if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, - (const void *) &tcp_nodelay, sizeof(int)) - == -1) - { -#if (NGX_SOLARIS) - /* Solaris returns EINVAL if a socket has been shut down */ - c->log_error = NGX_ERROR_IGNORE_EINVAL; -#endif - - ngx_connection_error(c, ngx_socket_errno, - "setsockopt(TCP_NODELAY) failed"); - - c->log_error = NGX_ERROR_INFO; - goto error; - } - - c->tcp_nodelay = NGX_TCP_NODELAY_SET; - } - - if (cl) { - ngx_add_timer(wev, clcf->send_timeout); - - } else { - if (wev->timer_set) { - ngx_del_timer(wev); - } - } - - for ( /* void */ ; out; out = fn) { - fn = out->next; - - if (out->handler(sc, out) != NGX_OK) { - out->blocked = 1; - out->priority = NGX_SPDY_HIGHEST_PRIORITY; - break; - } - - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0, - "spdy frame sent: %p sid:%ui bl:%d len:%uz", - out, out->stream ? out->stream->id : 0, - out->blocked, out->length); - } - - frame = NULL; - - for ( /* void */ ; out; out = fn) { - fn = out->next; - out->next = frame; - frame = out; - } - - sc->last_out = frame; - - return NGX_OK; - -error: - - c->error = 1; - - if (!sc->blocked) { - ngx_post_event(wev, &ngx_posted_events); - } - - return NGX_ERROR; -} - - -static void -ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc) -{ - ngx_connection_t *c; - ngx_http_spdy_srv_conf_t *sscf; - - if (sc->last_out || sc->processing) { - return; - } - - c = sc->connection; - - if (c->error) { - ngx_http_close_connection(c); - return; - } - - if (c->buffered) { - return; - } - - sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx, - ngx_http_spdy_module); - if (sc->incomplete) { - ngx_add_timer(c->read, sscf->recv_timeout); - return; - } - - if (ngx_terminate || ngx_exiting) { - ngx_http_close_connection(c); - return; - } - - ngx_destroy_pool(sc->pool); - - sc->pool = NULL; - sc->free_ctl_frames = NULL; - sc->free_fake_connections = NULL; - -#if (NGX_HTTP_SSL) - if (c->ssl) { - ngx_ssl_free_buffer(c); - } -#endif - - c->destroyed = 1; - c->idle = 1; - ngx_reusable_connection(c, 1); - - c->write->handler = ngx_http_empty_handler; - c->read->handler = ngx_http_spdy_keepalive_handler; - - if (c->write->timer_set) { - ngx_del_timer(c->write); - } - - ngx_add_timer(c->read, sscf->keepalive_timeout); -} - - -static u_char * -ngx_http_spdy_proxy_protocol(ngx_http_spdy_connection_t *sc, u_char *pos, - u_char *end) -{ - ngx_log_t *log; - - log = sc->connection->log; - log->action = "reading PROXY protocol"; - - pos = ngx_proxy_protocol_read(sc->connection, pos, end); - - log->action = "processing SPDY"; - - if (pos == NULL) { - return ngx_http_spdy_state_protocol_error(sc); - } - - return ngx_http_spdy_state_complete(sc, pos, end); -} - - -static u_char * -ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos, - u_char *end) -{ - uint32_t head, flen; - ngx_uint_t type; - - if (end - pos < NGX_SPDY_FRAME_HEADER_SIZE) { - return ngx_http_spdy_state_save(sc, pos, end, - ngx_http_spdy_state_head); - } - - head = ngx_spdy_frame_parse_uint32(pos); - - pos += sizeof(uint32_t); - - flen = ngx_spdy_frame_parse_uint32(pos); - - sc->flags = ngx_spdy_frame_flags(flen); - sc->length = ngx_spdy_frame_length(flen); - - pos += sizeof(uint32_t); - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "process spdy frame head:%08XD f:%Xd l:%uz", - head, sc->flags, sc->length); - - if (ngx_spdy_ctl_frame_check(head)) { - type = ngx_spdy_ctl_frame_type(head); - - switch (type) { - - case NGX_SPDY_SYN_STREAM: - return ngx_http_spdy_state_syn_stream(sc, pos, end); - - case NGX_SPDY_SYN_REPLY: - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client sent unexpected SYN_REPLY frame"); - return ngx_http_spdy_state_protocol_error(sc); - - case NGX_SPDY_RST_STREAM: - return ngx_http_spdy_state_rst_stream(sc, pos, end); - - case NGX_SPDY_SETTINGS: - return ngx_http_spdy_state_settings(sc, pos, end); - - case NGX_SPDY_PING: - return ngx_http_spdy_state_ping(sc, pos, end); - - case NGX_SPDY_GOAWAY: - return ngx_http_spdy_state_skip(sc, pos, end); /* TODO */ - - case NGX_SPDY_HEADERS: - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client sent unexpected HEADERS frame"); - return ngx_http_spdy_state_protocol_error(sc); - - case NGX_SPDY_WINDOW_UPDATE: - return ngx_http_spdy_state_window_update(sc, pos, end); - - default: - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy control frame with unknown type %ui", type); - return ngx_http_spdy_state_skip(sc, pos, end); - } - } - - if (ngx_spdy_data_frame_check(head)) { - sc->stream = ngx_http_spdy_get_stream_by_id(sc, head); - return ngx_http_spdy_state_data(sc, pos, end); - } - - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client sent invalid frame"); - - return ngx_http_spdy_state_protocol_error(sc); -} - - -static u_char * -ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, u_char *pos, - u_char *end) -{ - ngx_uint_t sid, prio; - ngx_http_spdy_stream_t *stream; - ngx_http_spdy_srv_conf_t *sscf; - - if (end - pos < NGX_SPDY_SYN_STREAM_SIZE) { - return ngx_http_spdy_state_save(sc, pos, end, - ngx_http_spdy_state_syn_stream); - } - - if (sc->length <= NGX_SPDY_SYN_STREAM_SIZE) { - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client sent SYN_STREAM frame with incorrect length %uz", - sc->length); - - return ngx_http_spdy_state_protocol_error(sc); - } - - sc->length -= NGX_SPDY_SYN_STREAM_SIZE; - - sid = ngx_spdy_frame_parse_sid(pos); - prio = pos[8] >> 5; - - pos += NGX_SPDY_SYN_STREAM_SIZE; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy SYN_STREAM frame sid:%ui prio:%ui", sid, prio); - - if (sid % 2 == 0 || sid <= sc->last_sid) { - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client sent SYN_STREAM frame " - "with invalid Stream-ID %ui", sid); - - stream = ngx_http_spdy_get_stream_by_id(sc, sid); - - if (stream) { - if (ngx_http_spdy_terminate_stream(sc, stream, - NGX_SPDY_PROTOCOL_ERROR) - != NGX_OK) - { - return ngx_http_spdy_state_internal_error(sc); - } - } - - return ngx_http_spdy_state_protocol_error(sc); - } - - sc->last_sid = sid; - - sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx, - ngx_http_spdy_module); - - if (sc->processing >= sscf->concurrent_streams) { - - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "concurrent streams exceeded %ui", sc->processing); - - if (ngx_http_spdy_send_rst_stream(sc, sid, NGX_SPDY_REFUSED_STREAM, - prio) - != NGX_OK) - { - return ngx_http_spdy_state_internal_error(sc); - } - - return ngx_http_spdy_state_headers_skip(sc, pos, end); - } - - stream = ngx_http_spdy_create_stream(sc, sid, prio); - if (stream == NULL) { - return ngx_http_spdy_state_internal_error(sc); - } - - stream->in_closed = (sc->flags & NGX_SPDY_FLAG_FIN) ? 1 : 0; - - stream->request->request_length = NGX_SPDY_FRAME_HEADER_SIZE - + NGX_SPDY_SYN_STREAM_SIZE - + sc->length; - - sc->stream = stream; - - return ngx_http_spdy_state_headers(sc, pos, end); -} - - -static u_char * -ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, - u_char *end) -{ - int z; - size_t size; - ngx_buf_t *buf; - ngx_int_t rc; - ngx_http_request_t *r; - - size = end - pos; - - if (size == 0) { - return ngx_http_spdy_state_save(sc, pos, end, - ngx_http_spdy_state_headers); - } - - if (size > sc->length) { - size = sc->length; - } - - r = sc->stream->request; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "process spdy header block %uz of %uz", size, sc->length); - - buf = r->header_in; - - sc->zstream_in.next_in = pos; - sc->zstream_in.avail_in = size; - sc->zstream_in.next_out = buf->last; - - /* one byte is reserved for null-termination of the last header value */ - sc->zstream_in.avail_out = buf->end - buf->last - 1; - - z = inflate(&sc->zstream_in, Z_NO_FLUSH); - - if (z == Z_NEED_DICT) { - z = inflateSetDictionary(&sc->zstream_in, ngx_http_spdy_dict, - sizeof(ngx_http_spdy_dict)); - - if (z != Z_OK) { - if (z == Z_DATA_ERROR) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent SYN_STREAM frame with header " - "block encoded using wrong dictionary: %ul", - (u_long) sc->zstream_in.adler); - - return ngx_http_spdy_state_protocol_error(sc); - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "inflateSetDictionary() failed: %d", z); - - return ngx_http_spdy_state_internal_error(sc); - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy inflateSetDictionary(): %d", z); - - z = sc->zstream_in.avail_in ? inflate(&sc->zstream_in, Z_NO_FLUSH) - : Z_OK; - } - - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d", - sc->zstream_in.next_in, sc->zstream_in.next_out, - sc->zstream_in.avail_in, sc->zstream_in.avail_out, - z); - - if (z != Z_OK) { - return ngx_http_spdy_state_inflate_error(sc, z); - } - - sc->length -= sc->zstream_in.next_in - pos; - pos = sc->zstream_in.next_in; - - buf->last = sc->zstream_in.next_out; - - if (r->headers_in.headers.part.elts == NULL) { - - if (buf->last - buf->pos < NGX_SPDY_NV_NUM_SIZE) { - - if (sc->length == 0) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "premature end of spdy header block"); - - return ngx_http_spdy_state_headers_error(sc, pos, end); - } - - return ngx_http_spdy_state_save(sc, pos, end, - ngx_http_spdy_state_headers); - } - - sc->entries = ngx_spdy_frame_parse_uint32(buf->pos); - - buf->pos += NGX_SPDY_NV_NUM_SIZE; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy header block has %ui entries", - sc->entries); - - if (ngx_list_init(&r->headers_in.headers, r->pool, 20, - sizeof(ngx_table_elt_t)) - != NGX_OK) - { - ngx_http_spdy_close_stream(sc->stream, - NGX_HTTP_INTERNAL_SERVER_ERROR); - return ngx_http_spdy_state_headers_skip(sc, pos, end); - } - - if (ngx_array_init(&r->headers_in.cookies, r->pool, 2, - sizeof(ngx_table_elt_t *)) - != NGX_OK) - { - ngx_http_spdy_close_stream(sc->stream, - NGX_HTTP_INTERNAL_SERVER_ERROR); - return ngx_http_spdy_state_headers_skip(sc, pos, end); - } - } - - while (sc->entries) { - - rc = ngx_http_spdy_parse_header(r); - - switch (rc) { - - case NGX_DONE: - sc->entries--; - - case NGX_OK: - break; - - case NGX_AGAIN: - - if (sc->zstream_in.avail_in) { - - rc = ngx_http_spdy_alloc_large_header_buffer(r); - - if (rc == NGX_DECLINED) { - ngx_http_finalize_request(r, - NGX_HTTP_REQUEST_HEADER_TOO_LARGE); - return ngx_http_spdy_state_headers_skip(sc, pos, end); - } - - if (rc != NGX_OK) { - ngx_http_spdy_close_stream(sc->stream, - NGX_HTTP_INTERNAL_SERVER_ERROR); - return ngx_http_spdy_state_headers_skip(sc, pos, end); - } - - /* null-terminate the last processed header name or value */ - *buf->pos = '\0'; - - buf = r->header_in; - - sc->zstream_in.next_out = buf->last; - - /* one byte is reserved for null-termination */ - sc->zstream_in.avail_out = buf->end - buf->last - 1; - - z = inflate(&sc->zstream_in, Z_NO_FLUSH); - - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d", - sc->zstream_in.next_in, sc->zstream_in.next_out, - sc->zstream_in.avail_in, sc->zstream_in.avail_out, - z); - - if (z != Z_OK) { - return ngx_http_spdy_state_inflate_error(sc, z); - } - - sc->length -= sc->zstream_in.next_in - pos; - pos = sc->zstream_in.next_in; - - buf->last = sc->zstream_in.next_out; - - continue; - } - - if (sc->length == 0) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "premature end of spdy header block"); - - return ngx_http_spdy_state_headers_error(sc, pos, end); - } - - return ngx_http_spdy_state_save(sc, pos, end, - ngx_http_spdy_state_headers); - - case NGX_HTTP_PARSE_INVALID_HEADER: - ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); - return ngx_http_spdy_state_headers_skip(sc, pos, end); - - default: /* NGX_ERROR */ - return ngx_http_spdy_state_headers_error(sc, pos, end); - } - - /* a header line has been parsed successfully */ - - rc = ngx_http_spdy_handle_request_header(r); - - if (rc != NGX_OK) { - if (rc == NGX_HTTP_PARSE_INVALID_HEADER) { - ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); - return ngx_http_spdy_state_headers_skip(sc, pos, end); - } - - if (rc != NGX_ABORT) { - ngx_http_spdy_close_stream(sc->stream, - NGX_HTTP_INTERNAL_SERVER_ERROR); - } - - return ngx_http_spdy_state_headers_skip(sc, pos, end); - } - } - - if (buf->pos != buf->last || sc->zstream_in.avail_in) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "incorrect number of spdy header block entries"); - - return ngx_http_spdy_state_headers_error(sc, pos, end); - } - - if (sc->length) { - return ngx_http_spdy_state_save(sc, pos, end, - ngx_http_spdy_state_headers); - } - - /* null-terminate the last header value */ - *buf->pos = '\0'; - - ngx_http_spdy_run_request(r); - - return ngx_http_spdy_state_complete(sc, pos, end); -} - - -static u_char * -ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos, - u_char *end) -{ - int n; - size_t size; - u_char buffer[NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE]; - - if (sc->length == 0) { - return ngx_http_spdy_state_complete(sc, pos, end); - } - - size = end - pos; - - if (size == 0) { - return ngx_http_spdy_state_save(sc, pos, end, - ngx_http_spdy_state_headers_skip); - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy header block skip %uz of %uz", size, sc->length); - - sc->zstream_in.next_in = pos; - sc->zstream_in.avail_in = (size < sc->length) ? size : sc->length; - - while (sc->zstream_in.avail_in) { - sc->zstream_in.next_out = buffer; - sc->zstream_in.avail_out = NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE; - - n = inflate(&sc->zstream_in, Z_NO_FLUSH); - - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d", - sc->zstream_in.next_in, sc->zstream_in.next_out, - sc->zstream_in.avail_in, sc->zstream_in.avail_out, - n); - - if (n != Z_OK) { - return ngx_http_spdy_state_inflate_error(sc, n); - } - } - - pos = sc->zstream_in.next_in; - - if (size < sc->length) { - sc->length -= size; - return ngx_http_spdy_state_save(sc, pos, end, - ngx_http_spdy_state_headers_skip); - } - - return ngx_http_spdy_state_complete(sc, pos, end); -} - - -static u_char * -ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc, u_char *pos, - u_char *end) -{ - ngx_http_spdy_stream_t *stream; - - stream = sc->stream; - - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client sent SYN_STREAM frame for stream %ui " - "with invalid header block", stream->id); - - if (ngx_http_spdy_send_rst_stream(sc, stream->id, NGX_SPDY_PROTOCOL_ERROR, - stream->priority) - != NGX_OK) - { - return ngx_http_spdy_state_internal_error(sc); - } - - stream->out_closed = 1; - - ngx_http_spdy_close_stream(stream, NGX_HTTP_BAD_REQUEST); - - return ngx_http_spdy_state_headers_skip(sc, pos, end); -} - - -static u_char * -ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, u_char *pos, - u_char *end) -{ - size_t delta; - ngx_uint_t sid; - ngx_event_t *wev; - ngx_queue_t *q; - ngx_http_spdy_stream_t *stream; - - if (end - pos < NGX_SPDY_WINDOW_UPDATE_SIZE) { - return ngx_http_spdy_state_save(sc, pos, end, - ngx_http_spdy_state_window_update); - } - - if (sc->length != NGX_SPDY_WINDOW_UPDATE_SIZE) { - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client sent WINDOW_UPDATE frame " - "with incorrect length %uz", sc->length); - - return ngx_http_spdy_state_protocol_error(sc); - } - - sid = ngx_spdy_frame_parse_sid(pos); - - pos += NGX_SPDY_SID_SIZE; - - delta = ngx_spdy_frame_parse_delta(pos); - - pos += NGX_SPDY_DELTA_SIZE; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy WINDOW_UPDATE sid:%ui delta:%uz", sid, delta); - - if (sid) { - stream = ngx_http_spdy_get_stream_by_id(sc, sid); - - if (stream == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "unknown spdy stream"); - - return ngx_http_spdy_state_complete(sc, pos, end); - } - - if (stream->send_window > (ssize_t) (NGX_SPDY_MAX_WINDOW - delta)) { - - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client violated flow control for stream %ui: " - "received WINDOW_UPDATE frame with delta %uz " - "not allowed for window %z", - sid, delta, stream->send_window); - - if (ngx_http_spdy_terminate_stream(sc, stream, - NGX_SPDY_FLOW_CONTROL_ERROR) - == NGX_ERROR) - { - return ngx_http_spdy_state_internal_error(sc); - } - - return ngx_http_spdy_state_complete(sc, pos, end); - } - - stream->send_window += delta; - - if (stream->exhausted) { - stream->exhausted = 0; - - wev = stream->request->connection->write; - - if (!wev->timer_set) { - wev->delayed = 0; - wev->handler(wev); - } - } - - } else { - sc->send_window += delta; - - if (sc->send_window > NGX_SPDY_MAX_WINDOW) { - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client violated connection flow control: " - "received WINDOW_UPDATE frame with delta %uz " - "not allowed for window %uz", - delta, sc->send_window); - - return ngx_http_spdy_state_protocol_error(sc); - } - - while (!ngx_queue_empty(&sc->waiting)) { - q = ngx_queue_head(&sc->waiting); - - ngx_queue_remove(q); - - stream = ngx_queue_data(q, ngx_http_spdy_stream_t, queue); - - stream->handled = 0; - - wev = stream->request->connection->write; - - if (!wev->timer_set) { - wev->delayed = 0; - wev->handler(wev); - - if (sc->send_window == 0) { - break; - } - } - } - } - - return ngx_http_spdy_state_complete(sc, pos, end); -} - - -static u_char * -ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos, - u_char *end) -{ - ngx_http_spdy_stream_t *stream; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy DATA frame"); - - if (sc->length > sc->recv_window) { - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client violated connection flow control: " - "received DATA frame length %uz, available window %uz", - sc->length, sc->recv_window); - - return ngx_http_spdy_state_protocol_error(sc); - } - - sc->recv_window -= sc->length; - - if (sc->recv_window < NGX_SPDY_MAX_WINDOW / 4) { - - if (ngx_http_spdy_send_window_update(sc, 0, - NGX_SPDY_MAX_WINDOW - - sc->recv_window) - == NGX_ERROR) - { - return ngx_http_spdy_state_internal_error(sc); - } - - sc->recv_window = NGX_SPDY_MAX_WINDOW; - } - - stream = sc->stream; - - if (stream == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "unknown spdy stream"); - - return ngx_http_spdy_state_skip(sc, pos, end); - } - - if (sc->length > stream->recv_window) { - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client violated flow control for stream %ui: " - "received DATA frame length %uz, available window %uz", - stream->id, sc->length, stream->recv_window); - - if (ngx_http_spdy_terminate_stream(sc, stream, - NGX_SPDY_FLOW_CONTROL_ERROR) - == NGX_ERROR) - { - return ngx_http_spdy_state_internal_error(sc); - } - - return ngx_http_spdy_state_skip(sc, pos, end); - } - - stream->recv_window -= sc->length; - - if (stream->recv_window < NGX_SPDY_STREAM_WINDOW / 4) { - - if (ngx_http_spdy_send_window_update(sc, stream->id, - NGX_SPDY_STREAM_WINDOW - - stream->recv_window) - == NGX_ERROR) - { - return ngx_http_spdy_state_internal_error(sc); - } - - stream->recv_window = NGX_SPDY_STREAM_WINDOW; - } - - if (stream->in_closed) { - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client sent DATA frame for half-closed stream %ui", - stream->id); - - if (ngx_http_spdy_terminate_stream(sc, stream, - NGX_SPDY_STREAM_ALREADY_CLOSED) - == NGX_ERROR) - { - return ngx_http_spdy_state_internal_error(sc); - } - - return ngx_http_spdy_state_skip(sc, pos, end); - } - - return ngx_http_spdy_state_read_data(sc, pos, end); -} - - -static u_char * -ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos, - u_char *end) -{ - size_t size; - ssize_t n; - ngx_buf_t *buf; - ngx_int_t rc; - ngx_temp_file_t *tf; - ngx_http_request_t *r; - ngx_http_spdy_stream_t *stream; - ngx_http_request_body_t *rb; - ngx_http_core_loc_conf_t *clcf; - - stream = sc->stream; - - if (stream == NULL) { - return ngx_http_spdy_state_skip(sc, pos, end); - } - - if (stream->skip_data) { - - if (sc->flags & NGX_SPDY_FLAG_FIN) { - stream->in_closed = 1; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "skipping spdy DATA frame, reason: %d", - stream->skip_data); - - return ngx_http_spdy_state_skip(sc, pos, end); - } - - size = end - pos; - - if (size > sc->length) { - size = sc->length; - } - - r = stream->request; - - if (r->request_body == NULL - && ngx_http_spdy_init_request_body(r) != NGX_OK) - { - stream->skip_data = NGX_SPDY_DATA_INTERNAL_ERROR; - return ngx_http_spdy_state_skip(sc, pos, end); - } - - rb = r->request_body; - tf = rb->temp_file; - buf = rb->buf; - - if (size) { - rb->rest += size; - - if (r->headers_in.content_length_n != -1 - && r->headers_in.content_length_n < rb->rest) - { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client intended to send body data " - "larger than declared"); - - stream->skip_data = NGX_SPDY_DATA_ERROR; - goto error; - - } else { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - if (clcf->client_max_body_size - && clcf->client_max_body_size < rb->rest) - { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "client intended to send " - "too large chunked body: %O bytes", rb->rest); - - stream->skip_data = NGX_SPDY_DATA_ERROR; - goto error; - } - } - - sc->length -= size; - - if (tf) { - buf->start = pos; - buf->pos = pos; - - pos += size; - - buf->end = pos; - buf->last = pos; - - n = ngx_write_chain_to_temp_file(tf, rb->bufs); - - /* TODO: n == 0 or not complete and level event */ - - if (n == NGX_ERROR) { - stream->skip_data = NGX_SPDY_DATA_INTERNAL_ERROR; - goto error; - } - - tf->offset += n; - - } else { - buf->last = ngx_cpymem(buf->last, pos, size); - pos += size; - } - - r->request_length += size; - } - - if (sc->length) { - return ngx_http_spdy_state_save(sc, pos, end, - ngx_http_spdy_state_read_data); - } - - if (sc->flags & NGX_SPDY_FLAG_FIN) { - - stream->in_closed = 1; - - if (r->headers_in.content_length_n < 0) { - r->headers_in.content_length_n = rb->rest; - - } else if (r->headers_in.content_length_n != rb->rest) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client prematurely closed stream: " - "only %O out of %O bytes of request body received", - rb->rest, r->headers_in.content_length_n); - - stream->skip_data = NGX_SPDY_DATA_ERROR; - goto error; - } - - if (tf) { - ngx_memzero(buf, sizeof(ngx_buf_t)); - - buf->in_file = 1; - buf->file_last = tf->file.offset; - buf->file = &tf->file; - - rb->buf = NULL; - } - - if (rb->post_handler) { - r->read_event_handler = ngx_http_block_reading; - rb->post_handler(r); - } - } - - return ngx_http_spdy_state_complete(sc, pos, end); - -error: - - if (rb->post_handler) { - - if (stream->skip_data == NGX_SPDY_DATA_ERROR) { - rc = (r->headers_in.content_length_n == -1) - ? NGX_HTTP_REQUEST_ENTITY_TOO_LARGE - : NGX_HTTP_BAD_REQUEST; - - } else { - rc = NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_http_finalize_request(r, rc); - } - - return ngx_http_spdy_state_skip(sc, pos, end); -} - - -static u_char * -ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos, - u_char *end) -{ - ngx_uint_t sid, status; - ngx_event_t *ev; - ngx_connection_t *fc; - ngx_http_spdy_stream_t *stream; - - if (end - pos < NGX_SPDY_RST_STREAM_SIZE) { - return ngx_http_spdy_state_save(sc, pos, end, - ngx_http_spdy_state_rst_stream); - } - - if (sc->length != NGX_SPDY_RST_STREAM_SIZE) { - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client sent RST_STREAM frame with incorrect length %uz", - sc->length); - - return ngx_http_spdy_state_protocol_error(sc); - } - - sid = ngx_spdy_frame_parse_sid(pos); - - pos += NGX_SPDY_SID_SIZE; - - status = ngx_spdy_frame_parse_uint32(pos); - - pos += sizeof(uint32_t); - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy RST_STREAM sid:%ui st:%ui", sid, status); - - stream = ngx_http_spdy_get_stream_by_id(sc, sid); - - if (stream == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "unknown spdy stream"); - - return ngx_http_spdy_state_complete(sc, pos, end); - } - - stream->in_closed = 1; - stream->out_closed = 1; - - fc = stream->request->connection; - fc->error = 1; - - switch (status) { - - case NGX_SPDY_CANCEL: - ngx_log_error(NGX_LOG_INFO, fc->log, 0, - "client canceled stream %ui", sid); - break; - - case NGX_SPDY_INTERNAL_ERROR: - ngx_log_error(NGX_LOG_INFO, fc->log, 0, - "client terminated stream %ui due to internal error", - sid); - break; - - default: - ngx_log_error(NGX_LOG_INFO, fc->log, 0, - "client terminated stream %ui with status %ui", - sid, status); - break; - } - - ev = fc->read; - ev->handler(ev); - - return ngx_http_spdy_state_complete(sc, pos, end); -} - - -static u_char * -ngx_http_spdy_state_ping(ngx_http_spdy_connection_t *sc, u_char *pos, - u_char *end) -{ - u_char *p; - ngx_buf_t *buf; - ngx_http_spdy_out_frame_t *frame; - - if (end - pos < NGX_SPDY_PING_SIZE) { - return ngx_http_spdy_state_save(sc, pos, end, - ngx_http_spdy_state_ping); - } - - if (sc->length != NGX_SPDY_PING_SIZE) { - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client sent PING frame with incorrect length %uz", - sc->length); - - return ngx_http_spdy_state_protocol_error(sc); - } - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy PING frame"); - - frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_PING_SIZE, - NGX_SPDY_HIGHEST_PRIORITY); - if (frame == NULL) { - return ngx_http_spdy_state_internal_error(sc); - } - - buf = frame->first->buf; - - p = buf->pos; - - p = ngx_spdy_frame_write_head(p, NGX_SPDY_PING); - p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_PING_SIZE); - - p = ngx_cpymem(p, pos, NGX_SPDY_PING_SIZE); - - buf->last = p; - - ngx_http_spdy_queue_frame(sc, frame); - - pos += NGX_SPDY_PING_SIZE; - - return ngx_http_spdy_state_complete(sc, pos, end); -} - - -static u_char * -ngx_http_spdy_state_skip(ngx_http_spdy_connection_t *sc, u_char *pos, - u_char *end) -{ - size_t size; - - size = end - pos; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy frame skip %uz of %uz", size, sc->length); - - if (size < sc->length) { - sc->length -= size; - return ngx_http_spdy_state_save(sc, end, end, - ngx_http_spdy_state_skip); - } - - return ngx_http_spdy_state_complete(sc, pos + sc->length, end); -} - - -static u_char * -ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc, u_char *pos, - u_char *end) -{ - ngx_uint_t fid, val; - - if (sc->entries == 0) { - - if (end - pos < NGX_SPDY_SETTINGS_NUM_SIZE) { - return ngx_http_spdy_state_save(sc, pos, end, - ngx_http_spdy_state_settings); - } - - sc->entries = ngx_spdy_frame_parse_uint32(pos); - - pos += NGX_SPDY_SETTINGS_NUM_SIZE; - sc->length -= NGX_SPDY_SETTINGS_NUM_SIZE; - - if (sc->length < sc->entries * NGX_SPDY_SETTINGS_PAIR_SIZE) { - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client sent SETTINGS frame with incorrect " - "length %uz or number of entries %ui", - sc->length, sc->entries); - - return ngx_http_spdy_state_protocol_error(sc); - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy SETTINGS frame has %ui entries", sc->entries); - } - - while (sc->entries) { - if (end - pos < NGX_SPDY_SETTINGS_PAIR_SIZE) { - return ngx_http_spdy_state_save(sc, pos, end, - ngx_http_spdy_state_settings); - } - - sc->entries--; - sc->length -= NGX_SPDY_SETTINGS_PAIR_SIZE; - - fid = ngx_spdy_frame_parse_uint32(pos); - - pos += NGX_SPDY_SETTINGS_FID_SIZE; - - val = ngx_spdy_frame_parse_uint32(pos); - - pos += NGX_SPDY_SETTINGS_VAL_SIZE; - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy SETTINGS entry fl:%ui id:%ui val:%ui", - ngx_spdy_frame_flags(fid), ngx_spdy_frame_id(fid), val); - - if (ngx_spdy_frame_flags(fid) == NGX_SPDY_SETTINGS_FLAG_PERSISTED) { - continue; - } - - switch (ngx_spdy_frame_id(fid)) { - - case NGX_SPDY_SETTINGS_INIT_WINDOW: - - if (val > NGX_SPDY_MAX_WINDOW) { - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client sent SETTINGS frame with " - "incorrect INIT_WINDOW value: %ui", val); - - return ngx_http_spdy_state_protocol_error(sc); - } - - if (ngx_http_spdy_adjust_windows(sc, val - sc->init_window) - != NGX_OK) - { - return ngx_http_spdy_state_internal_error(sc); - } - - sc->init_window = val; - - continue; - } - } - - return ngx_http_spdy_state_complete(sc, pos, end); -} - - -static u_char * -ngx_http_spdy_state_complete(ngx_http_spdy_connection_t *sc, u_char *pos, - u_char *end) -{ - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy frame complete pos:%p end:%p", pos, end); - - if (pos > end) { - ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0, - "receive buffer overrun"); - - ngx_debug_point(); - return ngx_http_spdy_state_internal_error(sc); - } - - sc->handler = ngx_http_spdy_state_head; - sc->stream = NULL; - - return pos; -} - - -static u_char * -ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end, ngx_http_spdy_handler_pt handler) -{ - size_t size; - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy frame state save pos:%p end:%p handler:%p", - pos, end, handler); - - size = end - pos; - - if (size > NGX_SPDY_STATE_BUFFER_SIZE) { - ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0, - "state buffer overflow: %uz bytes required", size); - - ngx_debug_point(); - return ngx_http_spdy_state_internal_error(sc); - } - - ngx_memcpy(sc->buffer, pos, NGX_SPDY_STATE_BUFFER_SIZE); - - sc->buffer_used = size; - sc->handler = handler; - sc->incomplete = 1; - - return end; -} - - -static u_char * -ngx_http_spdy_state_inflate_error(ngx_http_spdy_connection_t *sc, int rc) -{ - if (rc == Z_DATA_ERROR || rc == Z_STREAM_END) { - ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0, - "client sent SYN_STREAM frame with " - "corrupted header block, inflate() failed: %d", rc); - - return ngx_http_spdy_state_protocol_error(sc); - } - - ngx_log_error(NGX_LOG_ERR, sc->connection->log, 0, - "inflate() failed: %d", rc); - - return ngx_http_spdy_state_internal_error(sc); -} - - -static u_char * -ngx_http_spdy_state_protocol_error(ngx_http_spdy_connection_t *sc) -{ - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy state protocol error"); - - if (sc->stream) { - sc->stream->out_closed = 1; - ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST); - } - - ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST); - - return NULL; -} - - -static u_char * -ngx_http_spdy_state_internal_error(ngx_http_spdy_connection_t *sc) -{ - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy state internal error"); - - if (sc->stream) { - sc->stream->out_closed = 1; - ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_INTERNAL_SERVER_ERROR); - } - - ngx_http_spdy_finalize_connection(sc, NGX_HTTP_INTERNAL_SERVER_ERROR); - - return NULL; -} - - -static ngx_int_t -ngx_http_spdy_send_window_update(ngx_http_spdy_connection_t *sc, ngx_uint_t sid, - ngx_uint_t delta) -{ - u_char *p; - ngx_buf_t *buf; - ngx_http_spdy_out_frame_t *frame; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy send WINDOW_UPDATE sid:%ui delta:%ui", sid, delta); - - frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_WINDOW_UPDATE_SIZE, - NGX_SPDY_HIGHEST_PRIORITY); - if (frame == NULL) { - return NGX_ERROR; - } - - buf = frame->first->buf; - - p = buf->pos; - - p = ngx_spdy_frame_write_head(p, NGX_SPDY_WINDOW_UPDATE); - p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_WINDOW_UPDATE_SIZE); - - p = ngx_spdy_frame_write_sid(p, sid); - p = ngx_spdy_frame_aligned_write_uint32(p, delta); - - buf->last = p; - - ngx_http_spdy_queue_frame(sc, frame); - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_spdy_send_rst_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t sid, - ngx_uint_t status, ngx_uint_t priority) -{ - u_char *p; - ngx_buf_t *buf; - ngx_http_spdy_out_frame_t *frame; - - if (sc->connection->error) { - return NGX_OK; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy send RST_STREAM sid:%ui st:%ui", sid, status); - - frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_RST_STREAM_SIZE, - priority); - if (frame == NULL) { - return NGX_ERROR; - } - - buf = frame->first->buf; - - p = buf->pos; - - p = ngx_spdy_frame_write_head(p, NGX_SPDY_RST_STREAM); - p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_RST_STREAM_SIZE); - - p = ngx_spdy_frame_write_sid(p, sid); - p = ngx_spdy_frame_aligned_write_uint32(p, status); - - buf->last = p; - - ngx_http_spdy_queue_frame(sc, frame); - - return NGX_OK; -} - - -#if 0 -static ngx_int_t -ngx_http_spdy_send_goaway(ngx_http_spdy_connection_t *sc) -{ - u_char *p; - ngx_buf_t *buf; - ngx_http_spdy_out_frame_t *frame; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy send GOAWAY sid:%ui", sc->last_sid); - - frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_GOAWAY_SIZE, - NGX_SPDY_HIGHEST_PRIORITY); - if (frame == NULL) { - return NGX_ERROR; - } - - buf = frame->first->buf; - - p = buf->pos; - - p = ngx_spdy_frame_write_head(p, NGX_SPDY_GOAWAY); - p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_GOAWAY_SIZE); - - p = ngx_spdy_frame_write_sid(p, sc->last_sid); - - buf->last = p; - - ngx_http_spdy_queue_frame(sc, frame); - - return NGX_OK; -} -#endif - - -static ngx_int_t -ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc) -{ - u_char *p; - ngx_buf_t *buf; - ngx_chain_t *cl; - ngx_http_spdy_srv_conf_t *sscf; - ngx_http_spdy_out_frame_t *frame; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy send SETTINGS frame"); - - frame = ngx_palloc(sc->pool, sizeof(ngx_http_spdy_out_frame_t)); - if (frame == NULL) { - return NGX_ERROR; - } - - cl = ngx_alloc_chain_link(sc->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - buf = ngx_create_temp_buf(sc->pool, NGX_SPDY_FRAME_HEADER_SIZE - + NGX_SPDY_SETTINGS_NUM_SIZE - + 2 * NGX_SPDY_SETTINGS_PAIR_SIZE); - if (buf == NULL) { - return NGX_ERROR; - } - - buf->last_buf = 1; - - cl->buf = buf; - cl->next = NULL; - - frame->first = cl; - frame->last = cl; - frame->handler = ngx_http_spdy_settings_frame_handler; - frame->stream = NULL; -#if (NGX_DEBUG) - frame->length = NGX_SPDY_SETTINGS_NUM_SIZE - + 2 * NGX_SPDY_SETTINGS_PAIR_SIZE; -#endif - frame->priority = NGX_SPDY_HIGHEST_PRIORITY; - frame->blocked = 0; - - p = buf->pos; - - p = ngx_spdy_frame_write_head(p, NGX_SPDY_SETTINGS); - p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_CLEAR_SETTINGS, - NGX_SPDY_SETTINGS_NUM_SIZE - + 2 * NGX_SPDY_SETTINGS_PAIR_SIZE); - - p = ngx_spdy_frame_aligned_write_uint32(p, 2); - - sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx, - ngx_http_spdy_module); - - p = ngx_spdy_frame_write_flags_and_id(p, 0, NGX_SPDY_SETTINGS_MAX_STREAMS); - p = ngx_spdy_frame_aligned_write_uint32(p, sscf->concurrent_streams); - - p = ngx_spdy_frame_write_flags_and_id(p, 0, NGX_SPDY_SETTINGS_INIT_WINDOW); - p = ngx_spdy_frame_aligned_write_uint32(p, NGX_SPDY_STREAM_WINDOW); - - buf->last = p; - - ngx_http_spdy_queue_frame(sc, frame); - - return NGX_OK; -} - - -ngx_int_t -ngx_http_spdy_settings_frame_handler(ngx_http_spdy_connection_t *sc, - ngx_http_spdy_out_frame_t *frame) -{ - ngx_buf_t *buf; - - buf = frame->first->buf; - - if (buf->pos != buf->last) { - return NGX_AGAIN; - } - - ngx_free_chain(sc->pool, frame->first); - - return NGX_OK; -} - - -static ngx_http_spdy_out_frame_t * -ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t length, - ngx_uint_t priority) -{ - ngx_chain_t *cl; - ngx_http_spdy_out_frame_t *frame; - - frame = sc->free_ctl_frames; - - if (frame) { - sc->free_ctl_frames = frame->next; - - cl = frame->first; - cl->buf->pos = cl->buf->start; - - } else { - frame = ngx_palloc(sc->pool, sizeof(ngx_http_spdy_out_frame_t)); - if (frame == NULL) { - return NULL; - } - - cl = ngx_alloc_chain_link(sc->pool); - if (cl == NULL) { - return NULL; - } - - cl->buf = ngx_create_temp_buf(sc->pool, - NGX_SPDY_CTL_FRAME_BUFFER_SIZE); - if (cl->buf == NULL) { - return NULL; - } - - cl->buf->last_buf = 1; - - frame->first = cl; - frame->last = cl; - frame->handler = ngx_http_spdy_ctl_frame_handler; - frame->stream = NULL; - } - -#if (NGX_DEBUG) - if (length > NGX_SPDY_CTL_FRAME_BUFFER_SIZE - NGX_SPDY_FRAME_HEADER_SIZE) { - ngx_log_error(NGX_LOG_ALERT, sc->pool->log, 0, - "requested control frame is too large: %uz", length); - return NULL; - } - - frame->length = length; -#endif - - frame->priority = priority; - frame->blocked = 0; - - return frame; -} - - -static ngx_int_t -ngx_http_spdy_ctl_frame_handler(ngx_http_spdy_connection_t *sc, - ngx_http_spdy_out_frame_t *frame) -{ - ngx_buf_t *buf; - - buf = frame->first->buf; - - if (buf->pos != buf->last) { - return NGX_AGAIN; - } - - frame->next = sc->free_ctl_frames; - sc->free_ctl_frames = frame; - - return NGX_OK; -} - - -static ngx_http_spdy_stream_t * -ngx_http_spdy_create_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t id, - ngx_uint_t priority) -{ - ngx_log_t *log; - ngx_uint_t index; - ngx_event_t *rev, *wev; - ngx_connection_t *fc; - ngx_http_log_ctx_t *ctx; - ngx_http_request_t *r; - ngx_http_spdy_stream_t *stream; - ngx_http_core_srv_conf_t *cscf; - ngx_http_spdy_srv_conf_t *sscf; - - fc = sc->free_fake_connections; - - if (fc) { - sc->free_fake_connections = fc->data; - - rev = fc->read; - wev = fc->write; - log = fc->log; - ctx = log->data; - - } else { - fc = ngx_palloc(sc->pool, sizeof(ngx_connection_t)); - if (fc == NULL) { - return NULL; - } - - rev = ngx_palloc(sc->pool, sizeof(ngx_event_t)); - if (rev == NULL) { - return NULL; - } - - wev = ngx_palloc(sc->pool, sizeof(ngx_event_t)); - if (wev == NULL) { - return NULL; - } - - log = ngx_palloc(sc->pool, sizeof(ngx_log_t)); - if (log == NULL) { - return NULL; - } - - ctx = ngx_palloc(sc->pool, sizeof(ngx_http_log_ctx_t)); - if (ctx == NULL) { - return NULL; - } - - ctx->connection = fc; - ctx->request = NULL; - } - - ngx_memcpy(log, sc->connection->log, sizeof(ngx_log_t)); - - log->data = ctx; - - ngx_memzero(rev, sizeof(ngx_event_t)); - - rev->data = fc; - rev->ready = 1; - rev->handler = ngx_http_spdy_close_stream_handler; - rev->log = log; - - ngx_memcpy(wev, rev, sizeof(ngx_event_t)); - - wev->write = 1; - - ngx_memcpy(fc, sc->connection, sizeof(ngx_connection_t)); - - fc->data = sc->http_connection; - fc->read = rev; - fc->write = wev; - fc->sent = 0; - fc->log = log; - fc->buffered = 0; - fc->sndlowat = 1; - fc->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; - - r = ngx_http_create_request(fc); - if (r == NULL) { - return NULL; - } - - r->valid_location = 1; - - fc->data = r; - sc->connection->requests++; - - cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); - - r->header_in = ngx_create_temp_buf(r->pool, - cscf->client_header_buffer_size); - if (r->header_in == NULL) { - ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NULL; - } - - r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE; - - stream = ngx_pcalloc(r->pool, sizeof(ngx_http_spdy_stream_t)); - if (stream == NULL) { - ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NULL; - } - - r->spdy_stream = stream; - - stream->id = id; - stream->request = r; - stream->connection = sc; - - stream->send_window = sc->init_window; - stream->recv_window = NGX_SPDY_STREAM_WINDOW; - - stream->priority = priority; - - sscf = ngx_http_get_module_srv_conf(r, ngx_http_spdy_module); - - index = ngx_http_spdy_stream_index(sscf, id); - - stream->index = sc->streams_index[index]; - sc->streams_index[index] = stream; - - sc->processing++; - - return stream; -} - - -static ngx_http_spdy_stream_t * -ngx_http_spdy_get_stream_by_id(ngx_http_spdy_connection_t *sc, - ngx_uint_t sid) -{ - ngx_http_spdy_stream_t *stream; - ngx_http_spdy_srv_conf_t *sscf; - - sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx, - ngx_http_spdy_module); - - stream = sc->streams_index[ngx_http_spdy_stream_index(sscf, sid)]; - - while (stream) { - if (stream->id == sid) { - return stream; - } - - stream = stream->index; - } - - return NULL; -} - - -static ngx_int_t -ngx_http_spdy_parse_header(ngx_http_request_t *r) -{ - u_char *p, *end, ch; - ngx_uint_t hash; - ngx_http_core_srv_conf_t *cscf; - - enum { - sw_name_len = 0, - sw_name, - sw_value_len, - sw_value - } state; - - state = r->state; - - p = r->header_in->pos; - end = r->header_in->last; - - switch (state) { - - case sw_name_len: - - if (end - p < NGX_SPDY_NV_NLEN_SIZE) { - return NGX_AGAIN; - } - - r->lowcase_index = ngx_spdy_frame_parse_uint32(p); - - if (r->lowcase_index == 0) { - return NGX_ERROR; - } - - /* null-terminate the previous header value */ - *p = '\0'; - - p += NGX_SPDY_NV_NLEN_SIZE; - - r->invalid_header = 0; - - state = sw_name; - - /* fall through */ - - case sw_name: - - if ((ngx_uint_t) (end - p) < r->lowcase_index) { - break; - } - - cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); - - r->header_name_start = p; - r->header_name_end = p + r->lowcase_index; - - if (p[0] == ':') { - p++; - } - - hash = 0; - - for ( /* void */ ; p != r->header_name_end; p++) { - - ch = *p; - - hash = ngx_hash(hash, ch); - - if ((ch >= 'a' && ch <= 'z') - || (ch == '-') - || (ch >= '0' && ch <= '9') - || (ch == '_' && cscf->underscores_in_headers)) - { - continue; - } - - switch (ch) { - case '\0': - case LF: - case CR: - case ':': - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent invalid header name: \"%*s\"", - r->lowcase_index, r->header_name_start); - - return NGX_HTTP_PARSE_INVALID_HEADER; - } - - if (ch >= 'A' && ch <= 'Z') { - return NGX_ERROR; - } - - r->invalid_header = 1; - } - - r->header_hash = hash; - - state = sw_value_len; - - /* fall through */ - - case sw_value_len: - - if (end - p < NGX_SPDY_NV_VLEN_SIZE) { - break; - } - - r->lowcase_index = ngx_spdy_frame_parse_uint32(p); - - /* null-terminate header name */ - *p = '\0'; - - p += NGX_SPDY_NV_VLEN_SIZE; - - state = sw_value; - - /* fall through */ - - case sw_value: - - if ((ngx_uint_t) (end - p) < r->lowcase_index) { - break; - } - - r->header_start = p; - - while (r->lowcase_index--) { - ch = *p; - - if (ch == '\0') { - - if (p == r->header_start) { - return NGX_ERROR; - } - - r->header_end = p; - r->header_in->pos = p + 1; - - r->state = sw_value; - - return NGX_OK; - } - - if (ch == CR || ch == LF) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent header \"%*s\" with " - "invalid value: \"%*s\\%c...\"", - r->header_name_end - r->header_name_start, - r->header_name_start, - p - r->header_start, - r->header_start, - ch == CR ? 'r' : 'n'); - - return NGX_HTTP_PARSE_INVALID_HEADER; - } - - p++; - } - - r->header_end = p; - r->header_in->pos = p; - - r->state = 0; - - return NGX_DONE; - } - - r->header_in->pos = p; - r->state = state; - - return NGX_AGAIN; -} - - -static ngx_int_t -ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r) -{ - u_char *old, *new, *p; - size_t rest; - ngx_buf_t *buf; - ngx_http_spdy_stream_t *stream; - ngx_http_core_srv_conf_t *cscf; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy alloc large header buffer"); - - stream = r->spdy_stream; - - cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); - - if (stream->header_buffers - == (ngx_uint_t) cscf->large_client_header_buffers.num) - { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent too large request"); - - return NGX_DECLINED; - } - - rest = r->header_in->last - r->header_in->pos; - - /* - * One more byte is needed for null-termination - * and another one for further progress. - */ - if (rest > cscf->large_client_header_buffers.size - 2) { - p = r->header_in->pos; - - if (rest > NGX_MAX_ERROR_STR - 300) { - rest = NGX_MAX_ERROR_STR - 300; - } - - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent too long header name or value: \"%*s...\"", - rest, p); - - return NGX_DECLINED; - } - - buf = ngx_create_temp_buf(r->pool, cscf->large_client_header_buffers.size); - if (buf == NULL) { - return NGX_ERROR; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy large header alloc: %p %uz", - buf->pos, buf->end - buf->last); - - old = r->header_in->pos; - new = buf->pos; - - if (rest) { - buf->last = ngx_cpymem(new, old, rest); - } - - r->header_in = buf; - - stream->header_buffers++; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_spdy_handle_request_header(ngx_http_request_t *r) -{ - ngx_uint_t i; - ngx_table_elt_t *h; - ngx_http_core_srv_conf_t *cscf; - ngx_http_spdy_request_header_t *sh; - - if (r->invalid_header) { - cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); - - if (cscf->ignore_invalid_headers) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent invalid header: \"%*s\"", - r->header_end - r->header_name_start, - r->header_name_start); - return NGX_OK; - } - - } - - if (r->header_name_start[0] == ':') { - r->header_name_start++; - - for (i = 0; i < NGX_SPDY_REQUEST_HEADERS; i++) { - sh = &ngx_http_spdy_request_headers[i]; - - if (sh->hash != r->header_hash - || sh->len != r->header_name_end - r->header_name_start - || ngx_strncmp(sh->header, r->header_name_start, sh->len) != 0) - { - continue; - } - - return sh->handler(r); - } - - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent invalid header name: \":%*s\"", - r->header_end - r->header_name_start, - r->header_name_start); - - return NGX_HTTP_PARSE_INVALID_HEADER; - } - - h = ngx_list_push(&r->headers_in.headers); - if (h == NULL) { - return NGX_ERROR; - } - - h->hash = r->header_hash; - - h->key.len = r->header_name_end - r->header_name_start; - h->key.data = r->header_name_start; - - h->value.len = r->header_end - r->header_start; - h->value.data = r->header_start; - - h->lowcase_key = h->key.data; - - return NGX_OK; -} - - -void -ngx_http_spdy_request_headers_init(void) -{ - ngx_uint_t i; - ngx_http_spdy_request_header_t *h; - - for (i = 0; i < NGX_SPDY_REQUEST_HEADERS; i++) { - h = &ngx_http_spdy_request_headers[i]; - h->hash = ngx_hash_key(h->header, h->len); - } -} - - -static ngx_int_t -ngx_http_spdy_parse_method(ngx_http_request_t *r) -{ - size_t k, len; - ngx_uint_t n; - const u_char *p, *m; - - /* - * This array takes less than 256 sequential bytes, - * and if typical CPU cache line size is 64 bytes, - * it is prefetched for 4 load operations. - */ - static const struct { - u_char len; - const u_char method[11]; - uint32_t value; - } tests[] = { - { 3, "GET", NGX_HTTP_GET }, - { 4, "POST", NGX_HTTP_POST }, - { 4, "HEAD", NGX_HTTP_HEAD }, - { 7, "OPTIONS", NGX_HTTP_OPTIONS }, - { 8, "PROPFIND", NGX_HTTP_PROPFIND }, - { 3, "PUT", NGX_HTTP_PUT }, - { 5, "MKCOL", NGX_HTTP_MKCOL }, - { 6, "DELETE", NGX_HTTP_DELETE }, - { 4, "COPY", NGX_HTTP_COPY }, - { 4, "MOVE", NGX_HTTP_MOVE }, - { 9, "PROPPATCH", NGX_HTTP_PROPPATCH }, - { 4, "LOCK", NGX_HTTP_LOCK }, - { 6, "UNLOCK", NGX_HTTP_UNLOCK }, - { 5, "PATCH", NGX_HTTP_PATCH }, - { 5, "TRACE", NGX_HTTP_TRACE } - }, *test; - - if (r->method_name.len) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent duplicate :method header"); - - return NGX_HTTP_PARSE_INVALID_HEADER; - } - - len = r->header_end - r->header_start; - - r->method_name.len = len; - r->method_name.data = r->header_start; - - test = tests; - n = sizeof(tests) / sizeof(tests[0]); - - do { - if (len == test->len) { - p = r->method_name.data; - m = test->method; - k = len; - - do { - if (*p++ != *m++) { - goto next; - } - } while (--k); - - r->method = test->value; - return NGX_OK; - } - - next: - test++; - - } while (--n); - - p = r->method_name.data; - - do { - if ((*p < 'A' || *p > 'Z') && *p != '_') { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent invalid method: \"%V\"", - &r->method_name); - - return NGX_HTTP_PARSE_INVALID_HEADER; - } - - p++; - - } while (--len); - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_spdy_parse_scheme(ngx_http_request_t *r) -{ - if (r->schema_start) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent duplicate :schema header"); - - return NGX_HTTP_PARSE_INVALID_HEADER; - } - - r->schema_start = r->header_start; - r->schema_end = r->header_end; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_spdy_parse_host(ngx_http_request_t *r) -{ - ngx_table_elt_t *h; - - if (r->headers_in.host) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent duplicate :host header"); - - return NGX_HTTP_PARSE_INVALID_HEADER; - } - - h = ngx_list_push(&r->headers_in.headers); - if (h == NULL) { - return NGX_ERROR; - } - - r->headers_in.host = h; - - h->hash = r->header_hash; - - h->key.len = r->header_name_end - r->header_name_start; - h->key.data = r->header_name_start; - - h->value.len = r->header_end - r->header_start; - h->value.data = r->header_start; - - h->lowcase_key = h->key.data; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_spdy_parse_path(ngx_http_request_t *r) -{ - if (r->unparsed_uri.len) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent duplicate :path header"); - - return NGX_HTTP_PARSE_INVALID_HEADER; - } - - r->uri_start = r->header_start; - r->uri_end = r->header_end; - - if (ngx_http_parse_uri(r) != NGX_OK) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent invalid URI: \"%*s\"", - r->uri_end - r->uri_start, r->uri_start); - - return NGX_HTTP_PARSE_INVALID_HEADER; - } - - if (ngx_http_process_request_uri(r) != NGX_OK) { - /* - * request has been finalized already - * in ngx_http_process_request_uri() - */ - return NGX_ABORT; - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_spdy_parse_version(ngx_http_request_t *r) -{ - u_char *p, ch; - - if (r->http_protocol.len) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent duplicate :version header"); - - return NGX_HTTP_PARSE_INVALID_HEADER; - } - - p = r->header_start; - - if (r->header_end - p < 8 || !(ngx_str5cmp(p, 'H', 'T', 'T', 'P', '/'))) { - goto invalid; - } - - ch = *(p + 5); - - if (ch < '1' || ch > '9') { - goto invalid; - } - - r->http_major = ch - '0'; - - for (p += 6; p != r->header_end - 2; p++) { - - ch = *p; - - if (ch == '.') { - break; - } - - if (ch < '0' || ch > '9') { - goto invalid; - } - - r->http_major = r->http_major * 10 + ch - '0'; - } - - if (*p != '.') { - goto invalid; - } - - ch = *(p + 1); - - if (ch < '0' || ch > '9') { - goto invalid; - } - - r->http_minor = ch - '0'; - - for (p += 2; p != r->header_end; p++) { - - ch = *p; - - if (ch < '0' || ch > '9') { - goto invalid; - } - - r->http_minor = r->http_minor * 10 + ch - '0'; - } - - r->http_protocol.len = r->header_end - r->header_start; - r->http_protocol.data = r->header_start; - r->http_version = r->http_major * 1000 + r->http_minor; - - return NGX_OK; - -invalid: - - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent invalid http version: \"%*s\"", - r->header_end - r->header_start, r->header_start); - - return NGX_HTTP_PARSE_INVALID_HEADER; -} - - -static ngx_int_t -ngx_http_spdy_construct_request_line(ngx_http_request_t *r) -{ - u_char *p; - - if (r->method_name.len == 0 - || r->unparsed_uri.len == 0 - || r->http_protocol.len == 0) - { - ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); - return NGX_ERROR; - } - - r->request_line.len = r->method_name.len + 1 - + r->unparsed_uri.len + 1 - + r->http_protocol.len; - - p = ngx_pnalloc(r->pool, r->request_line.len + 1); - if (p == NULL) { - ngx_http_spdy_close_stream(r->spdy_stream, - NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_ERROR; - } - - r->request_line.data = p; - - p = ngx_cpymem(p, r->method_name.data, r->method_name.len); - - *p++ = ' '; - - p = ngx_cpymem(p, r->unparsed_uri.data, r->unparsed_uri.len); - - *p++ = ' '; - - ngx_memcpy(p, r->http_protocol.data, r->http_protocol.len + 1); - - /* some modules expect the space character after method name */ - r->method_name.data = r->request_line.data; - - return NGX_OK; -} - - -static void -ngx_http_spdy_run_request(ngx_http_request_t *r) -{ - ngx_uint_t i; - ngx_list_part_t *part; - ngx_table_elt_t *h; - ngx_http_header_t *hh; - ngx_http_core_main_conf_t *cmcf; - - if (ngx_http_spdy_construct_request_line(r) != NGX_OK) { - return; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy http request line: \"%V\"", &r->request_line); - - cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - - part = &r->headers_in.headers.part; - h = part->elts; - - for (i = 0 ;; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - h = part->elts; - i = 0; - } - - hh = ngx_hash_find(&cmcf->headers_in_hash, h[i].hash, - h[i].lowcase_key, h[i].key.len); - - if (hh && hh->handler(r, &h[i], hh->offset) != NGX_OK) { - return; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy http header: \"%V: %V\"", &h[i].key, &h[i].value); - } - - r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE; - - if (ngx_http_process_request_header(r) != NGX_OK) { - return; - } - - if (r->headers_in.content_length_n > 0 && r->spdy_stream->in_closed) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client prematurely closed stream"); - - r->spdy_stream->skip_data = NGX_SPDY_DATA_ERROR; - - ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); - return; - } - - ngx_http_process_request(r); -} - - -static ngx_int_t -ngx_http_spdy_init_request_body(ngx_http_request_t *r) -{ - ngx_buf_t *buf; - ngx_temp_file_t *tf; - ngx_http_request_body_t *rb; - ngx_http_core_loc_conf_t *clcf; - - rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); - if (rb == NULL) { - return NGX_ERROR; - } - - r->request_body = rb; - - if (r->spdy_stream->in_closed) { - return NGX_OK; - } - - rb->rest = r->headers_in.content_length_n; - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - if (r->request_body_in_file_only - || rb->rest > (off_t) clcf->client_body_buffer_size - || rb->rest < 0) - { - tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); - if (tf == NULL) { - return NGX_ERROR; - } - - tf->file.fd = NGX_INVALID_FILE; - tf->file.log = r->connection->log; - tf->path = clcf->client_body_temp_path; - tf->pool = r->pool; - tf->warn = "a client request body is buffered to a temporary file"; - tf->log_level = r->request_body_file_log_level; - tf->persistent = r->request_body_in_persistent_file; - tf->clean = r->request_body_in_clean_file; - - if (r->request_body_file_group_access) { - tf->access = 0660; - } - - rb->temp_file = tf; - - if (r->spdy_stream->in_closed - && ngx_create_temp_file(&tf->file, tf->path, tf->pool, - tf->persistent, tf->clean, tf->access) - != NGX_OK) - { - return NGX_ERROR; - } - - buf = ngx_calloc_buf(r->pool); - if (buf == NULL) { - return NGX_ERROR; - } - - } else { - - if (rb->rest == 0) { - return NGX_OK; - } - - buf = ngx_create_temp_buf(r->pool, (size_t) rb->rest); - if (buf == NULL) { - return NGX_ERROR; - } - } - - rb->buf = buf; - - rb->bufs = ngx_alloc_chain_link(r->pool); - if (rb->bufs == NULL) { - return NGX_ERROR; - } - - rb->bufs->buf = buf; - rb->bufs->next = NULL; - - rb->rest = 0; - - return NGX_OK; -} - - -ngx_int_t -ngx_http_spdy_read_request_body(ngx_http_request_t *r, - ngx_http_client_body_handler_pt post_handler) -{ - ngx_http_spdy_stream_t *stream; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy read request body"); - - stream = r->spdy_stream; - - switch (stream->skip_data) { - - case NGX_SPDY_DATA_DISCARD: - post_handler(r); - return NGX_OK; - - case NGX_SPDY_DATA_ERROR: - if (r->headers_in.content_length_n == -1) { - return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; - } else { - return NGX_HTTP_BAD_REQUEST; - } - - case NGX_SPDY_DATA_INTERNAL_ERROR: - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (!r->request_body && ngx_http_spdy_init_request_body(r) != NGX_OK) { - stream->skip_data = NGX_SPDY_DATA_INTERNAL_ERROR; - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (stream->in_closed) { - post_handler(r); - return NGX_OK; - } - - r->request_body->post_handler = post_handler; - - r->read_event_handler = ngx_http_test_reading; - r->write_event_handler = ngx_http_request_empty_handler; - - return NGX_AGAIN; -} - - -static ngx_int_t -ngx_http_spdy_terminate_stream(ngx_http_spdy_connection_t *sc, - ngx_http_spdy_stream_t *stream, ngx_uint_t status) -{ - ngx_event_t *rev; - ngx_connection_t *fc; - - if (ngx_http_spdy_send_rst_stream(sc, stream->id, status, - NGX_SPDY_HIGHEST_PRIORITY) - == NGX_ERROR) - { - return NGX_ERROR; - } - - stream->out_closed = 1; - - fc = stream->request->connection; - fc->error = 1; - - rev = fc->read; - rev->handler(rev); - - return NGX_OK; -} - - -static void -ngx_http_spdy_close_stream_handler(ngx_event_t *ev) -{ - ngx_connection_t *fc; - ngx_http_request_t *r; - - fc = ev->data; - r = fc->data; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy close stream handler"); - - ngx_http_spdy_close_stream(r->spdy_stream, 0); -} - - -void -ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc) -{ - ngx_event_t *ev; - ngx_connection_t *fc; - ngx_http_spdy_stream_t **index, *s; - ngx_http_spdy_srv_conf_t *sscf; - ngx_http_spdy_connection_t *sc; - - sc = stream->connection; - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy close stream %ui, queued %ui, processing %ui", - stream->id, stream->queued, sc->processing); - - fc = stream->request->connection; - - if (stream->queued) { - fc->write->handler = ngx_http_spdy_close_stream_handler; - return; - } - - if (!stream->out_closed) { - if (ngx_http_spdy_send_rst_stream(sc, stream->id, - NGX_SPDY_INTERNAL_ERROR, - stream->priority) - != NGX_OK) - { - sc->connection->error = 1; - } - } - - if (sc->stream == stream) { - sc->stream = NULL; - } - - sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx, - ngx_http_spdy_module); - - index = sc->streams_index + ngx_http_spdy_stream_index(sscf, stream->id); - - for ( ;; ) { - s = *index; - - if (s == NULL) { - break; - } - - if (s == stream) { - *index = s->index; - break; - } - - index = &s->index; - } - - ngx_http_free_request(stream->request, rc); - - ev = fc->read; - - if (ev->active || ev->disabled) { - ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0, - "fake read event was activated"); - } - - if (ev->timer_set) { - ngx_del_timer(ev); - } - - if (ev->posted) { - ngx_delete_posted_event(ev); - } - - ev = fc->write; - - if (ev->active || ev->disabled) { - ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0, - "fake write event was activated"); - } - - if (ev->timer_set) { - ngx_del_timer(ev); - } - - if (ev->posted) { - ngx_delete_posted_event(ev); - } - - fc->data = sc->free_fake_connections; - sc->free_fake_connections = fc; - - sc->processing--; - - if (sc->processing || sc->blocked) { - return; - } - - ev = sc->connection->read; - - ev->handler = ngx_http_spdy_handle_connection_handler; - ngx_post_event(ev, &ngx_posted_events); -} - - -static void -ngx_http_spdy_handle_connection_handler(ngx_event_t *rev) -{ - ngx_connection_t *c; - - rev->handler = ngx_http_spdy_read_handler; - - if (rev->ready) { - ngx_http_spdy_read_handler(rev); - return; - } - - c = rev->data; - - ngx_http_spdy_handle_connection(c->data); -} - - -static void -ngx_http_spdy_keepalive_handler(ngx_event_t *rev) -{ - ngx_connection_t *c; - ngx_http_spdy_srv_conf_t *sscf; - ngx_http_spdy_connection_t *sc; - - c = rev->data; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy keepalive handler"); - - if (rev->timedout || c->close) { - ngx_http_close_connection(c); - return; - } - -#if (NGX_HAVE_KQUEUE) - - if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { - if (rev->pending_eof) { - c->log->handler = NULL; - ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno, - "kevent() reported that client %V closed " - "keepalive connection", &c->addr_text); -#if (NGX_HTTP_SSL) - if (c->ssl) { - c->ssl->no_send_shutdown = 1; - } -#endif - ngx_http_close_connection(c); - return; - } - } - -#endif - - c->destroyed = 0; - c->idle = 0; - ngx_reusable_connection(c, 0); - - sc = c->data; - - sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx, - ngx_http_spdy_module); - - sc->pool = ngx_create_pool(sscf->pool_size, sc->connection->log); - if (sc->pool == NULL) { - ngx_http_close_connection(c); - return; - } - - sc->streams_index = ngx_pcalloc(sc->pool, - ngx_http_spdy_streams_index_size(sscf) - * sizeof(ngx_http_spdy_stream_t *)); - if (sc->streams_index == NULL) { - ngx_http_close_connection(c); - return; - } - - c->write->handler = ngx_http_spdy_write_handler; - - rev->handler = ngx_http_spdy_read_handler; - ngx_http_spdy_read_handler(rev); -} - - -static void -ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc, - ngx_int_t rc) -{ - ngx_uint_t i, size; - ngx_event_t *ev; - ngx_connection_t *c, *fc; - ngx_http_request_t *r; - ngx_http_spdy_stream_t *stream; - ngx_http_spdy_srv_conf_t *sscf; - - c = sc->connection; - - if (!sc->processing) { - ngx_http_close_connection(c); - return; - } - - c->error = 1; - c->read->handler = ngx_http_empty_handler; - c->write->handler = ngx_http_empty_handler; - - sc->last_out = NULL; - - sc->blocked = 1; - - sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx, - ngx_http_spdy_module); - - size = ngx_http_spdy_streams_index_size(sscf); - - for (i = 0; i < size; i++) { - stream = sc->streams_index[i]; - - while (stream) { - stream->handled = 0; - - r = stream->request; - fc = r->connection; - - fc->error = 1; - - if (stream->queued) { - stream->queued = 0; - - ev = fc->write; - ev->delayed = 0; - - } else { - ev = fc->read; - } - - stream = stream->index; - - ev->eof = 1; - ev->handler(ev); - } - } - - sc->blocked = 0; - - if (sc->processing) { - return; - } - - ngx_http_close_connection(c); -} - - -static ngx_int_t -ngx_http_spdy_adjust_windows(ngx_http_spdy_connection_t *sc, ssize_t delta) -{ - ngx_uint_t i, size; - ngx_event_t *wev; - ngx_http_spdy_stream_t *stream, *sn; - ngx_http_spdy_srv_conf_t *sscf; - - sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx, - ngx_http_spdy_module); - - size = ngx_http_spdy_streams_index_size(sscf); - - for (i = 0; i < size; i++) { - - for (stream = sc->streams_index[i]; stream; stream = sn) { - sn = stream->index; - - if (delta > 0 - && stream->send_window - > (ssize_t) (NGX_SPDY_MAX_WINDOW - delta)) - { - if (ngx_http_spdy_terminate_stream(sc, stream, - NGX_SPDY_FLOW_CONTROL_ERROR) - == NGX_ERROR) - { - return NGX_ERROR; - } - - continue; - } - - stream->send_window += delta; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy:%ui adjust window:%z", - stream->id, stream->send_window); - - if (stream->send_window > 0 && stream->exhausted) { - stream->exhausted = 0; - - wev = stream->request->connection->write; - - if (!wev->timer_set) { - wev->delayed = 0; - wev->handler(wev); - } - } - } - } - - return NGX_OK; -} - - -static void -ngx_http_spdy_pool_cleanup(void *data) -{ - ngx_http_spdy_connection_t *sc = data; - - if (sc->pool) { - ngx_destroy_pool(sc->pool); - } -} - - -static void * -ngx_http_spdy_zalloc(void *opaque, u_int items, u_int size) -{ - ngx_http_spdy_connection_t *sc = opaque; - - return ngx_palloc(sc->connection->pool, items * size); -} - - -static void -ngx_http_spdy_zfree(void *opaque, void *address) -{ -#if 0 - ngx_http_spdy_connection_t *sc = opaque; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy zfree: %p", address); -#endif -} diff --git a/src/http/ngx_http_spdy.h b/src/http/ngx_http_spdy.h deleted file mode 100644 index df24495..0000000 --- a/src/http/ngx_http_spdy.h +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (C) Nginx, Inc. - * Copyright (C) Valentin V. Bartenev - */ - - -#ifndef _NGX_HTTP_SPDY_H_INCLUDED_ -#define _NGX_HTTP_SPDY_H_INCLUDED_ - - -#include -#include -#include - -#include - - -#define NGX_SPDY_VERSION 3 - -#define NGX_SPDY_NPN_ADVERTISE "\x08spdy/3.1" -#define NGX_SPDY_NPN_NEGOTIATED "spdy/3.1" - -#define NGX_SPDY_STATE_BUFFER_SIZE 16 - -#define NGX_SPDY_CTL_BIT 1 - -#define NGX_SPDY_SYN_STREAM 1 -#define NGX_SPDY_SYN_REPLY 2 -#define NGX_SPDY_RST_STREAM 3 -#define NGX_SPDY_SETTINGS 4 -#define NGX_SPDY_PING 6 -#define NGX_SPDY_GOAWAY 7 -#define NGX_SPDY_HEADERS 8 -#define NGX_SPDY_WINDOW_UPDATE 9 - -#define NGX_SPDY_FRAME_HEADER_SIZE 8 - -#define NGX_SPDY_SID_SIZE 4 -#define NGX_SPDY_DELTA_SIZE 4 - -#define NGX_SPDY_SYN_STREAM_SIZE 10 -#define NGX_SPDY_SYN_REPLY_SIZE 4 -#define NGX_SPDY_RST_STREAM_SIZE 8 -#define NGX_SPDY_PING_SIZE 4 -#define NGX_SPDY_GOAWAY_SIZE 8 -#define NGX_SPDY_WINDOW_UPDATE_SIZE 8 -#define NGX_SPDY_NV_NUM_SIZE 4 -#define NGX_SPDY_NV_NLEN_SIZE 4 -#define NGX_SPDY_NV_VLEN_SIZE 4 -#define NGX_SPDY_SETTINGS_NUM_SIZE 4 -#define NGX_SPDY_SETTINGS_FID_SIZE 4 -#define NGX_SPDY_SETTINGS_VAL_SIZE 4 - -#define NGX_SPDY_SETTINGS_PAIR_SIZE \ - (NGX_SPDY_SETTINGS_FID_SIZE + NGX_SPDY_SETTINGS_VAL_SIZE) - -#define NGX_SPDY_HIGHEST_PRIORITY 0 -#define NGX_SPDY_LOWEST_PRIORITY 7 - -#define NGX_SPDY_FLAG_FIN 0x01 -#define NGX_SPDY_FLAG_UNIDIRECTIONAL 0x02 -#define NGX_SPDY_FLAG_CLEAR_SETTINGS 0x01 - -#define NGX_SPDY_MAX_FRAME_SIZE ((1 << 24) - 1) - -#define NGX_SPDY_DATA_DISCARD 1 -#define NGX_SPDY_DATA_ERROR 2 -#define NGX_SPDY_DATA_INTERNAL_ERROR 3 - - -typedef struct ngx_http_spdy_connection_s ngx_http_spdy_connection_t; -typedef struct ngx_http_spdy_out_frame_s ngx_http_spdy_out_frame_t; - - -typedef u_char *(*ngx_http_spdy_handler_pt) (ngx_http_spdy_connection_t *sc, - u_char *pos, u_char *end); - -struct ngx_http_spdy_connection_s { - ngx_connection_t *connection; - ngx_http_connection_t *http_connection; - - ngx_uint_t processing; - - size_t send_window; - size_t recv_window; - size_t init_window; - - ngx_queue_t waiting; - - u_char buffer[NGX_SPDY_STATE_BUFFER_SIZE]; - size_t buffer_used; - ngx_http_spdy_handler_pt handler; - - z_stream zstream_in; - z_stream zstream_out; - - ngx_pool_t *pool; - - ngx_http_spdy_out_frame_t *free_ctl_frames; - ngx_connection_t *free_fake_connections; - - ngx_http_spdy_stream_t **streams_index; - - ngx_http_spdy_out_frame_t *last_out; - - ngx_queue_t posted; - - ngx_http_spdy_stream_t *stream; - - ngx_uint_t entries; - size_t length; - u_char flags; - - ngx_uint_t last_sid; - - unsigned blocked:1; - unsigned incomplete:1; -}; - - -struct ngx_http_spdy_stream_s { - ngx_uint_t id; - ngx_http_request_t *request; - ngx_http_spdy_connection_t *connection; - ngx_http_spdy_stream_t *index; - - ngx_uint_t header_buffers; - ngx_uint_t queued; - - /* - * A change to SETTINGS_INITIAL_WINDOW_SIZE could cause the - * send_window to become negative, hence it's signed. - */ - ssize_t send_window; - size_t recv_window; - - ngx_http_spdy_out_frame_t *free_frames; - ngx_chain_t *free_data_headers; - ngx_chain_t *free_bufs; - - ngx_queue_t queue; - - unsigned priority:3; - unsigned handled:1; - unsigned blocked:1; - unsigned exhausted:1; - unsigned in_closed:1; - unsigned out_closed:1; - unsigned skip_data:2; -}; - - -struct ngx_http_spdy_out_frame_s { - ngx_http_spdy_out_frame_t *next; - ngx_chain_t *first; - ngx_chain_t *last; - ngx_int_t (*handler)(ngx_http_spdy_connection_t *sc, - ngx_http_spdy_out_frame_t *frame); - - ngx_http_spdy_stream_t *stream; - size_t length; - - ngx_uint_t priority; - unsigned blocked:1; - unsigned fin:1; -}; - - -static ngx_inline void -ngx_http_spdy_queue_frame(ngx_http_spdy_connection_t *sc, - ngx_http_spdy_out_frame_t *frame) -{ - ngx_http_spdy_out_frame_t **out; - - for (out = &sc->last_out; *out; out = &(*out)->next) - { - /* - * NB: higher values represent lower priorities. - */ - if (frame->priority >= (*out)->priority) { - break; - } - } - - frame->next = *out; - *out = frame; -} - - -static ngx_inline void -ngx_http_spdy_queue_blocked_frame(ngx_http_spdy_connection_t *sc, - ngx_http_spdy_out_frame_t *frame) -{ - ngx_http_spdy_out_frame_t **out; - - for (out = &sc->last_out; *out; out = &(*out)->next) - { - if ((*out)->blocked) { - break; - } - } - - frame->next = *out; - *out = frame; -} - - -void ngx_http_spdy_init(ngx_event_t *rev); -void ngx_http_spdy_request_headers_init(void); - -ngx_int_t ngx_http_spdy_read_request_body(ngx_http_request_t *r, - ngx_http_client_body_handler_pt post_handler); - -void ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc); - -ngx_int_t ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc); - - -#define ngx_spdy_frame_aligned_write_uint16(p, s) \ - (*(uint16_t *) (p) = htons((uint16_t) (s)), (p) + sizeof(uint16_t)) - -#define ngx_spdy_frame_aligned_write_uint32(p, s) \ - (*(uint32_t *) (p) = htonl((uint32_t) (s)), (p) + sizeof(uint32_t)) - -#if (NGX_HAVE_NONALIGNED) - -#define ngx_spdy_frame_write_uint16 ngx_spdy_frame_aligned_write_uint16 -#define ngx_spdy_frame_write_uint32 ngx_spdy_frame_aligned_write_uint32 - -#else - -#define ngx_spdy_frame_write_uint16(p, s) \ - ((p)[0] = (u_char) ((s) >> 8), \ - (p)[1] = (u_char) (s), \ - (p) + sizeof(uint16_t)) - -#define ngx_spdy_frame_write_uint32(p, s) \ - ((p)[0] = (u_char) ((s) >> 24), \ - (p)[1] = (u_char) ((s) >> 16), \ - (p)[2] = (u_char) ((s) >> 8), \ - (p)[3] = (u_char) (s), \ - (p) + sizeof(uint32_t)) - -#endif - - -#define ngx_spdy_ctl_frame_head(t) \ - ((uint32_t) NGX_SPDY_CTL_BIT << 31 | NGX_SPDY_VERSION << 16 | (t)) - -#define ngx_spdy_frame_write_head(p, t) \ - ngx_spdy_frame_aligned_write_uint32(p, ngx_spdy_ctl_frame_head(t)) - -#define ngx_spdy_frame_write_flags_and_len(p, f, l) \ - ngx_spdy_frame_aligned_write_uint32(p, (f) << 24 | (l)) -#define ngx_spdy_frame_write_flags_and_id(p, f, i) \ - ngx_spdy_frame_aligned_write_uint32(p, (f) << 24 | (i)) - -#define ngx_spdy_frame_write_sid ngx_spdy_frame_aligned_write_uint32 -#define ngx_spdy_frame_write_window ngx_spdy_frame_aligned_write_uint32 - -#endif /* _NGX_HTTP_SPDY_H_INCLUDED_ */ diff --git a/src/http/ngx_http_spdy_filter_module.c b/src/http/ngx_http_spdy_filter_module.c deleted file mode 100644 index 377e935..0000000 --- a/src/http/ngx_http_spdy_filter_module.c +++ /dev/null @@ -1,1222 +0,0 @@ - -/* - * Copyright (C) Nginx, Inc. - * Copyright (C) Valentin V. Bartenev - */ - - -#include -#include -#include -#include -#include - -#include - - -#define ngx_http_spdy_nv_nsize(h) (NGX_SPDY_NV_NLEN_SIZE + sizeof(h) - 1) -#define ngx_http_spdy_nv_vsize(h) (NGX_SPDY_NV_VLEN_SIZE + sizeof(h) - 1) - -#define ngx_http_spdy_nv_write_num ngx_spdy_frame_write_uint32 -#define ngx_http_spdy_nv_write_nlen ngx_spdy_frame_write_uint32 -#define ngx_http_spdy_nv_write_vlen ngx_spdy_frame_write_uint32 - -#define ngx_http_spdy_nv_write_name(p, h) \ - ngx_cpymem(ngx_http_spdy_nv_write_nlen(p, sizeof(h) - 1), h, sizeof(h) - 1) - -#define ngx_http_spdy_nv_write_val(p, h) \ - ngx_cpymem(ngx_http_spdy_nv_write_vlen(p, sizeof(h) - 1), h, sizeof(h) - 1) - - -static ngx_chain_t *ngx_http_spdy_send_chain(ngx_connection_t *fc, - ngx_chain_t *in, off_t limit); - -static ngx_inline ngx_int_t ngx_http_spdy_filter_send( - ngx_connection_t *fc, ngx_http_spdy_stream_t *stream); -static ngx_inline ngx_int_t ngx_http_spdy_flow_control( - ngx_http_spdy_connection_t *sc, ngx_http_spdy_stream_t *stream); -static void ngx_http_spdy_waiting_queue(ngx_http_spdy_connection_t *sc, - ngx_http_spdy_stream_t *stream); - -static ngx_chain_t *ngx_http_spdy_filter_get_shadow( - ngx_http_spdy_stream_t *stream, ngx_buf_t *buf, off_t offset, off_t size); -static ngx_http_spdy_out_frame_t *ngx_http_spdy_filter_get_data_frame( - ngx_http_spdy_stream_t *stream, size_t len, ngx_chain_t *first, - ngx_chain_t *last); - -static ngx_int_t ngx_http_spdy_syn_frame_handler( - ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame); -static ngx_int_t ngx_http_spdy_data_frame_handler( - ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame); -static ngx_inline void ngx_http_spdy_handle_frame( - ngx_http_spdy_stream_t *stream, ngx_http_spdy_out_frame_t *frame); -static ngx_inline void ngx_http_spdy_handle_stream( - ngx_http_spdy_connection_t *sc, ngx_http_spdy_stream_t *stream); - -static void ngx_http_spdy_filter_cleanup(void *data); - -static ngx_int_t ngx_http_spdy_filter_init(ngx_conf_t *cf); - - -static ngx_http_module_t ngx_http_spdy_filter_module_ctx = { - NULL, /* preconfiguration */ - ngx_http_spdy_filter_init, /* postconfiguration */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - NULL, /* create location configuration */ - NULL /* merge location configuration */ -}; - - -ngx_module_t ngx_http_spdy_filter_module = { - NGX_MODULE_V1, - &ngx_http_spdy_filter_module_ctx, /* module context */ - NULL, /* 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_http_output_header_filter_pt ngx_http_next_header_filter; - - -static ngx_int_t -ngx_http_spdy_header_filter(ngx_http_request_t *r) -{ - int rc; - size_t len; - u_char *p, *buf, *last; - ngx_buf_t *b; - ngx_str_t host; - ngx_uint_t i, j, count, port; - ngx_chain_t *cl; - ngx_list_part_t *part, *pt; - ngx_table_elt_t *header, *h; - ngx_connection_t *c; - ngx_http_cleanup_t *cln; - ngx_http_core_loc_conf_t *clcf; - ngx_http_core_srv_conf_t *cscf; - ngx_http_spdy_stream_t *stream; - ngx_http_spdy_out_frame_t *frame; - ngx_http_spdy_connection_t *sc; - struct sockaddr_in *sin; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif - u_char addr[NGX_SOCKADDR_STRLEN]; - - if (!r->spdy_stream) { - return ngx_http_next_header_filter(r); - } - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "spdy header filter"); - - if (r->header_sent) { - return NGX_OK; - } - - r->header_sent = 1; - - if (r != r->main) { - return NGX_OK; - } - - c = r->connection; - - if (r->method == NGX_HTTP_HEAD) { - r->header_only = 1; - } - - switch (r->headers_out.status) { - - case NGX_HTTP_OK: - case NGX_HTTP_PARTIAL_CONTENT: - break; - - case NGX_HTTP_NOT_MODIFIED: - r->header_only = 1; - break; - - case NGX_HTTP_NO_CONTENT: - r->header_only = 1; - - ngx_str_null(&r->headers_out.content_type); - - r->headers_out.content_length = NULL; - r->headers_out.content_length_n = -1; - - /* fall through */ - - default: - r->headers_out.last_modified_time = -1; - r->headers_out.last_modified = NULL; - } - - len = NGX_SPDY_NV_NUM_SIZE - + ngx_http_spdy_nv_nsize(":version") - + ngx_http_spdy_nv_vsize("HTTP/1.1") - + ngx_http_spdy_nv_nsize(":status") - + (r->headers_out.status_line.len - ? NGX_SPDY_NV_VLEN_SIZE + r->headers_out.status_line.len - : ngx_http_spdy_nv_vsize("418")); - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - if (r->headers_out.server == NULL) { - len += ngx_http_spdy_nv_nsize("server"); - len += clcf->server_tokens ? ngx_http_spdy_nv_vsize(NGINX_VER) - : ngx_http_spdy_nv_vsize("nginx"); - } - - if (r->headers_out.date == NULL) { - len += ngx_http_spdy_nv_nsize("date") - + ngx_http_spdy_nv_vsize("Wed, 31 Dec 1986 10:00:00 GMT"); - } - - if (r->headers_out.content_type.len) { - len += ngx_http_spdy_nv_nsize("content-type") - + NGX_SPDY_NV_VLEN_SIZE + r->headers_out.content_type.len; - - if (r->headers_out.content_type_len == r->headers_out.content_type.len - && r->headers_out.charset.len) - { - len += sizeof("; charset=") - 1 + r->headers_out.charset.len; - } - } - - if (r->headers_out.content_length == NULL - && r->headers_out.content_length_n >= 0) - { - len += ngx_http_spdy_nv_nsize("content-length") - + NGX_SPDY_NV_VLEN_SIZE + NGX_OFF_T_LEN; - } - - if (r->headers_out.last_modified == NULL - && r->headers_out.last_modified_time != -1) - { - len += ngx_http_spdy_nv_nsize("last-modified") - + ngx_http_spdy_nv_vsize("Wed, 31 Dec 1986 10:00:00 GMT"); - } - - if (r->headers_out.location - && r->headers_out.location->value.len - && r->headers_out.location->value.data[0] == '/') - { - r->headers_out.location->hash = 0; - - if (clcf->server_name_in_redirect) { - cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); - host = cscf->server_name; - - } else if (r->headers_in.server.len) { - host = r->headers_in.server; - - } else { - host.len = NGX_SOCKADDR_STRLEN; - host.data = addr; - - if (ngx_connection_local_sockaddr(c, &host, 0) != NGX_OK) { - return NGX_ERROR; - } - } - - switch (c->local_sockaddr->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) c->local_sockaddr; - port = ntohs(sin6->sin6_port); - break; -#endif -#if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - port = 0; - break; -#endif - default: /* AF_INET */ - sin = (struct sockaddr_in *) c->local_sockaddr; - port = ntohs(sin->sin_port); - break; - } - - len += ngx_http_spdy_nv_nsize("location") - + ngx_http_spdy_nv_vsize("https://") - + host.len - + r->headers_out.location->value.len; - - if (clcf->port_in_redirect) { - -#if (NGX_HTTP_SSL) - if (c->ssl) - port = (port == 443) ? 0 : port; - else -#endif - port = (port == 80) ? 0 : port; - - } else { - port = 0; - } - - if (port) { - len += sizeof(":65535") - 1; - } - - } else { - ngx_str_null(&host); - port = 0; - } - - part = &r->headers_out.headers.part; - header = part->elts; - - for (i = 0; /* void */; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - header = part->elts; - i = 0; - } - - if (header[i].hash == 0) { - continue; - } - - len += NGX_SPDY_NV_NLEN_SIZE + header[i].key.len - + NGX_SPDY_NV_VLEN_SIZE + header[i].value.len; - } - - buf = ngx_alloc(len, r->pool->log); - if (buf == NULL) { - return NGX_ERROR; - } - - last = buf + NGX_SPDY_NV_NUM_SIZE; - - last = ngx_http_spdy_nv_write_name(last, ":version"); - last = ngx_http_spdy_nv_write_val(last, "HTTP/1.1"); - - last = ngx_http_spdy_nv_write_name(last, ":status"); - - if (r->headers_out.status_line.len) { - last = ngx_http_spdy_nv_write_vlen(last, - r->headers_out.status_line.len); - last = ngx_cpymem(last, r->headers_out.status_line.data, - r->headers_out.status_line.len); - } else { - last = ngx_http_spdy_nv_write_vlen(last, 3); - last = ngx_sprintf(last, "%03ui", r->headers_out.status); - } - - count = 2; - - if (r->headers_out.server == NULL) { - last = ngx_http_spdy_nv_write_name(last, "server"); - last = clcf->server_tokens - ? ngx_http_spdy_nv_write_val(last, NGINX_VER) - : ngx_http_spdy_nv_write_val(last, "nginx"); - - count++; - } - - if (r->headers_out.date == NULL) { - last = ngx_http_spdy_nv_write_name(last, "date"); - - last = ngx_http_spdy_nv_write_vlen(last, ngx_cached_http_time.len); - - last = ngx_cpymem(last, ngx_cached_http_time.data, - ngx_cached_http_time.len); - - count++; - } - - if (r->headers_out.content_type.len) { - - last = ngx_http_spdy_nv_write_name(last, "content-type"); - - p = last + NGX_SPDY_NV_VLEN_SIZE; - - last = ngx_cpymem(p, r->headers_out.content_type.data, - r->headers_out.content_type.len); - - if (r->headers_out.content_type_len == r->headers_out.content_type.len - && r->headers_out.charset.len) - { - last = ngx_cpymem(last, "; charset=", sizeof("; charset=") - 1); - - last = ngx_cpymem(last, r->headers_out.charset.data, - r->headers_out.charset.len); - - /* update r->headers_out.content_type for possible logging */ - - r->headers_out.content_type.len = last - p; - r->headers_out.content_type.data = p; - } - - (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE, - r->headers_out.content_type.len); - - count++; - } - - if (r->headers_out.content_length == NULL - && r->headers_out.content_length_n >= 0) - { - last = ngx_http_spdy_nv_write_name(last, "content-length"); - - p = last + NGX_SPDY_NV_VLEN_SIZE; - - last = ngx_sprintf(p, "%O", r->headers_out.content_length_n); - - (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE, - last - p); - - count++; - } - - if (r->headers_out.last_modified == NULL - && r->headers_out.last_modified_time != -1) - { - last = ngx_http_spdy_nv_write_name(last, "last-modified"); - - p = last + NGX_SPDY_NV_VLEN_SIZE; - - last = ngx_http_time(p, r->headers_out.last_modified_time); - - (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE, - last - p); - - count++; - } - - if (host.data) { - - last = ngx_http_spdy_nv_write_name(last, "location"); - - p = last + NGX_SPDY_NV_VLEN_SIZE; - - last = ngx_cpymem(p, "http", sizeof("http") - 1); - -#if (NGX_HTTP_SSL) - if (c->ssl) { - *last++ ='s'; - } -#endif - - *last++ = ':'; *last++ = '/'; *last++ = '/'; - - last = ngx_cpymem(last, host.data, host.len); - - if (port) { - last = ngx_sprintf(last, ":%ui", port); - } - - last = ngx_cpymem(last, r->headers_out.location->value.data, - r->headers_out.location->value.len); - - /* update r->headers_out.location->value for possible logging */ - - r->headers_out.location->value.len = last - p; - r->headers_out.location->value.data = p; - ngx_str_set(&r->headers_out.location->key, "location"); - - (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE, - r->headers_out.location->value.len); - - count++; - } - - part = &r->headers_out.headers.part; - header = part->elts; - - for (i = 0; /* void */; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - header = part->elts; - i = 0; - } - - if (header[i].hash == 0 || header[i].hash == 2) { - continue; - } - - last = ngx_http_spdy_nv_write_nlen(last, header[i].key.len); - - ngx_strlow(last, header[i].key.data, header[i].key.len); - last += header[i].key.len; - - p = last + NGX_SPDY_NV_VLEN_SIZE; - - last = ngx_cpymem(p, header[i].value.data, header[i].value.len); - - pt = part; - h = header; - - for (j = i + 1; /* void */; j++) { - - if (j >= pt->nelts) { - if (pt->next == NULL) { - break; - } - - pt = pt->next; - h = pt->elts; - j = 0; - } - - if (h[j].hash == 0 || h[j].hash == 2 - || h[j].key.len != header[i].key.len - || ngx_strncasecmp(header[i].key.data, h[j].key.data, - header[i].key.len)) - { - continue; - } - - if (h[j].value.len) { - if (last != p) { - *last++ = '\0'; - } - - last = ngx_cpymem(last, h[j].value.data, h[j].value.len); - } - - h[j].hash = 2; - } - - (void) ngx_http_spdy_nv_write_vlen(p - NGX_SPDY_NV_VLEN_SIZE, - last - p); - - count++; - } - - (void) ngx_http_spdy_nv_write_num(buf, count); - - stream = r->spdy_stream; - sc = stream->connection; - - len = last - buf; - - b = ngx_create_temp_buf(r->pool, NGX_SPDY_FRAME_HEADER_SIZE - + NGX_SPDY_SYN_REPLY_SIZE - + deflateBound(&sc->zstream_out, len)); - if (b == NULL) { - ngx_free(buf); - return NGX_ERROR; - } - - b->last += NGX_SPDY_FRAME_HEADER_SIZE + NGX_SPDY_SYN_REPLY_SIZE; - - sc->zstream_out.next_in = buf; - sc->zstream_out.avail_in = len; - sc->zstream_out.next_out = b->last; - sc->zstream_out.avail_out = b->end - b->last; - - rc = deflate(&sc->zstream_out, Z_SYNC_FLUSH); - - ngx_free(buf); - - if (rc != Z_OK) { - ngx_log_error(NGX_LOG_ALERT, c->log, 0, "deflate() failed: %d", rc); - return NGX_ERROR; - } - - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0, - "spdy deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d", - sc->zstream_out.next_in, sc->zstream_out.next_out, - sc->zstream_out.avail_in, sc->zstream_out.avail_out, - rc); - - b->last = sc->zstream_out.next_out; - - p = b->pos; - p = ngx_spdy_frame_write_head(p, NGX_SPDY_SYN_REPLY); - - len = b->last - b->pos; - - r->header_size = len; - - len -= NGX_SPDY_FRAME_HEADER_SIZE; - - if (r->header_only) { - b->last_buf = 1; - p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_FIN, len); - - } else { - p = ngx_spdy_frame_write_flags_and_len(p, 0, len); - } - - (void) ngx_spdy_frame_write_sid(p, stream->id); - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - cl->next = NULL; - - frame = ngx_palloc(r->pool, sizeof(ngx_http_spdy_out_frame_t)); - if (frame == NULL) { - return NGX_ERROR; - } - - frame->first = cl; - frame->last = cl; - frame->handler = ngx_http_spdy_syn_frame_handler; - frame->stream = stream; - frame->length = len; - frame->priority = stream->priority; - frame->blocked = 1; - frame->fin = r->header_only; - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0, - "spdy:%ui create SYN_REPLY frame %p: len:%uz", - stream->id, frame, frame->length); - - ngx_http_spdy_queue_blocked_frame(sc, frame); - - cln = ngx_http_cleanup_add(r, 0); - if (cln == NULL) { - return NGX_ERROR; - } - - cln->handler = ngx_http_spdy_filter_cleanup; - cln->data = stream; - - stream->queued = 1; - - c->send_chain = ngx_http_spdy_send_chain; - c->need_last_buf = 1; - - return ngx_http_spdy_filter_send(c, stream); -} - - -static ngx_chain_t * -ngx_http_spdy_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) -{ - off_t size, offset; - size_t rest, frame_size; - ngx_chain_t *cl, *out, **ln; - ngx_http_request_t *r; - ngx_http_spdy_stream_t *stream; - ngx_http_spdy_loc_conf_t *slcf; - ngx_http_spdy_out_frame_t *frame; - ngx_http_spdy_connection_t *sc; - - r = fc->data; - stream = r->spdy_stream; - -#if (NGX_SUPPRESS_WARN) - size = 0; -#endif - - while (in) { - size = ngx_buf_size(in->buf); - - if (size || in->buf->last_buf) { - break; - } - - in = in->next; - } - - if (in == NULL) { - - if (stream->queued) { - fc->write->delayed = 1; - } else { - fc->buffered &= ~NGX_SPDY_BUFFERED; - } - - return NULL; - } - - sc = stream->connection; - - if (size && ngx_http_spdy_flow_control(sc, stream) == NGX_DECLINED) { - fc->write->delayed = 1; - return in; - } - - if (limit == 0 || limit > (off_t) sc->send_window) { - limit = sc->send_window; - } - - if (limit > stream->send_window) { - limit = (stream->send_window > 0) ? stream->send_window : 0; - } - - if (in->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow) { - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_CHAIN_ERROR; - } - - cl->buf = in->buf; - in->buf = cl->buf->shadow; - - offset = ngx_buf_in_memory(in->buf) - ? (cl->buf->pos - in->buf->pos) - : (cl->buf->file_pos - in->buf->file_pos); - - cl->next = stream->free_bufs; - stream->free_bufs = cl; - - } else { - offset = 0; - } - -#if (NGX_SUPPRESS_WARN) - cl = NULL; -#endif - - slcf = ngx_http_get_module_loc_conf(r, ngx_http_spdy_module); - - frame_size = (limit <= (off_t) slcf->chunk_size) ? (size_t) limit - : slcf->chunk_size; - - for ( ;; ) { - ln = &out; - rest = frame_size; - - while ((off_t) rest >= size) { - - if (offset) { - cl = ngx_http_spdy_filter_get_shadow(stream, in->buf, - offset, size); - if (cl == NULL) { - return NGX_CHAIN_ERROR; - } - - offset = 0; - - } else { - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_CHAIN_ERROR; - } - - cl->buf = in->buf; - } - - *ln = cl; - ln = &cl->next; - - rest -= (size_t) size; - in = in->next; - - if (in == NULL) { - frame_size -= rest; - rest = 0; - break; - } - - size = ngx_buf_size(in->buf); - } - - if (rest) { - cl = ngx_http_spdy_filter_get_shadow(stream, in->buf, - offset, rest); - if (cl == NULL) { - return NGX_CHAIN_ERROR; - } - - cl->buf->flush = 0; - cl->buf->last_buf = 0; - - *ln = cl; - - offset += rest; - size -= rest; - } - - frame = ngx_http_spdy_filter_get_data_frame(stream, frame_size, - out, cl); - if (frame == NULL) { - return NGX_CHAIN_ERROR; - } - - ngx_http_spdy_queue_frame(sc, frame); - - sc->send_window -= frame_size; - - stream->send_window -= frame_size; - stream->queued++; - - if (in == NULL) { - break; - } - - limit -= frame_size; - - if (limit == 0) { - break; - } - - if (limit < (off_t) slcf->chunk_size) { - frame_size = (size_t) limit; - } - } - - if (offset) { - cl = ngx_http_spdy_filter_get_shadow(stream, in->buf, offset, size); - if (cl == NULL) { - return NGX_CHAIN_ERROR; - } - - in->buf = cl->buf; - ngx_free_chain(r->pool, cl); - } - - if (ngx_http_spdy_filter_send(fc, stream) == NGX_ERROR) { - return NGX_CHAIN_ERROR; - } - - if (in && ngx_http_spdy_flow_control(sc, stream) == NGX_DECLINED) { - fc->write->delayed = 1; - } - - return in; -} - - -static ngx_chain_t * -ngx_http_spdy_filter_get_shadow(ngx_http_spdy_stream_t *stream, ngx_buf_t *buf, - off_t offset, off_t size) -{ - ngx_buf_t *chunk; - ngx_chain_t *cl; - - cl = ngx_chain_get_free_buf(stream->request->pool, &stream->free_bufs); - if (cl == NULL) { - return NULL; - } - - chunk = cl->buf; - - ngx_memcpy(chunk, buf, sizeof(ngx_buf_t)); - - chunk->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow; - chunk->shadow = buf; - - if (ngx_buf_in_memory(chunk)) { - chunk->pos += offset; - chunk->last = chunk->pos + size; - } - - if (chunk->in_file) { - chunk->file_pos += offset; - chunk->file_last = chunk->file_pos + size; - } - - return cl; -} - - -static ngx_http_spdy_out_frame_t * -ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream, - size_t len, ngx_chain_t *first, ngx_chain_t *last) -{ - u_char *p; - ngx_buf_t *buf; - ngx_uint_t flags; - ngx_chain_t *cl; - ngx_http_spdy_out_frame_t *frame; - - - frame = stream->free_frames; - - if (frame) { - stream->free_frames = frame->next; - - } else { - frame = ngx_palloc(stream->request->pool, - sizeof(ngx_http_spdy_out_frame_t)); - if (frame == NULL) { - return NULL; - } - } - - flags = last->buf->last_buf ? NGX_SPDY_FLAG_FIN : 0; - - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0, - "spdy:%ui create DATA frame %p: len:%uz flags:%ui", - stream->id, frame, len, flags); - - cl = ngx_chain_get_free_buf(stream->request->pool, - &stream->free_data_headers); - if (cl == NULL) { - return NULL; - } - - buf = cl->buf; - - if (buf->start) { - p = buf->start; - buf->pos = p; - - p += NGX_SPDY_SID_SIZE; - - (void) ngx_spdy_frame_write_flags_and_len(p, flags, len); - - } else { - p = ngx_palloc(stream->request->pool, NGX_SPDY_FRAME_HEADER_SIZE); - if (p == NULL) { - return NULL; - } - - buf->pos = p; - buf->start = p; - - p = ngx_spdy_frame_write_sid(p, stream->id); - p = ngx_spdy_frame_write_flags_and_len(p, flags, len); - - buf->last = p; - buf->end = p; - - buf->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_get_data_frame; - buf->memory = 1; - } - - cl->next = first; - first = cl; - - last->buf->flush = 1; - - frame->first = first; - frame->last = last; - frame->handler = ngx_http_spdy_data_frame_handler; - frame->stream = stream; - frame->length = len; - frame->priority = stream->priority; - frame->blocked = 0; - frame->fin = last->buf->last_buf; - - return frame; -} - - -static ngx_inline ngx_int_t -ngx_http_spdy_filter_send(ngx_connection_t *fc, ngx_http_spdy_stream_t *stream) -{ - stream->blocked = 1; - - if (ngx_http_spdy_send_output_queue(stream->connection) == NGX_ERROR) { - fc->error = 1; - return NGX_ERROR; - } - - stream->blocked = 0; - - if (stream->queued) { - fc->buffered |= NGX_SPDY_BUFFERED; - fc->write->delayed = 1; - return NGX_AGAIN; - } - - fc->buffered &= ~NGX_SPDY_BUFFERED; - - return NGX_OK; -} - - -static ngx_inline ngx_int_t -ngx_http_spdy_flow_control(ngx_http_spdy_connection_t *sc, - ngx_http_spdy_stream_t *stream) -{ - if (stream->send_window <= 0) { - stream->exhausted = 1; - return NGX_DECLINED; - } - - if (sc->send_window == 0) { - ngx_http_spdy_waiting_queue(sc, stream); - return NGX_DECLINED; - } - - return NGX_OK; -} - - -static void -ngx_http_spdy_waiting_queue(ngx_http_spdy_connection_t *sc, - ngx_http_spdy_stream_t *stream) -{ - ngx_queue_t *q; - ngx_http_spdy_stream_t *s; - - if (stream->handled) { - return; - } - - stream->handled = 1; - - for (q = ngx_queue_last(&sc->waiting); - q != ngx_queue_sentinel(&sc->waiting); - q = ngx_queue_prev(q)) - { - s = ngx_queue_data(q, ngx_http_spdy_stream_t, queue); - - /* - * NB: higher values represent lower priorities. - */ - if (stream->priority >= s->priority) { - break; - } - } - - ngx_queue_insert_after(q, &stream->queue); -} - - -static ngx_int_t -ngx_http_spdy_syn_frame_handler(ngx_http_spdy_connection_t *sc, - ngx_http_spdy_out_frame_t *frame) -{ - ngx_buf_t *buf; - ngx_http_spdy_stream_t *stream; - - buf = frame->first->buf; - - if (buf->pos != buf->last) { - return NGX_AGAIN; - } - - stream = frame->stream; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy:%ui SYN_REPLY frame %p was sent", stream->id, frame); - - ngx_free_chain(stream->request->pool, frame->first); - - ngx_http_spdy_handle_frame(stream, frame); - - ngx_http_spdy_handle_stream(sc, stream); - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_spdy_data_frame_handler(ngx_http_spdy_connection_t *sc, - ngx_http_spdy_out_frame_t *frame) -{ - ngx_buf_t *buf; - ngx_chain_t *cl, *ln; - ngx_http_spdy_stream_t *stream; - - stream = frame->stream; - - cl = frame->first; - - if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_data_frame) { - - if (cl->buf->pos != cl->buf->last) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy:%ui DATA frame %p was sent partially", - stream->id, frame); - - return NGX_AGAIN; - } - - ln = cl->next; - - cl->next = stream->free_data_headers; - stream->free_data_headers = cl; - - if (cl == frame->last) { - goto done; - } - - cl = ln; - } - - for ( ;; ) { - if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow) { - buf = cl->buf->shadow; - - if (ngx_buf_in_memory(buf)) { - buf->pos = cl->buf->pos; - } - - if (buf->in_file) { - buf->file_pos = cl->buf->file_pos; - } - } - - if (ngx_buf_size(cl->buf) != 0) { - - if (cl != frame->first) { - frame->first = cl; - ngx_http_spdy_handle_stream(sc, stream); - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy:%ui DATA frame %p was sent partially", - stream->id, frame); - - return NGX_AGAIN; - } - - ln = cl->next; - - if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow) { - cl->next = stream->free_bufs; - stream->free_bufs = cl; - - } else { - ngx_free_chain(stream->request->pool, cl); - } - - if (cl == frame->last) { - goto done; - } - - cl = ln; - } - -done: - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, - "spdy:%ui DATA frame %p was sent", stream->id, frame); - - stream->request->header_size += NGX_SPDY_FRAME_HEADER_SIZE; - - ngx_http_spdy_handle_frame(stream, frame); - - ngx_http_spdy_handle_stream(sc, stream); - - return NGX_OK; -} - - -static ngx_inline void -ngx_http_spdy_handle_frame(ngx_http_spdy_stream_t *stream, - ngx_http_spdy_out_frame_t *frame) -{ - ngx_http_request_t *r; - - r = stream->request; - - r->connection->sent += NGX_SPDY_FRAME_HEADER_SIZE + frame->length; - - if (frame->fin) { - stream->out_closed = 1; - } - - frame->next = stream->free_frames; - stream->free_frames = frame; - - stream->queued--; -} - - -static ngx_inline void -ngx_http_spdy_handle_stream(ngx_http_spdy_connection_t *sc, - ngx_http_spdy_stream_t *stream) -{ - ngx_event_t *wev; - - if (stream->handled || stream->blocked || stream->exhausted) { - return; - } - - wev = stream->request->connection->write; - - /* - * This timer can only be set if the stream was delayed because of rate - * limit. In that case the event should be triggered by the timer. - */ - - if (!wev->timer_set) { - wev->delayed = 0; - - stream->handled = 1; - ngx_queue_insert_tail(&sc->posted, &stream->queue); - } -} - - -static void -ngx_http_spdy_filter_cleanup(void *data) -{ - ngx_http_spdy_stream_t *stream = data; - - size_t delta; - ngx_http_spdy_out_frame_t *frame, **fn; - ngx_http_spdy_connection_t *sc; - - if (stream->handled) { - stream->handled = 0; - ngx_queue_remove(&stream->queue); - } - - if (stream->queued == 0) { - return; - } - - delta = 0; - sc = stream->connection; - fn = &sc->last_out; - - for ( ;; ) { - frame = *fn; - - if (frame == NULL) { - break; - } - - if (frame->stream == stream && !frame->blocked) { - *fn = frame->next; - - delta += frame->length; - - if (--stream->queued == 0) { - break; - } - - continue; - } - - fn = &frame->next; - } - - if (sc->send_window == 0 && delta && !ngx_queue_empty(&sc->waiting)) { - ngx_queue_add(&sc->posted, &sc->waiting); - ngx_queue_init(&sc->waiting); - } - - sc->send_window += delta; -} - - -static ngx_int_t -ngx_http_spdy_filter_init(ngx_conf_t *cf) -{ - ngx_http_next_header_filter = ngx_http_top_header_filter; - ngx_http_top_header_filter = ngx_http_spdy_header_filter; - - return NGX_OK; -} diff --git a/src/http/ngx_http_spdy_module.c b/src/http/ngx_http_spdy_module.c deleted file mode 100644 index 5178a36..0000000 --- a/src/http/ngx_http_spdy_module.c +++ /dev/null @@ -1,408 +0,0 @@ - -/* - * Copyright (C) Nginx, Inc. - * Copyright (C) Valentin V. Bartenev - */ - - -#include -#include -#include -#include - - -static ngx_int_t ngx_http_spdy_add_variables(ngx_conf_t *cf); - -static ngx_int_t ngx_http_spdy_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); -static ngx_int_t ngx_http_spdy_request_priority_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); - -static ngx_int_t ngx_http_spdy_module_init(ngx_cycle_t *cycle); - -static void *ngx_http_spdy_create_main_conf(ngx_conf_t *cf); -static char *ngx_http_spdy_init_main_conf(ngx_conf_t *cf, void *conf); -static void *ngx_http_spdy_create_srv_conf(ngx_conf_t *cf); -static char *ngx_http_spdy_merge_srv_conf(ngx_conf_t *cf, void *parent, - void *child); -static void *ngx_http_spdy_create_loc_conf(ngx_conf_t *cf); -static char *ngx_http_spdy_merge_loc_conf(ngx_conf_t *cf, void *parent, - void *child); - -static char *ngx_http_spdy_recv_buffer_size(ngx_conf_t *cf, void *post, - void *data); -static char *ngx_http_spdy_pool_size(ngx_conf_t *cf, void *post, void *data); -static char *ngx_http_spdy_streams_index_mask(ngx_conf_t *cf, void *post, - void *data); -static char *ngx_http_spdy_chunk_size(ngx_conf_t *cf, void *post, void *data); - - -static ngx_conf_num_bounds_t ngx_http_spdy_headers_comp_bounds = { - ngx_conf_check_num_bounds, 0, 9 -}; - -static ngx_conf_post_t ngx_http_spdy_recv_buffer_size_post = - { ngx_http_spdy_recv_buffer_size }; -static ngx_conf_post_t ngx_http_spdy_pool_size_post = - { ngx_http_spdy_pool_size }; -static ngx_conf_post_t ngx_http_spdy_streams_index_mask_post = - { ngx_http_spdy_streams_index_mask }; -static ngx_conf_post_t ngx_http_spdy_chunk_size_post = - { ngx_http_spdy_chunk_size }; - - -static ngx_command_t ngx_http_spdy_commands[] = { - - { ngx_string("spdy_recv_buffer_size"), - NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_MAIN_CONF_OFFSET, - offsetof(ngx_http_spdy_main_conf_t, recv_buffer_size), - &ngx_http_spdy_recv_buffer_size_post }, - - { ngx_string("spdy_pool_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_spdy_srv_conf_t, pool_size), - &ngx_http_spdy_pool_size_post }, - - { ngx_string("spdy_max_concurrent_streams"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_spdy_srv_conf_t, concurrent_streams), - NULL }, - - { ngx_string("spdy_streams_index_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_spdy_srv_conf_t, streams_index_mask), - &ngx_http_spdy_streams_index_mask_post }, - - { ngx_string("spdy_recv_timeout"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_spdy_srv_conf_t, recv_timeout), - NULL }, - - { ngx_string("spdy_keepalive_timeout"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_spdy_srv_conf_t, keepalive_timeout), - NULL }, - - { ngx_string("spdy_headers_comp"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_spdy_srv_conf_t, headers_comp), - &ngx_http_spdy_headers_comp_bounds }, - - { ngx_string("spdy_chunk_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_spdy_loc_conf_t, chunk_size), - &ngx_http_spdy_chunk_size_post }, - - ngx_null_command -}; - - -static ngx_http_module_t ngx_http_spdy_module_ctx = { - ngx_http_spdy_add_variables, /* preconfiguration */ - NULL, /* postconfiguration */ - - ngx_http_spdy_create_main_conf, /* create main configuration */ - ngx_http_spdy_init_main_conf, /* init main configuration */ - - ngx_http_spdy_create_srv_conf, /* create server configuration */ - ngx_http_spdy_merge_srv_conf, /* merge server configuration */ - - ngx_http_spdy_create_loc_conf, /* create location configuration */ - ngx_http_spdy_merge_loc_conf /* merge location configuration */ -}; - - -ngx_module_t ngx_http_spdy_module = { - NGX_MODULE_V1, - &ngx_http_spdy_module_ctx, /* module context */ - ngx_http_spdy_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init master */ - ngx_http_spdy_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_http_variable_t ngx_http_spdy_vars[] = { - - { ngx_string("spdy"), NULL, - ngx_http_spdy_variable, 0, 0, 0 }, - - { ngx_string("spdy_request_priority"), NULL, - ngx_http_spdy_request_priority_variable, 0, 0, 0 }, - - { ngx_null_string, NULL, NULL, 0, 0, 0 } -}; - - -static ngx_int_t -ngx_http_spdy_add_variables(ngx_conf_t *cf) -{ - ngx_http_variable_t *var, *v; - - for (v = ngx_http_spdy_vars; v->name.len; v++) { - var = ngx_http_add_variable(cf, &v->name, v->flags); - if (var == NULL) { - return NGX_ERROR; - } - - var->get_handler = v->get_handler; - var->data = v->data; - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_spdy_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) -{ - if (r->spdy_stream) { - v->len = sizeof("3.1") - 1; - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - v->data = (u_char *) "3.1"; - - return NGX_OK; - } - - *v = ngx_http_variable_null_value; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_spdy_request_priority_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) -{ - if (r->spdy_stream) { - v->len = 1; - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - - v->data = ngx_pnalloc(r->pool, 1); - if (v->data == NULL) { - return NGX_ERROR; - } - - v->data[0] = '0' + (u_char) r->spdy_stream->priority; - - return NGX_OK; - } - - *v = ngx_http_variable_null_value; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_spdy_module_init(ngx_cycle_t *cycle) -{ - ngx_http_spdy_request_headers_init(); - - return NGX_OK; -} - - -static void * -ngx_http_spdy_create_main_conf(ngx_conf_t *cf) -{ - ngx_http_spdy_main_conf_t *smcf; - - smcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_spdy_main_conf_t)); - if (smcf == NULL) { - return NULL; - } - - smcf->recv_buffer_size = NGX_CONF_UNSET_SIZE; - - return smcf; -} - - -static char * -ngx_http_spdy_init_main_conf(ngx_conf_t *cf, void *conf) -{ - ngx_http_spdy_main_conf_t *smcf = conf; - - ngx_conf_init_size_value(smcf->recv_buffer_size, 256 * 1024); - - return NGX_CONF_OK; -} - - -static void * -ngx_http_spdy_create_srv_conf(ngx_conf_t *cf) -{ - ngx_http_spdy_srv_conf_t *sscf; - - sscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_spdy_srv_conf_t)); - if (sscf == NULL) { - return NULL; - } - - sscf->pool_size = NGX_CONF_UNSET_SIZE; - - sscf->concurrent_streams = NGX_CONF_UNSET_UINT; - sscf->streams_index_mask = NGX_CONF_UNSET_UINT; - - sscf->recv_timeout = NGX_CONF_UNSET_MSEC; - sscf->keepalive_timeout = NGX_CONF_UNSET_MSEC; - - sscf->headers_comp = NGX_CONF_UNSET; - - return sscf; -} - - -static char * -ngx_http_spdy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_http_spdy_srv_conf_t *prev = parent; - ngx_http_spdy_srv_conf_t *conf = child; - - ngx_conf_merge_size_value(conf->pool_size, prev->pool_size, 4096); - - ngx_conf_merge_uint_value(conf->concurrent_streams, - prev->concurrent_streams, 100); - - ngx_conf_merge_uint_value(conf->streams_index_mask, - prev->streams_index_mask, 32 - 1); - - ngx_conf_merge_msec_value(conf->recv_timeout, - prev->recv_timeout, 30000); - ngx_conf_merge_msec_value(conf->keepalive_timeout, - prev->keepalive_timeout, 180000); - - ngx_conf_merge_value(conf->headers_comp, prev->headers_comp, 0); - - return NGX_CONF_OK; -} - - -static void * -ngx_http_spdy_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_spdy_loc_conf_t *slcf; - - slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_spdy_loc_conf_t)); - if (slcf == NULL) { - return NULL; - } - - slcf->chunk_size = NGX_CONF_UNSET_SIZE; - - return slcf; -} - - -static char * -ngx_http_spdy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_http_spdy_loc_conf_t *prev = parent; - ngx_http_spdy_loc_conf_t *conf = child; - - ngx_conf_merge_size_value(conf->chunk_size, prev->chunk_size, 8 * 1024); - - return NGX_CONF_OK; -} - - -static char * -ngx_http_spdy_recv_buffer_size(ngx_conf_t *cf, void *post, void *data) -{ - size_t *sp = data; - - if (*sp <= 2 * NGX_SPDY_STATE_BUFFER_SIZE) { - return "value is too small"; - } - - return NGX_CONF_OK; -} - - -static char * -ngx_http_spdy_pool_size(ngx_conf_t *cf, void *post, void *data) -{ - size_t *sp = data; - - if (*sp < NGX_MIN_POOL_SIZE) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the pool size must be no less than %uz", - NGX_MIN_POOL_SIZE); - return NGX_CONF_ERROR; - } - - if (*sp % NGX_POOL_ALIGNMENT) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the pool size must be a multiple of %uz", - NGX_POOL_ALIGNMENT); - return NGX_CONF_ERROR; - } - - return NGX_CONF_OK; -} - - -static char * -ngx_http_spdy_streams_index_mask(ngx_conf_t *cf, void *post, void *data) -{ - ngx_uint_t *np = data; - - ngx_uint_t mask; - - mask = *np - 1; - - if (*np == 0 || (*np & mask)) { - return "must be a power of two"; - } - - *np = mask; - - return NGX_CONF_OK; -} - - -static char * -ngx_http_spdy_chunk_size(ngx_conf_t *cf, void *post, void *data) -{ - size_t *sp = data; - - if (*sp == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the spdy chunk size cannot be zero"); - return NGX_CONF_ERROR; - } - - if (*sp > NGX_SPDY_MAX_FRAME_SIZE) { - *sp = NGX_SPDY_MAX_FRAME_SIZE; - } - - return NGX_CONF_OK; -} diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 4b0332a..1530596 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -475,8 +475,8 @@ ngx_http_upstream_init(ngx_http_request_t *r) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http init upstream, client timer: %d", c->read->timer_set); -#if (NGX_HTTP_SPDY) - if (r->spdy_stream) { +#if (NGX_HTTP_V2) + if (r->stream) { ngx_http_upstream_init_request(r); return; } @@ -534,15 +534,24 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) r->write_event_handler = ngx_http_request_empty_handler; - if (rc == NGX_DONE) { - return; - } - if (rc == NGX_ERROR) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } + if (rc == NGX_OK) { + rc = ngx_http_upstream_cache_send(r, u); + + if (rc == NGX_DONE) { + return; + } + + if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) { + rc = NGX_DECLINED; + r->cached = 0; + } + } + if (rc != NGX_DECLINED) { ngx_http_finalize_request(r, rc); return; @@ -837,13 +846,7 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u) case NGX_OK: - rc = ngx_http_upstream_cache_send(r, u); - - if (rc != NGX_HTTP_UPSTREAM_INVALID_HEADER) { - return rc; - } - - break; + return NGX_OK; case NGX_HTTP_CACHE_STALE: @@ -1148,8 +1151,8 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, return; } -#if (NGX_HTTP_SPDY) - if (r->spdy_stream) { +#if (NGX_HTTP_V2) + if (r->stream) { return; } #endif diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c new file mode 100644 index 0000000..bf07997 --- /dev/null +++ b/src/http/v2/ngx_http_v2.c @@ -0,0 +1,4036 @@ + +/* + * Copyright (C) Nginx, Inc. + * Copyright (C) Valentin V. Bartenev + */ + + +#include +#include +#include +#include + + +/* errors */ +#define NGX_HTTP_V2_NO_ERROR 0x0 +#define NGX_HTTP_V2_PROTOCOL_ERROR 0x1 +#define NGX_HTTP_V2_INTERNAL_ERROR 0x2 +#define NGX_HTTP_V2_FLOW_CTRL_ERROR 0x3 +#define NGX_HTTP_V2_SETTINGS_TIMEOUT 0x4 +#define NGX_HTTP_V2_STREAM_CLOSED 0x5 +#define NGX_HTTP_V2_SIZE_ERROR 0x6 +#define NGX_HTTP_V2_REFUSED_STREAM 0x7 +#define NGX_HTTP_V2_CANCEL 0x8 +#define NGX_HTTP_V2_COMP_ERROR 0x9 +#define NGX_HTTP_V2_CONNECT_ERROR 0xa +#define NGX_HTTP_V2_ENHANCE_YOUR_CALM 0xb +#define NGX_HTTP_V2_INADEQUATE_SECURITY 0xc +#define NGX_HTTP_V2_HTTP_1_1_REQUIRED 0xd + +/* frame sizes */ +#define NGX_HTTP_V2_RST_STREAM_SIZE 4 +#define NGX_HTTP_V2_PRIORITY_SIZE 5 +#define NGX_HTTP_V2_PING_SIZE 8 +#define NGX_HTTP_V2_GOAWAY_SIZE 8 +#define NGX_HTTP_V2_WINDOW_UPDATE_SIZE 4 + +#define NGX_HTTP_V2_STREAM_ID_SIZE 4 + +#define NGX_HTTP_V2_SETTINGS_PARAM_SIZE 6 + +/* settings fields */ +#define NGX_HTTP_V2_HEADER_TABLE_SIZE_SETTING 0x1 +#define NGX_HTTP_V2_MAX_STREAMS_SETTING 0x3 +#define NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING 0x4 +#define NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING 0x5 + +#define NGX_HTTP_V2_FRAME_BUFFER_SIZE 24 + +#define NGX_HTTP_V2_DEFAULT_FRAME_SIZE (1 << 14) + +#define NGX_HTTP_V2_MAX_WINDOW ((1U << 31) - 1) +#define NGX_HTTP_V2_DEFAULT_WINDOW 65535 + +#define NGX_HTTP_V2_ROOT (void *) -1 + + +static void ngx_http_v2_read_handler(ngx_event_t *rev); +static void ngx_http_v2_write_handler(ngx_event_t *wev); +static void ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c); + +static u_char *ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_preface(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_preface_end(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_head(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_header_block(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_field_huff(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_field_raw(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_field_skip(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_header_complete(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_handle_continuation(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end, ngx_http_v2_handler_pt handler); +static u_char *ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_rst_stream(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_settings(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_push_promise(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_ping(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_goaway(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_window_update(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_continuation(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_complete(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_skip_padded(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_skip(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_skip_headers(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); +static u_char *ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end, ngx_http_v2_handler_pt handler); +static u_char *ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c, + ngx_uint_t err); + +static ngx_int_t ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c, + u_char **pos, u_char *end, ngx_uint_t prefix); + +static ngx_http_v2_stream_t *ngx_http_v2_create_stream( + ngx_http_v2_connection_t *h2c); +static ngx_http_v2_node_t *ngx_http_v2_get_node_by_id( + ngx_http_v2_connection_t *h2c, ngx_uint_t sid, ngx_uint_t alloc); +static ngx_http_v2_node_t *ngx_http_v2_get_closed_node( + ngx_http_v2_connection_t *h2c); +#define ngx_http_v2_index_size(h2scf) (h2scf->streams_index_mask + 1) +#define ngx_http_v2_index(h2scf, sid) ((sid >> 1) & h2scf->streams_index_mask) + +static ngx_int_t ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, + ngx_uint_t ack); +static ngx_int_t ngx_http_v2_settings_frame_handler( + ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame); +static ngx_int_t ngx_http_v2_send_window_update(ngx_http_v2_connection_t *h2c, + ngx_uint_t sid, size_t window); +static ngx_int_t ngx_http_v2_send_rst_stream(ngx_http_v2_connection_t *h2c, + ngx_uint_t sid, ngx_uint_t status); + +static ngx_http_v2_out_frame_t *ngx_http_v2_get_frame( + ngx_http_v2_connection_t *h2c, size_t length, ngx_uint_t type, + u_char flags, ngx_uint_t sid); +static ngx_int_t ngx_http_v2_frame_handler(ngx_http_v2_connection_t *h2c, + ngx_http_v2_out_frame_t *frame); + +static ngx_int_t ngx_http_v2_validate_header(ngx_http_request_t *r, + ngx_http_v2_header_t *header); +static ngx_int_t ngx_http_v2_pseudo_header(ngx_http_request_t *r, + ngx_http_v2_header_t *header); +static ngx_int_t ngx_http_v2_parse_path(ngx_http_request_t *r, + ngx_http_v2_header_t *header); +static ngx_int_t ngx_http_v2_parse_method(ngx_http_request_t *r, + ngx_http_v2_header_t *header); +static ngx_int_t ngx_http_v2_parse_scheme(ngx_http_request_t *r, + ngx_http_v2_header_t *header); +static ngx_int_t ngx_http_v2_parse_authority(ngx_http_request_t *r, + ngx_http_v2_header_t *header); +static ngx_int_t ngx_http_v2_construct_request_line(ngx_http_request_t *r); +static ngx_int_t ngx_http_v2_cookie(ngx_http_request_t *r, + ngx_http_v2_header_t *header); +static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r); +static void ngx_http_v2_run_request(ngx_http_request_t *r); +static ngx_int_t ngx_http_v2_init_request_body(ngx_http_request_t *r); + +static ngx_int_t ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, + ngx_http_v2_stream_t *stream, ngx_uint_t status); +static void ngx_http_v2_close_stream_handler(ngx_event_t *ev); +static void ngx_http_v2_handle_connection_handler(ngx_event_t *rev); +static void ngx_http_v2_idle_handler(ngx_event_t *rev); +static void ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c, + ngx_uint_t status); + +static ngx_int_t ngx_http_v2_adjust_windows(ngx_http_v2_connection_t *h2c, + ssize_t delta); +static void ngx_http_v2_set_dependency(ngx_http_v2_connection_t *h2c, + ngx_http_v2_node_t *node, ngx_uint_t depend, ngx_uint_t exclusive); +static void ngx_http_v2_node_children_update(ngx_http_v2_node_t *node); + +static void ngx_http_v2_pool_cleanup(void *data); + + +static ngx_http_v2_handler_pt ngx_http_v2_frame_states[] = { + ngx_http_v2_state_data, + ngx_http_v2_state_headers, + ngx_http_v2_state_priority, + ngx_http_v2_state_rst_stream, + ngx_http_v2_state_settings, + ngx_http_v2_state_push_promise, + ngx_http_v2_state_ping, + ngx_http_v2_state_goaway, + ngx_http_v2_state_window_update, + ngx_http_v2_state_continuation +}; + +#define NGX_HTTP_V2_FRAME_STATES \ + (sizeof(ngx_http_v2_frame_states) / sizeof(ngx_http_v2_handler_pt)) + + +void +ngx_http_v2_init(ngx_event_t *rev) +{ + ngx_connection_t *c; + ngx_pool_cleanup_t *cln; + ngx_http_connection_t *hc; + ngx_http_v2_srv_conf_t *h2scf; + ngx_http_v2_main_conf_t *h2mcf; + ngx_http_v2_connection_t *h2c; + + c = rev->data; + hc = c->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "init http2 connection"); + + c->log->action = "processing HTTP/2 connection"; + + h2mcf = ngx_http_get_module_main_conf(hc->conf_ctx, ngx_http_v2_module); + + if (h2mcf->recv_buffer == NULL) { + h2mcf->recv_buffer = ngx_palloc(ngx_cycle->pool, + h2mcf->recv_buffer_size); + if (h2mcf->recv_buffer == NULL) { + ngx_http_close_connection(c); + return; + } + } + + h2c = ngx_pcalloc(c->pool, sizeof(ngx_http_v2_connection_t)); + if (h2c == NULL) { + ngx_http_close_connection(c); + return; + } + + h2c->connection = c; + h2c->http_connection = hc; + + h2c->send_window = NGX_HTTP_V2_DEFAULT_WINDOW; + h2c->recv_window = NGX_HTTP_V2_MAX_WINDOW; + + h2c->init_window = NGX_HTTP_V2_DEFAULT_WINDOW; + + h2c->frame_size = NGX_HTTP_V2_DEFAULT_FRAME_SIZE; + + h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module); + + h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); + if (h2c->pool == NULL) { + ngx_http_close_connection(c); + return; + } + + cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_pool_cleanup_file_t)); + if (cln == NULL) { + ngx_http_close_connection(c); + return; + } + + cln->handler = ngx_http_v2_pool_cleanup; + cln->data = h2c; + + h2c->streams_index = ngx_pcalloc(c->pool, ngx_http_v2_index_size(h2scf) + * sizeof(ngx_http_v2_node_t *)); + if (h2c->streams_index == NULL) { + ngx_http_close_connection(c); + return; + } + + if (ngx_http_v2_send_settings(h2c, 0) == NGX_ERROR) { + ngx_http_close_connection(c); + return; + } + + if (ngx_http_v2_send_window_update(h2c, 0, NGX_HTTP_V2_MAX_WINDOW + - NGX_HTTP_V2_DEFAULT_WINDOW) + == NGX_ERROR) + { + ngx_http_close_connection(c); + return; + } + + h2c->state.handler = hc->proxy_protocol ? ngx_http_v2_state_proxy_protocol + : ngx_http_v2_state_preface; + + ngx_queue_init(&h2c->waiting); + ngx_queue_init(&h2c->posted); + ngx_queue_init(&h2c->dependencies); + ngx_queue_init(&h2c->closed); + + c->data = h2c; + + rev->handler = ngx_http_v2_read_handler; + c->write->handler = ngx_http_v2_write_handler; + + ngx_http_v2_read_handler(rev); +} + + +static void +ngx_http_v2_read_handler(ngx_event_t *rev) +{ + u_char *p, *end; + size_t available; + ssize_t n; + ngx_connection_t *c; + ngx_http_v2_main_conf_t *h2mcf; + ngx_http_v2_connection_t *h2c; + + c = rev->data; + h2c = c->data; + + if (rev->timedout) { + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); + ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 read handler"); + + h2c->blocked = 1; + + h2mcf = ngx_http_get_module_main_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); + + available = h2mcf->recv_buffer_size - 2 * NGX_HTTP_V2_STATE_BUFFER_SIZE; + + do { + p = h2mcf->recv_buffer; + + ngx_memcpy(p, h2c->state.buffer, NGX_HTTP_V2_STATE_BUFFER_SIZE); + end = p + h2c->state.buffer_used; + + n = c->recv(c, end, available); + + if (n == NGX_AGAIN) { + break; + } + + if (n == 0 && (h2c->state.incomplete || h2c->processing)) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client prematurely closed connection"); + } + + if (n == 0 || n == NGX_ERROR) { + c->error = 1; + ngx_http_v2_finalize_connection(h2c, 0); + return; + } + + end += n; + + h2c->state.buffer_used = 0; + h2c->state.incomplete = 0; + + do { + p = h2c->state.handler(h2c, p, end); + + if (p == NULL) { + return; + } + + } while (p != end); + + } while (rev->ready); + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + return; + } + + if (h2c->last_out && ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) { + ngx_http_v2_finalize_connection(h2c, 0); + return; + } + + h2c->blocked = 0; + + if (h2c->processing) { + if (rev->timer_set) { + ngx_del_timer(rev); + } + + return; + } + + ngx_http_v2_handle_connection(h2c); +} + + +static void +ngx_http_v2_write_handler(ngx_event_t *wev) +{ + ngx_int_t rc; + ngx_queue_t *q; + ngx_connection_t *c; + ngx_http_v2_stream_t *stream; + ngx_http_v2_connection_t *h2c; + + c = wev->data; + h2c = c->data; + + if (wev->timedout) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http2 write event timed out"); + c->error = 1; + ngx_http_v2_finalize_connection(h2c, 0); + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 write handler"); + + h2c->blocked = 1; + + rc = ngx_http_v2_send_output_queue(h2c); + + if (rc == NGX_ERROR) { + ngx_http_v2_finalize_connection(h2c, 0); + return; + } + + while (!ngx_queue_empty(&h2c->posted)) { + q = ngx_queue_head(&h2c->posted); + + ngx_queue_remove(q); + + stream = ngx_queue_data(q, ngx_http_v2_stream_t, queue); + + stream->handled = 0; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "run http2 stream %ui", stream->node->id); + + wev = stream->request->connection->write; + wev->handler(wev); + } + + h2c->blocked = 0; + + if (rc == NGX_AGAIN) { + return; + } + + ngx_http_v2_handle_connection(h2c); +} + + +ngx_int_t +ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c) +{ + int tcp_nodelay; + ngx_chain_t *cl; + ngx_event_t *wev; + ngx_connection_t *c; + ngx_http_v2_out_frame_t *out, *frame, *fn; + ngx_http_core_loc_conf_t *clcf; + + c = h2c->connection; + + if (c->error) { + return NGX_ERROR; + } + + wev = c->write; + + if (!wev->ready) { + return NGX_OK; + } + + cl = NULL; + out = NULL; + + for (frame = h2c->last_out; frame; frame = fn) { + frame->last->next = cl; + cl = frame->first; + + fn = frame->next; + frame->next = out; + out = frame; + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http2 frame out: %p sid:%ui bl:%d len:%uz", + out, out->stream ? out->stream->node->id : 0, + out->blocked, out->length); + } + + cl = c->send_chain(c, cl, 0); + + if (cl == NGX_CHAIN_ERROR) { + goto error; + } + + clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx, + ngx_http_core_module); + + if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { + goto error; + } + + if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) { + if (ngx_tcp_push(c->fd) == -1) { + ngx_connection_error(c, ngx_socket_errno, ngx_tcp_push_n " failed"); + goto error; + } + + c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; + tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0; + + } else { + tcp_nodelay = 1; + } + + if (tcp_nodelay + && clcf->tcp_nodelay + && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) + { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); + + if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, + (const void *) &tcp_nodelay, sizeof(int)) + == -1) + { +#if (NGX_SOLARIS) + /* Solaris returns EINVAL if a socket has been shut down */ + c->log_error = NGX_ERROR_IGNORE_EINVAL; +#endif + + ngx_connection_error(c, ngx_socket_errno, + "setsockopt(TCP_NODELAY) failed"); + + c->log_error = NGX_ERROR_INFO; + goto error; + } + + c->tcp_nodelay = NGX_TCP_NODELAY_SET; + } + + if (cl) { + ngx_add_timer(wev, clcf->send_timeout); + + } else { + if (wev->timer_set) { + ngx_del_timer(wev); + } + } + + for ( /* void */ ; out; out = fn) { + fn = out->next; + + if (out->handler(h2c, out) != NGX_OK) { + out->blocked = 1; + break; + } + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http2 frame sent: %p sid:%ui bl:%d len:%uz", + out, out->stream ? out->stream->node->id : 0, + out->blocked, out->length); + } + + frame = NULL; + + for ( /* void */ ; out; out = fn) { + fn = out->next; + out->next = frame; + frame = out; + } + + h2c->last_out = frame; + + return NGX_OK; + +error: + + c->error = 1; + + if (!h2c->blocked) { + ngx_post_event(wev, &ngx_posted_events); + } + + return NGX_ERROR; +} + + +static void +ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) +{ + ngx_connection_t *c; + ngx_http_v2_srv_conf_t *h2scf; + + if (h2c->last_out || h2c->processing) { + return; + } + + c = h2c->connection; + + if (c->error) { + ngx_http_close_connection(c); + return; + } + + if (c->buffered) { + return; + } + + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); + if (h2c->state.incomplete) { + ngx_add_timer(c->read, h2scf->recv_timeout); + return; + } + + if (ngx_terminate || ngx_exiting) { + ngx_http_close_connection(c); + return; + } + + ngx_destroy_pool(h2c->pool); + + h2c->pool = NULL; + h2c->free_frames = NULL; + h2c->free_fake_connections = NULL; + +#if (NGX_HTTP_SSL) + if (c->ssl) { + ngx_ssl_free_buffer(c); + } +#endif + + c->destroyed = 1; + c->idle = 1; + ngx_reusable_connection(c, 1); + + c->write->handler = ngx_http_empty_handler; + c->read->handler = ngx_http_v2_idle_handler; + + if (c->write->timer_set) { + ngx_del_timer(c->write); + } + + ngx_add_timer(c->read, h2scf->idle_timeout); +} + + +static u_char * +ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + ngx_log_t *log; + + log = h2c->connection->log; + log->action = "reading PROXY protocol"; + + pos = ngx_proxy_protocol_read(h2c->connection, pos, end); + + log->action = "processing HTTP/2 connection"; + + if (pos == NULL) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); + } + + return ngx_http_v2_state_preface(h2c, pos, end); +} + + +static u_char * +ngx_http_v2_state_preface(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + static const u_char preface[] = "PRI * HTTP/2.0\r\n"; + + if ((size_t) (end - pos) < sizeof(preface) - 1) { + return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_preface); + } + + if (ngx_memcmp(pos, preface, sizeof(preface) - 1) != 0) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "invalid http2 connection preface \"%*s\"", + sizeof(preface) - 1, pos); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); + } + + return ngx_http_v2_state_preface_end(h2c, pos + sizeof(preface) - 1, end); +} + + +static u_char * +ngx_http_v2_state_preface_end(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + static const u_char preface[] = "\r\nSM\r\n\r\n"; + + if ((size_t) (end - pos) < sizeof(preface) - 1) { + return ngx_http_v2_state_save(h2c, pos, end, + ngx_http_v2_state_preface_end); + } + + if (ngx_memcmp(pos, preface, sizeof(preface) - 1) != 0) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "invalid http2 connection preface \"%*s\"", + sizeof(preface) - 1, pos); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 preface verified"); + + return ngx_http_v2_state_head(h2c, pos + sizeof(preface) - 1, end); +} + + +static u_char * +ngx_http_v2_state_head(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) +{ + uint32_t head; + ngx_uint_t type; + + if (end - pos < NGX_HTTP_V2_FRAME_HEADER_SIZE) { + return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_head); + } + + head = ngx_http_v2_parse_uint32(pos); + + h2c->state.length = ngx_http_v2_parse_length(head); + h2c->state.flags = pos[4]; + + h2c->state.sid = ngx_http_v2_parse_sid(&pos[5]); + + pos += NGX_HTTP_V2_FRAME_HEADER_SIZE; + + type = ngx_http_v2_parse_type(head); + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "process http2 frame type:%ui f:%Xd l:%uz sid:%ui", + type, h2c->state.flags, h2c->state.length, h2c->state.sid); + + if (type >= NGX_HTTP_V2_FRAME_STATES) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 frame with unknown type %ui", type); + return ngx_http_v2_state_skip(h2c, pos, end); + } + + return ngx_http_v2_frame_states[type](h2c, pos, end); +} + + +static u_char * +ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) +{ + ngx_http_v2_node_t *node; + ngx_http_v2_stream_t *stream; + + if (h2c->state.flags & NGX_HTTP_V2_PADDED_FLAG) { + + if (h2c->state.length == 0) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent padded DATA frame " + "with incorrect length: %uz", + h2c->state.length); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + if (end - pos == 0) { + return ngx_http_v2_state_save(h2c, pos, end, + ngx_http_v2_state_data); + } + + h2c->state.padding = *pos++; + h2c->state.length--; + + if (h2c->state.padding > h2c->state.length) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent padded DATA frame " + "with incorrect length: %uz, padding: %uz", + h2c->state.length, h2c->state.padding); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + h2c->state.length -= h2c->state.padding; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 DATA frame"); + + if (h2c->state.length > h2c->recv_window) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client violated connection flow control: " + "received DATA frame length %uz, available window %uz", + h2c->state.length, h2c->recv_window); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_FLOW_CTRL_ERROR); + } + + h2c->recv_window -= h2c->state.length; + + if (h2c->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4) { + + if (ngx_http_v2_send_window_update(h2c, 0, NGX_HTTP_V2_MAX_WINDOW + - h2c->recv_window) + == NGX_ERROR) + { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + h2c->recv_window = NGX_HTTP_V2_MAX_WINDOW; + } + + node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0); + + if (node == NULL || node->stream == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "unknown http2 stream"); + + return ngx_http_v2_state_skip_padded(h2c, pos, end); + } + + stream = node->stream; + + if (h2c->state.length > stream->recv_window) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client violated flow control for stream %ui: " + "received DATA frame length %uz, available window %uz", + node->id, h2c->state.length, stream->recv_window); + + if (ngx_http_v2_terminate_stream(h2c, stream, + NGX_HTTP_V2_FLOW_CTRL_ERROR) + == NGX_ERROR) + { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + return ngx_http_v2_state_skip_padded(h2c, pos, end); + } + + stream->recv_window -= h2c->state.length; + + if (stream->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4) { + + if (ngx_http_v2_send_window_update(h2c, node->id, + NGX_HTTP_V2_MAX_WINDOW + - stream->recv_window) + == NGX_ERROR) + { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + stream->recv_window = NGX_HTTP_V2_MAX_WINDOW; + } + + if (stream->in_closed) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent DATA frame for half-closed stream %ui", + node->id); + + if (ngx_http_v2_terminate_stream(h2c, stream, + NGX_HTTP_V2_STREAM_CLOSED) + == NGX_ERROR) + { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + return ngx_http_v2_state_skip_padded(h2c, pos, end); + } + + h2c->state.stream = stream; + + return ngx_http_v2_state_read_data(h2c, pos, end); +} + + +static u_char * +ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + size_t size; + ssize_t n; + ngx_buf_t *buf; + ngx_int_t rc; + ngx_temp_file_t *tf; + ngx_http_request_t *r; + ngx_http_v2_stream_t *stream; + ngx_http_request_body_t *rb; + ngx_http_core_loc_conf_t *clcf; + + stream = h2c->state.stream; + + if (stream == NULL) { + return ngx_http_v2_state_skip_padded(h2c, pos, end); + } + + if (stream->skip_data) { + stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "skipping http2 DATA frame, reason: %d", + stream->skip_data); + + return ngx_http_v2_state_skip_padded(h2c, pos, end); + } + + size = end - pos; + + if (size > h2c->state.length) { + size = h2c->state.length; + } + + r = stream->request; + + if (r->request_body == NULL + && ngx_http_v2_init_request_body(r) != NGX_OK) + { + stream->skip_data = NGX_HTTP_V2_DATA_INTERNAL_ERROR; + return ngx_http_v2_state_skip_padded(h2c, pos, end); + } + + rb = r->request_body; + tf = rb->temp_file; + buf = rb->buf; + + if (size) { + rb->rest += size; + + if (r->headers_in.content_length_n != -1 + && r->headers_in.content_length_n < rb->rest) + { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client intended to send body data " + "larger than declared"); + + stream->skip_data = NGX_HTTP_V2_DATA_ERROR; + goto error; + + } else { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->client_max_body_size + && clcf->client_max_body_size < rb->rest) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "client intended to send " + "too large chunked body: %O bytes", rb->rest); + + stream->skip_data = NGX_HTTP_V2_DATA_ERROR; + goto error; + } + } + + h2c->state.length -= size; + + if (tf) { + buf->start = pos; + buf->pos = pos; + + pos += size; + + buf->end = pos; + buf->last = pos; + + n = ngx_write_chain_to_temp_file(tf, rb->bufs); + + /* TODO: n == 0 or not complete and level event */ + + if (n == NGX_ERROR) { + stream->skip_data = NGX_HTTP_V2_DATA_INTERNAL_ERROR; + goto error; + } + + tf->offset += n; + + } else { + buf->last = ngx_cpymem(buf->last, pos, size); + pos += size; + } + + r->request_length += size; + } + + if (h2c->state.length) { + return ngx_http_v2_state_save(h2c, pos, end, + ngx_http_v2_state_read_data); + } + + if (h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG) { + stream->in_closed = 1; + + if (r->headers_in.content_length_n < 0) { + r->headers_in.content_length_n = rb->rest; + + } else if (r->headers_in.content_length_n != rb->rest) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client prematurely closed stream: " + "only %O out of %O bytes of request body received", + rb->rest, r->headers_in.content_length_n); + + stream->skip_data = NGX_HTTP_V2_DATA_ERROR; + goto error; + } + + if (tf) { + ngx_memzero(buf, sizeof(ngx_buf_t)); + + buf->in_file = 1; + buf->file_last = tf->file.offset; + buf->file = &tf->file; + + rb->buf = NULL; + } + + if (rb->post_handler) { + r->read_event_handler = ngx_http_block_reading; + rb->post_handler(r); + } + } + + if (h2c->state.padding) { + return ngx_http_v2_state_skip_padded(h2c, pos, end); + } + + return ngx_http_v2_state_complete(h2c, pos, end); + +error: + + if (rb->post_handler) { + + if (stream->skip_data == NGX_HTTP_V2_DATA_ERROR) { + rc = (r->headers_in.content_length_n == -1) + ? NGX_HTTP_REQUEST_ENTITY_TOO_LARGE : NGX_HTTP_BAD_REQUEST; + + } else { + rc = NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ngx_http_finalize_request(r, rc); + } + + return ngx_http_v2_state_skip_padded(h2c, pos, end); +} + + +static u_char * +ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + size_t size; + ngx_uint_t padded, priority, depend, dependency, excl, weight; + ngx_http_v2_node_t *node; + ngx_http_v2_stream_t *stream; + ngx_http_v2_srv_conf_t *h2scf; + + padded = h2c->state.flags & NGX_HTTP_V2_PADDED_FLAG; + priority = h2c->state.flags & NGX_HTTP_V2_PRIORITY_FLAG; + + size = 0; + + if (padded) { + size++; + } + + if (priority) { + size += sizeof(uint32_t) + 1; + } + + if (h2c->state.length < size) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent HEADERS frame with incorrect length %uz", + h2c->state.length); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + if (h2c->state.length == size) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent HEADERS frame with empty header block"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + if ((size_t) (end - pos) < size) { + return ngx_http_v2_state_save(h2c, pos, end, + ngx_http_v2_state_headers); + } + + h2c->state.length -= size; + + if (padded) { + h2c->state.padding = *pos++; + + if (h2c->state.padding > h2c->state.length) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent padded HEADERS frame " + "with incorrect length: %uz, padding: %uz", + h2c->state.length, h2c->state.padding); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + h2c->state.length -= h2c->state.padding; + } + + depend = 0; + excl = 0; + weight = 16; + + if (priority) { + dependency = ngx_http_v2_parse_uint32(pos); + + depend = dependency & 0x7fffffff; + excl = dependency >> 31; + weight = pos[4] + 1; + + pos += sizeof(uint32_t) + 1; + } + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 HEADERS frame sid:%ui on %ui excl:%ui weight:%ui", + h2c->state.sid, depend, excl, weight); + + if (h2c->state.sid % 2 == 0 || h2c->state.sid <= h2c->last_sid) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent HEADERS frame with incorrect identifier " + "%ui, the last was %ui", h2c->state.sid, h2c->last_sid); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); + } + + h2c->last_sid = h2c->state.sid; + + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); + + h2c->state.header_limit = h2scf->max_header_size; + + if (h2c->processing >= h2scf->concurrent_streams) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "concurrent streams exceeded %ui", h2c->processing); + + if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, + NGX_HTTP_V2_REFUSED_STREAM) + != NGX_OK) + { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + return ngx_http_v2_state_skip_headers(h2c, pos, end); + } + + node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 1); + + if (node == NULL) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + } + + if (node->parent) { + ngx_queue_remove(&node->reuse); + h2c->closed_nodes--; + } + + stream = ngx_http_v2_create_stream(h2c); + if (stream == NULL) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + } + + stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; + stream->node = node; + + node->stream = stream; + + h2c->state.stream = stream; + h2c->state.pool = stream->request->pool; + + if (priority || node->parent == NULL) { + node->weight = weight; + ngx_http_v2_set_dependency(h2c, node, depend, excl); + } + + return ngx_http_v2_state_header_block(h2c, pos, end); +} + + +static u_char * +ngx_http_v2_state_header_block(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + u_char ch; + ngx_int_t value; + ngx_uint_t indexed, size_update, prefix; + ngx_http_v2_srv_conf_t *h2scf; + + if (end - pos < 1) { + return ngx_http_v2_state_save(h2c, pos, end, + ngx_http_v2_state_header_block); + } + + if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) + && h2c->state.length < NGX_HTTP_V2_INT_OCTETS) + { + return ngx_http_v2_handle_continuation(h2c, pos, end, + ngx_http_v2_state_header_block); + } + + size_update = 0; + indexed = 0; + + ch = *pos; + + if (ch >= (1 << 7)) { + /* indexed header field */ + indexed = 1; + prefix = ngx_http_v2_prefix(7); + + } else if (ch >= (1 << 6)) { + /* literal header field with incremental indexing */ + h2c->state.index = 1; + prefix = ngx_http_v2_prefix(6); + + } else if (ch >= (1 << 5)) { + /* dynamic table size update */ + size_update = 1; + prefix = ngx_http_v2_prefix(5); + + } else if (ch >= (1 << 4)) { + /* literal header field never indexed */ + prefix = ngx_http_v2_prefix(4); + + } else { + /* literal header field without indexing */ + prefix = ngx_http_v2_prefix(3); + } + + value = ngx_http_v2_parse_int(h2c, &pos, end, prefix); + + if (value < 0) { + if (value == NGX_AGAIN) { + return ngx_http_v2_state_save(h2c, pos, end, + ngx_http_v2_state_header_block); + } + + if (value == NGX_DECLINED) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent header block with too long %s value", + size_update ? "size update" : "header index"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR); + } + + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent header block with incorrect length"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + if (indexed) { + if (ngx_http_v2_get_indexed_header(h2c, value, 0) != NGX_OK) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR); + } + + return ngx_http_v2_state_process_header(h2c, pos, end); + } + + if (size_update) { + if (ngx_http_v2_table_size(h2c, value) != NGX_OK) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR); + } + + return ngx_http_v2_state_header_complete(h2c, pos, end); + } + + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); + + h2c->state.field_limit = h2scf->max_field_size; + + if (value == 0) { + h2c->state.parse_name = 1; + + } else { + if (ngx_http_v2_get_indexed_header(h2c, value, 1) != NGX_OK) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR); + } + + h2c->state.field_limit -= h2c->state.header.name.len; + } + + h2c->state.parse_value = 1; + + return ngx_http_v2_state_field_len(h2c, pos, end); +} + + +static u_char * +ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + size_t alloc; + ngx_int_t len; + ngx_uint_t huff; + + if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) + && h2c->state.length < NGX_HTTP_V2_INT_OCTETS) + { + return ngx_http_v2_handle_continuation(h2c, pos, end, + ngx_http_v2_state_field_len); + } + + if (h2c->state.length < 1) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent header block with incorrect length"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + if (end - pos < 1) { + return ngx_http_v2_state_save(h2c, pos, end, + ngx_http_v2_state_field_len); + } + + huff = *pos >> 7; + len = ngx_http_v2_parse_int(h2c, &pos, end, ngx_http_v2_prefix(7)); + + if (len < 0) { + if (len == NGX_AGAIN) { + return ngx_http_v2_state_save(h2c, pos, end, + ngx_http_v2_state_field_len); + } + + if (len == NGX_DECLINED) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent header field with too long length value"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR); + } + + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent header block with incorrect length"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 hpack %s string length: %i", + huff ? "encoded" : "raw", len); + + if ((size_t) len > h2c->state.field_limit) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client exceeded http2_max_field_size limit"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM); + } + + h2c->state.field_limit -= len; + h2c->state.field_rest = len; + + if (h2c->state.stream == NULL && !h2c->state.index) { + return ngx_http_v2_state_field_skip(h2c, pos, end); + } + + alloc = (huff ? len * 8 / 5 : len) + 1; + + h2c->state.field_start = ngx_pnalloc(h2c->state.pool, alloc); + if (h2c->state.field_start == NULL) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + } + + h2c->state.field_end = h2c->state.field_start; + + if (huff) { + return ngx_http_v2_state_field_huff(h2c, pos, end); + } + + return ngx_http_v2_state_field_raw(h2c, pos, end); +} + + +static u_char * +ngx_http_v2_state_field_huff(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + size_t size; + + size = end - pos; + + if (size > h2c->state.field_rest) { + size = h2c->state.field_rest; + } + + if (size > h2c->state.length) { + size = h2c->state.length; + } + + h2c->state.length -= size; + h2c->state.field_rest -= size; + + if (ngx_http_v2_huff_decode(&h2c->state.field_state, pos, size, + &h2c->state.field_end, + h2c->state.field_rest == 0, + h2c->connection->log) + != NGX_OK) + { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent invalid encoded header field"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR); + } + + pos += size; + + if (h2c->state.field_rest == 0) { + *h2c->state.field_end = '\0'; + return ngx_http_v2_state_process_header(h2c, pos, end); + } + + if (h2c->state.length) { + return ngx_http_v2_state_save(h2c, pos, end, + ngx_http_v2_state_field_huff); + } + + if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent header field with incorrect length"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + return ngx_http_v2_handle_continuation(h2c, pos, end, + ngx_http_v2_state_field_huff); +} + + +static u_char * +ngx_http_v2_state_field_raw(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + size_t size; + + size = end - pos; + + if (size > h2c->state.field_rest) { + size = h2c->state.field_rest; + } + + if (size > h2c->state.length) { + size = h2c->state.length; + } + + h2c->state.length -= size; + h2c->state.field_rest -= size; + + h2c->state.field_end = ngx_cpymem(h2c->state.field_end, pos, size); + + pos += size; + + if (h2c->state.field_rest == 0) { + *h2c->state.field_end = '\0'; + return ngx_http_v2_state_process_header(h2c, pos, end); + } + + if (h2c->state.length) { + return ngx_http_v2_state_save(h2c, pos, end, + ngx_http_v2_state_field_raw); + } + + if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent header field with incorrect length"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + return ngx_http_v2_handle_continuation(h2c, pos, end, + ngx_http_v2_state_field_raw); +} + + +static u_char * +ngx_http_v2_state_field_skip(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + size_t size; + + size = end - pos; + + if (size > h2c->state.field_rest) { + size = h2c->state.field_rest; + } + + if (size > h2c->state.length) { + size = h2c->state.length; + } + + h2c->state.length -= size; + h2c->state.field_rest -= size; + + pos += size; + + if (h2c->state.field_rest == 0) { + return ngx_http_v2_state_process_header(h2c, pos, end); + } + + if (h2c->state.length) { + return ngx_http_v2_state_save(h2c, pos, end, + ngx_http_v2_state_field_skip); + } + + if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent header field with incorrect length"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + return ngx_http_v2_handle_continuation(h2c, pos, end, + ngx_http_v2_state_field_skip); +} + + +static u_char * +ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + size_t len; + ngx_int_t rc; + ngx_table_elt_t *h; + ngx_http_header_t *hh; + ngx_http_request_t *r; + ngx_http_v2_header_t *header; + ngx_http_core_srv_conf_t *cscf; + ngx_http_core_main_conf_t *cmcf; + + static ngx_str_t cookie = ngx_string("cookie"); + + header = &h2c->state.header; + + if (h2c->state.parse_name) { + h2c->state.parse_name = 0; + + header->name.len = h2c->state.field_end - h2c->state.field_start; + header->name.data = h2c->state.field_start; + + return ngx_http_v2_state_field_len(h2c, pos, end); + } + + if (h2c->state.parse_value) { + h2c->state.parse_value = 0; + + header->value.len = h2c->state.field_end - h2c->state.field_start; + header->value.data = h2c->state.field_start; + } + + len = header->name.len + header->value.len; + + if (len > h2c->state.header_limit) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client exceeded http2_max_header_size limit"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM); + } + + h2c->state.header_limit -= len; + + if (h2c->state.index) { + if (ngx_http_v2_add_header(h2c, header) != NGX_OK) { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + h2c->state.index = 0; + } + + if (h2c->state.stream == NULL) { + return ngx_http_v2_state_header_complete(h2c, pos, end); + } + + r = h2c->state.stream->request; + + /* TODO Optimization: validate headers while parsing. */ + if (ngx_http_v2_validate_header(r, header) != NGX_OK) { + if (ngx_http_v2_terminate_stream(h2c, h2c->state.stream, + NGX_HTTP_V2_PROTOCOL_ERROR) + == NGX_ERROR) + { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + goto error; + } + + if (header->name.data[0] == ':') { + rc = ngx_http_v2_pseudo_header(r, header); + + if (rc == NGX_OK) { + return ngx_http_v2_state_header_complete(h2c, pos, end); + } + + if (rc == NGX_ABORT) { + goto error; + } + + if (rc == NGX_DECLINED) { + if (ngx_http_v2_terminate_stream(h2c, h2c->state.stream, + NGX_HTTP_V2_PROTOCOL_ERROR) + == NGX_ERROR) + { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + goto error; + } + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + } + + if (r->invalid_header) { + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + if (cscf->ignore_invalid_headers) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid header: \"%V\"", &header->name); + + return ngx_http_v2_state_header_complete(h2c, pos, end); + } + } + + if (header->name.len == cookie.len + && ngx_memcmp(header->name.data, cookie.data, cookie.len) == 0) + { + if (ngx_http_v2_cookie(r, header) != NGX_OK) { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + return ngx_http_v2_state_header_complete(h2c, pos, end); + } + + h = ngx_list_push(&r->headers_in.headers); + if (h == NULL) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + } + + h->key.len = header->name.len; + h->key.data = header->name.data; + + /* TODO Optimization: precalculate hash and hadnler for indexed headers. */ + h->hash = ngx_hash_key(h->key.data, h->key.len); + + h->value.len = header->value.len; + h->value.data = header->value.data; + + h->lowcase_key = h->key.data; + + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + + hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, + h->lowcase_key, h->key.len); + + if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { + goto error; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http2 http header: \"%V: %V\"", &h->key, &h->value); + + return ngx_http_v2_state_header_complete(h2c, pos, end); + +error: + + h2c->state.stream = NULL; + h2c->state.pool = NULL; + + return ngx_http_v2_state_header_complete(h2c, pos, end); +} + + +static u_char * +ngx_http_v2_state_header_complete(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + ngx_http_v2_stream_t *stream; + + if (h2c->state.length) { + h2c->state.handler = h2c->state.pool ? ngx_http_v2_state_header_block + : ngx_http_v2_state_skip_headers; + return pos; + } + + if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG)) { + return ngx_http_v2_handle_continuation(h2c, pos, end, + ngx_http_v2_state_header_complete); + } + + stream = h2c->state.stream; + + if (stream) { + ngx_http_v2_run_request(stream->request); + + } else if (h2c->state.pool) { + ngx_destroy_pool(h2c->state.pool); + } + + h2c->state.pool = NULL; + + if (h2c->state.padding) { + return ngx_http_v2_state_skip_padded(h2c, pos, end); + } + + return ngx_http_v2_state_complete(h2c, pos, end); +} + + +static u_char * +ngx_http_v2_handle_continuation(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end, ngx_http_v2_handler_pt handler) +{ + u_char *p; + size_t len; + uint32_t head; + + len = h2c->state.length; + + if ((size_t) (end - pos) < len + NGX_HTTP_V2_FRAME_HEADER_SIZE) { + return ngx_http_v2_state_save(h2c, pos, end, handler); + } + + p = pos + len; + + head = ngx_http_v2_parse_uint32(p); + + if (ngx_http_v2_parse_type(head) != NGX_HTTP_V2_CONTINUATION_FRAME) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent inappropriate frame while CONTINUATION was expected"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); + } + + h2c->state.length += ngx_http_v2_parse_length(head); + h2c->state.flags |= p[4]; + + if (h2c->state.sid != ngx_http_v2_parse_sid(&p[5])) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent CONTINUATION frame with incorrect identifier"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); + } + + p = pos; + pos += NGX_HTTP_V2_FRAME_HEADER_SIZE; + + ngx_memcpy(pos, p, len); + + h2c->state.handler = handler; + return pos; +} + + +static u_char * +ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + ngx_uint_t depend, dependency, excl, weight; + ngx_http_v2_node_t *node; + + if (h2c->state.length != NGX_HTTP_V2_PRIORITY_SIZE) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent PRIORITY frame with incorrect length %uz", + h2c->state.length); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + if (end - pos < NGX_HTTP_V2_PRIORITY_SIZE) { + return ngx_http_v2_state_save(h2c, pos, end, + ngx_http_v2_state_priority); + } + + dependency = ngx_http_v2_parse_uint32(pos); + + depend = dependency & 0x7fffffff; + excl = dependency >> 31; + weight = pos[4] + 1; + + pos += NGX_HTTP_V2_PRIORITY_SIZE; + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 PRIORITY frame sid:%ui on %ui excl:%ui weight:%ui", + h2c->state.sid, depend, excl, weight); + + if (h2c->state.sid == 0) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent PRIORITY frame with incorrect identifier"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); + } + + if (depend == h2c->state.sid) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent PRIORITY frame for stream %ui " + "with incorrect dependancy", h2c->state.sid); + + node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0); + + if (node && node->stream) { + if (ngx_http_v2_terminate_stream(h2c, node->stream, + NGX_HTTP_V2_PROTOCOL_ERROR) + == NGX_ERROR) + { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + } else { + if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, + NGX_HTTP_V2_PROTOCOL_ERROR) + == NGX_ERROR) + { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + } + + return ngx_http_v2_state_complete(h2c, pos, end); + } + + node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 1); + + if (node == NULL) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + } + + node->weight = weight; + + if (node->stream == NULL) { + if (node->parent == NULL) { + h2c->closed_nodes++; + + } else { + ngx_queue_remove(&node->reuse); + } + + ngx_queue_insert_tail(&h2c->closed, &node->reuse); + } + + ngx_http_v2_set_dependency(h2c, node, depend, excl); + + return ngx_http_v2_state_complete(h2c, pos, end); +} + + +static u_char * +ngx_http_v2_state_rst_stream(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + ngx_uint_t status; + ngx_event_t *ev; + ngx_connection_t *fc; + ngx_http_v2_node_t *node; + ngx_http_v2_stream_t *stream; + + if (h2c->state.length != NGX_HTTP_V2_RST_STREAM_SIZE) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent RST_STREAM frame with incorrect length %uz", + h2c->state.length); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + if (end - pos < NGX_HTTP_V2_RST_STREAM_SIZE) { + return ngx_http_v2_state_save(h2c, pos, end, + ngx_http_v2_state_rst_stream); + } + + status = ngx_http_v2_parse_uint32(pos); + + pos += NGX_HTTP_V2_RST_STREAM_SIZE; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 RST_STREAM frame, sid:%ui status:%ui", + h2c->state.sid, status); + + if (h2c->state.sid == 0) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent RST_STREAM frame with incorrect identifier"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); + } + + node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0); + + if (node == NULL || node->stream == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "unknown http2 stream"); + + return ngx_http_v2_state_complete(h2c, pos, end); + } + + stream = node->stream; + + stream->in_closed = 1; + stream->out_closed = 1; + + fc = stream->request->connection; + fc->error = 1; + + switch (status) { + + case NGX_HTTP_V2_CANCEL: + ngx_log_error(NGX_LOG_INFO, fc->log, 0, + "client canceled stream %ui", h2c->state.sid); + break; + + case NGX_HTTP_V2_INTERNAL_ERROR: + ngx_log_error(NGX_LOG_INFO, fc->log, 0, + "client terminated stream %ui due to internal error", + h2c->state.sid); + break; + + default: + ngx_log_error(NGX_LOG_INFO, fc->log, 0, + "client terminated stream %ui with status %ui", + h2c->state.sid, status); + break; + } + + ev = fc->read; + ev->handler(ev); + + return ngx_http_v2_state_complete(h2c, pos, end); +} + + +static u_char * +ngx_http_v2_state_settings(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + if (h2c->state.flags == NGX_HTTP_V2_ACK_FLAG) { + + if (h2c->state.length != 0) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent SETTINGS frame with the ACK flag " + "and nonzero length"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + /* TODO settings acknowledged */ + + return ngx_http_v2_state_complete(h2c, pos, end); + } + + if (h2c->state.length % NGX_HTTP_V2_SETTINGS_PARAM_SIZE) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent SETTINGS frame with incorrect length %uz", + h2c->state.length); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + ngx_http_v2_send_settings(h2c, 1); + + return ngx_http_v2_state_settings_params(h2c, pos, end); +} + + +static u_char * +ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + ngx_uint_t id, value; + + while (h2c->state.length) { + if (end - pos < NGX_HTTP_V2_SETTINGS_PARAM_SIZE) { + return ngx_http_v2_state_save(h2c, pos, end, + ngx_http_v2_state_settings_params); + } + + h2c->state.length -= NGX_HTTP_V2_SETTINGS_PARAM_SIZE; + + id = ngx_http_v2_parse_uint16(pos); + value = ngx_http_v2_parse_uint32(&pos[2]); + + switch (id) { + + case NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING: + + if (value > NGX_HTTP_V2_MAX_WINDOW) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent SETTINGS frame with incorrect " + "INITIAL_WINDOW_SIZE value %ui", value); + + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_FLOW_CTRL_ERROR); + } + + if (ngx_http_v2_adjust_windows(h2c, value - h2c->init_window) + != NGX_OK) + { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + h2c->init_window = value; + break; + + case NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING: + if (value > NGX_HTTP_V2_MAX_FRAME_SIZE + || value < NGX_HTTP_V2_DEFAULT_FRAME_SIZE) + { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent SETTINGS frame with incorrect " + "MAX_FRAME_SIZE value %ui", value); + + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_PROTOCOL_ERROR); + } + + h2c->frame_size = value; + break; + + default: + break; + } + + pos += NGX_HTTP_V2_SETTINGS_PARAM_SIZE; + } + + return ngx_http_v2_state_complete(h2c, pos, end); +} + + +static u_char * +ngx_http_v2_state_push_promise(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent PUSH_PROMISE frame"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); +} + + +static u_char * +ngx_http_v2_state_ping(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) +{ + ngx_buf_t *buf; + ngx_http_v2_out_frame_t *frame; + + if (h2c->state.length != NGX_HTTP_V2_PING_SIZE) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent PING frame with incorrect length %uz", + h2c->state.length); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + if (end - pos < NGX_HTTP_V2_PING_SIZE) { + return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_ping); + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 PING frame, flags: %ui", h2c->state.flags); + + if (h2c->state.flags & NGX_HTTP_V2_ACK_FLAG) { + return ngx_http_v2_state_skip(h2c, pos, end); + } + + frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_PING_SIZE, + NGX_HTTP_V2_PING_FRAME, + NGX_HTTP_V2_ACK_FLAG, 0); + if (frame == NULL) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + } + + buf = frame->first->buf; + + buf->last = ngx_cpymem(buf->last, pos, NGX_HTTP_V2_PING_SIZE); + + ngx_http_v2_queue_blocked_frame(h2c, frame); + + return ngx_http_v2_state_complete(h2c, pos + NGX_HTTP_V2_PING_SIZE, end); +} + + +static u_char * +ngx_http_v2_state_goaway(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ +#if (NGX_DEBUG) + ngx_uint_t last_sid, error; +#endif + + if (h2c->state.length < NGX_HTTP_V2_GOAWAY_SIZE) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent GOAWAY frame " + "with incorrect length %uz", h2c->state.length); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + if (end - pos < NGX_HTTP_V2_GOAWAY_SIZE) { + return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_goaway); + } + +#if (NGX_DEBUG) + h2c->state.length -= NGX_HTTP_V2_GOAWAY_SIZE; + + last_sid = ngx_http_v2_parse_sid(pos); + error = ngx_http_v2_parse_uint32(&pos[4]); + + pos += NGX_HTTP_V2_GOAWAY_SIZE; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 GOAWAY frame: last sid %ui, error %ui", + last_sid, error); +#endif + + return ngx_http_v2_state_skip(h2c, pos, end); +} + + +static u_char * +ngx_http_v2_state_window_update(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + size_t window; + ngx_event_t *wev; + ngx_queue_t *q; + ngx_http_v2_node_t *node; + ngx_http_v2_stream_t *stream; + + if (h2c->state.length != NGX_HTTP_V2_WINDOW_UPDATE_SIZE) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent WINDOW_UPDATE frame " + "with incorrect length %uz", h2c->state.length); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + + if (end - pos < NGX_HTTP_V2_WINDOW_UPDATE_SIZE) { + return ngx_http_v2_state_save(h2c, pos, end, + ngx_http_v2_state_window_update); + } + + window = ngx_http_v2_parse_window(pos); + + pos += NGX_HTTP_V2_WINDOW_UPDATE_SIZE; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 WINDOW_UPDATE frame sid:%ui window:%uz", + h2c->state.sid, window); + + if (h2c->state.sid) { + node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0); + + if (node == NULL || node->stream == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "unknown http2 stream"); + + return ngx_http_v2_state_complete(h2c, pos, end); + } + + stream = node->stream; + + if (window > (size_t) (NGX_HTTP_V2_MAX_WINDOW - stream->send_window)) { + + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client violated flow control for stream %ui: " + "received WINDOW_UPDATE frame " + "with window increment %uz " + "not allowed for window %z", + h2c->state.sid, window, stream->send_window); + + if (ngx_http_v2_terminate_stream(h2c, stream, + NGX_HTTP_V2_FLOW_CTRL_ERROR) + == NGX_ERROR) + { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + return ngx_http_v2_state_complete(h2c, pos, end); + } + + stream->send_window += window; + + if (stream->exhausted) { + stream->exhausted = 0; + + wev = stream->request->connection->write; + + if (!wev->timer_set) { + wev->delayed = 0; + wev->handler(wev); + } + } + + return ngx_http_v2_state_complete(h2c, pos, end); + } + + if (window > NGX_HTTP_V2_MAX_WINDOW - h2c->send_window) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client violated connection flow control: " + "received WINDOW_UPDATE frame " + "with window increment %uz " + "not allowed for window %uz", + window, h2c->send_window); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_FLOW_CTRL_ERROR); + } + + h2c->send_window += window; + + while (!ngx_queue_empty(&h2c->waiting)) { + q = ngx_queue_head(&h2c->waiting); + + ngx_queue_remove(q); + + stream = ngx_queue_data(q, ngx_http_v2_stream_t, queue); + + stream->handled = 0; + + wev = stream->request->connection->write; + + if (!wev->timer_set) { + wev->delayed = 0; + wev->handler(wev); + + if (h2c->send_window == 0) { + break; + } + } + } + + return ngx_http_v2_state_complete(h2c, pos, end); +} + + +static u_char * +ngx_http_v2_state_continuation(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent unexpected CONTINUATION frame"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); +} + + +static u_char * +ngx_http_v2_state_complete(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 frame complete pos:%p end:%p", pos, end); + + if (pos > end) { + ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, + "receive buffer overrun"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + } + + h2c->state.stream = NULL; + h2c->state.handler = ngx_http_v2_state_head; + + return pos; +} + + +static u_char * +ngx_http_v2_state_skip_padded(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + h2c->state.length += h2c->state.padding; + h2c->state.padding = 0; + + return ngx_http_v2_state_skip(h2c, pos, end); +} + + +static u_char * +ngx_http_v2_state_skip(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) +{ + size_t size; + + size = end - pos; + + if (size < h2c->state.length) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 frame skip %uz of %uz", size, h2c->state.length); + + h2c->state.length -= size; + return ngx_http_v2_state_save(h2c, end, end, ngx_http_v2_state_skip); + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 frame skip %uz", h2c->state.length); + + return ngx_http_v2_state_complete(h2c, pos + h2c->state.length, end); +} + + +static u_char * +ngx_http_v2_state_skip_headers(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end) +{ + h2c->state.pool = ngx_create_pool(1024, h2c->connection->log); + if (h2c->state.pool == NULL) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + } + + return ngx_http_v2_state_header_block(h2c, pos, end); +} + + +static u_char * +ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end, + ngx_http_v2_handler_pt handler) +{ + size_t size; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 frame state save pos:%p end:%p handler:%p", + pos, end, handler); + + size = end - pos; + + if (size > NGX_HTTP_V2_STATE_BUFFER_SIZE) { + ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, + "state buffer overflow: %uz bytes required", size); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + } + + ngx_memcpy(h2c->state.buffer, pos, NGX_HTTP_V2_STATE_BUFFER_SIZE); + + h2c->state.buffer_used = size; + h2c->state.handler = handler; + h2c->state.incomplete = 1; + + return end; +} + + +static u_char * +ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c, + ngx_uint_t err) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 state connection error"); + + if (err == NGX_HTTP_V2_INTERNAL_ERROR) { + ngx_debug_point(); + } + + if (h2c->state.stream) { + h2c->state.stream->out_closed = 1; + h2c->state.pool = NULL; + ngx_http_v2_close_stream(h2c->state.stream, NGX_HTTP_BAD_REQUEST); + } + + ngx_http_v2_finalize_connection(h2c, err); + + return NULL; +} + + +static ngx_int_t +ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c, u_char **pos, u_char *end, + ngx_uint_t prefix) +{ + u_char *start, *p; + ngx_uint_t value, octet, shift; + + start = *pos; + p = start; + + value = *p++ & prefix; + + if (value != prefix) { + if (h2c->state.length == 0) { + return NGX_ERROR; + } + + h2c->state.length--; + + *pos = p; + return value; + } + + if (end - p > NGX_HTTP_V2_INT_OCTETS - 1) { + end = p + NGX_HTTP_V2_INT_OCTETS - 1; + } + + for (shift = 0; p != end; shift += 7) { + octet = *p++; + + value += (octet & 0x7f) << shift; + + if (octet < 128) { + if ((size_t) (p - start) > h2c->state.length) { + return NGX_ERROR; + } + + h2c->state.length -= p - start; + + *pos = p; + return value; + } + } + + if ((size_t) (end - start) >= NGX_HTTP_V2_INT_OCTETS) { + return NGX_DECLINED; + } + + if ((size_t) (end - start) >= h2c->state.length) { + return NGX_ERROR; + } + + return NGX_AGAIN; +} + + +static ngx_int_t +ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, ngx_uint_t ack) +{ + size_t len; + ngx_buf_t *buf; + ngx_chain_t *cl; + ngx_http_v2_srv_conf_t *h2scf; + ngx_http_v2_out_frame_t *frame; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 send SETTINGS frame"); + + frame = ngx_palloc(h2c->pool, sizeof(ngx_http_v2_out_frame_t)); + if (frame == NULL) { + return NGX_ERROR; + } + + cl = ngx_alloc_chain_link(h2c->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + len = ack ? 0 : (sizeof(uint16_t) + sizeof(uint32_t)) * 3; + + buf = ngx_create_temp_buf(h2c->pool, NGX_HTTP_V2_FRAME_HEADER_SIZE + len); + if (buf == NULL) { + return NGX_ERROR; + } + + buf->last_buf = 1; + + cl->buf = buf; + cl->next = NULL; + + frame->first = cl; + frame->last = cl; + frame->handler = ngx_http_v2_settings_frame_handler; + frame->stream = NULL; +#if (NGX_DEBUG) + frame->length = len; +#endif + frame->blocked = 0; + + buf->last = ngx_http_v2_write_len_and_type(buf->last, len, + NGX_HTTP_V2_SETTINGS_FRAME); + + *buf->last++ = ack ? NGX_HTTP_V2_ACK_FLAG : NGX_HTTP_V2_NO_FLAG; + + buf->last = ngx_http_v2_write_sid(buf->last, 0); + + if (!ack) { + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); + + buf->last = ngx_http_v2_write_uint16(buf->last, + NGX_HTTP_V2_MAX_STREAMS_SETTING); + buf->last = ngx_http_v2_write_uint32(buf->last, + h2scf->concurrent_streams); + + buf->last = ngx_http_v2_write_uint16(buf->last, + NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING); + buf->last = ngx_http_v2_write_uint32(buf->last, + NGX_HTTP_V2_MAX_WINDOW); + + buf->last = ngx_http_v2_write_uint16(buf->last, + NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING); + buf->last = ngx_http_v2_write_uint32(buf->last, + NGX_HTTP_V2_MAX_FRAME_SIZE); + } + + ngx_http_v2_queue_blocked_frame(h2c, frame); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v2_settings_frame_handler(ngx_http_v2_connection_t *h2c, + ngx_http_v2_out_frame_t *frame) +{ + ngx_buf_t *buf; + + buf = frame->first->buf; + + if (buf->pos != buf->last) { + return NGX_AGAIN; + } + + ngx_free_chain(h2c->pool, frame->first); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v2_send_window_update(ngx_http_v2_connection_t *h2c, ngx_uint_t sid, + size_t window) +{ + ngx_buf_t *buf; + ngx_http_v2_out_frame_t *frame; + + frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_WINDOW_UPDATE_SIZE, + NGX_HTTP_V2_WINDOW_UPDATE_FRAME, + NGX_HTTP_V2_NO_FLAG, sid); + if (frame == NULL) { + return NGX_ERROR; + } + + buf = frame->first->buf; + + buf->last = ngx_http_v2_write_uint32(buf->last, window); + + ngx_http_v2_queue_blocked_frame(h2c, frame); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v2_send_rst_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t sid, + ngx_uint_t status) +{ + ngx_buf_t *buf; + ngx_http_v2_out_frame_t *frame; + + frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_RST_STREAM_SIZE, + NGX_HTTP_V2_RST_STREAM_FRAME, + NGX_HTTP_V2_NO_FLAG, sid); + if (frame == NULL) { + return NGX_ERROR; + } + + buf = frame->first->buf; + + buf->last = ngx_http_v2_write_uint32(buf->last, status); + + ngx_http_v2_queue_blocked_frame(h2c, frame); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v2_send_goaway(ngx_http_v2_connection_t *h2c, ngx_uint_t status) +{ + ngx_buf_t *buf; + ngx_http_v2_out_frame_t *frame; + + frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_GOAWAY_SIZE, + NGX_HTTP_V2_GOAWAY_FRAME, + NGX_HTTP_V2_NO_FLAG, 0); + if (frame == NULL) { + return NGX_ERROR; + } + + buf = frame->first->buf; + + buf->last = ngx_http_v2_write_sid(buf->last, h2c->last_sid); + buf->last = ngx_http_v2_write_uint32(buf->last, status); + + ngx_http_v2_queue_blocked_frame(h2c, frame); + + return NGX_OK; +} + + +static ngx_http_v2_out_frame_t * +ngx_http_v2_get_frame(ngx_http_v2_connection_t *h2c, size_t length, + ngx_uint_t type, u_char flags, ngx_uint_t sid) +{ + ngx_buf_t *buf; + ngx_pool_t *pool; + ngx_http_v2_out_frame_t *frame; + + frame = h2c->free_frames; + + if (frame) { + h2c->free_frames = frame->next; + + buf = frame->first->buf; + buf->pos = buf->start; + + frame->blocked = 0; + + } else { + pool = h2c->pool ? h2c->pool : h2c->connection->pool; + + frame = ngx_pcalloc(pool, sizeof(ngx_http_v2_out_frame_t)); + if (frame == NULL) { + return NULL; + } + + frame->first = ngx_alloc_chain_link(pool); + if (frame->first == NULL) { + return NULL; + } + + buf = ngx_create_temp_buf(pool, NGX_HTTP_V2_FRAME_BUFFER_SIZE); + if (buf == NULL) { + return NULL; + } + + buf->last_buf = 1; + + frame->first->buf = buf; + frame->last = frame->first; + + frame->handler = ngx_http_v2_frame_handler; + } + +#if (NGX_DEBUG) + if (length > NGX_HTTP_V2_FRAME_BUFFER_SIZE - NGX_HTTP_V2_FRAME_HEADER_SIZE) + { + ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, + "requested control frame is too large: %uz", length); + return NULL; + } + + frame->length = length; +#endif + + buf->last = ngx_http_v2_write_len_and_type(buf->pos, length, type); + + *buf->last++ = flags; + + buf->last = ngx_http_v2_write_sid(buf->last, sid); + + return frame; +} + + +static ngx_int_t +ngx_http_v2_frame_handler(ngx_http_v2_connection_t *h2c, + ngx_http_v2_out_frame_t *frame) +{ + ngx_buf_t *buf; + + buf = frame->first->buf; + + if (buf->pos != buf->last) { + return NGX_AGAIN; + } + + frame->next = h2c->free_frames; + h2c->free_frames = frame; + + return NGX_OK; +} + + +static ngx_http_v2_stream_t * +ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c) +{ + ngx_log_t *log; + ngx_event_t *rev, *wev; + ngx_connection_t *fc; + ngx_http_log_ctx_t *ctx; + ngx_http_request_t *r; + ngx_http_v2_stream_t *stream; + ngx_http_core_srv_conf_t *cscf; + + fc = h2c->free_fake_connections; + + if (fc) { + h2c->free_fake_connections = fc->data; + + rev = fc->read; + wev = fc->write; + log = fc->log; + ctx = log->data; + + } else { + fc = ngx_palloc(h2c->pool, sizeof(ngx_connection_t)); + if (fc == NULL) { + return NULL; + } + + rev = ngx_palloc(h2c->pool, sizeof(ngx_event_t)); + if (rev == NULL) { + return NULL; + } + + wev = ngx_palloc(h2c->pool, sizeof(ngx_event_t)); + if (wev == NULL) { + return NULL; + } + + log = ngx_palloc(h2c->pool, sizeof(ngx_log_t)); + if (log == NULL) { + return NULL; + } + + ctx = ngx_palloc(h2c->pool, sizeof(ngx_http_log_ctx_t)); + if (ctx == NULL) { + return NULL; + } + + ctx->connection = fc; + ctx->request = NULL; + ctx->current_request = NULL; + } + + ngx_memcpy(log, h2c->connection->log, sizeof(ngx_log_t)); + + log->data = ctx; + + ngx_memzero(rev, sizeof(ngx_event_t)); + + rev->data = fc; + rev->ready = 1; + rev->handler = ngx_http_v2_close_stream_handler; + rev->log = log; + + ngx_memcpy(wev, rev, sizeof(ngx_event_t)); + + wev->write = 1; + + ngx_memcpy(fc, h2c->connection, sizeof(ngx_connection_t)); + + fc->data = h2c->http_connection; + fc->read = rev; + fc->write = wev; + fc->sent = 0; + fc->log = log; + fc->buffered = 0; + fc->sndlowat = 1; + fc->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; + + r = ngx_http_create_request(fc); + if (r == NULL) { + return NULL; + } + + r->http_version = NGX_HTTP_VERSION_20; + r->valid_location = 1; + + fc->data = r; + h2c->connection->requests++; + + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + r->header_in = ngx_create_temp_buf(r->pool, + cscf->client_header_buffer_size); + if (r->header_in == NULL) { + ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NULL; + } + + if (ngx_list_init(&r->headers_in.headers, r->pool, 20, + sizeof(ngx_table_elt_t)) + != NGX_OK) + { + ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NULL; + } + + r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE; + + stream = ngx_pcalloc(r->pool, sizeof(ngx_http_v2_stream_t)); + if (stream == NULL) { + ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NULL; + } + + r->stream = stream; + + stream->request = r; + stream->connection = h2c; + + stream->send_window = h2c->init_window; + stream->recv_window = NGX_HTTP_V2_MAX_WINDOW; + + h2c->processing++; + + return stream; +} + + +static ngx_http_v2_node_t * +ngx_http_v2_get_node_by_id(ngx_http_v2_connection_t *h2c, ngx_uint_t sid, + ngx_uint_t alloc) +{ + ngx_uint_t index; + ngx_http_v2_node_t *node; + ngx_http_v2_srv_conf_t *h2scf; + + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); + + index = ngx_http_v2_index(h2scf, sid); + + for (node = h2c->streams_index[index]; node; node = node->index) { + + if (node->id == sid) { + return node; + } + } + + if (!alloc) { + return NULL; + } + + if (h2c->closed_nodes < 32) { + node = ngx_pcalloc(h2c->connection->pool, sizeof(ngx_http_v2_node_t)); + if (node == NULL) { + return NULL; + } + + } else { + node = ngx_http_v2_get_closed_node(h2c); + } + + node->id = sid; + + ngx_queue_init(&node->children); + + node->index = h2c->streams_index[index]; + h2c->streams_index[index] = node; + + return node; +} + + +static ngx_http_v2_node_t * +ngx_http_v2_get_closed_node(ngx_http_v2_connection_t *h2c) +{ + ngx_uint_t weight; + ngx_queue_t *q, *children; + ngx_http_v2_node_t *node, **next, *n, *parent, *child; + ngx_http_v2_srv_conf_t *h2scf; + + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); + + h2c->closed_nodes--; + + q = ngx_queue_head(&h2c->closed); + + ngx_queue_remove(q); + + node = ngx_queue_data(q, ngx_http_v2_node_t, reuse); + + next = &h2c->streams_index[ngx_http_v2_index(h2scf, node->id)]; + + for ( ;; ) { + n = *next; + + if (n == node) { + *next = n->index; + break; + } + + next = &n->index; + } + + ngx_queue_remove(&node->queue); + + weight = 0; + + for (q = ngx_queue_head(&node->children); + q != ngx_queue_sentinel(&node->children); + q = ngx_queue_next(q)) + { + child = ngx_queue_data(q, ngx_http_v2_node_t, queue); + weight += child->weight; + } + + for (q = ngx_queue_head(&node->children); + q != ngx_queue_sentinel(&node->children); + q = ngx_queue_next(q)) + { + child = ngx_queue_data(q, ngx_http_v2_node_t, queue); + child->weight = node->weight * child->weight / weight; + + if (child->weight == 0) { + child->weight = 1; + } + } + + parent = node->parent; + + if (parent == NGX_HTTP_V2_ROOT) { + node->rank = 0; + node->rel_weight = 1.0; + + children = &h2c->dependencies; + + } else { + node->rank = parent->rank; + node->rel_weight = parent->rel_weight; + + children = &parent->children; + } + + ngx_http_v2_node_children_update(node); + ngx_queue_add(children, &node->children); + + ngx_memzero(node, sizeof(ngx_http_v2_node_t)); + + return node; +} + + +static ngx_int_t +ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header) +{ + u_char ch; + ngx_uint_t i; + ngx_http_core_srv_conf_t *cscf; + + if (header->name.len == 0) { + return NGX_ERROR; + } + + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + for (i = (header->name.data[0] == ':'); i != header->name.len; i++) { + ch = header->name.data[i]; + + if ((ch >= 'a' && ch <= 'z') + || (ch == '-') + || (ch >= '0' && ch <= '9') + || (ch == '_' && cscf->underscores_in_headers)) + { + continue; + } + + switch (ch) { + case '\0': + case LF: + case CR: + case ':': + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid header name: \"%V\"", + &header->name); + + return NGX_ERROR; + } + + if (ch >= 'A' && ch <= 'Z') { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid header name: \"%V\"", + &header->name); + + return NGX_ERROR; + } + + r->invalid_header = 1; + } + + for (i = 0; i != header->value.len; i++) { + ch = header->value.data[i]; + + switch (ch) { + case '\0': + case LF: + case CR: + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent header \"%V\" with " + "invalid value: \"%V\"", + &header->name, &header->value); + + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v2_pseudo_header(ngx_http_request_t *r, ngx_http_v2_header_t *header) +{ + header->name.len--; + header->name.data++; + + switch (header->name.len) { + case 4: + if (ngx_memcmp(header->name.data, "path", sizeof("path") - 1) + == 0) + { + return ngx_http_v2_parse_path(r, header); + } + + break; + + case 6: + if (ngx_memcmp(header->name.data, "method", sizeof("method") - 1) + == 0) + { + return ngx_http_v2_parse_method(r, header); + } + + if (ngx_memcmp(header->name.data, "scheme", sizeof("scheme") - 1) + == 0) + { + return ngx_http_v2_parse_scheme(r, header); + } + + break; + + case 9: + if (ngx_memcmp(header->name.data, "authority", sizeof("authority") - 1) + == 0) + { + return ngx_http_v2_parse_authority(r, header); + } + + break; + } + + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent unknown pseudo header \"%V\"", + &header->name); + + return NGX_DECLINED; +} + + +static ngx_int_t +ngx_http_v2_parse_path(ngx_http_request_t *r, ngx_http_v2_header_t *header) +{ + if (r->unparsed_uri.len) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent duplicate :path header"); + + return NGX_DECLINED; + } + + if (header->value.len == 0) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent empty :path header"); + + return NGX_DECLINED; + } + + r->uri_start = header->value.data; + r->uri_end = header->value.data + header->value.len; + + if (ngx_http_parse_uri(r) != NGX_OK) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid :path header: \"%V\"", + &header->value); + + return NGX_DECLINED; + } + + if (ngx_http_process_request_uri(r) != NGX_OK) { + /* + * request has been finalized already + * in ngx_http_process_request_uri() + */ + return NGX_ABORT; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v2_parse_method(ngx_http_request_t *r, ngx_http_v2_header_t *header) +{ + size_t k, len; + ngx_uint_t n; + const u_char *p, *m; + + /* + * This array takes less than 256 sequential bytes, + * and if typical CPU cache line size is 64 bytes, + * it is prefetched for 4 load operations. + */ + static const struct { + u_char len; + const u_char method[11]; + uint32_t value; + } tests[] = { + { 3, "GET", NGX_HTTP_GET }, + { 4, "POST", NGX_HTTP_POST }, + { 4, "HEAD", NGX_HTTP_HEAD }, + { 7, "OPTIONS", NGX_HTTP_OPTIONS }, + { 8, "PROPFIND", NGX_HTTP_PROPFIND }, + { 3, "PUT", NGX_HTTP_PUT }, + { 5, "MKCOL", NGX_HTTP_MKCOL }, + { 6, "DELETE", NGX_HTTP_DELETE }, + { 4, "COPY", NGX_HTTP_COPY }, + { 4, "MOVE", NGX_HTTP_MOVE }, + { 9, "PROPPATCH", NGX_HTTP_PROPPATCH }, + { 4, "LOCK", NGX_HTTP_LOCK }, + { 6, "UNLOCK", NGX_HTTP_UNLOCK }, + { 5, "PATCH", NGX_HTTP_PATCH }, + { 5, "TRACE", NGX_HTTP_TRACE } + }, *test; + + if (r->method_name.len) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent duplicate :method header"); + + return NGX_DECLINED; + } + + if (header->value.len == 0) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent empty :method header"); + + return NGX_DECLINED; + } + + r->method_name.len = header->value.len; + r->method_name.data = header->value.data; + + len = r->method_name.len; + n = sizeof(tests) / sizeof(tests[0]); + test = tests; + + do { + if (len == test->len) { + p = r->method_name.data; + m = test->method; + k = len; + + do { + if (*p++ != *m++) { + goto next; + } + } while (--k); + + r->method = test->value; + return NGX_OK; + } + + next: + test++; + + } while (--n); + + p = r->method_name.data; + + do { + if ((*p < 'A' || *p > 'Z') && *p != '_') { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid method: \"%V\"", + &r->method_name); + + return NGX_DECLINED; + } + + p++; + + } while (--len); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v2_parse_scheme(ngx_http_request_t *r, ngx_http_v2_header_t *header) +{ + if (r->schema_start) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent duplicate :schema header"); + + return NGX_DECLINED; + } + + if (header->value.len == 0) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent empty :schema header"); + + return NGX_DECLINED; + } + + r->schema_start = header->value.data; + r->schema_end = header->value.data + header->value.len; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v2_parse_authority(ngx_http_request_t *r, ngx_http_v2_header_t *header) +{ + ngx_table_elt_t *h; + ngx_http_header_t *hh; + ngx_http_core_main_conf_t *cmcf; + + static ngx_str_t host = ngx_string("host"); + + h = ngx_list_push(&r->headers_in.headers); + if (h == NULL) { + return NGX_ERROR; + } + + h->hash = ngx_hash_key(host.data, host.len); + + h->key.len = host.len; + h->key.data = host.data; + + h->value.len = header->value.len; + h->value.data = header->value.data; + + h->lowcase_key = host.data; + + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + + hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, + h->lowcase_key, h->key.len); + + if (hh == NULL) { + return NGX_ERROR; + } + + if (hh->handler(r, h, hh->offset) != NGX_OK) { + /* + * request has been finalized already + * in ngx_http_process_host() + */ + return NGX_ABORT; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v2_construct_request_line(ngx_http_request_t *r) +{ + u_char *p; + + static const u_char ending[] = " HTTP/2.0"; + + if (r->method_name.len == 0 + || r->unparsed_uri.len == 0) + { + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; + } + + r->request_line.len = r->method_name.len + 1 + + r->unparsed_uri.len + + sizeof(ending) - 1; + + p = ngx_pnalloc(r->pool, r->request_line.len + 1); + if (p == NULL) { + ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } + + r->request_line.data = p; + + p = ngx_cpymem(p, r->method_name.data, r->method_name.len); + + *p++ = ' '; + + p = ngx_cpymem(p, r->unparsed_uri.data, r->unparsed_uri.len); + + ngx_memcpy(p, ending, sizeof(ending)); + + /* some modules expect the space character after method name */ + r->method_name.data = r->request_line.data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http2 http request line: \"%V\"", &r->request_line); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v2_cookie(ngx_http_request_t *r, ngx_http_v2_header_t *header) +{ + ngx_str_t *val; + ngx_array_t *cookies; + + cookies = r->stream->cookies; + + if (cookies == NULL) { + cookies = ngx_array_create(r->pool, 2, sizeof(ngx_str_t)); + if (cookies == NULL) { + return NGX_ERROR; + } + + r->stream->cookies = cookies; + } + + val = ngx_array_push(cookies); + if (val == NULL) { + return NGX_ERROR; + } + + val->len = header->value.len; + val->data = header->value.data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v2_construct_cookie_header(ngx_http_request_t *r) +{ + u_char *buf, *p, *end; + size_t len; + ngx_str_t *vals; + ngx_uint_t i; + ngx_array_t *cookies; + ngx_table_elt_t *h; + ngx_http_header_t *hh; + ngx_http_core_main_conf_t *cmcf; + + static ngx_str_t cookie = ngx_string("cookie"); + + cookies = r->stream->cookies; + + if (cookies == NULL) { + return NGX_OK; + } + + vals = cookies->elts; + + i = 0; + len = 0; + + do { + len += vals[i].len + 2; + } while (++i != cookies->nelts); + + len -= 2; + + buf = ngx_pnalloc(r->pool, len + 1); + if (buf == NULL) { + ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } + + p = buf; + end = buf + len; + + for (i = 0; /* void */ ; i++) { + + p = ngx_cpymem(p, vals[i].data, vals[i].len); + + if (p == end) { + *p = '\0'; + break; + } + + *p++ = ';'; *p++ = ' '; + } + + h = ngx_list_push(&r->headers_in.headers); + if (h == NULL) { + ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } + + h->hash = ngx_hash_key(cookie.data, cookie.len); + + h->key.len = cookie.len; + h->key.data = cookie.data; + + h->value.len = len; + h->value.data = buf; + + h->lowcase_key = cookie.data; + + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + + hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, + h->lowcase_key, h->key.len); + + if (hh == NULL) { + ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } + + if (hh->handler(r, h, hh->offset) != NGX_OK) { + /* + * request has been finalized already + * in ngx_http_process_multi_header_lines() + */ + return NGX_ERROR; + } + + return NGX_OK; +} + + +static void +ngx_http_v2_run_request(ngx_http_request_t *r) +{ + if (ngx_http_v2_construct_request_line(r) != NGX_OK) { + return; + } + + if (ngx_http_v2_construct_cookie_header(r) != NGX_OK) { + return; + } + + r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE; + + if (ngx_http_process_request_header(r) != NGX_OK) { + return; + } + + if (r->headers_in.content_length_n > 0 && r->stream->in_closed) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client prematurely closed stream"); + + r->stream->skip_data = NGX_HTTP_V2_DATA_ERROR; + + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return; + } + + ngx_http_process_request(r); +} + + +static ngx_int_t +ngx_http_v2_init_request_body(ngx_http_request_t *r) +{ + ngx_buf_t *buf; + ngx_temp_file_t *tf; + ngx_http_request_body_t *rb; + ngx_http_core_loc_conf_t *clcf; + + rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); + if (rb == NULL) { + return NGX_ERROR; + } + + r->request_body = rb; + + if (r->stream->in_closed) { + return NGX_OK; + } + + rb->rest = r->headers_in.content_length_n; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (r->request_body_in_file_only + || rb->rest > (off_t) clcf->client_body_buffer_size + || rb->rest < 0) + { + tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); + if (tf == NULL) { + return NGX_ERROR; + } + + tf->file.fd = NGX_INVALID_FILE; + tf->file.log = r->connection->log; + tf->path = clcf->client_body_temp_path; + tf->pool = r->pool; + tf->warn = "a client request body is buffered to a temporary file"; + tf->log_level = r->request_body_file_log_level; + tf->persistent = r->request_body_in_persistent_file; + tf->clean = r->request_body_in_clean_file; + + if (r->request_body_file_group_access) { + tf->access = 0660; + } + + rb->temp_file = tf; + + if (r->stream->in_closed + && ngx_create_temp_file(&tf->file, tf->path, tf->pool, + tf->persistent, tf->clean, tf->access) + != NGX_OK) + { + return NGX_ERROR; + } + + buf = ngx_calloc_buf(r->pool); + if (buf == NULL) { + return NGX_ERROR; + } + + } else { + + if (rb->rest == 0) { + return NGX_OK; + } + + buf = ngx_create_temp_buf(r->pool, (size_t) rb->rest); + if (buf == NULL) { + return NGX_ERROR; + } + } + + rb->buf = buf; + + rb->bufs = ngx_alloc_chain_link(r->pool); + if (rb->bufs == NULL) { + return NGX_ERROR; + } + + rb->bufs->buf = buf; + rb->bufs->next = NULL; + + rb->rest = 0; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_v2_read_request_body(ngx_http_request_t *r, + ngx_http_client_body_handler_pt post_handler) +{ + ngx_http_v2_stream_t *stream; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http2 read request body"); + + stream = r->stream; + + switch (stream->skip_data) { + + case NGX_HTTP_V2_DATA_DISCARD: + post_handler(r); + return NGX_OK; + + case NGX_HTTP_V2_DATA_ERROR: + if (r->headers_in.content_length_n == -1) { + return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; + } else { + return NGX_HTTP_BAD_REQUEST; + } + + case NGX_HTTP_V2_DATA_INTERNAL_ERROR: + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (!r->request_body && ngx_http_v2_init_request_body(r) != NGX_OK) { + stream->skip_data = NGX_HTTP_V2_DATA_INTERNAL_ERROR; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (stream->in_closed) { + post_handler(r); + return NGX_OK; + } + + r->request_body->post_handler = post_handler; + + r->read_event_handler = ngx_http_test_reading; + r->write_event_handler = ngx_http_request_empty_handler; + + return NGX_AGAIN; +} + + +static ngx_int_t +ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, + ngx_http_v2_stream_t *stream, ngx_uint_t status) +{ + ngx_event_t *rev; + ngx_connection_t *fc; + + if (ngx_http_v2_send_rst_stream(h2c, stream->node->id, status) + == NGX_ERROR) + { + return NGX_ERROR; + } + + stream->out_closed = 1; + + fc = stream->request->connection; + fc->error = 1; + + rev = fc->read; + rev->handler(rev); + + return NGX_OK; +} + + +void +ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) +{ + ngx_event_t *ev; + ngx_connection_t *fc; + ngx_http_v2_node_t *node; + ngx_http_v2_connection_t *h2c; + + h2c = stream->connection; + node = stream->node; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 close stream %ui, queued %ui, processing %ui", + node->id, stream->queued, h2c->processing); + + fc = stream->request->connection; + + if (stream->queued) { + fc->write->handler = ngx_http_v2_close_stream_handler; + return; + } + + if (!stream->out_closed) { + if (ngx_http_v2_send_rst_stream(h2c, node->id, + NGX_HTTP_V2_INTERNAL_ERROR) + != NGX_OK) + { + h2c->connection->error = 1; + } + } + + node->stream = NULL; + + ngx_queue_insert_tail(&h2c->closed, &node->reuse); + h2c->closed_nodes++; + + ngx_http_free_request(stream->request, rc); + + ev = fc->read; + + if (ev->active || ev->disabled) { + ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, + "fake read event was activated"); + } + + if (ev->timer_set) { + ngx_del_timer(ev); + } + + if (ev->posted) { + ngx_delete_posted_event(ev); + } + + ev = fc->write; + + if (ev->active || ev->disabled) { + ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, + "fake write event was activated"); + } + + if (ev->timer_set) { + ngx_del_timer(ev); + } + + if (ev->posted) { + ngx_delete_posted_event(ev); + } + + fc->data = h2c->free_fake_connections; + h2c->free_fake_connections = fc; + + h2c->processing--; + + if (h2c->processing || h2c->blocked) { + return; + } + + ev = h2c->connection->read; + + ev->handler = ngx_http_v2_handle_connection_handler; + ngx_post_event(ev, &ngx_posted_events); +} + + +static void +ngx_http_v2_close_stream_handler(ngx_event_t *ev) +{ + ngx_connection_t *fc; + ngx_http_request_t *r; + + fc = ev->data; + r = fc->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http2 close stream handler"); + + ngx_http_v2_close_stream(r->stream, 0); +} + + +static void +ngx_http_v2_handle_connection_handler(ngx_event_t *rev) +{ + ngx_connection_t *c; + + rev->handler = ngx_http_v2_read_handler; + + if (rev->ready) { + ngx_http_v2_read_handler(rev); + return; + } + + c = rev->data; + + ngx_http_v2_handle_connection(c->data); +} + + +static void +ngx_http_v2_idle_handler(ngx_event_t *rev) +{ + ngx_connection_t *c; + ngx_http_v2_srv_conf_t *h2scf; + ngx_http_v2_connection_t *h2c; + + c = rev->data; + h2c = c->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 idle handler"); + + if (rev->timedout || c->close) { + ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR); + return; + } + +#if (NGX_HAVE_KQUEUE) + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + if (rev->pending_eof) { + c->log->handler = NULL; + ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno, + "kevent() reported that client %V closed " + "idle connection", &c->addr_text); +#if (NGX_HTTP_SSL) + if (c->ssl) { + c->ssl->no_send_shutdown = 1; + } +#endif + ngx_http_close_connection(c); + return; + } + } + +#endif + + c->destroyed = 0; + c->idle = 0; + ngx_reusable_connection(c, 0); + + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); + + h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); + if (h2c->pool == NULL) { + ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + return; + } + + c->write->handler = ngx_http_v2_write_handler; + + rev->handler = ngx_http_v2_read_handler; + ngx_http_v2_read_handler(rev); +} + + +static void +ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c, + ngx_uint_t status) +{ + ngx_uint_t i, size; + ngx_event_t *ev; + ngx_connection_t *c, *fc; + ngx_http_request_t *r; + ngx_http_v2_node_t *node; + ngx_http_v2_stream_t *stream; + ngx_http_v2_srv_conf_t *h2scf; + + c = h2c->connection; + + h2c->blocked = 1; + + if (!c->error && ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) { + (void) ngx_http_v2_send_output_queue(h2c); + } + + if (!h2c->processing) { + ngx_http_close_connection(c); + return; + } + + c->error = 1; + c->read->handler = ngx_http_empty_handler; + c->write->handler = ngx_http_empty_handler; + + h2c->last_out = NULL; + + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); + + size = ngx_http_v2_index_size(h2scf); + + for (i = 0; i < size; i++) { + + for (node = h2c->streams_index[i]; node; node = node->index) { + stream = node->stream; + + if (stream == NULL) { + continue; + } + + stream->handled = 0; + + r = stream->request; + fc = r->connection; + + fc->error = 1; + + if (stream->queued) { + stream->queued = 0; + + ev = fc->write; + ev->delayed = 0; + + } else { + ev = fc->read; + } + + ev->eof = 1; + ev->handler(ev); + } + } + + h2c->blocked = 0; + + if (h2c->processing) { + return; + } + + ngx_http_close_connection(c); +} + + +static ngx_int_t +ngx_http_v2_adjust_windows(ngx_http_v2_connection_t *h2c, ssize_t delta) +{ + ngx_uint_t i, size; + ngx_event_t *wev; + ngx_http_v2_node_t *node; + ngx_http_v2_stream_t *stream; + ngx_http_v2_srv_conf_t *h2scf; + + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); + + size = ngx_http_v2_index_size(h2scf); + + for (i = 0; i < size; i++) { + + for (node = h2c->streams_index[i]; node; node = node->index) { + stream = node->stream; + + if (stream == NULL) { + continue; + } + + if (delta > 0 + && stream->send_window + > (ssize_t) (NGX_HTTP_V2_MAX_WINDOW - delta)) + { + if (ngx_http_v2_terminate_stream(h2c, stream, + NGX_HTTP_V2_FLOW_CTRL_ERROR) + == NGX_ERROR) + { + return NGX_ERROR; + } + + continue; + } + + stream->send_window += delta; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2:%ui adjusted window: %z", + node->id, stream->send_window); + + if (stream->send_window > 0 && stream->exhausted) { + stream->exhausted = 0; + + wev = stream->request->connection->write; + + if (!wev->timer_set) { + wev->delayed = 0; + wev->handler(wev); + } + } + } + } + + return NGX_OK; +} + + +static void +ngx_http_v2_set_dependency(ngx_http_v2_connection_t *h2c, + ngx_http_v2_node_t *node, ngx_uint_t depend, ngx_uint_t exclusive) +{ + ngx_queue_t *children; + ngx_http_v2_node_t *parent, *next; + + parent = depend ? ngx_http_v2_get_node_by_id(h2c, depend, 0) : NULL; + + if (parent == NULL) { + parent = NGX_HTTP_V2_ROOT; + + if (depend != 0) { + exclusive = 0; + } + + node->rank = 1; + node->rel_weight = (1.0 / 256) * node->weight; + + children = &h2c->dependencies; + + } else { + if (node->parent != NULL) { + + for (next = parent->parent; + next != NGX_HTTP_V2_ROOT && next->rank >= node->rank; + next = next->parent) + { + if (next != node) { + continue; + } + + ngx_queue_remove(&parent->queue); + ngx_queue_insert_after(&node->queue, &parent->queue); + + parent->parent = node->parent; + + if (node->parent == NGX_HTTP_V2_ROOT) { + parent->rank = 1; + parent->rel_weight = (1.0 / 256) * parent->weight; + + } else { + parent->rank = node->parent->rank + 1; + parent->rel_weight = (node->parent->rel_weight / 256) + * parent->weight; + } + + if (!exclusive) { + ngx_http_v2_node_children_update(parent); + } + + break; + } + } + + node->rank = parent->rank + 1; + node->rel_weight = (parent->rel_weight / 256) * node->weight; + + if (parent->stream == NULL) { + ngx_queue_remove(&parent->reuse); + ngx_queue_insert_tail(&h2c->closed, &parent->reuse); + } + + children = &parent->children; + } + + if (exclusive) { + ngx_queue_add(&node->children, children); + ngx_queue_init(children); + } + + if (node->parent != NULL) { + ngx_queue_remove(&node->queue); + } + + ngx_queue_insert_tail(children, &node->queue); + + node->parent = parent; + + ngx_http_v2_node_children_update(node); +} + + +static void +ngx_http_v2_node_children_update(ngx_http_v2_node_t *node) +{ + ngx_queue_t *q; + ngx_http_v2_node_t *child; + + for (q = ngx_queue_head(&node->children); + q != ngx_queue_sentinel(&node->children); + q = ngx_queue_next(q)) + { + child = ngx_queue_data(q, ngx_http_v2_node_t, queue); + + child->rank = node->rank + 1; + child->rel_weight = (node->rel_weight / 256) * child->weight; + + ngx_http_v2_node_children_update(child); + } +} + + +static void +ngx_http_v2_pool_cleanup(void *data) +{ + ngx_http_v2_connection_t *h2c = data; + + if (h2c->state.pool) { + ngx_destroy_pool(h2c->state.pool); + } + + if (h2c->pool) { + ngx_destroy_pool(h2c->pool); + } +} diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h new file mode 100644 index 0000000..b7e73c9 --- /dev/null +++ b/src/http/v2/ngx_http_v2.h @@ -0,0 +1,333 @@ +/* + * Copyright (C) Nginx, Inc. + * Copyright (C) Valentin V. Bartenev + */ + + +#ifndef _NGX_HTTP_V2_H_INCLUDED_ +#define _NGX_HTTP_V2_H_INCLUDED_ + + +#include +#include +#include + + +#define NGX_HTTP_V2_ALPN_ADVERTISE "\x02h2" +#define NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_V2_ALPN_ADVERTISE + +#define NGX_HTTP_V2_STATE_BUFFER_SIZE 16 + +#define NGX_HTTP_V2_MAX_FRAME_SIZE ((1 << 24) - 1) + +#define NGX_HTTP_V2_INT_OCTETS 4 +#define NGX_HTTP_V2_MAX_FIELD ((1 << NGX_HTTP_V2_INT_OCTETS * 7) - 1) + +#define NGX_HTTP_V2_DATA_DISCARD 1 +#define NGX_HTTP_V2_DATA_ERROR 2 +#define NGX_HTTP_V2_DATA_INTERNAL_ERROR 3 + +#define NGX_HTTP_V2_FRAME_HEADER_SIZE 9 + +/* frame types */ +#define NGX_HTTP_V2_DATA_FRAME 0x0 +#define NGX_HTTP_V2_HEADERS_FRAME 0x1 +#define NGX_HTTP_V2_PRIORITY_FRAME 0x2 +#define NGX_HTTP_V2_RST_STREAM_FRAME 0x3 +#define NGX_HTTP_V2_SETTINGS_FRAME 0x4 +#define NGX_HTTP_V2_PUSH_PROMISE_FRAME 0x5 +#define NGX_HTTP_V2_PING_FRAME 0x6 +#define NGX_HTTP_V2_GOAWAY_FRAME 0x7 +#define NGX_HTTP_V2_WINDOW_UPDATE_FRAME 0x8 +#define NGX_HTTP_V2_CONTINUATION_FRAME 0x9 + +/* frame flags */ +#define NGX_HTTP_V2_NO_FLAG 0x00 +#define NGX_HTTP_V2_ACK_FLAG 0x01 +#define NGX_HTTP_V2_END_STREAM_FLAG 0x01 +#define NGX_HTTP_V2_END_HEADERS_FLAG 0x04 +#define NGX_HTTP_V2_PADDED_FLAG 0x08 +#define NGX_HTTP_V2_PRIORITY_FLAG 0x20 + + +typedef struct ngx_http_v2_connection_s ngx_http_v2_connection_t; +typedef struct ngx_http_v2_node_s ngx_http_v2_node_t; +typedef struct ngx_http_v2_out_frame_s ngx_http_v2_out_frame_t; + + +typedef u_char *(*ngx_http_v2_handler_pt) (ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end); + + +typedef struct { + ngx_str_t name; + ngx_str_t value; +} ngx_http_v2_header_t; + + +typedef struct { + ngx_uint_t sid; + size_t length; + size_t padding; + unsigned flags:8; + + unsigned incomplete:1; + + /* HPACK */ + unsigned parse_name:1; + unsigned parse_value:1; + unsigned index:1; + ngx_http_v2_header_t header; + size_t header_limit; + size_t field_limit; + u_char field_state; + u_char *field_start; + u_char *field_end; + size_t field_rest; + ngx_pool_t *pool; + + ngx_http_v2_stream_t *stream; + + u_char buffer[NGX_HTTP_V2_STATE_BUFFER_SIZE]; + size_t buffer_used; + ngx_http_v2_handler_pt handler; +} ngx_http_v2_state_t; + + + +typedef struct { + ngx_http_v2_header_t **entries; + + ngx_uint_t added; + ngx_uint_t deleted; + ngx_uint_t reused; + ngx_uint_t allocated; + + size_t size; + size_t free; + u_char *storage; + u_char *pos; +} ngx_http_v2_hpack_t; + + +struct ngx_http_v2_connection_s { + ngx_connection_t *connection; + ngx_http_connection_t *http_connection; + + ngx_uint_t processing; + + size_t send_window; + size_t recv_window; + size_t init_window; + + size_t frame_size; + + ngx_queue_t waiting; + + ngx_http_v2_state_t state; + + ngx_http_v2_hpack_t hpack; + + ngx_pool_t *pool; + + ngx_http_v2_out_frame_t *free_frames; + ngx_connection_t *free_fake_connections; + + ngx_http_v2_node_t **streams_index; + + ngx_http_v2_out_frame_t *last_out; + + ngx_queue_t posted; + ngx_queue_t dependencies; + ngx_queue_t closed; + + ngx_uint_t last_sid; + + unsigned closed_nodes:8; + unsigned blocked:1; +}; + + +struct ngx_http_v2_node_s { + ngx_uint_t id; + ngx_http_v2_node_t *index; + ngx_http_v2_node_t *parent; + ngx_queue_t queue; + ngx_queue_t children; + ngx_queue_t reuse; + ngx_uint_t rank; + ngx_uint_t weight; + double rel_weight; + ngx_http_v2_stream_t *stream; +}; + + +struct ngx_http_v2_stream_s { + ngx_http_request_t *request; + ngx_http_v2_connection_t *connection; + ngx_http_v2_node_t *node; + + ngx_uint_t header_buffers; + ngx_uint_t queued; + + /* + * A change to SETTINGS_INITIAL_WINDOW_SIZE could cause the + * send_window to become negative, hence it's signed. + */ + ssize_t send_window; + size_t recv_window; + + ngx_http_v2_out_frame_t *free_frames; + ngx_chain_t *free_data_headers; + ngx_chain_t *free_bufs; + + ngx_queue_t queue; + + ngx_array_t *cookies; + + size_t header_limit; + + unsigned handled:1; + unsigned blocked:1; + unsigned exhausted:1; + unsigned in_closed:1; + unsigned out_closed:1; + unsigned skip_data:2; +}; + + +struct ngx_http_v2_out_frame_s { + ngx_http_v2_out_frame_t *next; + ngx_chain_t *first; + ngx_chain_t *last; + ngx_int_t (*handler)(ngx_http_v2_connection_t *h2c, + ngx_http_v2_out_frame_t *frame); + + ngx_http_v2_stream_t *stream; + size_t length; + + unsigned blocked:1; + unsigned fin:1; +}; + + +static ngx_inline void +ngx_http_v2_queue_frame(ngx_http_v2_connection_t *h2c, + ngx_http_v2_out_frame_t *frame) +{ + ngx_http_v2_out_frame_t **out; + + for (out = &h2c->last_out; *out; out = &(*out)->next) { + + if ((*out)->blocked || (*out)->stream == NULL) { + break; + } + + if ((*out)->stream->node->rank < frame->stream->node->rank + || ((*out)->stream->node->rank == frame->stream->node->rank + && (*out)->stream->node->rel_weight + >= frame->stream->node->rel_weight)) + { + break; + } + } + + frame->next = *out; + *out = frame; +} + + +static ngx_inline void +ngx_http_v2_queue_blocked_frame(ngx_http_v2_connection_t *h2c, + ngx_http_v2_out_frame_t *frame) +{ + ngx_http_v2_out_frame_t **out; + + for (out = &h2c->last_out; *out; out = &(*out)->next) + { + if ((*out)->blocked || (*out)->stream == NULL) { + break; + } + } + + frame->next = *out; + *out = frame; +} + + +void ngx_http_v2_init(ngx_event_t *rev); +void ngx_http_v2_request_headers_init(void); + +ngx_int_t ngx_http_v2_read_request_body(ngx_http_request_t *r, + ngx_http_client_body_handler_pt post_handler); + +void ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc); + +ngx_int_t ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c); + + +ngx_int_t ngx_http_v2_get_indexed_header(ngx_http_v2_connection_t *h2c, + ngx_uint_t index, ngx_uint_t name_only); +ngx_int_t ngx_http_v2_add_header(ngx_http_v2_connection_t *h2c, + ngx_http_v2_header_t *header); +ngx_int_t ngx_http_v2_table_size(ngx_http_v2_connection_t *h2c, size_t size); + + +ngx_int_t ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, + u_char **dst, ngx_uint_t last, ngx_log_t *log); + + +#define ngx_http_v2_prefix(bits) ((1 << (bits)) - 1) + + +#if (NGX_HAVE_NONALIGNED) + +#define ngx_http_v2_parse_uint16(p) ntohs(*(uint16_t *) (p)) +#define ngx_http_v2_parse_uint32(p) ntohl(*(uint32_t *) (p)) + +#else + +#define ngx_http_v2_parse_uint16(p) ((p)[0] << 8 | (p)[1]) +#define ngx_http_v2_parse_uint32(p) \ + ((p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3]) + +#endif + +#define ngx_http_v2_parse_length(p) ((p) >> 8) +#define ngx_http_v2_parse_type(p) ((p) & 0xff) +#define ngx_http_v2_parse_sid(p) (ngx_http_v2_parse_uint32(p) & 0x7fffffff) +#define ngx_http_v2_parse_window(p) (ngx_http_v2_parse_uint32(p) & 0x7fffffff) + + +#define ngx_http_v2_write_uint16_aligned(p, s) \ + (*(uint16_t *) (p) = htons((uint16_t) (s)), (p) + sizeof(uint16_t)) +#define ngx_http_v2_write_uint32_aligned(p, s) \ + (*(uint32_t *) (p) = htonl((uint32_t) (s)), (p) + sizeof(uint32_t)) + +#if (NGX_HAVE_NONALIGNED) + +#define ngx_http_v2_write_uint16 ngx_http_v2_write_uint16_aligned +#define ngx_http_v2_write_uint32 ngx_http_v2_write_uint32_aligned + +#else + +#define ngx_http_v2_write_uint16(p, s) \ + ((p)[0] = (u_char) ((s) >> 8), \ + (p)[1] = (u_char) (s), \ + (p) + sizeof(uint16_t)) + +#define ngx_http_v2_write_uint32(p, s) \ + ((p)[0] = (u_char) ((s) >> 24), \ + (p)[1] = (u_char) ((s) >> 16), \ + (p)[2] = (u_char) ((s) >> 8), \ + (p)[3] = (u_char) (s), \ + (p) + sizeof(uint32_t)) + +#endif + +#define ngx_http_v2_write_len_and_type(p, l, t) \ + ngx_http_v2_write_uint32_aligned(p, (l) << 8 | (t)) + +#define ngx_http_v2_write_sid ngx_http_v2_write_uint32 + +#endif /* _NGX_HTTP_V2_H_INCLUDED_ */ diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c new file mode 100644 index 0000000..17cfcd8 --- /dev/null +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -0,0 +1,1291 @@ + +/* + * Copyright (C) Nginx, Inc. + * Copyright (C) Valentin V. Bartenev + */ + + +#include +#include +#include +#include +#include + + +#define ngx_http_v2_integer_octets(v) (((v) + 127) / 128) + +#define ngx_http_v2_literal_size(h) \ + (ngx_http_v2_integer_octets(sizeof(h) - 1) + sizeof(h) - 1) + +#define ngx_http_v2_indexed(i) (128 + (i)) +#define ngx_http_v2_inc_indexed(i) (64 + (i)) + + +#define NGX_HTTP_V2_STATUS_INDEX 8 +#define NGX_HTTP_V2_STATUS_200_INDEX 8 +#define NGX_HTTP_V2_STATUS_204_INDEX 9 +#define NGX_HTTP_V2_STATUS_206_INDEX 10 +#define NGX_HTTP_V2_STATUS_304_INDEX 11 +#define NGX_HTTP_V2_STATUS_400_INDEX 12 +#define NGX_HTTP_V2_STATUS_404_INDEX 13 +#define NGX_HTTP_V2_STATUS_500_INDEX 14 + +#define NGX_HTTP_V2_CONTENT_LENGTH_INDEX 28 +#define NGX_HTTP_V2_CONTENT_TYPE_INDEX 31 +#define NGX_HTTP_V2_DATE_INDEX 33 +#define NGX_HTTP_V2_LAST_MODIFIED_INDEX 44 +#define NGX_HTTP_V2_LOCATION_INDEX 46 +#define NGX_HTTP_V2_SERVER_INDEX 54 +#define NGX_HTTP_V2_VARY_INDEX 59 + + +static u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, + ngx_uint_t value); +static void ngx_http_v2_write_headers_head(u_char *pos, size_t length, + ngx_uint_t sid, ngx_uint_t end_headers, ngx_uint_t end_stream); +static void ngx_http_v2_write_continuation_head(u_char *pos, size_t length, + ngx_uint_t sid, ngx_uint_t end_headers); + +static ngx_chain_t *ngx_http_v2_send_chain(ngx_connection_t *fc, + ngx_chain_t *in, off_t limit); + +static ngx_chain_t *ngx_http_v2_filter_get_shadow( + ngx_http_v2_stream_t *stream, ngx_buf_t *buf, off_t offset, off_t size); +static ngx_http_v2_out_frame_t *ngx_http_v2_filter_get_data_frame( + ngx_http_v2_stream_t *stream, size_t len, ngx_chain_t *first, + ngx_chain_t *last); + +static ngx_inline ngx_int_t ngx_http_v2_flow_control( + ngx_http_v2_connection_t *h2c, ngx_http_v2_stream_t *stream); +static void ngx_http_v2_waiting_queue(ngx_http_v2_connection_t *h2c, + ngx_http_v2_stream_t *stream); + +static ngx_inline ngx_int_t ngx_http_v2_filter_send( + ngx_connection_t *fc, ngx_http_v2_stream_t *stream); + +static ngx_int_t ngx_http_v2_headers_frame_handler( + ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame); +static ngx_int_t ngx_http_v2_data_frame_handler( + ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame); +static ngx_inline void ngx_http_v2_handle_frame( + ngx_http_v2_stream_t *stream, ngx_http_v2_out_frame_t *frame); +static ngx_inline void ngx_http_v2_handle_stream( + ngx_http_v2_connection_t *h2c, ngx_http_v2_stream_t *stream); + +static void ngx_http_v2_filter_cleanup(void *data); + +static ngx_int_t ngx_http_v2_filter_init(ngx_conf_t *cf); + + +static ngx_http_module_t ngx_http_v2_filter_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_v2_filter_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_v2_filter_module = { + NGX_MODULE_V1, + &ngx_http_v2_filter_module_ctx, /* module context */ + NULL, /* 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_http_output_header_filter_pt ngx_http_next_header_filter; + + +static ngx_int_t +ngx_http_v2_header_filter(ngx_http_request_t *r) +{ + u_char status, *p, *head; + size_t len, rest, frame_size; + ngx_buf_t *b; + ngx_str_t host, location; + ngx_uint_t i, port, continuation; + ngx_chain_t *cl; + ngx_list_part_t *part; + ngx_table_elt_t *header; + ngx_connection_t *fc; + ngx_http_cleanup_t *cln; + ngx_http_v2_stream_t *stream; + ngx_http_v2_out_frame_t *frame; + ngx_http_core_loc_conf_t *clcf; + ngx_http_core_srv_conf_t *cscf; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + u_char addr[NGX_SOCKADDR_STRLEN]; + + + if (!r->stream) { + return ngx_http_next_header_filter(r); + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http2 header filter"); + + if (r->header_sent) { + return NGX_OK; + } + + r->header_sent = 1; + + if (r != r->main) { + return NGX_OK; + } + + if (r->method == NGX_HTTP_HEAD) { + r->header_only = 1; + } + + switch (r->headers_out.status) { + + case NGX_HTTP_OK: + status = ngx_http_v2_indexed(NGX_HTTP_V2_STATUS_200_INDEX); + break; + + case NGX_HTTP_NO_CONTENT: + r->header_only = 1; + + ngx_str_null(&r->headers_out.content_type); + + r->headers_out.content_length = NULL; + r->headers_out.content_length_n = -1; + + r->headers_out.last_modified_time = -1; + r->headers_out.last_modified = NULL; + + status = ngx_http_v2_indexed(NGX_HTTP_V2_STATUS_204_INDEX); + break; + + case NGX_HTTP_PARTIAL_CONTENT: + status = ngx_http_v2_indexed(NGX_HTTP_V2_STATUS_206_INDEX); + break; + + case NGX_HTTP_NOT_MODIFIED: + r->header_only = 1; + status = ngx_http_v2_indexed(NGX_HTTP_V2_STATUS_304_INDEX); + break; + + default: + r->headers_out.last_modified_time = -1; + r->headers_out.last_modified = NULL; + + switch (r->headers_out.status) { + + case NGX_HTTP_BAD_REQUEST: + status = ngx_http_v2_indexed(NGX_HTTP_V2_STATUS_400_INDEX); + break; + + case NGX_HTTP_NOT_FOUND: + status = ngx_http_v2_indexed(NGX_HTTP_V2_STATUS_404_INDEX); + break; + + case NGX_HTTP_INTERNAL_SERVER_ERROR: + status = ngx_http_v2_indexed(NGX_HTTP_V2_STATUS_500_INDEX); + break; + + default: + status = 0; + } + } + + len = status ? 1 : 1 + ngx_http_v2_literal_size("418"); + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (r->headers_out.server == NULL) { + len += 1 + clcf->server_tokens ? ngx_http_v2_literal_size(NGINX_VER) + : ngx_http_v2_literal_size("nginx"); + } + + if (r->headers_out.date == NULL) { + len += 1 + ngx_http_v2_literal_size("Wed, 31 Dec 1986 18:00:00 GMT"); + } + + if (r->headers_out.content_type.len) { + len += NGX_HTTP_V2_INT_OCTETS + r->headers_out.content_type.len; + + if (r->headers_out.content_type_len == r->headers_out.content_type.len + && r->headers_out.charset.len) + { + len += sizeof("; charset=") - 1 + r->headers_out.charset.len; + } + } + + if (r->headers_out.content_length == NULL + && r->headers_out.content_length_n >= 0) + { + len += 1 + ngx_http_v2_integer_octets(NGX_OFF_T_LEN) + NGX_OFF_T_LEN; + } + + if (r->headers_out.last_modified == NULL + && r->headers_out.last_modified_time != -1) + { + len += 1 + ngx_http_v2_literal_size("Wed, 31 Dec 1986 18:00:00 GMT"); + } + + fc = r->connection; + + if (r->headers_out.location && r->headers_out.location->value.len) { + + if (r->headers_out.location->value.data[0] == '/') { + if (clcf->server_name_in_redirect) { + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + host = cscf->server_name; + + } else if (r->headers_in.server.len) { + host = r->headers_in.server; + + } else { + host.len = NGX_SOCKADDR_STRLEN; + host.data = addr; + + if (ngx_connection_local_sockaddr(fc, &host, 0) != NGX_OK) { + return NGX_ERROR; + } + } + + switch (fc->local_sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) fc->local_sockaddr; + port = ntohs(sin6->sin6_port); + break; +#endif +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + port = 0; + break; +#endif + default: /* AF_INET */ + sin = (struct sockaddr_in *) fc->local_sockaddr; + port = ntohs(sin->sin_port); + break; + } + + location.len = sizeof("https://") - 1 + host.len + + r->headers_out.location->value.len; + + if (clcf->port_in_redirect) { + +#if (NGX_HTTP_SSL) + if (fc->ssl) + port = (port == 443) ? 0 : port; + else +#endif + port = (port == 80) ? 0 : port; + + } else { + port = 0; + } + + if (port) { + location.len += sizeof(":65535") - 1; + } + + location.data = ngx_pnalloc(r->pool, location.len); + if (location.data == NULL) { + return NGX_ERROR; + } + + p = ngx_cpymem(location.data, "http", sizeof("http") - 1); + +#if (NGX_HTTP_SSL) + if (fc->ssl) { + *p++ = 's'; + } +#endif + + *p++ = ':'; *p++ = '/'; *p++ = '/'; + p = ngx_cpymem(p, host.data, host.len); + + if (port) { + p = ngx_sprintf(p, ":%ui", port); + } + + p = ngx_cpymem(p, r->headers_out.location->value.data, + r->headers_out.location->value.len); + + /* update r->headers_out.location->value for possible logging */ + + r->headers_out.location->value.len = p - location.data; + r->headers_out.location->value.data = location.data; + ngx_str_set(&r->headers_out.location->key, "Location"); + } + + r->headers_out.location->hash = 0; + + len += 1 + NGX_HTTP_V2_INT_OCTETS + r->headers_out.location->value.len; + } + +#if (NGX_HTTP_GZIP) + if (r->gzip_vary) { + if (clcf->gzip_vary) { + len += 1 + ngx_http_v2_literal_size("Accept-Encoding"); + + } else { + r->gzip_vary = 0; + } + } +#endif + + part = &r->headers_out.headers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].hash == 0) { + continue; + } + + if (header[i].key.len > NGX_HTTP_V2_MAX_FIELD) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + "too long response header name: \"%V\"", + &header[i].key); + return NGX_ERROR; + } + + if (header[i].value.len > NGX_HTTP_V2_MAX_FIELD) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + "too long response header value: \"%V: %V\"", + &header[i].key, &header[i].value); + return NGX_ERROR; + } + + len += 1 + NGX_HTTP_V2_INT_OCTETS + header[i].key.len + + NGX_HTTP_V2_INT_OCTETS + header[i].value.len; + } + + stream = r->stream; + frame_size = stream->connection->frame_size; + + len += NGX_HTTP_V2_FRAME_HEADER_SIZE + * ((len + frame_size - 1) / frame_size); + + b = ngx_create_temp_buf(r->pool, len); + if (b == NULL) { + return NGX_ERROR; + } + + b->last_buf = r->header_only; + + b->last += NGX_HTTP_V2_FRAME_HEADER_SIZE; + + if (status) { + *b->last++ = status; + + } else { + *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_STATUS_INDEX); + *b->last++ = 3; + b->last = ngx_sprintf(b->last, "%03ui", r->headers_out.status); + } + + if (r->headers_out.server == NULL) { + *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_SERVER_INDEX); + + if (clcf->server_tokens) { + *b->last++ = sizeof(NGINX_VER) - 1; + b->last = ngx_cpymem(b->last, NGINX_VER, sizeof(NGINX_VER) - 1); + + } else { + *b->last++ = sizeof("nginx") - 1; + b->last = ngx_cpymem(b->last, "nginx", sizeof("nginx") - 1); + } + } + + if (r->headers_out.date == NULL) { + *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_DATE_INDEX); + *b->last++ = (u_char) ngx_cached_http_time.len; + + b->last = ngx_cpymem(b->last, ngx_cached_http_time.data, + ngx_cached_http_time.len); + } + + if (r->headers_out.content_type.len) { + *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_CONTENT_TYPE_INDEX); + + if (r->headers_out.content_type_len == r->headers_out.content_type.len + && r->headers_out.charset.len) + { + *b->last = 0; + b->last = ngx_http_v2_write_int(b->last, ngx_http_v2_prefix(7), + r->headers_out.content_type.len + + sizeof("; charset=") - 1 + + r->headers_out.charset.len); + + p = b->last; + + b->last = ngx_cpymem(p, r->headers_out.content_type.data, + r->headers_out.content_type.len); + + b->last = ngx_cpymem(b->last, "; charset=", + sizeof("; charset=") - 1); + + b->last = ngx_cpymem(b->last, r->headers_out.charset.data, + r->headers_out.charset.len); + + /* update r->headers_out.content_type for possible logging */ + + r->headers_out.content_type.len = b->last - p; + r->headers_out.content_type.data = p; + + } else { + *b->last = 0; + b->last = ngx_http_v2_write_int(b->last, ngx_http_v2_prefix(7), + r->headers_out.content_type.len); + b->last = ngx_cpymem(b->last, r->headers_out.content_type.data, + r->headers_out.content_type.len); + } + } + + if (r->headers_out.content_length == NULL + && r->headers_out.content_length_n >= 0) + { + *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_CONTENT_LENGTH_INDEX); + + p = b->last; + b->last = ngx_sprintf(b->last + 1, "%O", + r->headers_out.content_length_n); + *p = (u_char) (b->last - p - 1); + } + + if (r->headers_out.last_modified == NULL + && r->headers_out.last_modified_time != -1) + { + *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_LAST_MODIFIED_INDEX); + + p = b->last; + b->last = ngx_http_time(b->last + 1, r->headers_out.last_modified_time); + *p = (u_char) (b->last - p - 1); + } + + if (r->headers_out.location && r->headers_out.location->value.len) { + *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_LOCATION_INDEX); + + *b->last = 0; + b->last = ngx_http_v2_write_int(b->last, ngx_http_v2_prefix(7), + r->headers_out.location->value.len); + b->last = ngx_cpymem(b->last, r->headers_out.location->value.data, + r->headers_out.location->value.len); + } + +#if (NGX_HTTP_GZIP) + if (r->gzip_vary) { + *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_VARY_INDEX); + *b->last++ = sizeof("Accept-Encoding") - 1; + b->last = ngx_cpymem(b->last, "Accept-Encoding", + sizeof("Accept-Encoding") - 1); + } +#endif + + continuation = 0; + head = b->pos; + + len = b->last - head - NGX_HTTP_V2_FRAME_HEADER_SIZE; + rest = frame_size - len; + + part = &r->headers_out.headers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].hash == 0) { + continue; + } + + len = 1 + NGX_HTTP_V2_INT_OCTETS * 2 + + header[i].key.len + + header[i].value.len; + + if (len > rest) { + len = b->last - head - NGX_HTTP_V2_FRAME_HEADER_SIZE; + + if (continuation) { + ngx_http_v2_write_continuation_head(head, len, + stream->node->id, 0); + } else { + continuation = 1; + ngx_http_v2_write_headers_head(head, len, stream->node->id, 0, + r->header_only); + } + + rest = frame_size; + head = b->last; + + b->last += NGX_HTTP_V2_FRAME_HEADER_SIZE; + } + + p = b->last; + + *p++ = 0; + + *p = 0; + p = ngx_http_v2_write_int(p, ngx_http_v2_prefix(7), header[i].key.len); + ngx_strlow(p, header[i].key.data, header[i].key.len); + p += header[i].key.len; + + *p = 0; + p = ngx_http_v2_write_int(p, ngx_http_v2_prefix(7), + header[i].value.len); + p = ngx_cpymem(p, header[i].value.data, header[i].value.len); + + rest -= p - b->last; + b->last = p; + } + + len = b->last - head - NGX_HTTP_V2_FRAME_HEADER_SIZE; + + if (continuation) { + ngx_http_v2_write_continuation_head(head, len, stream->node->id, 1); + + } else { + ngx_http_v2_write_headers_head(head, len, stream->node->id, 1, + r->header_only); + } + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf = b; + cl->next = NULL; + + frame = ngx_palloc(r->pool, sizeof(ngx_http_v2_out_frame_t)); + if (frame == NULL) { + return NGX_ERROR; + } + + frame->first = cl; + frame->last = cl; + frame->handler = ngx_http_v2_headers_frame_handler; + frame->stream = stream; + frame->length = b->last - b->pos - NGX_HTTP_V2_FRAME_HEADER_SIZE; + frame->blocked = 1; + frame->fin = r->header_only; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0, + "http2:%ui create HEADERS frame %p: len:%uz", + stream->node->id, frame, frame->length); + + ngx_http_v2_queue_blocked_frame(stream->connection, frame); + + cln = ngx_http_cleanup_add(r, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_http_v2_filter_cleanup; + cln->data = stream; + + stream->queued = 1; + + fc->send_chain = ngx_http_v2_send_chain; + fc->need_last_buf = 1; + + return ngx_http_v2_filter_send(fc, stream); +} + + +static u_char * +ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, ngx_uint_t value) +{ + if (value < prefix) { + *pos++ |= value; + return pos; + } + + *pos++ |= prefix; + value -= prefix; + + while (value >= 128) { + *pos++ = value % 128 + 128; + value /= 128; + } + + *pos++ = (u_char) value; + + return pos; +} + + +static void +ngx_http_v2_write_headers_head(u_char *pos, size_t length, ngx_uint_t sid, + ngx_uint_t end_headers, ngx_uint_t end_stream) +{ + u_char flags; + + pos = ngx_http_v2_write_len_and_type(pos, length, + NGX_HTTP_V2_HEADERS_FRAME); + + flags = NGX_HTTP_V2_NO_FLAG; + + if (end_headers) { + flags |= NGX_HTTP_V2_END_HEADERS_FLAG; + } + + if (end_stream) { + flags |= NGX_HTTP_V2_END_STREAM_FLAG; + } + + *pos++ = flags; + + (void) ngx_http_v2_write_sid(pos, sid); +} + + +static void +ngx_http_v2_write_continuation_head(u_char *pos, size_t length, ngx_uint_t sid, + ngx_uint_t end_headers) +{ + pos = ngx_http_v2_write_len_and_type(pos, length, + NGX_HTTP_V2_CONTINUATION_FRAME); + + *pos++ = end_headers ? NGX_HTTP_V2_END_HEADERS_FLAG : NGX_HTTP_V2_NO_FLAG; + + (void) ngx_http_v2_write_sid(pos, sid); +} + + +static ngx_chain_t * +ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) +{ + off_t size, offset; + size_t rest, frame_size; + ngx_chain_t *cl, *out, **ln; + ngx_http_request_t *r; + ngx_http_v2_stream_t *stream; + ngx_http_v2_loc_conf_t *h2lcf; + ngx_http_v2_out_frame_t *frame; + ngx_http_v2_connection_t *h2c; + + r = fc->data; + stream = r->stream; + +#if (NGX_SUPPRESS_WARN) + size = 0; +#endif + + while (in) { + size = ngx_buf_size(in->buf); + + if (size || in->buf->last_buf) { + break; + } + + in = in->next; + } + + if (in == NULL) { + + if (stream->queued) { + fc->write->delayed = 1; + } else { + fc->buffered &= ~NGX_HTTP_V2_BUFFERED; + } + + return NULL; + } + + h2c = stream->connection; + + if (size && ngx_http_v2_flow_control(h2c, stream) == NGX_DECLINED) { + fc->write->delayed = 1; + return in; + } + + if (in->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_filter_get_shadow) { + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_CHAIN_ERROR; + } + + cl->buf = in->buf; + in->buf = cl->buf->shadow; + + offset = ngx_buf_in_memory(in->buf) + ? (cl->buf->pos - in->buf->pos) + : (cl->buf->file_pos - in->buf->file_pos); + + cl->next = stream->free_bufs; + stream->free_bufs = cl; + + } else { + offset = 0; + } + + if (limit == 0 || limit > (off_t) h2c->send_window) { + limit = h2c->send_window; + } + + if (limit > stream->send_window) { + limit = (stream->send_window > 0) ? stream->send_window : 0; + } + + h2lcf = ngx_http_get_module_loc_conf(r, ngx_http_v2_module); + + frame_size = (h2lcf->chunk_size < h2c->frame_size) + ? h2lcf->chunk_size : h2c->frame_size; + +#if (NGX_SUPPRESS_WARN) + cl = NULL; +#endif + + for ( ;; ) { + if ((off_t) frame_size > limit) { + frame_size = (size_t) limit; + } + + ln = &out; + rest = frame_size; + + while ((off_t) rest >= size) { + + if (offset) { + cl = ngx_http_v2_filter_get_shadow(stream, in->buf, + offset, size); + if (cl == NULL) { + return NGX_CHAIN_ERROR; + } + + offset = 0; + + } else { + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_CHAIN_ERROR; + } + + cl->buf = in->buf; + } + + *ln = cl; + ln = &cl->next; + + rest -= (size_t) size; + in = in->next; + + if (in == NULL) { + frame_size -= rest; + rest = 0; + break; + } + + size = ngx_buf_size(in->buf); + } + + if (rest) { + cl = ngx_http_v2_filter_get_shadow(stream, in->buf, offset, rest); + if (cl == NULL) { + return NGX_CHAIN_ERROR; + } + + cl->buf->flush = 0; + cl->buf->last_buf = 0; + + *ln = cl; + + offset += rest; + size -= rest; + } + + frame = ngx_http_v2_filter_get_data_frame(stream, frame_size, out, cl); + if (frame == NULL) { + return NGX_CHAIN_ERROR; + } + + ngx_http_v2_queue_frame(h2c, frame); + + h2c->send_window -= frame_size; + + stream->send_window -= frame_size; + stream->queued++; + + if (in == NULL) { + break; + } + + limit -= frame_size; + + if (limit == 0) { + break; + } + } + + if (offset) { + cl = ngx_http_v2_filter_get_shadow(stream, in->buf, offset, size); + if (cl == NULL) { + return NGX_CHAIN_ERROR; + } + + in->buf = cl->buf; + ngx_free_chain(r->pool, cl); + } + + if (ngx_http_v2_filter_send(fc, stream) == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + if (in && ngx_http_v2_flow_control(h2c, stream) == NGX_DECLINED) { + fc->write->delayed = 1; + } + + return in; +} + + +static ngx_chain_t * +ngx_http_v2_filter_get_shadow(ngx_http_v2_stream_t *stream, ngx_buf_t *buf, + off_t offset, off_t size) +{ + ngx_buf_t *chunk; + ngx_chain_t *cl; + + cl = ngx_chain_get_free_buf(stream->request->pool, &stream->free_bufs); + if (cl == NULL) { + return NULL; + } + + chunk = cl->buf; + + ngx_memcpy(chunk, buf, sizeof(ngx_buf_t)); + + chunk->tag = (ngx_buf_tag_t) &ngx_http_v2_filter_get_shadow; + chunk->shadow = buf; + + if (ngx_buf_in_memory(chunk)) { + chunk->pos += offset; + chunk->last = chunk->pos + size; + } + + if (chunk->in_file) { + chunk->file_pos += offset; + chunk->file_last = chunk->file_pos + size; + } + + return cl; +} + + +static ngx_http_v2_out_frame_t * +ngx_http_v2_filter_get_data_frame(ngx_http_v2_stream_t *stream, + size_t len, ngx_chain_t *first, ngx_chain_t *last) +{ + u_char flags; + ngx_buf_t *buf; + ngx_chain_t *cl; + ngx_http_v2_out_frame_t *frame; + + + frame = stream->free_frames; + + if (frame) { + stream->free_frames = frame->next; + + } else { + frame = ngx_palloc(stream->request->pool, + sizeof(ngx_http_v2_out_frame_t)); + if (frame == NULL) { + return NULL; + } + } + + flags = last->buf->last_buf ? NGX_HTTP_V2_END_STREAM_FLAG : 0; + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0, + "http2:%ui create DATA frame %p: len:%uz flags:%ui", + stream->node->id, frame, len, (ngx_uint_t) flags); + + cl = ngx_chain_get_free_buf(stream->request->pool, + &stream->free_data_headers); + if (cl == NULL) { + return NULL; + } + + buf = cl->buf; + + if (!buf->start) { + buf->start = ngx_palloc(stream->request->pool, + NGX_HTTP_V2_FRAME_HEADER_SIZE); + if (buf->start == NULL) { + return NULL; + } + + buf->end = buf->start + NGX_HTTP_V2_FRAME_HEADER_SIZE; + buf->last = buf->end; + + buf->tag = (ngx_buf_tag_t) &ngx_http_v2_filter_get_data_frame; + buf->memory = 1; + } + + buf->pos = buf->start; + buf->last = buf->pos; + + buf->last = ngx_http_v2_write_len_and_type(buf->last, len, + NGX_HTTP_V2_DATA_FRAME); + *buf->last++ = flags; + + buf->last = ngx_http_v2_write_sid(buf->last, stream->node->id); + + cl->next = first; + first = cl; + + last->buf->flush = 1; + + frame->first = first; + frame->last = last; + frame->handler = ngx_http_v2_data_frame_handler; + frame->stream = stream; + frame->length = len; + frame->blocked = 0; + frame->fin = last->buf->last_buf; + + return frame; +} + + +static ngx_inline ngx_int_t +ngx_http_v2_filter_send(ngx_connection_t *fc, ngx_http_v2_stream_t *stream) +{ + stream->blocked = 1; + + if (ngx_http_v2_send_output_queue(stream->connection) == NGX_ERROR) { + fc->error = 1; + return NGX_ERROR; + } + + stream->blocked = 0; + + if (stream->queued) { + fc->buffered |= NGX_HTTP_V2_BUFFERED; + fc->write->delayed = 1; + return NGX_AGAIN; + } + + fc->buffered &= ~NGX_HTTP_V2_BUFFERED; + + return NGX_OK; +} + + +static ngx_inline ngx_int_t +ngx_http_v2_flow_control(ngx_http_v2_connection_t *h2c, + ngx_http_v2_stream_t *stream) +{ + if (stream->send_window <= 0) { + stream->exhausted = 1; + return NGX_DECLINED; + } + + if (h2c->send_window == 0) { + ngx_http_v2_waiting_queue(h2c, stream); + return NGX_DECLINED; + } + + return NGX_OK; +} + + +static void +ngx_http_v2_waiting_queue(ngx_http_v2_connection_t *h2c, + ngx_http_v2_stream_t *stream) +{ + ngx_queue_t *q; + ngx_http_v2_stream_t *s; + + if (stream->handled) { + return; + } + + stream->handled = 1; + + for (q = ngx_queue_last(&h2c->waiting); + q != ngx_queue_sentinel(&h2c->waiting); + q = ngx_queue_prev(q)) + { + s = ngx_queue_data(q, ngx_http_v2_stream_t, queue); + + if (s->node->rank < stream->node->rank + || (s->node->rank == stream->node->rank + && s->node->rel_weight >= stream->node->rel_weight)) + { + break; + } + } + + ngx_queue_insert_after(q, &stream->queue); +} + + + +static ngx_int_t +ngx_http_v2_headers_frame_handler(ngx_http_v2_connection_t *h2c, + ngx_http_v2_out_frame_t *frame) +{ + ngx_buf_t *buf; + ngx_http_v2_stream_t *stream; + + buf = frame->first->buf; + + if (buf->pos != buf->last) { + return NGX_AGAIN; + } + + stream = frame->stream; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2:%ui HEADERS frame %p was sent", + stream->node->id, frame); + + ngx_free_chain(stream->request->pool, frame->first); + + ngx_http_v2_handle_frame(stream, frame); + + ngx_http_v2_handle_stream(h2c, stream); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v2_data_frame_handler(ngx_http_v2_connection_t *h2c, + ngx_http_v2_out_frame_t *frame) +{ + ngx_buf_t *buf; + ngx_chain_t *cl, *ln; + ngx_http_v2_stream_t *stream; + + stream = frame->stream; + + cl = frame->first; + + if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_filter_get_data_frame) { + + if (cl->buf->pos != cl->buf->last) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2:%ui DATA frame %p was sent partially", + stream->node->id, frame); + + return NGX_AGAIN; + } + + ln = cl->next; + + cl->next = stream->free_data_headers; + stream->free_data_headers = cl; + + if (cl == frame->last) { + goto done; + } + + cl = ln; + } + + for ( ;; ) { + if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_filter_get_shadow) { + buf = cl->buf->shadow; + + if (ngx_buf_in_memory(buf)) { + buf->pos = cl->buf->pos; + } + + if (buf->in_file) { + buf->file_pos = cl->buf->file_pos; + } + } + + if (ngx_buf_size(cl->buf) != 0) { + + if (cl != frame->first) { + frame->first = cl; + ngx_http_v2_handle_stream(h2c, stream); + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2:%ui DATA frame %p was sent partially", + stream->node->id, frame); + + return NGX_AGAIN; + } + + ln = cl->next; + + if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_filter_get_shadow) { + cl->next = stream->free_bufs; + stream->free_bufs = cl; + + } else { + ngx_free_chain(stream->request->pool, cl); + } + + if (cl == frame->last) { + goto done; + } + + cl = ln; + } + +done: + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2:%ui DATA frame %p was sent", + stream->node->id, frame); + + stream->request->header_size += NGX_HTTP_V2_FRAME_HEADER_SIZE; + + ngx_http_v2_handle_frame(stream, frame); + + ngx_http_v2_handle_stream(h2c, stream); + + return NGX_OK; +} + + +static ngx_inline void +ngx_http_v2_handle_frame(ngx_http_v2_stream_t *stream, + ngx_http_v2_out_frame_t *frame) +{ + ngx_http_request_t *r; + + r = stream->request; + + r->connection->sent += NGX_HTTP_V2_FRAME_HEADER_SIZE + frame->length; + + if (frame->fin) { + stream->out_closed = 1; + } + + frame->next = stream->free_frames; + stream->free_frames = frame; + + stream->queued--; +} + + +static ngx_inline void +ngx_http_v2_handle_stream(ngx_http_v2_connection_t *h2c, + ngx_http_v2_stream_t *stream) +{ + ngx_event_t *wev; + + if (stream->handled || stream->blocked || stream->exhausted) { + return; + } + + wev = stream->request->connection->write; + + /* + * This timer can only be set if the stream was delayed because of rate + * limit. In that case the event should be triggered by the timer. + */ + + if (!wev->timer_set) { + wev->delayed = 0; + + stream->handled = 1; + ngx_queue_insert_tail(&h2c->posted, &stream->queue); + } +} + + +static void +ngx_http_v2_filter_cleanup(void *data) +{ + ngx_http_v2_stream_t *stream = data; + + size_t window; + ngx_http_v2_out_frame_t *frame, **fn; + ngx_http_v2_connection_t *h2c; + + if (stream->handled) { + stream->handled = 0; + ngx_queue_remove(&stream->queue); + } + + if (stream->queued == 0) { + return; + } + + window = 0; + h2c = stream->connection; + fn = &h2c->last_out; + + for ( ;; ) { + frame = *fn; + + if (frame == NULL) { + break; + } + + if (frame->stream == stream && !frame->blocked) { + *fn = frame->next; + + window += frame->length; + + if (--stream->queued == 0) { + break; + } + + continue; + } + + fn = &frame->next; + } + + if (h2c->send_window == 0 && window && !ngx_queue_empty(&h2c->waiting)) { + ngx_queue_add(&h2c->posted, &h2c->waiting); + ngx_queue_init(&h2c->waiting); + } + + h2c->send_window += window; +} + + +static ngx_int_t +ngx_http_v2_filter_init(ngx_conf_t *cf) +{ + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_v2_header_filter; + + return NGX_OK; +} diff --git a/src/http/v2/ngx_http_v2_huff_decode.c b/src/http/v2/ngx_http_v2_huff_decode.c new file mode 100644 index 0000000..49ca576 --- /dev/null +++ b/src/http/v2/ngx_http_v2_huff_decode.c @@ -0,0 +1,2714 @@ + +/* + * Copyright (C) Nginx, Inc. + * Copyright (C) Valentin V. Bartenev + */ + + +#include +#include +#include + + +typedef struct { + u_char next; + u_char emit; + u_char sym; + u_char ending; +} ngx_http_v2_huff_decode_code_t; + + +static ngx_inline ngx_int_t ngx_http_v2_huff_decode_bits(u_char *state, + u_char *ending, ngx_uint_t bits, u_char **dst); + + +static ngx_http_v2_huff_decode_code_t ngx_http_v2_huff_decode_codes[256][16] = +{ + /* 0 */ + { + {0x04, 0x00, 0x00, 0x00}, {0x05, 0x00, 0x00, 0x00}, + {0x07, 0x00, 0x00, 0x00}, {0x08, 0x00, 0x00, 0x00}, + {0x0b, 0x00, 0x00, 0x00}, {0x0c, 0x00, 0x00, 0x00}, + {0x10, 0x00, 0x00, 0x00}, {0x13, 0x00, 0x00, 0x00}, + {0x19, 0x00, 0x00, 0x00}, {0x1c, 0x00, 0x00, 0x00}, + {0x20, 0x00, 0x00, 0x00}, {0x23, 0x00, 0x00, 0x00}, + {0x2a, 0x00, 0x00, 0x00}, {0x31, 0x00, 0x00, 0x00}, + {0x39, 0x00, 0x00, 0x00}, {0x40, 0x00, 0x00, 0x01} + }, + { + {0x00, 0x01, 0x30, 0x01}, {0x00, 0x01, 0x31, 0x01}, + {0x00, 0x01, 0x32, 0x01}, {0x00, 0x01, 0x61, 0x01}, + {0x00, 0x01, 0x63, 0x01}, {0x00, 0x01, 0x65, 0x01}, + {0x00, 0x01, 0x69, 0x01}, {0x00, 0x01, 0x6f, 0x01}, + {0x00, 0x01, 0x73, 0x01}, {0x00, 0x01, 0x74, 0x01}, + {0x0d, 0x00, 0x00, 0x00}, {0x0e, 0x00, 0x00, 0x00}, + {0x11, 0x00, 0x00, 0x00}, {0x12, 0x00, 0x00, 0x00}, + {0x14, 0x00, 0x00, 0x00}, {0x15, 0x00, 0x00, 0x00} + }, + { + {0x01, 0x01, 0x30, 0x00}, {0x16, 0x01, 0x30, 0x01}, + {0x01, 0x01, 0x31, 0x00}, {0x16, 0x01, 0x31, 0x01}, + {0x01, 0x01, 0x32, 0x00}, {0x16, 0x01, 0x32, 0x01}, + {0x01, 0x01, 0x61, 0x00}, {0x16, 0x01, 0x61, 0x01}, + {0x01, 0x01, 0x63, 0x00}, {0x16, 0x01, 0x63, 0x01}, + {0x01, 0x01, 0x65, 0x00}, {0x16, 0x01, 0x65, 0x01}, + {0x01, 0x01, 0x69, 0x00}, {0x16, 0x01, 0x69, 0x01}, + {0x01, 0x01, 0x6f, 0x00}, {0x16, 0x01, 0x6f, 0x01} + }, + { + {0x02, 0x01, 0x30, 0x00}, {0x09, 0x01, 0x30, 0x00}, + {0x17, 0x01, 0x30, 0x00}, {0x28, 0x01, 0x30, 0x01}, + {0x02, 0x01, 0x31, 0x00}, {0x09, 0x01, 0x31, 0x00}, + {0x17, 0x01, 0x31, 0x00}, {0x28, 0x01, 0x31, 0x01}, + {0x02, 0x01, 0x32, 0x00}, {0x09, 0x01, 0x32, 0x00}, + {0x17, 0x01, 0x32, 0x00}, {0x28, 0x01, 0x32, 0x01}, + {0x02, 0x01, 0x61, 0x00}, {0x09, 0x01, 0x61, 0x00}, + {0x17, 0x01, 0x61, 0x00}, {0x28, 0x01, 0x61, 0x01} + }, + { + {0x03, 0x01, 0x30, 0x00}, {0x06, 0x01, 0x30, 0x00}, + {0x0a, 0x01, 0x30, 0x00}, {0x0f, 0x01, 0x30, 0x00}, + {0x18, 0x01, 0x30, 0x00}, {0x1f, 0x01, 0x30, 0x00}, + {0x29, 0x01, 0x30, 0x00}, {0x38, 0x01, 0x30, 0x01}, + {0x03, 0x01, 0x31, 0x00}, {0x06, 0x01, 0x31, 0x00}, + {0x0a, 0x01, 0x31, 0x00}, {0x0f, 0x01, 0x31, 0x00}, + {0x18, 0x01, 0x31, 0x00}, {0x1f, 0x01, 0x31, 0x00}, + {0x29, 0x01, 0x31, 0x00}, {0x38, 0x01, 0x31, 0x01} + }, + /* 5 */ + { + {0x03, 0x01, 0x32, 0x00}, {0x06, 0x01, 0x32, 0x00}, + {0x0a, 0x01, 0x32, 0x00}, {0x0f, 0x01, 0x32, 0x00}, + {0x18, 0x01, 0x32, 0x00}, {0x1f, 0x01, 0x32, 0x00}, + {0x29, 0x01, 0x32, 0x00}, {0x38, 0x01, 0x32, 0x01}, + {0x03, 0x01, 0x61, 0x00}, {0x06, 0x01, 0x61, 0x00}, + {0x0a, 0x01, 0x61, 0x00}, {0x0f, 0x01, 0x61, 0x00}, + {0x18, 0x01, 0x61, 0x00}, {0x1f, 0x01, 0x61, 0x00}, + {0x29, 0x01, 0x61, 0x00}, {0x38, 0x01, 0x61, 0x01} + }, + { + {0x02, 0x01, 0x63, 0x00}, {0x09, 0x01, 0x63, 0x00}, + {0x17, 0x01, 0x63, 0x00}, {0x28, 0x01, 0x63, 0x01}, + {0x02, 0x01, 0x65, 0x00}, {0x09, 0x01, 0x65, 0x00}, + {0x17, 0x01, 0x65, 0x00}, {0x28, 0x01, 0x65, 0x01}, + {0x02, 0x01, 0x69, 0x00}, {0x09, 0x01, 0x69, 0x00}, + {0x17, 0x01, 0x69, 0x00}, {0x28, 0x01, 0x69, 0x01}, + {0x02, 0x01, 0x6f, 0x00}, {0x09, 0x01, 0x6f, 0x00}, + {0x17, 0x01, 0x6f, 0x00}, {0x28, 0x01, 0x6f, 0x01} + }, + { + {0x03, 0x01, 0x63, 0x00}, {0x06, 0x01, 0x63, 0x00}, + {0x0a, 0x01, 0x63, 0x00}, {0x0f, 0x01, 0x63, 0x00}, + {0x18, 0x01, 0x63, 0x00}, {0x1f, 0x01, 0x63, 0x00}, + {0x29, 0x01, 0x63, 0x00}, {0x38, 0x01, 0x63, 0x01}, + {0x03, 0x01, 0x65, 0x00}, {0x06, 0x01, 0x65, 0x00}, + {0x0a, 0x01, 0x65, 0x00}, {0x0f, 0x01, 0x65, 0x00}, + {0x18, 0x01, 0x65, 0x00}, {0x1f, 0x01, 0x65, 0x00}, + {0x29, 0x01, 0x65, 0x00}, {0x38, 0x01, 0x65, 0x01} + }, + { + {0x03, 0x01, 0x69, 0x00}, {0x06, 0x01, 0x69, 0x00}, + {0x0a, 0x01, 0x69, 0x00}, {0x0f, 0x01, 0x69, 0x00}, + {0x18, 0x01, 0x69, 0x00}, {0x1f, 0x01, 0x69, 0x00}, + {0x29, 0x01, 0x69, 0x00}, {0x38, 0x01, 0x69, 0x01}, + {0x03, 0x01, 0x6f, 0x00}, {0x06, 0x01, 0x6f, 0x00}, + {0x0a, 0x01, 0x6f, 0x00}, {0x0f, 0x01, 0x6f, 0x00}, + {0x18, 0x01, 0x6f, 0x00}, {0x1f, 0x01, 0x6f, 0x00}, + {0x29, 0x01, 0x6f, 0x00}, {0x38, 0x01, 0x6f, 0x01} + }, + { + {0x01, 0x01, 0x73, 0x00}, {0x16, 0x01, 0x73, 0x01}, + {0x01, 0x01, 0x74, 0x00}, {0x16, 0x01, 0x74, 0x01}, + {0x00, 0x01, 0x20, 0x01}, {0x00, 0x01, 0x25, 0x01}, + {0x00, 0x01, 0x2d, 0x01}, {0x00, 0x01, 0x2e, 0x01}, + {0x00, 0x01, 0x2f, 0x01}, {0x00, 0x01, 0x33, 0x01}, + {0x00, 0x01, 0x34, 0x01}, {0x00, 0x01, 0x35, 0x01}, + {0x00, 0x01, 0x36, 0x01}, {0x00, 0x01, 0x37, 0x01}, + {0x00, 0x01, 0x38, 0x01}, {0x00, 0x01, 0x39, 0x01} + }, + /* 10 */ + { + {0x02, 0x01, 0x73, 0x00}, {0x09, 0x01, 0x73, 0x00}, + {0x17, 0x01, 0x73, 0x00}, {0x28, 0x01, 0x73, 0x01}, + {0x02, 0x01, 0x74, 0x00}, {0x09, 0x01, 0x74, 0x00}, + {0x17, 0x01, 0x74, 0x00}, {0x28, 0x01, 0x74, 0x01}, + {0x01, 0x01, 0x20, 0x00}, {0x16, 0x01, 0x20, 0x01}, + {0x01, 0x01, 0x25, 0x00}, {0x16, 0x01, 0x25, 0x01}, + {0x01, 0x01, 0x2d, 0x00}, {0x16, 0x01, 0x2d, 0x01}, + {0x01, 0x01, 0x2e, 0x00}, {0x16, 0x01, 0x2e, 0x01} + }, + { + {0x03, 0x01, 0x73, 0x00}, {0x06, 0x01, 0x73, 0x00}, + {0x0a, 0x01, 0x73, 0x00}, {0x0f, 0x01, 0x73, 0x00}, + {0x18, 0x01, 0x73, 0x00}, {0x1f, 0x01, 0x73, 0x00}, + {0x29, 0x01, 0x73, 0x00}, {0x38, 0x01, 0x73, 0x01}, + {0x03, 0x01, 0x74, 0x00}, {0x06, 0x01, 0x74, 0x00}, + {0x0a, 0x01, 0x74, 0x00}, {0x0f, 0x01, 0x74, 0x00}, + {0x18, 0x01, 0x74, 0x00}, {0x1f, 0x01, 0x74, 0x00}, + {0x29, 0x01, 0x74, 0x00}, {0x38, 0x01, 0x74, 0x01} + }, + { + {0x02, 0x01, 0x20, 0x00}, {0x09, 0x01, 0x20, 0x00}, + {0x17, 0x01, 0x20, 0x00}, {0x28, 0x01, 0x20, 0x01}, + {0x02, 0x01, 0x25, 0x00}, {0x09, 0x01, 0x25, 0x00}, + {0x17, 0x01, 0x25, 0x00}, {0x28, 0x01, 0x25, 0x01}, + {0x02, 0x01, 0x2d, 0x00}, {0x09, 0x01, 0x2d, 0x00}, + {0x17, 0x01, 0x2d, 0x00}, {0x28, 0x01, 0x2d, 0x01}, + {0x02, 0x01, 0x2e, 0x00}, {0x09, 0x01, 0x2e, 0x00}, + {0x17, 0x01, 0x2e, 0x00}, {0x28, 0x01, 0x2e, 0x01} + }, + { + {0x03, 0x01, 0x20, 0x00}, {0x06, 0x01, 0x20, 0x00}, + {0x0a, 0x01, 0x20, 0x00}, {0x0f, 0x01, 0x20, 0x00}, + {0x18, 0x01, 0x20, 0x00}, {0x1f, 0x01, 0x20, 0x00}, + {0x29, 0x01, 0x20, 0x00}, {0x38, 0x01, 0x20, 0x01}, + {0x03, 0x01, 0x25, 0x00}, {0x06, 0x01, 0x25, 0x00}, + {0x0a, 0x01, 0x25, 0x00}, {0x0f, 0x01, 0x25, 0x00}, + {0x18, 0x01, 0x25, 0x00}, {0x1f, 0x01, 0x25, 0x00}, + {0x29, 0x01, 0x25, 0x00}, {0x38, 0x01, 0x25, 0x01} + }, + { + {0x03, 0x01, 0x2d, 0x00}, {0x06, 0x01, 0x2d, 0x00}, + {0x0a, 0x01, 0x2d, 0x00}, {0x0f, 0x01, 0x2d, 0x00}, + {0x18, 0x01, 0x2d, 0x00}, {0x1f, 0x01, 0x2d, 0x00}, + {0x29, 0x01, 0x2d, 0x00}, {0x38, 0x01, 0x2d, 0x01}, + {0x03, 0x01, 0x2e, 0x00}, {0x06, 0x01, 0x2e, 0x00}, + {0x0a, 0x01, 0x2e, 0x00}, {0x0f, 0x01, 0x2e, 0x00}, + {0x18, 0x01, 0x2e, 0x00}, {0x1f, 0x01, 0x2e, 0x00}, + {0x29, 0x01, 0x2e, 0x00}, {0x38, 0x01, 0x2e, 0x01} + }, + /* 15 */ + { + {0x01, 0x01, 0x2f, 0x00}, {0x16, 0x01, 0x2f, 0x01}, + {0x01, 0x01, 0x33, 0x00}, {0x16, 0x01, 0x33, 0x01}, + {0x01, 0x01, 0x34, 0x00}, {0x16, 0x01, 0x34, 0x01}, + {0x01, 0x01, 0x35, 0x00}, {0x16, 0x01, 0x35, 0x01}, + {0x01, 0x01, 0x36, 0x00}, {0x16, 0x01, 0x36, 0x01}, + {0x01, 0x01, 0x37, 0x00}, {0x16, 0x01, 0x37, 0x01}, + {0x01, 0x01, 0x38, 0x00}, {0x16, 0x01, 0x38, 0x01}, + {0x01, 0x01, 0x39, 0x00}, {0x16, 0x01, 0x39, 0x01} + }, + { + {0x02, 0x01, 0x2f, 0x00}, {0x09, 0x01, 0x2f, 0x00}, + {0x17, 0x01, 0x2f, 0x00}, {0x28, 0x01, 0x2f, 0x01}, + {0x02, 0x01, 0x33, 0x00}, {0x09, 0x01, 0x33, 0x00}, + {0x17, 0x01, 0x33, 0x00}, {0x28, 0x01, 0x33, 0x01}, + {0x02, 0x01, 0x34, 0x00}, {0x09, 0x01, 0x34, 0x00}, + {0x17, 0x01, 0x34, 0x00}, {0x28, 0x01, 0x34, 0x01}, + {0x02, 0x01, 0x35, 0x00}, {0x09, 0x01, 0x35, 0x00}, + {0x17, 0x01, 0x35, 0x00}, {0x28, 0x01, 0x35, 0x01} + }, + { + {0x03, 0x01, 0x2f, 0x00}, {0x06, 0x01, 0x2f, 0x00}, + {0x0a, 0x01, 0x2f, 0x00}, {0x0f, 0x01, 0x2f, 0x00}, + {0x18, 0x01, 0x2f, 0x00}, {0x1f, 0x01, 0x2f, 0x00}, + {0x29, 0x01, 0x2f, 0x00}, {0x38, 0x01, 0x2f, 0x01}, + {0x03, 0x01, 0x33, 0x00}, {0x06, 0x01, 0x33, 0x00}, + {0x0a, 0x01, 0x33, 0x00}, {0x0f, 0x01, 0x33, 0x00}, + {0x18, 0x01, 0x33, 0x00}, {0x1f, 0x01, 0x33, 0x00}, + {0x29, 0x01, 0x33, 0x00}, {0x38, 0x01, 0x33, 0x01} + }, + { + {0x03, 0x01, 0x34, 0x00}, {0x06, 0x01, 0x34, 0x00}, + {0x0a, 0x01, 0x34, 0x00}, {0x0f, 0x01, 0x34, 0x00}, + {0x18, 0x01, 0x34, 0x00}, {0x1f, 0x01, 0x34, 0x00}, + {0x29, 0x01, 0x34, 0x00}, {0x38, 0x01, 0x34, 0x01}, + {0x03, 0x01, 0x35, 0x00}, {0x06, 0x01, 0x35, 0x00}, + {0x0a, 0x01, 0x35, 0x00}, {0x0f, 0x01, 0x35, 0x00}, + {0x18, 0x01, 0x35, 0x00}, {0x1f, 0x01, 0x35, 0x00}, + {0x29, 0x01, 0x35, 0x00}, {0x38, 0x01, 0x35, 0x01} + }, + { + {0x02, 0x01, 0x36, 0x00}, {0x09, 0x01, 0x36, 0x00}, + {0x17, 0x01, 0x36, 0x00}, {0x28, 0x01, 0x36, 0x01}, + {0x02, 0x01, 0x37, 0x00}, {0x09, 0x01, 0x37, 0x00}, + {0x17, 0x01, 0x37, 0x00}, {0x28, 0x01, 0x37, 0x01}, + {0x02, 0x01, 0x38, 0x00}, {0x09, 0x01, 0x38, 0x00}, + {0x17, 0x01, 0x38, 0x00}, {0x28, 0x01, 0x38, 0x01}, + {0x02, 0x01, 0x39, 0x00}, {0x09, 0x01, 0x39, 0x00}, + {0x17, 0x01, 0x39, 0x00}, {0x28, 0x01, 0x39, 0x01} + }, + /* 20 */ + { + {0x03, 0x01, 0x36, 0x00}, {0x06, 0x01, 0x36, 0x00}, + {0x0a, 0x01, 0x36, 0x00}, {0x0f, 0x01, 0x36, 0x00}, + {0x18, 0x01, 0x36, 0x00}, {0x1f, 0x01, 0x36, 0x00}, + {0x29, 0x01, 0x36, 0x00}, {0x38, 0x01, 0x36, 0x01}, + {0x03, 0x01, 0x37, 0x00}, {0x06, 0x01, 0x37, 0x00}, + {0x0a, 0x01, 0x37, 0x00}, {0x0f, 0x01, 0x37, 0x00}, + {0x18, 0x01, 0x37, 0x00}, {0x1f, 0x01, 0x37, 0x00}, + {0x29, 0x01, 0x37, 0x00}, {0x38, 0x01, 0x37, 0x01} + }, + { + {0x03, 0x01, 0x38, 0x00}, {0x06, 0x01, 0x38, 0x00}, + {0x0a, 0x01, 0x38, 0x00}, {0x0f, 0x01, 0x38, 0x00}, + {0x18, 0x01, 0x38, 0x00}, {0x1f, 0x01, 0x38, 0x00}, + {0x29, 0x01, 0x38, 0x00}, {0x38, 0x01, 0x38, 0x01}, + {0x03, 0x01, 0x39, 0x00}, {0x06, 0x01, 0x39, 0x00}, + {0x0a, 0x01, 0x39, 0x00}, {0x0f, 0x01, 0x39, 0x00}, + {0x18, 0x01, 0x39, 0x00}, {0x1f, 0x01, 0x39, 0x00}, + {0x29, 0x01, 0x39, 0x00}, {0x38, 0x01, 0x39, 0x01} + }, + { + {0x1a, 0x00, 0x00, 0x00}, {0x1b, 0x00, 0x00, 0x00}, + {0x1d, 0x00, 0x00, 0x00}, {0x1e, 0x00, 0x00, 0x00}, + {0x21, 0x00, 0x00, 0x00}, {0x22, 0x00, 0x00, 0x00}, + {0x24, 0x00, 0x00, 0x00}, {0x25, 0x00, 0x00, 0x00}, + {0x2b, 0x00, 0x00, 0x00}, {0x2e, 0x00, 0x00, 0x00}, + {0x32, 0x00, 0x00, 0x00}, {0x35, 0x00, 0x00, 0x00}, + {0x3a, 0x00, 0x00, 0x00}, {0x3d, 0x00, 0x00, 0x00}, + {0x41, 0x00, 0x00, 0x00}, {0x44, 0x00, 0x00, 0x01} + }, + { + {0x00, 0x01, 0x3d, 0x01}, {0x00, 0x01, 0x41, 0x01}, + {0x00, 0x01, 0x5f, 0x01}, {0x00, 0x01, 0x62, 0x01}, + {0x00, 0x01, 0x64, 0x01}, {0x00, 0x01, 0x66, 0x01}, + {0x00, 0x01, 0x67, 0x01}, {0x00, 0x01, 0x68, 0x01}, + {0x00, 0x01, 0x6c, 0x01}, {0x00, 0x01, 0x6d, 0x01}, + {0x00, 0x01, 0x6e, 0x01}, {0x00, 0x01, 0x70, 0x01}, + {0x00, 0x01, 0x72, 0x01}, {0x00, 0x01, 0x75, 0x01}, + {0x26, 0x00, 0x00, 0x00}, {0x27, 0x00, 0x00, 0x00} + }, + { + {0x01, 0x01, 0x3d, 0x00}, {0x16, 0x01, 0x3d, 0x01}, + {0x01, 0x01, 0x41, 0x00}, {0x16, 0x01, 0x41, 0x01}, + {0x01, 0x01, 0x5f, 0x00}, {0x16, 0x01, 0x5f, 0x01}, + {0x01, 0x01, 0x62, 0x00}, {0x16, 0x01, 0x62, 0x01}, + {0x01, 0x01, 0x64, 0x00}, {0x16, 0x01, 0x64, 0x01}, + {0x01, 0x01, 0x66, 0x00}, {0x16, 0x01, 0x66, 0x01}, + {0x01, 0x01, 0x67, 0x00}, {0x16, 0x01, 0x67, 0x01}, + {0x01, 0x01, 0x68, 0x00}, {0x16, 0x01, 0x68, 0x01} + }, + /* 25 */ + { + {0x02, 0x01, 0x3d, 0x00}, {0x09, 0x01, 0x3d, 0x00}, + {0x17, 0x01, 0x3d, 0x00}, {0x28, 0x01, 0x3d, 0x01}, + {0x02, 0x01, 0x41, 0x00}, {0x09, 0x01, 0x41, 0x00}, + {0x17, 0x01, 0x41, 0x00}, {0x28, 0x01, 0x41, 0x01}, + {0x02, 0x01, 0x5f, 0x00}, {0x09, 0x01, 0x5f, 0x00}, + {0x17, 0x01, 0x5f, 0x00}, {0x28, 0x01, 0x5f, 0x01}, + {0x02, 0x01, 0x62, 0x00}, {0x09, 0x01, 0x62, 0x00}, + {0x17, 0x01, 0x62, 0x00}, {0x28, 0x01, 0x62, 0x01} + }, + { + {0x03, 0x01, 0x3d, 0x00}, {0x06, 0x01, 0x3d, 0x00}, + {0x0a, 0x01, 0x3d, 0x00}, {0x0f, 0x01, 0x3d, 0x00}, + {0x18, 0x01, 0x3d, 0x00}, {0x1f, 0x01, 0x3d, 0x00}, + {0x29, 0x01, 0x3d, 0x00}, {0x38, 0x01, 0x3d, 0x01}, + {0x03, 0x01, 0x41, 0x00}, {0x06, 0x01, 0x41, 0x00}, + {0x0a, 0x01, 0x41, 0x00}, {0x0f, 0x01, 0x41, 0x00}, + {0x18, 0x01, 0x41, 0x00}, {0x1f, 0x01, 0x41, 0x00}, + {0x29, 0x01, 0x41, 0x00}, {0x38, 0x01, 0x41, 0x01} + }, + { + {0x03, 0x01, 0x5f, 0x00}, {0x06, 0x01, 0x5f, 0x00}, + {0x0a, 0x01, 0x5f, 0x00}, {0x0f, 0x01, 0x5f, 0x00}, + {0x18, 0x01, 0x5f, 0x00}, {0x1f, 0x01, 0x5f, 0x00}, + {0x29, 0x01, 0x5f, 0x00}, {0x38, 0x01, 0x5f, 0x01}, + {0x03, 0x01, 0x62, 0x00}, {0x06, 0x01, 0x62, 0x00}, + {0x0a, 0x01, 0x62, 0x00}, {0x0f, 0x01, 0x62, 0x00}, + {0x18, 0x01, 0x62, 0x00}, {0x1f, 0x01, 0x62, 0x00}, + {0x29, 0x01, 0x62, 0x00}, {0x38, 0x01, 0x62, 0x01} + }, + { + {0x02, 0x01, 0x64, 0x00}, {0x09, 0x01, 0x64, 0x00}, + {0x17, 0x01, 0x64, 0x00}, {0x28, 0x01, 0x64, 0x01}, + {0x02, 0x01, 0x66, 0x00}, {0x09, 0x01, 0x66, 0x00}, + {0x17, 0x01, 0x66, 0x00}, {0x28, 0x01, 0x66, 0x01}, + {0x02, 0x01, 0x67, 0x00}, {0x09, 0x01, 0x67, 0x00}, + {0x17, 0x01, 0x67, 0x00}, {0x28, 0x01, 0x67, 0x01}, + {0x02, 0x01, 0x68, 0x00}, {0x09, 0x01, 0x68, 0x00}, + {0x17, 0x01, 0x68, 0x00}, {0x28, 0x01, 0x68, 0x01} + }, + { + {0x03, 0x01, 0x64, 0x00}, {0x06, 0x01, 0x64, 0x00}, + {0x0a, 0x01, 0x64, 0x00}, {0x0f, 0x01, 0x64, 0x00}, + {0x18, 0x01, 0x64, 0x00}, {0x1f, 0x01, 0x64, 0x00}, + {0x29, 0x01, 0x64, 0x00}, {0x38, 0x01, 0x64, 0x01}, + {0x03, 0x01, 0x66, 0x00}, {0x06, 0x01, 0x66, 0x00}, + {0x0a, 0x01, 0x66, 0x00}, {0x0f, 0x01, 0x66, 0x00}, + {0x18, 0x01, 0x66, 0x00}, {0x1f, 0x01, 0x66, 0x00}, + {0x29, 0x01, 0x66, 0x00}, {0x38, 0x01, 0x66, 0x01} + }, + /* 30 */ + { + {0x03, 0x01, 0x67, 0x00}, {0x06, 0x01, 0x67, 0x00}, + {0x0a, 0x01, 0x67, 0x00}, {0x0f, 0x01, 0x67, 0x00}, + {0x18, 0x01, 0x67, 0x00}, {0x1f, 0x01, 0x67, 0x00}, + {0x29, 0x01, 0x67, 0x00}, {0x38, 0x01, 0x67, 0x01}, + {0x03, 0x01, 0x68, 0x00}, {0x06, 0x01, 0x68, 0x00}, + {0x0a, 0x01, 0x68, 0x00}, {0x0f, 0x01, 0x68, 0x00}, + {0x18, 0x01, 0x68, 0x00}, {0x1f, 0x01, 0x68, 0x00}, + {0x29, 0x01, 0x68, 0x00}, {0x38, 0x01, 0x68, 0x01} + }, + { + {0x01, 0x01, 0x6c, 0x00}, {0x16, 0x01, 0x6c, 0x01}, + {0x01, 0x01, 0x6d, 0x00}, {0x16, 0x01, 0x6d, 0x01}, + {0x01, 0x01, 0x6e, 0x00}, {0x16, 0x01, 0x6e, 0x01}, + {0x01, 0x01, 0x70, 0x00}, {0x16, 0x01, 0x70, 0x01}, + {0x01, 0x01, 0x72, 0x00}, {0x16, 0x01, 0x72, 0x01}, + {0x01, 0x01, 0x75, 0x00}, {0x16, 0x01, 0x75, 0x01}, + {0x00, 0x01, 0x3a, 0x01}, {0x00, 0x01, 0x42, 0x01}, + {0x00, 0x01, 0x43, 0x01}, {0x00, 0x01, 0x44, 0x01} + }, + { + {0x02, 0x01, 0x6c, 0x00}, {0x09, 0x01, 0x6c, 0x00}, + {0x17, 0x01, 0x6c, 0x00}, {0x28, 0x01, 0x6c, 0x01}, + {0x02, 0x01, 0x6d, 0x00}, {0x09, 0x01, 0x6d, 0x00}, + {0x17, 0x01, 0x6d, 0x00}, {0x28, 0x01, 0x6d, 0x01}, + {0x02, 0x01, 0x6e, 0x00}, {0x09, 0x01, 0x6e, 0x00}, + {0x17, 0x01, 0x6e, 0x00}, {0x28, 0x01, 0x6e, 0x01}, + {0x02, 0x01, 0x70, 0x00}, {0x09, 0x01, 0x70, 0x00}, + {0x17, 0x01, 0x70, 0x00}, {0x28, 0x01, 0x70, 0x01} + }, + { + {0x03, 0x01, 0x6c, 0x00}, {0x06, 0x01, 0x6c, 0x00}, + {0x0a, 0x01, 0x6c, 0x00}, {0x0f, 0x01, 0x6c, 0x00}, + {0x18, 0x01, 0x6c, 0x00}, {0x1f, 0x01, 0x6c, 0x00}, + {0x29, 0x01, 0x6c, 0x00}, {0x38, 0x01, 0x6c, 0x01}, + {0x03, 0x01, 0x6d, 0x00}, {0x06, 0x01, 0x6d, 0x00}, + {0x0a, 0x01, 0x6d, 0x00}, {0x0f, 0x01, 0x6d, 0x00}, + {0x18, 0x01, 0x6d, 0x00}, {0x1f, 0x01, 0x6d, 0x00}, + {0x29, 0x01, 0x6d, 0x00}, {0x38, 0x01, 0x6d, 0x01} + }, + { + {0x03, 0x01, 0x6e, 0x00}, {0x06, 0x01, 0x6e, 0x00}, + {0x0a, 0x01, 0x6e, 0x00}, {0x0f, 0x01, 0x6e, 0x00}, + {0x18, 0x01, 0x6e, 0x00}, {0x1f, 0x01, 0x6e, 0x00}, + {0x29, 0x01, 0x6e, 0x00}, {0x38, 0x01, 0x6e, 0x01}, + {0x03, 0x01, 0x70, 0x00}, {0x06, 0x01, 0x70, 0x00}, + {0x0a, 0x01, 0x70, 0x00}, {0x0f, 0x01, 0x70, 0x00}, + {0x18, 0x01, 0x70, 0x00}, {0x1f, 0x01, 0x70, 0x00}, + {0x29, 0x01, 0x70, 0x00}, {0x38, 0x01, 0x70, 0x01} + }, + /* 35 */ + { + {0x02, 0x01, 0x72, 0x00}, {0x09, 0x01, 0x72, 0x00}, + {0x17, 0x01, 0x72, 0x00}, {0x28, 0x01, 0x72, 0x01}, + {0x02, 0x01, 0x75, 0x00}, {0x09, 0x01, 0x75, 0x00}, + {0x17, 0x01, 0x75, 0x00}, {0x28, 0x01, 0x75, 0x01}, + {0x01, 0x01, 0x3a, 0x00}, {0x16, 0x01, 0x3a, 0x01}, + {0x01, 0x01, 0x42, 0x00}, {0x16, 0x01, 0x42, 0x01}, + {0x01, 0x01, 0x43, 0x00}, {0x16, 0x01, 0x43, 0x01}, + {0x01, 0x01, 0x44, 0x00}, {0x16, 0x01, 0x44, 0x01} + }, + { + {0x03, 0x01, 0x72, 0x00}, {0x06, 0x01, 0x72, 0x00}, + {0x0a, 0x01, 0x72, 0x00}, {0x0f, 0x01, 0x72, 0x00}, + {0x18, 0x01, 0x72, 0x00}, {0x1f, 0x01, 0x72, 0x00}, + {0x29, 0x01, 0x72, 0x00}, {0x38, 0x01, 0x72, 0x01}, + {0x03, 0x01, 0x75, 0x00}, {0x06, 0x01, 0x75, 0x00}, + {0x0a, 0x01, 0x75, 0x00}, {0x0f, 0x01, 0x75, 0x00}, + {0x18, 0x01, 0x75, 0x00}, {0x1f, 0x01, 0x75, 0x00}, + {0x29, 0x01, 0x75, 0x00}, {0x38, 0x01, 0x75, 0x01} + }, + { + {0x02, 0x01, 0x3a, 0x00}, {0x09, 0x01, 0x3a, 0x00}, + {0x17, 0x01, 0x3a, 0x00}, {0x28, 0x01, 0x3a, 0x01}, + {0x02, 0x01, 0x42, 0x00}, {0x09, 0x01, 0x42, 0x00}, + {0x17, 0x01, 0x42, 0x00}, {0x28, 0x01, 0x42, 0x01}, + {0x02, 0x01, 0x43, 0x00}, {0x09, 0x01, 0x43, 0x00}, + {0x17, 0x01, 0x43, 0x00}, {0x28, 0x01, 0x43, 0x01}, + {0x02, 0x01, 0x44, 0x00}, {0x09, 0x01, 0x44, 0x00}, + {0x17, 0x01, 0x44, 0x00}, {0x28, 0x01, 0x44, 0x01} + }, + { + {0x03, 0x01, 0x3a, 0x00}, {0x06, 0x01, 0x3a, 0x00}, + {0x0a, 0x01, 0x3a, 0x00}, {0x0f, 0x01, 0x3a, 0x00}, + {0x18, 0x01, 0x3a, 0x00}, {0x1f, 0x01, 0x3a, 0x00}, + {0x29, 0x01, 0x3a, 0x00}, {0x38, 0x01, 0x3a, 0x01}, + {0x03, 0x01, 0x42, 0x00}, {0x06, 0x01, 0x42, 0x00}, + {0x0a, 0x01, 0x42, 0x00}, {0x0f, 0x01, 0x42, 0x00}, + {0x18, 0x01, 0x42, 0x00}, {0x1f, 0x01, 0x42, 0x00}, + {0x29, 0x01, 0x42, 0x00}, {0x38, 0x01, 0x42, 0x01} + }, + { + {0x03, 0x01, 0x43, 0x00}, {0x06, 0x01, 0x43, 0x00}, + {0x0a, 0x01, 0x43, 0x00}, {0x0f, 0x01, 0x43, 0x00}, + {0x18, 0x01, 0x43, 0x00}, {0x1f, 0x01, 0x43, 0x00}, + {0x29, 0x01, 0x43, 0x00}, {0x38, 0x01, 0x43, 0x01}, + {0x03, 0x01, 0x44, 0x00}, {0x06, 0x01, 0x44, 0x00}, + {0x0a, 0x01, 0x44, 0x00}, {0x0f, 0x01, 0x44, 0x00}, + {0x18, 0x01, 0x44, 0x00}, {0x1f, 0x01, 0x44, 0x00}, + {0x29, 0x01, 0x44, 0x00}, {0x38, 0x01, 0x44, 0x01} + }, + /* 40 */ + { + {0x2c, 0x00, 0x00, 0x00}, {0x2d, 0x00, 0x00, 0x00}, + {0x2f, 0x00, 0x00, 0x00}, {0x30, 0x00, 0x00, 0x00}, + {0x33, 0x00, 0x00, 0x00}, {0x34, 0x00, 0x00, 0x00}, + {0x36, 0x00, 0x00, 0x00}, {0x37, 0x00, 0x00, 0x00}, + {0x3b, 0x00, 0x00, 0x00}, {0x3c, 0x00, 0x00, 0x00}, + {0x3e, 0x00, 0x00, 0x00}, {0x3f, 0x00, 0x00, 0x00}, + {0x42, 0x00, 0x00, 0x00}, {0x43, 0x00, 0x00, 0x00}, + {0x45, 0x00, 0x00, 0x00}, {0x48, 0x00, 0x00, 0x01} + }, + { + {0x00, 0x01, 0x45, 0x01}, {0x00, 0x01, 0x46, 0x01}, + {0x00, 0x01, 0x47, 0x01}, {0x00, 0x01, 0x48, 0x01}, + {0x00, 0x01, 0x49, 0x01}, {0x00, 0x01, 0x4a, 0x01}, + {0x00, 0x01, 0x4b, 0x01}, {0x00, 0x01, 0x4c, 0x01}, + {0x00, 0x01, 0x4d, 0x01}, {0x00, 0x01, 0x4e, 0x01}, + {0x00, 0x01, 0x4f, 0x01}, {0x00, 0x01, 0x50, 0x01}, + {0x00, 0x01, 0x51, 0x01}, {0x00, 0x01, 0x52, 0x01}, + {0x00, 0x01, 0x53, 0x01}, {0x00, 0x01, 0x54, 0x01} + }, + { + {0x01, 0x01, 0x45, 0x00}, {0x16, 0x01, 0x45, 0x01}, + {0x01, 0x01, 0x46, 0x00}, {0x16, 0x01, 0x46, 0x01}, + {0x01, 0x01, 0x47, 0x00}, {0x16, 0x01, 0x47, 0x01}, + {0x01, 0x01, 0x48, 0x00}, {0x16, 0x01, 0x48, 0x01}, + {0x01, 0x01, 0x49, 0x00}, {0x16, 0x01, 0x49, 0x01}, + {0x01, 0x01, 0x4a, 0x00}, {0x16, 0x01, 0x4a, 0x01}, + {0x01, 0x01, 0x4b, 0x00}, {0x16, 0x01, 0x4b, 0x01}, + {0x01, 0x01, 0x4c, 0x00}, {0x16, 0x01, 0x4c, 0x01} + }, + { + {0x02, 0x01, 0x45, 0x00}, {0x09, 0x01, 0x45, 0x00}, + {0x17, 0x01, 0x45, 0x00}, {0x28, 0x01, 0x45, 0x01}, + {0x02, 0x01, 0x46, 0x00}, {0x09, 0x01, 0x46, 0x00}, + {0x17, 0x01, 0x46, 0x00}, {0x28, 0x01, 0x46, 0x01}, + {0x02, 0x01, 0x47, 0x00}, {0x09, 0x01, 0x47, 0x00}, + {0x17, 0x01, 0x47, 0x00}, {0x28, 0x01, 0x47, 0x01}, + {0x02, 0x01, 0x48, 0x00}, {0x09, 0x01, 0x48, 0x00}, + {0x17, 0x01, 0x48, 0x00}, {0x28, 0x01, 0x48, 0x01} + }, + { + {0x03, 0x01, 0x45, 0x00}, {0x06, 0x01, 0x45, 0x00}, + {0x0a, 0x01, 0x45, 0x00}, {0x0f, 0x01, 0x45, 0x00}, + {0x18, 0x01, 0x45, 0x00}, {0x1f, 0x01, 0x45, 0x00}, + {0x29, 0x01, 0x45, 0x00}, {0x38, 0x01, 0x45, 0x01}, + {0x03, 0x01, 0x46, 0x00}, {0x06, 0x01, 0x46, 0x00}, + {0x0a, 0x01, 0x46, 0x00}, {0x0f, 0x01, 0x46, 0x00}, + {0x18, 0x01, 0x46, 0x00}, {0x1f, 0x01, 0x46, 0x00}, + {0x29, 0x01, 0x46, 0x00}, {0x38, 0x01, 0x46, 0x01} + }, + /* 45 */ + { + {0x03, 0x01, 0x47, 0x00}, {0x06, 0x01, 0x47, 0x00}, + {0x0a, 0x01, 0x47, 0x00}, {0x0f, 0x01, 0x47, 0x00}, + {0x18, 0x01, 0x47, 0x00}, {0x1f, 0x01, 0x47, 0x00}, + {0x29, 0x01, 0x47, 0x00}, {0x38, 0x01, 0x47, 0x01}, + {0x03, 0x01, 0x48, 0x00}, {0x06, 0x01, 0x48, 0x00}, + {0x0a, 0x01, 0x48, 0x00}, {0x0f, 0x01, 0x48, 0x00}, + {0x18, 0x01, 0x48, 0x00}, {0x1f, 0x01, 0x48, 0x00}, + {0x29, 0x01, 0x48, 0x00}, {0x38, 0x01, 0x48, 0x01} + }, + { + {0x02, 0x01, 0x49, 0x00}, {0x09, 0x01, 0x49, 0x00}, + {0x17, 0x01, 0x49, 0x00}, {0x28, 0x01, 0x49, 0x01}, + {0x02, 0x01, 0x4a, 0x00}, {0x09, 0x01, 0x4a, 0x00}, + {0x17, 0x01, 0x4a, 0x00}, {0x28, 0x01, 0x4a, 0x01}, + {0x02, 0x01, 0x4b, 0x00}, {0x09, 0x01, 0x4b, 0x00}, + {0x17, 0x01, 0x4b, 0x00}, {0x28, 0x01, 0x4b, 0x01}, + {0x02, 0x01, 0x4c, 0x00}, {0x09, 0x01, 0x4c, 0x00}, + {0x17, 0x01, 0x4c, 0x00}, {0x28, 0x01, 0x4c, 0x01} + }, + { + {0x03, 0x01, 0x49, 0x00}, {0x06, 0x01, 0x49, 0x00}, + {0x0a, 0x01, 0x49, 0x00}, {0x0f, 0x01, 0x49, 0x00}, + {0x18, 0x01, 0x49, 0x00}, {0x1f, 0x01, 0x49, 0x00}, + {0x29, 0x01, 0x49, 0x00}, {0x38, 0x01, 0x49, 0x01}, + {0x03, 0x01, 0x4a, 0x00}, {0x06, 0x01, 0x4a, 0x00}, + {0x0a, 0x01, 0x4a, 0x00}, {0x0f, 0x01, 0x4a, 0x00}, + {0x18, 0x01, 0x4a, 0x00}, {0x1f, 0x01, 0x4a, 0x00}, + {0x29, 0x01, 0x4a, 0x00}, {0x38, 0x01, 0x4a, 0x01} + }, + { + {0x03, 0x01, 0x4b, 0x00}, {0x06, 0x01, 0x4b, 0x00}, + {0x0a, 0x01, 0x4b, 0x00}, {0x0f, 0x01, 0x4b, 0x00}, + {0x18, 0x01, 0x4b, 0x00}, {0x1f, 0x01, 0x4b, 0x00}, + {0x29, 0x01, 0x4b, 0x00}, {0x38, 0x01, 0x4b, 0x01}, + {0x03, 0x01, 0x4c, 0x00}, {0x06, 0x01, 0x4c, 0x00}, + {0x0a, 0x01, 0x4c, 0x00}, {0x0f, 0x01, 0x4c, 0x00}, + {0x18, 0x01, 0x4c, 0x00}, {0x1f, 0x01, 0x4c, 0x00}, + {0x29, 0x01, 0x4c, 0x00}, {0x38, 0x01, 0x4c, 0x01} + }, + { + {0x01, 0x01, 0x4d, 0x00}, {0x16, 0x01, 0x4d, 0x01}, + {0x01, 0x01, 0x4e, 0x00}, {0x16, 0x01, 0x4e, 0x01}, + {0x01, 0x01, 0x4f, 0x00}, {0x16, 0x01, 0x4f, 0x01}, + {0x01, 0x01, 0x50, 0x00}, {0x16, 0x01, 0x50, 0x01}, + {0x01, 0x01, 0x51, 0x00}, {0x16, 0x01, 0x51, 0x01}, + {0x01, 0x01, 0x52, 0x00}, {0x16, 0x01, 0x52, 0x01}, + {0x01, 0x01, 0x53, 0x00}, {0x16, 0x01, 0x53, 0x01}, + {0x01, 0x01, 0x54, 0x00}, {0x16, 0x01, 0x54, 0x01} + }, + /* 50 */ + { + {0x02, 0x01, 0x4d, 0x00}, {0x09, 0x01, 0x4d, 0x00}, + {0x17, 0x01, 0x4d, 0x00}, {0x28, 0x01, 0x4d, 0x01}, + {0x02, 0x01, 0x4e, 0x00}, {0x09, 0x01, 0x4e, 0x00}, + {0x17, 0x01, 0x4e, 0x00}, {0x28, 0x01, 0x4e, 0x01}, + {0x02, 0x01, 0x4f, 0x00}, {0x09, 0x01, 0x4f, 0x00}, + {0x17, 0x01, 0x4f, 0x00}, {0x28, 0x01, 0x4f, 0x01}, + {0x02, 0x01, 0x50, 0x00}, {0x09, 0x01, 0x50, 0x00}, + {0x17, 0x01, 0x50, 0x00}, {0x28, 0x01, 0x50, 0x01} + }, + { + {0x03, 0x01, 0x4d, 0x00}, {0x06, 0x01, 0x4d, 0x00}, + {0x0a, 0x01, 0x4d, 0x00}, {0x0f, 0x01, 0x4d, 0x00}, + {0x18, 0x01, 0x4d, 0x00}, {0x1f, 0x01, 0x4d, 0x00}, + {0x29, 0x01, 0x4d, 0x00}, {0x38, 0x01, 0x4d, 0x01}, + {0x03, 0x01, 0x4e, 0x00}, {0x06, 0x01, 0x4e, 0x00}, + {0x0a, 0x01, 0x4e, 0x00}, {0x0f, 0x01, 0x4e, 0x00}, + {0x18, 0x01, 0x4e, 0x00}, {0x1f, 0x01, 0x4e, 0x00}, + {0x29, 0x01, 0x4e, 0x00}, {0x38, 0x01, 0x4e, 0x01} + }, + { + {0x03, 0x01, 0x4f, 0x00}, {0x06, 0x01, 0x4f, 0x00}, + {0x0a, 0x01, 0x4f, 0x00}, {0x0f, 0x01, 0x4f, 0x00}, + {0x18, 0x01, 0x4f, 0x00}, {0x1f, 0x01, 0x4f, 0x00}, + {0x29, 0x01, 0x4f, 0x00}, {0x38, 0x01, 0x4f, 0x01}, + {0x03, 0x01, 0x50, 0x00}, {0x06, 0x01, 0x50, 0x00}, + {0x0a, 0x01, 0x50, 0x00}, {0x0f, 0x01, 0x50, 0x00}, + {0x18, 0x01, 0x50, 0x00}, {0x1f, 0x01, 0x50, 0x00}, + {0x29, 0x01, 0x50, 0x00}, {0x38, 0x01, 0x50, 0x01} + }, + { + {0x02, 0x01, 0x51, 0x00}, {0x09, 0x01, 0x51, 0x00}, + {0x17, 0x01, 0x51, 0x00}, {0x28, 0x01, 0x51, 0x01}, + {0x02, 0x01, 0x52, 0x00}, {0x09, 0x01, 0x52, 0x00}, + {0x17, 0x01, 0x52, 0x00}, {0x28, 0x01, 0x52, 0x01}, + {0x02, 0x01, 0x53, 0x00}, {0x09, 0x01, 0x53, 0x00}, + {0x17, 0x01, 0x53, 0x00}, {0x28, 0x01, 0x53, 0x01}, + {0x02, 0x01, 0x54, 0x00}, {0x09, 0x01, 0x54, 0x00}, + {0x17, 0x01, 0x54, 0x00}, {0x28, 0x01, 0x54, 0x01} + }, + { + {0x03, 0x01, 0x51, 0x00}, {0x06, 0x01, 0x51, 0x00}, + {0x0a, 0x01, 0x51, 0x00}, {0x0f, 0x01, 0x51, 0x00}, + {0x18, 0x01, 0x51, 0x00}, {0x1f, 0x01, 0x51, 0x00}, + {0x29, 0x01, 0x51, 0x00}, {0x38, 0x01, 0x51, 0x01}, + {0x03, 0x01, 0x52, 0x00}, {0x06, 0x01, 0x52, 0x00}, + {0x0a, 0x01, 0x52, 0x00}, {0x0f, 0x01, 0x52, 0x00}, + {0x18, 0x01, 0x52, 0x00}, {0x1f, 0x01, 0x52, 0x00}, + {0x29, 0x01, 0x52, 0x00}, {0x38, 0x01, 0x52, 0x01} + }, + /* 55 */ + { + {0x03, 0x01, 0x53, 0x00}, {0x06, 0x01, 0x53, 0x00}, + {0x0a, 0x01, 0x53, 0x00}, {0x0f, 0x01, 0x53, 0x00}, + {0x18, 0x01, 0x53, 0x00}, {0x1f, 0x01, 0x53, 0x00}, + {0x29, 0x01, 0x53, 0x00}, {0x38, 0x01, 0x53, 0x01}, + {0x03, 0x01, 0x54, 0x00}, {0x06, 0x01, 0x54, 0x00}, + {0x0a, 0x01, 0x54, 0x00}, {0x0f, 0x01, 0x54, 0x00}, + {0x18, 0x01, 0x54, 0x00}, {0x1f, 0x01, 0x54, 0x00}, + {0x29, 0x01, 0x54, 0x00}, {0x38, 0x01, 0x54, 0x01} + }, + { + {0x00, 0x01, 0x55, 0x01}, {0x00, 0x01, 0x56, 0x01}, + {0x00, 0x01, 0x57, 0x01}, {0x00, 0x01, 0x59, 0x01}, + {0x00, 0x01, 0x6a, 0x01}, {0x00, 0x01, 0x6b, 0x01}, + {0x00, 0x01, 0x71, 0x01}, {0x00, 0x01, 0x76, 0x01}, + {0x00, 0x01, 0x77, 0x01}, {0x00, 0x01, 0x78, 0x01}, + {0x00, 0x01, 0x79, 0x01}, {0x00, 0x01, 0x7a, 0x01}, + {0x46, 0x00, 0x00, 0x00}, {0x47, 0x00, 0x00, 0x00}, + {0x49, 0x00, 0x00, 0x00}, {0x4a, 0x00, 0x00, 0x01} + }, + { + {0x01, 0x01, 0x55, 0x00}, {0x16, 0x01, 0x55, 0x01}, + {0x01, 0x01, 0x56, 0x00}, {0x16, 0x01, 0x56, 0x01}, + {0x01, 0x01, 0x57, 0x00}, {0x16, 0x01, 0x57, 0x01}, + {0x01, 0x01, 0x59, 0x00}, {0x16, 0x01, 0x59, 0x01}, + {0x01, 0x01, 0x6a, 0x00}, {0x16, 0x01, 0x6a, 0x01}, + {0x01, 0x01, 0x6b, 0x00}, {0x16, 0x01, 0x6b, 0x01}, + {0x01, 0x01, 0x71, 0x00}, {0x16, 0x01, 0x71, 0x01}, + {0x01, 0x01, 0x76, 0x00}, {0x16, 0x01, 0x76, 0x01} + }, + { + {0x02, 0x01, 0x55, 0x00}, {0x09, 0x01, 0x55, 0x00}, + {0x17, 0x01, 0x55, 0x00}, {0x28, 0x01, 0x55, 0x01}, + {0x02, 0x01, 0x56, 0x00}, {0x09, 0x01, 0x56, 0x00}, + {0x17, 0x01, 0x56, 0x00}, {0x28, 0x01, 0x56, 0x01}, + {0x02, 0x01, 0x57, 0x00}, {0x09, 0x01, 0x57, 0x00}, + {0x17, 0x01, 0x57, 0x00}, {0x28, 0x01, 0x57, 0x01}, + {0x02, 0x01, 0x59, 0x00}, {0x09, 0x01, 0x59, 0x00}, + {0x17, 0x01, 0x59, 0x00}, {0x28, 0x01, 0x59, 0x01} + }, + { + {0x03, 0x01, 0x55, 0x00}, {0x06, 0x01, 0x55, 0x00}, + {0x0a, 0x01, 0x55, 0x00}, {0x0f, 0x01, 0x55, 0x00}, + {0x18, 0x01, 0x55, 0x00}, {0x1f, 0x01, 0x55, 0x00}, + {0x29, 0x01, 0x55, 0x00}, {0x38, 0x01, 0x55, 0x01}, + {0x03, 0x01, 0x56, 0x00}, {0x06, 0x01, 0x56, 0x00}, + {0x0a, 0x01, 0x56, 0x00}, {0x0f, 0x01, 0x56, 0x00}, + {0x18, 0x01, 0x56, 0x00}, {0x1f, 0x01, 0x56, 0x00}, + {0x29, 0x01, 0x56, 0x00}, {0x38, 0x01, 0x56, 0x01} + }, + /* 60 */ + { + {0x03, 0x01, 0x57, 0x00}, {0x06, 0x01, 0x57, 0x00}, + {0x0a, 0x01, 0x57, 0x00}, {0x0f, 0x01, 0x57, 0x00}, + {0x18, 0x01, 0x57, 0x00}, {0x1f, 0x01, 0x57, 0x00}, + {0x29, 0x01, 0x57, 0x00}, {0x38, 0x01, 0x57, 0x01}, + {0x03, 0x01, 0x59, 0x00}, {0x06, 0x01, 0x59, 0x00}, + {0x0a, 0x01, 0x59, 0x00}, {0x0f, 0x01, 0x59, 0x00}, + {0x18, 0x01, 0x59, 0x00}, {0x1f, 0x01, 0x59, 0x00}, + {0x29, 0x01, 0x59, 0x00}, {0x38, 0x01, 0x59, 0x01} + }, + { + {0x02, 0x01, 0x6a, 0x00}, {0x09, 0x01, 0x6a, 0x00}, + {0x17, 0x01, 0x6a, 0x00}, {0x28, 0x01, 0x6a, 0x01}, + {0x02, 0x01, 0x6b, 0x00}, {0x09, 0x01, 0x6b, 0x00}, + {0x17, 0x01, 0x6b, 0x00}, {0x28, 0x01, 0x6b, 0x01}, + {0x02, 0x01, 0x71, 0x00}, {0x09, 0x01, 0x71, 0x00}, + {0x17, 0x01, 0x71, 0x00}, {0x28, 0x01, 0x71, 0x01}, + {0x02, 0x01, 0x76, 0x00}, {0x09, 0x01, 0x76, 0x00}, + {0x17, 0x01, 0x76, 0x00}, {0x28, 0x01, 0x76, 0x01} + }, + { + {0x03, 0x01, 0x6a, 0x00}, {0x06, 0x01, 0x6a, 0x00}, + {0x0a, 0x01, 0x6a, 0x00}, {0x0f, 0x01, 0x6a, 0x00}, + {0x18, 0x01, 0x6a, 0x00}, {0x1f, 0x01, 0x6a, 0x00}, + {0x29, 0x01, 0x6a, 0x00}, {0x38, 0x01, 0x6a, 0x01}, + {0x03, 0x01, 0x6b, 0x00}, {0x06, 0x01, 0x6b, 0x00}, + {0x0a, 0x01, 0x6b, 0x00}, {0x0f, 0x01, 0x6b, 0x00}, + {0x18, 0x01, 0x6b, 0x00}, {0x1f, 0x01, 0x6b, 0x00}, + {0x29, 0x01, 0x6b, 0x00}, {0x38, 0x01, 0x6b, 0x01} + }, + { + {0x03, 0x01, 0x71, 0x00}, {0x06, 0x01, 0x71, 0x00}, + {0x0a, 0x01, 0x71, 0x00}, {0x0f, 0x01, 0x71, 0x00}, + {0x18, 0x01, 0x71, 0x00}, {0x1f, 0x01, 0x71, 0x00}, + {0x29, 0x01, 0x71, 0x00}, {0x38, 0x01, 0x71, 0x01}, + {0x03, 0x01, 0x76, 0x00}, {0x06, 0x01, 0x76, 0x00}, + {0x0a, 0x01, 0x76, 0x00}, {0x0f, 0x01, 0x76, 0x00}, + {0x18, 0x01, 0x76, 0x00}, {0x1f, 0x01, 0x76, 0x00}, + {0x29, 0x01, 0x76, 0x00}, {0x38, 0x01, 0x76, 0x01} + }, + { + {0x01, 0x01, 0x77, 0x00}, {0x16, 0x01, 0x77, 0x01}, + {0x01, 0x01, 0x78, 0x00}, {0x16, 0x01, 0x78, 0x01}, + {0x01, 0x01, 0x79, 0x00}, {0x16, 0x01, 0x79, 0x01}, + {0x01, 0x01, 0x7a, 0x00}, {0x16, 0x01, 0x7a, 0x01}, + {0x00, 0x01, 0x26, 0x01}, {0x00, 0x01, 0x2a, 0x01}, + {0x00, 0x01, 0x2c, 0x01}, {0x00, 0x01, 0x3b, 0x01}, + {0x00, 0x01, 0x58, 0x01}, {0x00, 0x01, 0x5a, 0x01}, + {0x4b, 0x00, 0x00, 0x00}, {0x4e, 0x00, 0x00, 0x01} + }, + /* 65 */ + { + {0x02, 0x01, 0x77, 0x00}, {0x09, 0x01, 0x77, 0x00}, + {0x17, 0x01, 0x77, 0x00}, {0x28, 0x01, 0x77, 0x01}, + {0x02, 0x01, 0x78, 0x00}, {0x09, 0x01, 0x78, 0x00}, + {0x17, 0x01, 0x78, 0x00}, {0x28, 0x01, 0x78, 0x01}, + {0x02, 0x01, 0x79, 0x00}, {0x09, 0x01, 0x79, 0x00}, + {0x17, 0x01, 0x79, 0x00}, {0x28, 0x01, 0x79, 0x01}, + {0x02, 0x01, 0x7a, 0x00}, {0x09, 0x01, 0x7a, 0x00}, + {0x17, 0x01, 0x7a, 0x00}, {0x28, 0x01, 0x7a, 0x01} + }, + { + {0x03, 0x01, 0x77, 0x00}, {0x06, 0x01, 0x77, 0x00}, + {0x0a, 0x01, 0x77, 0x00}, {0x0f, 0x01, 0x77, 0x00}, + {0x18, 0x01, 0x77, 0x00}, {0x1f, 0x01, 0x77, 0x00}, + {0x29, 0x01, 0x77, 0x00}, {0x38, 0x01, 0x77, 0x01}, + {0x03, 0x01, 0x78, 0x00}, {0x06, 0x01, 0x78, 0x00}, + {0x0a, 0x01, 0x78, 0x00}, {0x0f, 0x01, 0x78, 0x00}, + {0x18, 0x01, 0x78, 0x00}, {0x1f, 0x01, 0x78, 0x00}, + {0x29, 0x01, 0x78, 0x00}, {0x38, 0x01, 0x78, 0x01} + }, + { + {0x03, 0x01, 0x79, 0x00}, {0x06, 0x01, 0x79, 0x00}, + {0x0a, 0x01, 0x79, 0x00}, {0x0f, 0x01, 0x79, 0x00}, + {0x18, 0x01, 0x79, 0x00}, {0x1f, 0x01, 0x79, 0x00}, + {0x29, 0x01, 0x79, 0x00}, {0x38, 0x01, 0x79, 0x01}, + {0x03, 0x01, 0x7a, 0x00}, {0x06, 0x01, 0x7a, 0x00}, + {0x0a, 0x01, 0x7a, 0x00}, {0x0f, 0x01, 0x7a, 0x00}, + {0x18, 0x01, 0x7a, 0x00}, {0x1f, 0x01, 0x7a, 0x00}, + {0x29, 0x01, 0x7a, 0x00}, {0x38, 0x01, 0x7a, 0x01} + }, + { + {0x01, 0x01, 0x26, 0x00}, {0x16, 0x01, 0x26, 0x01}, + {0x01, 0x01, 0x2a, 0x00}, {0x16, 0x01, 0x2a, 0x01}, + {0x01, 0x01, 0x2c, 0x00}, {0x16, 0x01, 0x2c, 0x01}, + {0x01, 0x01, 0x3b, 0x00}, {0x16, 0x01, 0x3b, 0x01}, + {0x01, 0x01, 0x58, 0x00}, {0x16, 0x01, 0x58, 0x01}, + {0x01, 0x01, 0x5a, 0x00}, {0x16, 0x01, 0x5a, 0x01}, + {0x4c, 0x00, 0x00, 0x00}, {0x4d, 0x00, 0x00, 0x00}, + {0x4f, 0x00, 0x00, 0x00}, {0x51, 0x00, 0x00, 0x01} + }, + { + {0x02, 0x01, 0x26, 0x00}, {0x09, 0x01, 0x26, 0x00}, + {0x17, 0x01, 0x26, 0x00}, {0x28, 0x01, 0x26, 0x01}, + {0x02, 0x01, 0x2a, 0x00}, {0x09, 0x01, 0x2a, 0x00}, + {0x17, 0x01, 0x2a, 0x00}, {0x28, 0x01, 0x2a, 0x01}, + {0x02, 0x01, 0x2c, 0x00}, {0x09, 0x01, 0x2c, 0x00}, + {0x17, 0x01, 0x2c, 0x00}, {0x28, 0x01, 0x2c, 0x01}, + {0x02, 0x01, 0x3b, 0x00}, {0x09, 0x01, 0x3b, 0x00}, + {0x17, 0x01, 0x3b, 0x00}, {0x28, 0x01, 0x3b, 0x01} + }, + /* 70 */ + { + {0x03, 0x01, 0x26, 0x00}, {0x06, 0x01, 0x26, 0x00}, + {0x0a, 0x01, 0x26, 0x00}, {0x0f, 0x01, 0x26, 0x00}, + {0x18, 0x01, 0x26, 0x00}, {0x1f, 0x01, 0x26, 0x00}, + {0x29, 0x01, 0x26, 0x00}, {0x38, 0x01, 0x26, 0x01}, + {0x03, 0x01, 0x2a, 0x00}, {0x06, 0x01, 0x2a, 0x00}, + {0x0a, 0x01, 0x2a, 0x00}, {0x0f, 0x01, 0x2a, 0x00}, + {0x18, 0x01, 0x2a, 0x00}, {0x1f, 0x01, 0x2a, 0x00}, + {0x29, 0x01, 0x2a, 0x00}, {0x38, 0x01, 0x2a, 0x01} + }, + { + {0x03, 0x01, 0x2c, 0x00}, {0x06, 0x01, 0x2c, 0x00}, + {0x0a, 0x01, 0x2c, 0x00}, {0x0f, 0x01, 0x2c, 0x00}, + {0x18, 0x01, 0x2c, 0x00}, {0x1f, 0x01, 0x2c, 0x00}, + {0x29, 0x01, 0x2c, 0x00}, {0x38, 0x01, 0x2c, 0x01}, + {0x03, 0x01, 0x3b, 0x00}, {0x06, 0x01, 0x3b, 0x00}, + {0x0a, 0x01, 0x3b, 0x00}, {0x0f, 0x01, 0x3b, 0x00}, + {0x18, 0x01, 0x3b, 0x00}, {0x1f, 0x01, 0x3b, 0x00}, + {0x29, 0x01, 0x3b, 0x00}, {0x38, 0x01, 0x3b, 0x01} + }, + { + {0x02, 0x01, 0x58, 0x00}, {0x09, 0x01, 0x58, 0x00}, + {0x17, 0x01, 0x58, 0x00}, {0x28, 0x01, 0x58, 0x01}, + {0x02, 0x01, 0x5a, 0x00}, {0x09, 0x01, 0x5a, 0x00}, + {0x17, 0x01, 0x5a, 0x00}, {0x28, 0x01, 0x5a, 0x01}, + {0x00, 0x01, 0x21, 0x01}, {0x00, 0x01, 0x22, 0x01}, + {0x00, 0x01, 0x28, 0x01}, {0x00, 0x01, 0x29, 0x01}, + {0x00, 0x01, 0x3f, 0x01}, {0x50, 0x00, 0x00, 0x00}, + {0x52, 0x00, 0x00, 0x00}, {0x54, 0x00, 0x00, 0x01} + }, + { + {0x03, 0x01, 0x58, 0x00}, {0x06, 0x01, 0x58, 0x00}, + {0x0a, 0x01, 0x58, 0x00}, {0x0f, 0x01, 0x58, 0x00}, + {0x18, 0x01, 0x58, 0x00}, {0x1f, 0x01, 0x58, 0x00}, + {0x29, 0x01, 0x58, 0x00}, {0x38, 0x01, 0x58, 0x01}, + {0x03, 0x01, 0x5a, 0x00}, {0x06, 0x01, 0x5a, 0x00}, + {0x0a, 0x01, 0x5a, 0x00}, {0x0f, 0x01, 0x5a, 0x00}, + {0x18, 0x01, 0x5a, 0x00}, {0x1f, 0x01, 0x5a, 0x00}, + {0x29, 0x01, 0x5a, 0x00}, {0x38, 0x01, 0x5a, 0x01} + }, + { + {0x01, 0x01, 0x21, 0x00}, {0x16, 0x01, 0x21, 0x01}, + {0x01, 0x01, 0x22, 0x00}, {0x16, 0x01, 0x22, 0x01}, + {0x01, 0x01, 0x28, 0x00}, {0x16, 0x01, 0x28, 0x01}, + {0x01, 0x01, 0x29, 0x00}, {0x16, 0x01, 0x29, 0x01}, + {0x01, 0x01, 0x3f, 0x00}, {0x16, 0x01, 0x3f, 0x01}, + {0x00, 0x01, 0x27, 0x01}, {0x00, 0x01, 0x2b, 0x01}, + {0x00, 0x01, 0x7c, 0x01}, {0x53, 0x00, 0x00, 0x00}, + {0x55, 0x00, 0x00, 0x00}, {0x58, 0x00, 0x00, 0x01} + }, + /* 75 */ + { + {0x02, 0x01, 0x21, 0x00}, {0x09, 0x01, 0x21, 0x00}, + {0x17, 0x01, 0x21, 0x00}, {0x28, 0x01, 0x21, 0x01}, + {0x02, 0x01, 0x22, 0x00}, {0x09, 0x01, 0x22, 0x00}, + {0x17, 0x01, 0x22, 0x00}, {0x28, 0x01, 0x22, 0x01}, + {0x02, 0x01, 0x28, 0x00}, {0x09, 0x01, 0x28, 0x00}, + {0x17, 0x01, 0x28, 0x00}, {0x28, 0x01, 0x28, 0x01}, + {0x02, 0x01, 0x29, 0x00}, {0x09, 0x01, 0x29, 0x00}, + {0x17, 0x01, 0x29, 0x00}, {0x28, 0x01, 0x29, 0x01} + }, + { + {0x03, 0x01, 0x21, 0x00}, {0x06, 0x01, 0x21, 0x00}, + {0x0a, 0x01, 0x21, 0x00}, {0x0f, 0x01, 0x21, 0x00}, + {0x18, 0x01, 0x21, 0x00}, {0x1f, 0x01, 0x21, 0x00}, + {0x29, 0x01, 0x21, 0x00}, {0x38, 0x01, 0x21, 0x01}, + {0x03, 0x01, 0x22, 0x00}, {0x06, 0x01, 0x22, 0x00}, + {0x0a, 0x01, 0x22, 0x00}, {0x0f, 0x01, 0x22, 0x00}, + {0x18, 0x01, 0x22, 0x00}, {0x1f, 0x01, 0x22, 0x00}, + {0x29, 0x01, 0x22, 0x00}, {0x38, 0x01, 0x22, 0x01} + }, + { + {0x03, 0x01, 0x28, 0x00}, {0x06, 0x01, 0x28, 0x00}, + {0x0a, 0x01, 0x28, 0x00}, {0x0f, 0x01, 0x28, 0x00}, + {0x18, 0x01, 0x28, 0x00}, {0x1f, 0x01, 0x28, 0x00}, + {0x29, 0x01, 0x28, 0x00}, {0x38, 0x01, 0x28, 0x01}, + {0x03, 0x01, 0x29, 0x00}, {0x06, 0x01, 0x29, 0x00}, + {0x0a, 0x01, 0x29, 0x00}, {0x0f, 0x01, 0x29, 0x00}, + {0x18, 0x01, 0x29, 0x00}, {0x1f, 0x01, 0x29, 0x00}, + {0x29, 0x01, 0x29, 0x00}, {0x38, 0x01, 0x29, 0x01} + }, + { + {0x02, 0x01, 0x3f, 0x00}, {0x09, 0x01, 0x3f, 0x00}, + {0x17, 0x01, 0x3f, 0x00}, {0x28, 0x01, 0x3f, 0x01}, + {0x01, 0x01, 0x27, 0x00}, {0x16, 0x01, 0x27, 0x01}, + {0x01, 0x01, 0x2b, 0x00}, {0x16, 0x01, 0x2b, 0x01}, + {0x01, 0x01, 0x7c, 0x00}, {0x16, 0x01, 0x7c, 0x01}, + {0x00, 0x01, 0x23, 0x01}, {0x00, 0x01, 0x3e, 0x01}, + {0x56, 0x00, 0x00, 0x00}, {0x57, 0x00, 0x00, 0x00}, + {0x59, 0x00, 0x00, 0x00}, {0x5a, 0x00, 0x00, 0x01} + }, + { + {0x03, 0x01, 0x3f, 0x00}, {0x06, 0x01, 0x3f, 0x00}, + {0x0a, 0x01, 0x3f, 0x00}, {0x0f, 0x01, 0x3f, 0x00}, + {0x18, 0x01, 0x3f, 0x00}, {0x1f, 0x01, 0x3f, 0x00}, + {0x29, 0x01, 0x3f, 0x00}, {0x38, 0x01, 0x3f, 0x01}, + {0x02, 0x01, 0x27, 0x00}, {0x09, 0x01, 0x27, 0x00}, + {0x17, 0x01, 0x27, 0x00}, {0x28, 0x01, 0x27, 0x01}, + {0x02, 0x01, 0x2b, 0x00}, {0x09, 0x01, 0x2b, 0x00}, + {0x17, 0x01, 0x2b, 0x00}, {0x28, 0x01, 0x2b, 0x01} + }, + /* 80 */ + { + {0x03, 0x01, 0x27, 0x00}, {0x06, 0x01, 0x27, 0x00}, + {0x0a, 0x01, 0x27, 0x00}, {0x0f, 0x01, 0x27, 0x00}, + {0x18, 0x01, 0x27, 0x00}, {0x1f, 0x01, 0x27, 0x00}, + {0x29, 0x01, 0x27, 0x00}, {0x38, 0x01, 0x27, 0x01}, + {0x03, 0x01, 0x2b, 0x00}, {0x06, 0x01, 0x2b, 0x00}, + {0x0a, 0x01, 0x2b, 0x00}, {0x0f, 0x01, 0x2b, 0x00}, + {0x18, 0x01, 0x2b, 0x00}, {0x1f, 0x01, 0x2b, 0x00}, + {0x29, 0x01, 0x2b, 0x00}, {0x38, 0x01, 0x2b, 0x01} + }, + { + {0x02, 0x01, 0x7c, 0x00}, {0x09, 0x01, 0x7c, 0x00}, + {0x17, 0x01, 0x7c, 0x00}, {0x28, 0x01, 0x7c, 0x01}, + {0x01, 0x01, 0x23, 0x00}, {0x16, 0x01, 0x23, 0x01}, + {0x01, 0x01, 0x3e, 0x00}, {0x16, 0x01, 0x3e, 0x01}, + {0x00, 0x01, 0x00, 0x01}, {0x00, 0x01, 0x24, 0x01}, + {0x00, 0x01, 0x40, 0x01}, {0x00, 0x01, 0x5b, 0x01}, + {0x00, 0x01, 0x5d, 0x01}, {0x00, 0x01, 0x7e, 0x01}, + {0x5b, 0x00, 0x00, 0x00}, {0x5c, 0x00, 0x00, 0x01} + }, + { + {0x03, 0x01, 0x7c, 0x00}, {0x06, 0x01, 0x7c, 0x00}, + {0x0a, 0x01, 0x7c, 0x00}, {0x0f, 0x01, 0x7c, 0x00}, + {0x18, 0x01, 0x7c, 0x00}, {0x1f, 0x01, 0x7c, 0x00}, + {0x29, 0x01, 0x7c, 0x00}, {0x38, 0x01, 0x7c, 0x01}, + {0x02, 0x01, 0x23, 0x00}, {0x09, 0x01, 0x23, 0x00}, + {0x17, 0x01, 0x23, 0x00}, {0x28, 0x01, 0x23, 0x01}, + {0x02, 0x01, 0x3e, 0x00}, {0x09, 0x01, 0x3e, 0x00}, + {0x17, 0x01, 0x3e, 0x00}, {0x28, 0x01, 0x3e, 0x01} + }, + { + {0x03, 0x01, 0x23, 0x00}, {0x06, 0x01, 0x23, 0x00}, + {0x0a, 0x01, 0x23, 0x00}, {0x0f, 0x01, 0x23, 0x00}, + {0x18, 0x01, 0x23, 0x00}, {0x1f, 0x01, 0x23, 0x00}, + {0x29, 0x01, 0x23, 0x00}, {0x38, 0x01, 0x23, 0x01}, + {0x03, 0x01, 0x3e, 0x00}, {0x06, 0x01, 0x3e, 0x00}, + {0x0a, 0x01, 0x3e, 0x00}, {0x0f, 0x01, 0x3e, 0x00}, + {0x18, 0x01, 0x3e, 0x00}, {0x1f, 0x01, 0x3e, 0x00}, + {0x29, 0x01, 0x3e, 0x00}, {0x38, 0x01, 0x3e, 0x01} + }, + { + {0x01, 0x01, 0x00, 0x00}, {0x16, 0x01, 0x00, 0x01}, + {0x01, 0x01, 0x24, 0x00}, {0x16, 0x01, 0x24, 0x01}, + {0x01, 0x01, 0x40, 0x00}, {0x16, 0x01, 0x40, 0x01}, + {0x01, 0x01, 0x5b, 0x00}, {0x16, 0x01, 0x5b, 0x01}, + {0x01, 0x01, 0x5d, 0x00}, {0x16, 0x01, 0x5d, 0x01}, + {0x01, 0x01, 0x7e, 0x00}, {0x16, 0x01, 0x7e, 0x01}, + {0x00, 0x01, 0x5e, 0x01}, {0x00, 0x01, 0x7d, 0x01}, + {0x5d, 0x00, 0x00, 0x00}, {0x5e, 0x00, 0x00, 0x01} + }, + /* 85 */ + { + {0x02, 0x01, 0x00, 0x00}, {0x09, 0x01, 0x00, 0x00}, + {0x17, 0x01, 0x00, 0x00}, {0x28, 0x01, 0x00, 0x01}, + {0x02, 0x01, 0x24, 0x00}, {0x09, 0x01, 0x24, 0x00}, + {0x17, 0x01, 0x24, 0x00}, {0x28, 0x01, 0x24, 0x01}, + {0x02, 0x01, 0x40, 0x00}, {0x09, 0x01, 0x40, 0x00}, + {0x17, 0x01, 0x40, 0x00}, {0x28, 0x01, 0x40, 0x01}, + {0x02, 0x01, 0x5b, 0x00}, {0x09, 0x01, 0x5b, 0x00}, + {0x17, 0x01, 0x5b, 0x00}, {0x28, 0x01, 0x5b, 0x01} + }, + { + {0x03, 0x01, 0x00, 0x00}, {0x06, 0x01, 0x00, 0x00}, + {0x0a, 0x01, 0x00, 0x00}, {0x0f, 0x01, 0x00, 0x00}, + {0x18, 0x01, 0x00, 0x00}, {0x1f, 0x01, 0x00, 0x00}, + {0x29, 0x01, 0x00, 0x00}, {0x38, 0x01, 0x00, 0x01}, + {0x03, 0x01, 0x24, 0x00}, {0x06, 0x01, 0x24, 0x00}, + {0x0a, 0x01, 0x24, 0x00}, {0x0f, 0x01, 0x24, 0x00}, + {0x18, 0x01, 0x24, 0x00}, {0x1f, 0x01, 0x24, 0x00}, + {0x29, 0x01, 0x24, 0x00}, {0x38, 0x01, 0x24, 0x01} + }, + { + {0x03, 0x01, 0x40, 0x00}, {0x06, 0x01, 0x40, 0x00}, + {0x0a, 0x01, 0x40, 0x00}, {0x0f, 0x01, 0x40, 0x00}, + {0x18, 0x01, 0x40, 0x00}, {0x1f, 0x01, 0x40, 0x00}, + {0x29, 0x01, 0x40, 0x00}, {0x38, 0x01, 0x40, 0x01}, + {0x03, 0x01, 0x5b, 0x00}, {0x06, 0x01, 0x5b, 0x00}, + {0x0a, 0x01, 0x5b, 0x00}, {0x0f, 0x01, 0x5b, 0x00}, + {0x18, 0x01, 0x5b, 0x00}, {0x1f, 0x01, 0x5b, 0x00}, + {0x29, 0x01, 0x5b, 0x00}, {0x38, 0x01, 0x5b, 0x01} + }, + { + {0x02, 0x01, 0x5d, 0x00}, {0x09, 0x01, 0x5d, 0x00}, + {0x17, 0x01, 0x5d, 0x00}, {0x28, 0x01, 0x5d, 0x01}, + {0x02, 0x01, 0x7e, 0x00}, {0x09, 0x01, 0x7e, 0x00}, + {0x17, 0x01, 0x7e, 0x00}, {0x28, 0x01, 0x7e, 0x01}, + {0x01, 0x01, 0x5e, 0x00}, {0x16, 0x01, 0x5e, 0x01}, + {0x01, 0x01, 0x7d, 0x00}, {0x16, 0x01, 0x7d, 0x01}, + {0x00, 0x01, 0x3c, 0x01}, {0x00, 0x01, 0x60, 0x01}, + {0x00, 0x01, 0x7b, 0x01}, {0x5f, 0x00, 0x00, 0x01} + }, + { + {0x03, 0x01, 0x5d, 0x00}, {0x06, 0x01, 0x5d, 0x00}, + {0x0a, 0x01, 0x5d, 0x00}, {0x0f, 0x01, 0x5d, 0x00}, + {0x18, 0x01, 0x5d, 0x00}, {0x1f, 0x01, 0x5d, 0x00}, + {0x29, 0x01, 0x5d, 0x00}, {0x38, 0x01, 0x5d, 0x01}, + {0x03, 0x01, 0x7e, 0x00}, {0x06, 0x01, 0x7e, 0x00}, + {0x0a, 0x01, 0x7e, 0x00}, {0x0f, 0x01, 0x7e, 0x00}, + {0x18, 0x01, 0x7e, 0x00}, {0x1f, 0x01, 0x7e, 0x00}, + {0x29, 0x01, 0x7e, 0x00}, {0x38, 0x01, 0x7e, 0x01} + }, + /* 90 */ + { + {0x02, 0x01, 0x5e, 0x00}, {0x09, 0x01, 0x5e, 0x00}, + {0x17, 0x01, 0x5e, 0x00}, {0x28, 0x01, 0x5e, 0x01}, + {0x02, 0x01, 0x7d, 0x00}, {0x09, 0x01, 0x7d, 0x00}, + {0x17, 0x01, 0x7d, 0x00}, {0x28, 0x01, 0x7d, 0x01}, + {0x01, 0x01, 0x3c, 0x00}, {0x16, 0x01, 0x3c, 0x01}, + {0x01, 0x01, 0x60, 0x00}, {0x16, 0x01, 0x60, 0x01}, + {0x01, 0x01, 0x7b, 0x00}, {0x16, 0x01, 0x7b, 0x01}, + {0x60, 0x00, 0x00, 0x00}, {0x6e, 0x00, 0x00, 0x01} + }, + { + {0x03, 0x01, 0x5e, 0x00}, {0x06, 0x01, 0x5e, 0x00}, + {0x0a, 0x01, 0x5e, 0x00}, {0x0f, 0x01, 0x5e, 0x00}, + {0x18, 0x01, 0x5e, 0x00}, {0x1f, 0x01, 0x5e, 0x00}, + {0x29, 0x01, 0x5e, 0x00}, {0x38, 0x01, 0x5e, 0x01}, + {0x03, 0x01, 0x7d, 0x00}, {0x06, 0x01, 0x7d, 0x00}, + {0x0a, 0x01, 0x7d, 0x00}, {0x0f, 0x01, 0x7d, 0x00}, + {0x18, 0x01, 0x7d, 0x00}, {0x1f, 0x01, 0x7d, 0x00}, + {0x29, 0x01, 0x7d, 0x00}, {0x38, 0x01, 0x7d, 0x01} + }, + { + {0x02, 0x01, 0x3c, 0x00}, {0x09, 0x01, 0x3c, 0x00}, + {0x17, 0x01, 0x3c, 0x00}, {0x28, 0x01, 0x3c, 0x01}, + {0x02, 0x01, 0x60, 0x00}, {0x09, 0x01, 0x60, 0x00}, + {0x17, 0x01, 0x60, 0x00}, {0x28, 0x01, 0x60, 0x01}, + {0x02, 0x01, 0x7b, 0x00}, {0x09, 0x01, 0x7b, 0x00}, + {0x17, 0x01, 0x7b, 0x00}, {0x28, 0x01, 0x7b, 0x01}, + {0x61, 0x00, 0x00, 0x00}, {0x65, 0x00, 0x00, 0x00}, + {0x6f, 0x00, 0x00, 0x00}, {0x85, 0x00, 0x00, 0x01} + }, + { + {0x03, 0x01, 0x3c, 0x00}, {0x06, 0x01, 0x3c, 0x00}, + {0x0a, 0x01, 0x3c, 0x00}, {0x0f, 0x01, 0x3c, 0x00}, + {0x18, 0x01, 0x3c, 0x00}, {0x1f, 0x01, 0x3c, 0x00}, + {0x29, 0x01, 0x3c, 0x00}, {0x38, 0x01, 0x3c, 0x01}, + {0x03, 0x01, 0x60, 0x00}, {0x06, 0x01, 0x60, 0x00}, + {0x0a, 0x01, 0x60, 0x00}, {0x0f, 0x01, 0x60, 0x00}, + {0x18, 0x01, 0x60, 0x00}, {0x1f, 0x01, 0x60, 0x00}, + {0x29, 0x01, 0x60, 0x00}, {0x38, 0x01, 0x60, 0x01} + }, + { + {0x03, 0x01, 0x7b, 0x00}, {0x06, 0x01, 0x7b, 0x00}, + {0x0a, 0x01, 0x7b, 0x00}, {0x0f, 0x01, 0x7b, 0x00}, + {0x18, 0x01, 0x7b, 0x00}, {0x1f, 0x01, 0x7b, 0x00}, + {0x29, 0x01, 0x7b, 0x00}, {0x38, 0x01, 0x7b, 0x01}, + {0x62, 0x00, 0x00, 0x00}, {0x63, 0x00, 0x00, 0x00}, + {0x66, 0x00, 0x00, 0x00}, {0x69, 0x00, 0x00, 0x00}, + {0x70, 0x00, 0x00, 0x00}, {0x77, 0x00, 0x00, 0x00}, + {0x86, 0x00, 0x00, 0x00}, {0x99, 0x00, 0x00, 0x01} + }, + /* 95 */ + { + {0x00, 0x01, 0x5c, 0x01}, {0x00, 0x01, 0xc3, 0x01}, + {0x00, 0x01, 0xd0, 0x01}, {0x64, 0x00, 0x00, 0x00}, + {0x67, 0x00, 0x00, 0x00}, {0x68, 0x00, 0x00, 0x00}, + {0x6a, 0x00, 0x00, 0x00}, {0x6b, 0x00, 0x00, 0x00}, + {0x71, 0x00, 0x00, 0x00}, {0x74, 0x00, 0x00, 0x00}, + {0x78, 0x00, 0x00, 0x00}, {0x7e, 0x00, 0x00, 0x00}, + {0x87, 0x00, 0x00, 0x00}, {0x8e, 0x00, 0x00, 0x00}, + {0x9a, 0x00, 0x00, 0x00}, {0xa9, 0x00, 0x00, 0x01} + }, + { + {0x01, 0x01, 0x5c, 0x00}, {0x16, 0x01, 0x5c, 0x01}, + {0x01, 0x01, 0xc3, 0x00}, {0x16, 0x01, 0xc3, 0x01}, + {0x01, 0x01, 0xd0, 0x00}, {0x16, 0x01, 0xd0, 0x01}, + {0x00, 0x01, 0x80, 0x01}, {0x00, 0x01, 0x82, 0x01}, + {0x00, 0x01, 0x83, 0x01}, {0x00, 0x01, 0xa2, 0x01}, + {0x00, 0x01, 0xb8, 0x01}, {0x00, 0x01, 0xc2, 0x01}, + {0x00, 0x01, 0xe0, 0x01}, {0x00, 0x01, 0xe2, 0x01}, + {0x6c, 0x00, 0x00, 0x00}, {0x6d, 0x00, 0x00, 0x00} + }, + { + {0x02, 0x01, 0x5c, 0x00}, {0x09, 0x01, 0x5c, 0x00}, + {0x17, 0x01, 0x5c, 0x00}, {0x28, 0x01, 0x5c, 0x01}, + {0x02, 0x01, 0xc3, 0x00}, {0x09, 0x01, 0xc3, 0x00}, + {0x17, 0x01, 0xc3, 0x00}, {0x28, 0x01, 0xc3, 0x01}, + {0x02, 0x01, 0xd0, 0x00}, {0x09, 0x01, 0xd0, 0x00}, + {0x17, 0x01, 0xd0, 0x00}, {0x28, 0x01, 0xd0, 0x01}, + {0x01, 0x01, 0x80, 0x00}, {0x16, 0x01, 0x80, 0x01}, + {0x01, 0x01, 0x82, 0x00}, {0x16, 0x01, 0x82, 0x01} + }, + { + {0x03, 0x01, 0x5c, 0x00}, {0x06, 0x01, 0x5c, 0x00}, + {0x0a, 0x01, 0x5c, 0x00}, {0x0f, 0x01, 0x5c, 0x00}, + {0x18, 0x01, 0x5c, 0x00}, {0x1f, 0x01, 0x5c, 0x00}, + {0x29, 0x01, 0x5c, 0x00}, {0x38, 0x01, 0x5c, 0x01}, + {0x03, 0x01, 0xc3, 0x00}, {0x06, 0x01, 0xc3, 0x00}, + {0x0a, 0x01, 0xc3, 0x00}, {0x0f, 0x01, 0xc3, 0x00}, + {0x18, 0x01, 0xc3, 0x00}, {0x1f, 0x01, 0xc3, 0x00}, + {0x29, 0x01, 0xc3, 0x00}, {0x38, 0x01, 0xc3, 0x01} + }, + { + {0x03, 0x01, 0xd0, 0x00}, {0x06, 0x01, 0xd0, 0x00}, + {0x0a, 0x01, 0xd0, 0x00}, {0x0f, 0x01, 0xd0, 0x00}, + {0x18, 0x01, 0xd0, 0x00}, {0x1f, 0x01, 0xd0, 0x00}, + {0x29, 0x01, 0xd0, 0x00}, {0x38, 0x01, 0xd0, 0x01}, + {0x02, 0x01, 0x80, 0x00}, {0x09, 0x01, 0x80, 0x00}, + {0x17, 0x01, 0x80, 0x00}, {0x28, 0x01, 0x80, 0x01}, + {0x02, 0x01, 0x82, 0x00}, {0x09, 0x01, 0x82, 0x00}, + {0x17, 0x01, 0x82, 0x00}, {0x28, 0x01, 0x82, 0x01} + }, + /* 100 */ + { + {0x03, 0x01, 0x80, 0x00}, {0x06, 0x01, 0x80, 0x00}, + {0x0a, 0x01, 0x80, 0x00}, {0x0f, 0x01, 0x80, 0x00}, + {0x18, 0x01, 0x80, 0x00}, {0x1f, 0x01, 0x80, 0x00}, + {0x29, 0x01, 0x80, 0x00}, {0x38, 0x01, 0x80, 0x01}, + {0x03, 0x01, 0x82, 0x00}, {0x06, 0x01, 0x82, 0x00}, + {0x0a, 0x01, 0x82, 0x00}, {0x0f, 0x01, 0x82, 0x00}, + {0x18, 0x01, 0x82, 0x00}, {0x1f, 0x01, 0x82, 0x00}, + {0x29, 0x01, 0x82, 0x00}, {0x38, 0x01, 0x82, 0x01} + }, + { + {0x01, 0x01, 0x83, 0x00}, {0x16, 0x01, 0x83, 0x01}, + {0x01, 0x01, 0xa2, 0x00}, {0x16, 0x01, 0xa2, 0x01}, + {0x01, 0x01, 0xb8, 0x00}, {0x16, 0x01, 0xb8, 0x01}, + {0x01, 0x01, 0xc2, 0x00}, {0x16, 0x01, 0xc2, 0x01}, + {0x01, 0x01, 0xe0, 0x00}, {0x16, 0x01, 0xe0, 0x01}, + {0x01, 0x01, 0xe2, 0x00}, {0x16, 0x01, 0xe2, 0x01}, + {0x00, 0x01, 0x99, 0x01}, {0x00, 0x01, 0xa1, 0x01}, + {0x00, 0x01, 0xa7, 0x01}, {0x00, 0x01, 0xac, 0x01} + }, + { + {0x02, 0x01, 0x83, 0x00}, {0x09, 0x01, 0x83, 0x00}, + {0x17, 0x01, 0x83, 0x00}, {0x28, 0x01, 0x83, 0x01}, + {0x02, 0x01, 0xa2, 0x00}, {0x09, 0x01, 0xa2, 0x00}, + {0x17, 0x01, 0xa2, 0x00}, {0x28, 0x01, 0xa2, 0x01}, + {0x02, 0x01, 0xb8, 0x00}, {0x09, 0x01, 0xb8, 0x00}, + {0x17, 0x01, 0xb8, 0x00}, {0x28, 0x01, 0xb8, 0x01}, + {0x02, 0x01, 0xc2, 0x00}, {0x09, 0x01, 0xc2, 0x00}, + {0x17, 0x01, 0xc2, 0x00}, {0x28, 0x01, 0xc2, 0x01} + }, + { + {0x03, 0x01, 0x83, 0x00}, {0x06, 0x01, 0x83, 0x00}, + {0x0a, 0x01, 0x83, 0x00}, {0x0f, 0x01, 0x83, 0x00}, + {0x18, 0x01, 0x83, 0x00}, {0x1f, 0x01, 0x83, 0x00}, + {0x29, 0x01, 0x83, 0x00}, {0x38, 0x01, 0x83, 0x01}, + {0x03, 0x01, 0xa2, 0x00}, {0x06, 0x01, 0xa2, 0x00}, + {0x0a, 0x01, 0xa2, 0x00}, {0x0f, 0x01, 0xa2, 0x00}, + {0x18, 0x01, 0xa2, 0x00}, {0x1f, 0x01, 0xa2, 0x00}, + {0x29, 0x01, 0xa2, 0x00}, {0x38, 0x01, 0xa2, 0x01} + }, + { + {0x03, 0x01, 0xb8, 0x00}, {0x06, 0x01, 0xb8, 0x00}, + {0x0a, 0x01, 0xb8, 0x00}, {0x0f, 0x01, 0xb8, 0x00}, + {0x18, 0x01, 0xb8, 0x00}, {0x1f, 0x01, 0xb8, 0x00}, + {0x29, 0x01, 0xb8, 0x00}, {0x38, 0x01, 0xb8, 0x01}, + {0x03, 0x01, 0xc2, 0x00}, {0x06, 0x01, 0xc2, 0x00}, + {0x0a, 0x01, 0xc2, 0x00}, {0x0f, 0x01, 0xc2, 0x00}, + {0x18, 0x01, 0xc2, 0x00}, {0x1f, 0x01, 0xc2, 0x00}, + {0x29, 0x01, 0xc2, 0x00}, {0x38, 0x01, 0xc2, 0x01} + }, + /* 105 */ + { + {0x02, 0x01, 0xe0, 0x00}, {0x09, 0x01, 0xe0, 0x00}, + {0x17, 0x01, 0xe0, 0x00}, {0x28, 0x01, 0xe0, 0x01}, + {0x02, 0x01, 0xe2, 0x00}, {0x09, 0x01, 0xe2, 0x00}, + {0x17, 0x01, 0xe2, 0x00}, {0x28, 0x01, 0xe2, 0x01}, + {0x01, 0x01, 0x99, 0x00}, {0x16, 0x01, 0x99, 0x01}, + {0x01, 0x01, 0xa1, 0x00}, {0x16, 0x01, 0xa1, 0x01}, + {0x01, 0x01, 0xa7, 0x00}, {0x16, 0x01, 0xa7, 0x01}, + {0x01, 0x01, 0xac, 0x00}, {0x16, 0x01, 0xac, 0x01} + }, + { + {0x03, 0x01, 0xe0, 0x00}, {0x06, 0x01, 0xe0, 0x00}, + {0x0a, 0x01, 0xe0, 0x00}, {0x0f, 0x01, 0xe0, 0x00}, + {0x18, 0x01, 0xe0, 0x00}, {0x1f, 0x01, 0xe0, 0x00}, + {0x29, 0x01, 0xe0, 0x00}, {0x38, 0x01, 0xe0, 0x01}, + {0x03, 0x01, 0xe2, 0x00}, {0x06, 0x01, 0xe2, 0x00}, + {0x0a, 0x01, 0xe2, 0x00}, {0x0f, 0x01, 0xe2, 0x00}, + {0x18, 0x01, 0xe2, 0x00}, {0x1f, 0x01, 0xe2, 0x00}, + {0x29, 0x01, 0xe2, 0x00}, {0x38, 0x01, 0xe2, 0x01} + }, + { + {0x02, 0x01, 0x99, 0x00}, {0x09, 0x01, 0x99, 0x00}, + {0x17, 0x01, 0x99, 0x00}, {0x28, 0x01, 0x99, 0x01}, + {0x02, 0x01, 0xa1, 0x00}, {0x09, 0x01, 0xa1, 0x00}, + {0x17, 0x01, 0xa1, 0x00}, {0x28, 0x01, 0xa1, 0x01}, + {0x02, 0x01, 0xa7, 0x00}, {0x09, 0x01, 0xa7, 0x00}, + {0x17, 0x01, 0xa7, 0x00}, {0x28, 0x01, 0xa7, 0x01}, + {0x02, 0x01, 0xac, 0x00}, {0x09, 0x01, 0xac, 0x00}, + {0x17, 0x01, 0xac, 0x00}, {0x28, 0x01, 0xac, 0x01} + }, + { + {0x03, 0x01, 0x99, 0x00}, {0x06, 0x01, 0x99, 0x00}, + {0x0a, 0x01, 0x99, 0x00}, {0x0f, 0x01, 0x99, 0x00}, + {0x18, 0x01, 0x99, 0x00}, {0x1f, 0x01, 0x99, 0x00}, + {0x29, 0x01, 0x99, 0x00}, {0x38, 0x01, 0x99, 0x01}, + {0x03, 0x01, 0xa1, 0x00}, {0x06, 0x01, 0xa1, 0x00}, + {0x0a, 0x01, 0xa1, 0x00}, {0x0f, 0x01, 0xa1, 0x00}, + {0x18, 0x01, 0xa1, 0x00}, {0x1f, 0x01, 0xa1, 0x00}, + {0x29, 0x01, 0xa1, 0x00}, {0x38, 0x01, 0xa1, 0x01} + }, + { + {0x03, 0x01, 0xa7, 0x00}, {0x06, 0x01, 0xa7, 0x00}, + {0x0a, 0x01, 0xa7, 0x00}, {0x0f, 0x01, 0xa7, 0x00}, + {0x18, 0x01, 0xa7, 0x00}, {0x1f, 0x01, 0xa7, 0x00}, + {0x29, 0x01, 0xa7, 0x00}, {0x38, 0x01, 0xa7, 0x01}, + {0x03, 0x01, 0xac, 0x00}, {0x06, 0x01, 0xac, 0x00}, + {0x0a, 0x01, 0xac, 0x00}, {0x0f, 0x01, 0xac, 0x00}, + {0x18, 0x01, 0xac, 0x00}, {0x1f, 0x01, 0xac, 0x00}, + {0x29, 0x01, 0xac, 0x00}, {0x38, 0x01, 0xac, 0x01} + }, + /* 110 */ + { + {0x72, 0x00, 0x00, 0x00}, {0x73, 0x00, 0x00, 0x00}, + {0x75, 0x00, 0x00, 0x00}, {0x76, 0x00, 0x00, 0x00}, + {0x79, 0x00, 0x00, 0x00}, {0x7b, 0x00, 0x00, 0x00}, + {0x7f, 0x00, 0x00, 0x00}, {0x82, 0x00, 0x00, 0x00}, + {0x88, 0x00, 0x00, 0x00}, {0x8b, 0x00, 0x00, 0x00}, + {0x8f, 0x00, 0x00, 0x00}, {0x92, 0x00, 0x00, 0x00}, + {0x9b, 0x00, 0x00, 0x00}, {0xa2, 0x00, 0x00, 0x00}, + {0xaa, 0x00, 0x00, 0x00}, {0xb4, 0x00, 0x00, 0x01} + }, + { + {0x00, 0x01, 0xb0, 0x01}, {0x00, 0x01, 0xb1, 0x01}, + {0x00, 0x01, 0xb3, 0x01}, {0x00, 0x01, 0xd1, 0x01}, + {0x00, 0x01, 0xd8, 0x01}, {0x00, 0x01, 0xd9, 0x01}, + {0x00, 0x01, 0xe3, 0x01}, {0x00, 0x01, 0xe5, 0x01}, + {0x00, 0x01, 0xe6, 0x01}, {0x7a, 0x00, 0x00, 0x00}, + {0x7c, 0x00, 0x00, 0x00}, {0x7d, 0x00, 0x00, 0x00}, + {0x80, 0x00, 0x00, 0x00}, {0x81, 0x00, 0x00, 0x00}, + {0x83, 0x00, 0x00, 0x00}, {0x84, 0x00, 0x00, 0x00} + }, + { + {0x01, 0x01, 0xb0, 0x00}, {0x16, 0x01, 0xb0, 0x01}, + {0x01, 0x01, 0xb1, 0x00}, {0x16, 0x01, 0xb1, 0x01}, + {0x01, 0x01, 0xb3, 0x00}, {0x16, 0x01, 0xb3, 0x01}, + {0x01, 0x01, 0xd1, 0x00}, {0x16, 0x01, 0xd1, 0x01}, + {0x01, 0x01, 0xd8, 0x00}, {0x16, 0x01, 0xd8, 0x01}, + {0x01, 0x01, 0xd9, 0x00}, {0x16, 0x01, 0xd9, 0x01}, + {0x01, 0x01, 0xe3, 0x00}, {0x16, 0x01, 0xe3, 0x01}, + {0x01, 0x01, 0xe5, 0x00}, {0x16, 0x01, 0xe5, 0x01} + }, + { + {0x02, 0x01, 0xb0, 0x00}, {0x09, 0x01, 0xb0, 0x00}, + {0x17, 0x01, 0xb0, 0x00}, {0x28, 0x01, 0xb0, 0x01}, + {0x02, 0x01, 0xb1, 0x00}, {0x09, 0x01, 0xb1, 0x00}, + {0x17, 0x01, 0xb1, 0x00}, {0x28, 0x01, 0xb1, 0x01}, + {0x02, 0x01, 0xb3, 0x00}, {0x09, 0x01, 0xb3, 0x00}, + {0x17, 0x01, 0xb3, 0x00}, {0x28, 0x01, 0xb3, 0x01}, + {0x02, 0x01, 0xd1, 0x00}, {0x09, 0x01, 0xd1, 0x00}, + {0x17, 0x01, 0xd1, 0x00}, {0x28, 0x01, 0xd1, 0x01} + }, + { + {0x03, 0x01, 0xb0, 0x00}, {0x06, 0x01, 0xb0, 0x00}, + {0x0a, 0x01, 0xb0, 0x00}, {0x0f, 0x01, 0xb0, 0x00}, + {0x18, 0x01, 0xb0, 0x00}, {0x1f, 0x01, 0xb0, 0x00}, + {0x29, 0x01, 0xb0, 0x00}, {0x38, 0x01, 0xb0, 0x01}, + {0x03, 0x01, 0xb1, 0x00}, {0x06, 0x01, 0xb1, 0x00}, + {0x0a, 0x01, 0xb1, 0x00}, {0x0f, 0x01, 0xb1, 0x00}, + {0x18, 0x01, 0xb1, 0x00}, {0x1f, 0x01, 0xb1, 0x00}, + {0x29, 0x01, 0xb1, 0x00}, {0x38, 0x01, 0xb1, 0x01} + }, + /* 115 */ + { + {0x03, 0x01, 0xb3, 0x00}, {0x06, 0x01, 0xb3, 0x00}, + {0x0a, 0x01, 0xb3, 0x00}, {0x0f, 0x01, 0xb3, 0x00}, + {0x18, 0x01, 0xb3, 0x00}, {0x1f, 0x01, 0xb3, 0x00}, + {0x29, 0x01, 0xb3, 0x00}, {0x38, 0x01, 0xb3, 0x01}, + {0x03, 0x01, 0xd1, 0x00}, {0x06, 0x01, 0xd1, 0x00}, + {0x0a, 0x01, 0xd1, 0x00}, {0x0f, 0x01, 0xd1, 0x00}, + {0x18, 0x01, 0xd1, 0x00}, {0x1f, 0x01, 0xd1, 0x00}, + {0x29, 0x01, 0xd1, 0x00}, {0x38, 0x01, 0xd1, 0x01} + }, + { + {0x02, 0x01, 0xd8, 0x00}, {0x09, 0x01, 0xd8, 0x00}, + {0x17, 0x01, 0xd8, 0x00}, {0x28, 0x01, 0xd8, 0x01}, + {0x02, 0x01, 0xd9, 0x00}, {0x09, 0x01, 0xd9, 0x00}, + {0x17, 0x01, 0xd9, 0x00}, {0x28, 0x01, 0xd9, 0x01}, + {0x02, 0x01, 0xe3, 0x00}, {0x09, 0x01, 0xe3, 0x00}, + {0x17, 0x01, 0xe3, 0x00}, {0x28, 0x01, 0xe3, 0x01}, + {0x02, 0x01, 0xe5, 0x00}, {0x09, 0x01, 0xe5, 0x00}, + {0x17, 0x01, 0xe5, 0x00}, {0x28, 0x01, 0xe5, 0x01} + }, + { + {0x03, 0x01, 0xd8, 0x00}, {0x06, 0x01, 0xd8, 0x00}, + {0x0a, 0x01, 0xd8, 0x00}, {0x0f, 0x01, 0xd8, 0x00}, + {0x18, 0x01, 0xd8, 0x00}, {0x1f, 0x01, 0xd8, 0x00}, + {0x29, 0x01, 0xd8, 0x00}, {0x38, 0x01, 0xd8, 0x01}, + {0x03, 0x01, 0xd9, 0x00}, {0x06, 0x01, 0xd9, 0x00}, + {0x0a, 0x01, 0xd9, 0x00}, {0x0f, 0x01, 0xd9, 0x00}, + {0x18, 0x01, 0xd9, 0x00}, {0x1f, 0x01, 0xd9, 0x00}, + {0x29, 0x01, 0xd9, 0x00}, {0x38, 0x01, 0xd9, 0x01} + }, + { + {0x03, 0x01, 0xe3, 0x00}, {0x06, 0x01, 0xe3, 0x00}, + {0x0a, 0x01, 0xe3, 0x00}, {0x0f, 0x01, 0xe3, 0x00}, + {0x18, 0x01, 0xe3, 0x00}, {0x1f, 0x01, 0xe3, 0x00}, + {0x29, 0x01, 0xe3, 0x00}, {0x38, 0x01, 0xe3, 0x01}, + {0x03, 0x01, 0xe5, 0x00}, {0x06, 0x01, 0xe5, 0x00}, + {0x0a, 0x01, 0xe5, 0x00}, {0x0f, 0x01, 0xe5, 0x00}, + {0x18, 0x01, 0xe5, 0x00}, {0x1f, 0x01, 0xe5, 0x00}, + {0x29, 0x01, 0xe5, 0x00}, {0x38, 0x01, 0xe5, 0x01} + }, + { + {0x01, 0x01, 0xe6, 0x00}, {0x16, 0x01, 0xe6, 0x01}, + {0x00, 0x01, 0x81, 0x01}, {0x00, 0x01, 0x84, 0x01}, + {0x00, 0x01, 0x85, 0x01}, {0x00, 0x01, 0x86, 0x01}, + {0x00, 0x01, 0x88, 0x01}, {0x00, 0x01, 0x92, 0x01}, + {0x00, 0x01, 0x9a, 0x01}, {0x00, 0x01, 0x9c, 0x01}, + {0x00, 0x01, 0xa0, 0x01}, {0x00, 0x01, 0xa3, 0x01}, + {0x00, 0x01, 0xa4, 0x01}, {0x00, 0x01, 0xa9, 0x01}, + {0x00, 0x01, 0xaa, 0x01}, {0x00, 0x01, 0xad, 0x01} + }, + /* 120 */ + { + {0x02, 0x01, 0xe6, 0x00}, {0x09, 0x01, 0xe6, 0x00}, + {0x17, 0x01, 0xe6, 0x00}, {0x28, 0x01, 0xe6, 0x01}, + {0x01, 0x01, 0x81, 0x00}, {0x16, 0x01, 0x81, 0x01}, + {0x01, 0x01, 0x84, 0x00}, {0x16, 0x01, 0x84, 0x01}, + {0x01, 0x01, 0x85, 0x00}, {0x16, 0x01, 0x85, 0x01}, + {0x01, 0x01, 0x86, 0x00}, {0x16, 0x01, 0x86, 0x01}, + {0x01, 0x01, 0x88, 0x00}, {0x16, 0x01, 0x88, 0x01}, + {0x01, 0x01, 0x92, 0x00}, {0x16, 0x01, 0x92, 0x01} + }, + { + {0x03, 0x01, 0xe6, 0x00}, {0x06, 0x01, 0xe6, 0x00}, + {0x0a, 0x01, 0xe6, 0x00}, {0x0f, 0x01, 0xe6, 0x00}, + {0x18, 0x01, 0xe6, 0x00}, {0x1f, 0x01, 0xe6, 0x00}, + {0x29, 0x01, 0xe6, 0x00}, {0x38, 0x01, 0xe6, 0x01}, + {0x02, 0x01, 0x81, 0x00}, {0x09, 0x01, 0x81, 0x00}, + {0x17, 0x01, 0x81, 0x00}, {0x28, 0x01, 0x81, 0x01}, + {0x02, 0x01, 0x84, 0x00}, {0x09, 0x01, 0x84, 0x00}, + {0x17, 0x01, 0x84, 0x00}, {0x28, 0x01, 0x84, 0x01} + }, + { + {0x03, 0x01, 0x81, 0x00}, {0x06, 0x01, 0x81, 0x00}, + {0x0a, 0x01, 0x81, 0x00}, {0x0f, 0x01, 0x81, 0x00}, + {0x18, 0x01, 0x81, 0x00}, {0x1f, 0x01, 0x81, 0x00}, + {0x29, 0x01, 0x81, 0x00}, {0x38, 0x01, 0x81, 0x01}, + {0x03, 0x01, 0x84, 0x00}, {0x06, 0x01, 0x84, 0x00}, + {0x0a, 0x01, 0x84, 0x00}, {0x0f, 0x01, 0x84, 0x00}, + {0x18, 0x01, 0x84, 0x00}, {0x1f, 0x01, 0x84, 0x00}, + {0x29, 0x01, 0x84, 0x00}, {0x38, 0x01, 0x84, 0x01} + }, + { + {0x02, 0x01, 0x85, 0x00}, {0x09, 0x01, 0x85, 0x00}, + {0x17, 0x01, 0x85, 0x00}, {0x28, 0x01, 0x85, 0x01}, + {0x02, 0x01, 0x86, 0x00}, {0x09, 0x01, 0x86, 0x00}, + {0x17, 0x01, 0x86, 0x00}, {0x28, 0x01, 0x86, 0x01}, + {0x02, 0x01, 0x88, 0x00}, {0x09, 0x01, 0x88, 0x00}, + {0x17, 0x01, 0x88, 0x00}, {0x28, 0x01, 0x88, 0x01}, + {0x02, 0x01, 0x92, 0x00}, {0x09, 0x01, 0x92, 0x00}, + {0x17, 0x01, 0x92, 0x00}, {0x28, 0x01, 0x92, 0x01} + }, + { + {0x03, 0x01, 0x85, 0x00}, {0x06, 0x01, 0x85, 0x00}, + {0x0a, 0x01, 0x85, 0x00}, {0x0f, 0x01, 0x85, 0x00}, + {0x18, 0x01, 0x85, 0x00}, {0x1f, 0x01, 0x85, 0x00}, + {0x29, 0x01, 0x85, 0x00}, {0x38, 0x01, 0x85, 0x01}, + {0x03, 0x01, 0x86, 0x00}, {0x06, 0x01, 0x86, 0x00}, + {0x0a, 0x01, 0x86, 0x00}, {0x0f, 0x01, 0x86, 0x00}, + {0x18, 0x01, 0x86, 0x00}, {0x1f, 0x01, 0x86, 0x00}, + {0x29, 0x01, 0x86, 0x00}, {0x38, 0x01, 0x86, 0x01} + }, + /* 125 */ + { + {0x03, 0x01, 0x88, 0x00}, {0x06, 0x01, 0x88, 0x00}, + {0x0a, 0x01, 0x88, 0x00}, {0x0f, 0x01, 0x88, 0x00}, + {0x18, 0x01, 0x88, 0x00}, {0x1f, 0x01, 0x88, 0x00}, + {0x29, 0x01, 0x88, 0x00}, {0x38, 0x01, 0x88, 0x01}, + {0x03, 0x01, 0x92, 0x00}, {0x06, 0x01, 0x92, 0x00}, + {0x0a, 0x01, 0x92, 0x00}, {0x0f, 0x01, 0x92, 0x00}, + {0x18, 0x01, 0x92, 0x00}, {0x1f, 0x01, 0x92, 0x00}, + {0x29, 0x01, 0x92, 0x00}, {0x38, 0x01, 0x92, 0x01} + }, + { + {0x01, 0x01, 0x9a, 0x00}, {0x16, 0x01, 0x9a, 0x01}, + {0x01, 0x01, 0x9c, 0x00}, {0x16, 0x01, 0x9c, 0x01}, + {0x01, 0x01, 0xa0, 0x00}, {0x16, 0x01, 0xa0, 0x01}, + {0x01, 0x01, 0xa3, 0x00}, {0x16, 0x01, 0xa3, 0x01}, + {0x01, 0x01, 0xa4, 0x00}, {0x16, 0x01, 0xa4, 0x01}, + {0x01, 0x01, 0xa9, 0x00}, {0x16, 0x01, 0xa9, 0x01}, + {0x01, 0x01, 0xaa, 0x00}, {0x16, 0x01, 0xaa, 0x01}, + {0x01, 0x01, 0xad, 0x00}, {0x16, 0x01, 0xad, 0x01} + }, + { + {0x02, 0x01, 0x9a, 0x00}, {0x09, 0x01, 0x9a, 0x00}, + {0x17, 0x01, 0x9a, 0x00}, {0x28, 0x01, 0x9a, 0x01}, + {0x02, 0x01, 0x9c, 0x00}, {0x09, 0x01, 0x9c, 0x00}, + {0x17, 0x01, 0x9c, 0x00}, {0x28, 0x01, 0x9c, 0x01}, + {0x02, 0x01, 0xa0, 0x00}, {0x09, 0x01, 0xa0, 0x00}, + {0x17, 0x01, 0xa0, 0x00}, {0x28, 0x01, 0xa0, 0x01}, + {0x02, 0x01, 0xa3, 0x00}, {0x09, 0x01, 0xa3, 0x00}, + {0x17, 0x01, 0xa3, 0x00}, {0x28, 0x01, 0xa3, 0x01} + }, + { + {0x03, 0x01, 0x9a, 0x00}, {0x06, 0x01, 0x9a, 0x00}, + {0x0a, 0x01, 0x9a, 0x00}, {0x0f, 0x01, 0x9a, 0x00}, + {0x18, 0x01, 0x9a, 0x00}, {0x1f, 0x01, 0x9a, 0x00}, + {0x29, 0x01, 0x9a, 0x00}, {0x38, 0x01, 0x9a, 0x01}, + {0x03, 0x01, 0x9c, 0x00}, {0x06, 0x01, 0x9c, 0x00}, + {0x0a, 0x01, 0x9c, 0x00}, {0x0f, 0x01, 0x9c, 0x00}, + {0x18, 0x01, 0x9c, 0x00}, {0x1f, 0x01, 0x9c, 0x00}, + {0x29, 0x01, 0x9c, 0x00}, {0x38, 0x01, 0x9c, 0x01} + }, + { + {0x03, 0x01, 0xa0, 0x00}, {0x06, 0x01, 0xa0, 0x00}, + {0x0a, 0x01, 0xa0, 0x00}, {0x0f, 0x01, 0xa0, 0x00}, + {0x18, 0x01, 0xa0, 0x00}, {0x1f, 0x01, 0xa0, 0x00}, + {0x29, 0x01, 0xa0, 0x00}, {0x38, 0x01, 0xa0, 0x01}, + {0x03, 0x01, 0xa3, 0x00}, {0x06, 0x01, 0xa3, 0x00}, + {0x0a, 0x01, 0xa3, 0x00}, {0x0f, 0x01, 0xa3, 0x00}, + {0x18, 0x01, 0xa3, 0x00}, {0x1f, 0x01, 0xa3, 0x00}, + {0x29, 0x01, 0xa3, 0x00}, {0x38, 0x01, 0xa3, 0x01} + }, + /* 130 */ + { + {0x02, 0x01, 0xa4, 0x00}, {0x09, 0x01, 0xa4, 0x00}, + {0x17, 0x01, 0xa4, 0x00}, {0x28, 0x01, 0xa4, 0x01}, + {0x02, 0x01, 0xa9, 0x00}, {0x09, 0x01, 0xa9, 0x00}, + {0x17, 0x01, 0xa9, 0x00}, {0x28, 0x01, 0xa9, 0x01}, + {0x02, 0x01, 0xaa, 0x00}, {0x09, 0x01, 0xaa, 0x00}, + {0x17, 0x01, 0xaa, 0x00}, {0x28, 0x01, 0xaa, 0x01}, + {0x02, 0x01, 0xad, 0x00}, {0x09, 0x01, 0xad, 0x00}, + {0x17, 0x01, 0xad, 0x00}, {0x28, 0x01, 0xad, 0x01} + }, + { + {0x03, 0x01, 0xa4, 0x00}, {0x06, 0x01, 0xa4, 0x00}, + {0x0a, 0x01, 0xa4, 0x00}, {0x0f, 0x01, 0xa4, 0x00}, + {0x18, 0x01, 0xa4, 0x00}, {0x1f, 0x01, 0xa4, 0x00}, + {0x29, 0x01, 0xa4, 0x00}, {0x38, 0x01, 0xa4, 0x01}, + {0x03, 0x01, 0xa9, 0x00}, {0x06, 0x01, 0xa9, 0x00}, + {0x0a, 0x01, 0xa9, 0x00}, {0x0f, 0x01, 0xa9, 0x00}, + {0x18, 0x01, 0xa9, 0x00}, {0x1f, 0x01, 0xa9, 0x00}, + {0x29, 0x01, 0xa9, 0x00}, {0x38, 0x01, 0xa9, 0x01} + }, + { + {0x03, 0x01, 0xaa, 0x00}, {0x06, 0x01, 0xaa, 0x00}, + {0x0a, 0x01, 0xaa, 0x00}, {0x0f, 0x01, 0xaa, 0x00}, + {0x18, 0x01, 0xaa, 0x00}, {0x1f, 0x01, 0xaa, 0x00}, + {0x29, 0x01, 0xaa, 0x00}, {0x38, 0x01, 0xaa, 0x01}, + {0x03, 0x01, 0xad, 0x00}, {0x06, 0x01, 0xad, 0x00}, + {0x0a, 0x01, 0xad, 0x00}, {0x0f, 0x01, 0xad, 0x00}, + {0x18, 0x01, 0xad, 0x00}, {0x1f, 0x01, 0xad, 0x00}, + {0x29, 0x01, 0xad, 0x00}, {0x38, 0x01, 0xad, 0x01} + }, + { + {0x89, 0x00, 0x00, 0x00}, {0x8a, 0x00, 0x00, 0x00}, + {0x8c, 0x00, 0x00, 0x00}, {0x8d, 0x00, 0x00, 0x00}, + {0x90, 0x00, 0x00, 0x00}, {0x91, 0x00, 0x00, 0x00}, + {0x93, 0x00, 0x00, 0x00}, {0x96, 0x00, 0x00, 0x00}, + {0x9c, 0x00, 0x00, 0x00}, {0x9f, 0x00, 0x00, 0x00}, + {0xa3, 0x00, 0x00, 0x00}, {0xa6, 0x00, 0x00, 0x00}, + {0xab, 0x00, 0x00, 0x00}, {0xae, 0x00, 0x00, 0x00}, + {0xb5, 0x00, 0x00, 0x00}, {0xbe, 0x00, 0x00, 0x01} + }, + { + {0x00, 0x01, 0xb2, 0x01}, {0x00, 0x01, 0xb5, 0x01}, + {0x00, 0x01, 0xb9, 0x01}, {0x00, 0x01, 0xba, 0x01}, + {0x00, 0x01, 0xbb, 0x01}, {0x00, 0x01, 0xbd, 0x01}, + {0x00, 0x01, 0xbe, 0x01}, {0x00, 0x01, 0xc4, 0x01}, + {0x00, 0x01, 0xc6, 0x01}, {0x00, 0x01, 0xe4, 0x01}, + {0x00, 0x01, 0xe8, 0x01}, {0x00, 0x01, 0xe9, 0x01}, + {0x94, 0x00, 0x00, 0x00}, {0x95, 0x00, 0x00, 0x00}, + {0x97, 0x00, 0x00, 0x00}, {0x98, 0x00, 0x00, 0x00} + }, + /* 135 */ + { + {0x01, 0x01, 0xb2, 0x00}, {0x16, 0x01, 0xb2, 0x01}, + {0x01, 0x01, 0xb5, 0x00}, {0x16, 0x01, 0xb5, 0x01}, + {0x01, 0x01, 0xb9, 0x00}, {0x16, 0x01, 0xb9, 0x01}, + {0x01, 0x01, 0xba, 0x00}, {0x16, 0x01, 0xba, 0x01}, + {0x01, 0x01, 0xbb, 0x00}, {0x16, 0x01, 0xbb, 0x01}, + {0x01, 0x01, 0xbd, 0x00}, {0x16, 0x01, 0xbd, 0x01}, + {0x01, 0x01, 0xbe, 0x00}, {0x16, 0x01, 0xbe, 0x01}, + {0x01, 0x01, 0xc4, 0x00}, {0x16, 0x01, 0xc4, 0x01} + }, + { + {0x02, 0x01, 0xb2, 0x00}, {0x09, 0x01, 0xb2, 0x00}, + {0x17, 0x01, 0xb2, 0x00}, {0x28, 0x01, 0xb2, 0x01}, + {0x02, 0x01, 0xb5, 0x00}, {0x09, 0x01, 0xb5, 0x00}, + {0x17, 0x01, 0xb5, 0x00}, {0x28, 0x01, 0xb5, 0x01}, + {0x02, 0x01, 0xb9, 0x00}, {0x09, 0x01, 0xb9, 0x00}, + {0x17, 0x01, 0xb9, 0x00}, {0x28, 0x01, 0xb9, 0x01}, + {0x02, 0x01, 0xba, 0x00}, {0x09, 0x01, 0xba, 0x00}, + {0x17, 0x01, 0xba, 0x00}, {0x28, 0x01, 0xba, 0x01} + }, + { + {0x03, 0x01, 0xb2, 0x00}, {0x06, 0x01, 0xb2, 0x00}, + {0x0a, 0x01, 0xb2, 0x00}, {0x0f, 0x01, 0xb2, 0x00}, + {0x18, 0x01, 0xb2, 0x00}, {0x1f, 0x01, 0xb2, 0x00}, + {0x29, 0x01, 0xb2, 0x00}, {0x38, 0x01, 0xb2, 0x01}, + {0x03, 0x01, 0xb5, 0x00}, {0x06, 0x01, 0xb5, 0x00}, + {0x0a, 0x01, 0xb5, 0x00}, {0x0f, 0x01, 0xb5, 0x00}, + {0x18, 0x01, 0xb5, 0x00}, {0x1f, 0x01, 0xb5, 0x00}, + {0x29, 0x01, 0xb5, 0x00}, {0x38, 0x01, 0xb5, 0x01} + }, + { + {0x03, 0x01, 0xb9, 0x00}, {0x06, 0x01, 0xb9, 0x00}, + {0x0a, 0x01, 0xb9, 0x00}, {0x0f, 0x01, 0xb9, 0x00}, + {0x18, 0x01, 0xb9, 0x00}, {0x1f, 0x01, 0xb9, 0x00}, + {0x29, 0x01, 0xb9, 0x00}, {0x38, 0x01, 0xb9, 0x01}, + {0x03, 0x01, 0xba, 0x00}, {0x06, 0x01, 0xba, 0x00}, + {0x0a, 0x01, 0xba, 0x00}, {0x0f, 0x01, 0xba, 0x00}, + {0x18, 0x01, 0xba, 0x00}, {0x1f, 0x01, 0xba, 0x00}, + {0x29, 0x01, 0xba, 0x00}, {0x38, 0x01, 0xba, 0x01} + }, + { + {0x02, 0x01, 0xbb, 0x00}, {0x09, 0x01, 0xbb, 0x00}, + {0x17, 0x01, 0xbb, 0x00}, {0x28, 0x01, 0xbb, 0x01}, + {0x02, 0x01, 0xbd, 0x00}, {0x09, 0x01, 0xbd, 0x00}, + {0x17, 0x01, 0xbd, 0x00}, {0x28, 0x01, 0xbd, 0x01}, + {0x02, 0x01, 0xbe, 0x00}, {0x09, 0x01, 0xbe, 0x00}, + {0x17, 0x01, 0xbe, 0x00}, {0x28, 0x01, 0xbe, 0x01}, + {0x02, 0x01, 0xc4, 0x00}, {0x09, 0x01, 0xc4, 0x00}, + {0x17, 0x01, 0xc4, 0x00}, {0x28, 0x01, 0xc4, 0x01} + }, + /* 140 */ + { + {0x03, 0x01, 0xbb, 0x00}, {0x06, 0x01, 0xbb, 0x00}, + {0x0a, 0x01, 0xbb, 0x00}, {0x0f, 0x01, 0xbb, 0x00}, + {0x18, 0x01, 0xbb, 0x00}, {0x1f, 0x01, 0xbb, 0x00}, + {0x29, 0x01, 0xbb, 0x00}, {0x38, 0x01, 0xbb, 0x01}, + {0x03, 0x01, 0xbd, 0x00}, {0x06, 0x01, 0xbd, 0x00}, + {0x0a, 0x01, 0xbd, 0x00}, {0x0f, 0x01, 0xbd, 0x00}, + {0x18, 0x01, 0xbd, 0x00}, {0x1f, 0x01, 0xbd, 0x00}, + {0x29, 0x01, 0xbd, 0x00}, {0x38, 0x01, 0xbd, 0x01} + }, + { + {0x03, 0x01, 0xbe, 0x00}, {0x06, 0x01, 0xbe, 0x00}, + {0x0a, 0x01, 0xbe, 0x00}, {0x0f, 0x01, 0xbe, 0x00}, + {0x18, 0x01, 0xbe, 0x00}, {0x1f, 0x01, 0xbe, 0x00}, + {0x29, 0x01, 0xbe, 0x00}, {0x38, 0x01, 0xbe, 0x01}, + {0x03, 0x01, 0xc4, 0x00}, {0x06, 0x01, 0xc4, 0x00}, + {0x0a, 0x01, 0xc4, 0x00}, {0x0f, 0x01, 0xc4, 0x00}, + {0x18, 0x01, 0xc4, 0x00}, {0x1f, 0x01, 0xc4, 0x00}, + {0x29, 0x01, 0xc4, 0x00}, {0x38, 0x01, 0xc4, 0x01} + }, + { + {0x01, 0x01, 0xc6, 0x00}, {0x16, 0x01, 0xc6, 0x01}, + {0x01, 0x01, 0xe4, 0x00}, {0x16, 0x01, 0xe4, 0x01}, + {0x01, 0x01, 0xe8, 0x00}, {0x16, 0x01, 0xe8, 0x01}, + {0x01, 0x01, 0xe9, 0x00}, {0x16, 0x01, 0xe9, 0x01}, + {0x00, 0x01, 0x01, 0x01}, {0x00, 0x01, 0x87, 0x01}, + {0x00, 0x01, 0x89, 0x01}, {0x00, 0x01, 0x8a, 0x01}, + {0x00, 0x01, 0x8b, 0x01}, {0x00, 0x01, 0x8c, 0x01}, + {0x00, 0x01, 0x8d, 0x01}, {0x00, 0x01, 0x8f, 0x01} + }, + { + {0x02, 0x01, 0xc6, 0x00}, {0x09, 0x01, 0xc6, 0x00}, + {0x17, 0x01, 0xc6, 0x00}, {0x28, 0x01, 0xc6, 0x01}, + {0x02, 0x01, 0xe4, 0x00}, {0x09, 0x01, 0xe4, 0x00}, + {0x17, 0x01, 0xe4, 0x00}, {0x28, 0x01, 0xe4, 0x01}, + {0x02, 0x01, 0xe8, 0x00}, {0x09, 0x01, 0xe8, 0x00}, + {0x17, 0x01, 0xe8, 0x00}, {0x28, 0x01, 0xe8, 0x01}, + {0x02, 0x01, 0xe9, 0x00}, {0x09, 0x01, 0xe9, 0x00}, + {0x17, 0x01, 0xe9, 0x00}, {0x28, 0x01, 0xe9, 0x01} + }, + { + {0x03, 0x01, 0xc6, 0x00}, {0x06, 0x01, 0xc6, 0x00}, + {0x0a, 0x01, 0xc6, 0x00}, {0x0f, 0x01, 0xc6, 0x00}, + {0x18, 0x01, 0xc6, 0x00}, {0x1f, 0x01, 0xc6, 0x00}, + {0x29, 0x01, 0xc6, 0x00}, {0x38, 0x01, 0xc6, 0x01}, + {0x03, 0x01, 0xe4, 0x00}, {0x06, 0x01, 0xe4, 0x00}, + {0x0a, 0x01, 0xe4, 0x00}, {0x0f, 0x01, 0xe4, 0x00}, + {0x18, 0x01, 0xe4, 0x00}, {0x1f, 0x01, 0xe4, 0x00}, + {0x29, 0x01, 0xe4, 0x00}, {0x38, 0x01, 0xe4, 0x01} + }, + /* 145 */ + { + {0x03, 0x01, 0xe8, 0x00}, {0x06, 0x01, 0xe8, 0x00}, + {0x0a, 0x01, 0xe8, 0x00}, {0x0f, 0x01, 0xe8, 0x00}, + {0x18, 0x01, 0xe8, 0x00}, {0x1f, 0x01, 0xe8, 0x00}, + {0x29, 0x01, 0xe8, 0x00}, {0x38, 0x01, 0xe8, 0x01}, + {0x03, 0x01, 0xe9, 0x00}, {0x06, 0x01, 0xe9, 0x00}, + {0x0a, 0x01, 0xe9, 0x00}, {0x0f, 0x01, 0xe9, 0x00}, + {0x18, 0x01, 0xe9, 0x00}, {0x1f, 0x01, 0xe9, 0x00}, + {0x29, 0x01, 0xe9, 0x00}, {0x38, 0x01, 0xe9, 0x01} + }, + { + {0x01, 0x01, 0x01, 0x00}, {0x16, 0x01, 0x01, 0x01}, + {0x01, 0x01, 0x87, 0x00}, {0x16, 0x01, 0x87, 0x01}, + {0x01, 0x01, 0x89, 0x00}, {0x16, 0x01, 0x89, 0x01}, + {0x01, 0x01, 0x8a, 0x00}, {0x16, 0x01, 0x8a, 0x01}, + {0x01, 0x01, 0x8b, 0x00}, {0x16, 0x01, 0x8b, 0x01}, + {0x01, 0x01, 0x8c, 0x00}, {0x16, 0x01, 0x8c, 0x01}, + {0x01, 0x01, 0x8d, 0x00}, {0x16, 0x01, 0x8d, 0x01}, + {0x01, 0x01, 0x8f, 0x00}, {0x16, 0x01, 0x8f, 0x01} + }, + { + {0x02, 0x01, 0x01, 0x00}, {0x09, 0x01, 0x01, 0x00}, + {0x17, 0x01, 0x01, 0x00}, {0x28, 0x01, 0x01, 0x01}, + {0x02, 0x01, 0x87, 0x00}, {0x09, 0x01, 0x87, 0x00}, + {0x17, 0x01, 0x87, 0x00}, {0x28, 0x01, 0x87, 0x01}, + {0x02, 0x01, 0x89, 0x00}, {0x09, 0x01, 0x89, 0x00}, + {0x17, 0x01, 0x89, 0x00}, {0x28, 0x01, 0x89, 0x01}, + {0x02, 0x01, 0x8a, 0x00}, {0x09, 0x01, 0x8a, 0x00}, + {0x17, 0x01, 0x8a, 0x00}, {0x28, 0x01, 0x8a, 0x01} + }, + { + {0x03, 0x01, 0x01, 0x00}, {0x06, 0x01, 0x01, 0x00}, + {0x0a, 0x01, 0x01, 0x00}, {0x0f, 0x01, 0x01, 0x00}, + {0x18, 0x01, 0x01, 0x00}, {0x1f, 0x01, 0x01, 0x00}, + {0x29, 0x01, 0x01, 0x00}, {0x38, 0x01, 0x01, 0x01}, + {0x03, 0x01, 0x87, 0x00}, {0x06, 0x01, 0x87, 0x00}, + {0x0a, 0x01, 0x87, 0x00}, {0x0f, 0x01, 0x87, 0x00}, + {0x18, 0x01, 0x87, 0x00}, {0x1f, 0x01, 0x87, 0x00}, + {0x29, 0x01, 0x87, 0x00}, {0x38, 0x01, 0x87, 0x01} + }, + { + {0x03, 0x01, 0x89, 0x00}, {0x06, 0x01, 0x89, 0x00}, + {0x0a, 0x01, 0x89, 0x00}, {0x0f, 0x01, 0x89, 0x00}, + {0x18, 0x01, 0x89, 0x00}, {0x1f, 0x01, 0x89, 0x00}, + {0x29, 0x01, 0x89, 0x00}, {0x38, 0x01, 0x89, 0x01}, + {0x03, 0x01, 0x8a, 0x00}, {0x06, 0x01, 0x8a, 0x00}, + {0x0a, 0x01, 0x8a, 0x00}, {0x0f, 0x01, 0x8a, 0x00}, + {0x18, 0x01, 0x8a, 0x00}, {0x1f, 0x01, 0x8a, 0x00}, + {0x29, 0x01, 0x8a, 0x00}, {0x38, 0x01, 0x8a, 0x01} + }, + /* 150 */ + { + {0x02, 0x01, 0x8b, 0x00}, {0x09, 0x01, 0x8b, 0x00}, + {0x17, 0x01, 0x8b, 0x00}, {0x28, 0x01, 0x8b, 0x01}, + {0x02, 0x01, 0x8c, 0x00}, {0x09, 0x01, 0x8c, 0x00}, + {0x17, 0x01, 0x8c, 0x00}, {0x28, 0x01, 0x8c, 0x01}, + {0x02, 0x01, 0x8d, 0x00}, {0x09, 0x01, 0x8d, 0x00}, + {0x17, 0x01, 0x8d, 0x00}, {0x28, 0x01, 0x8d, 0x01}, + {0x02, 0x01, 0x8f, 0x00}, {0x09, 0x01, 0x8f, 0x00}, + {0x17, 0x01, 0x8f, 0x00}, {0x28, 0x01, 0x8f, 0x01} + }, + { + {0x03, 0x01, 0x8b, 0x00}, {0x06, 0x01, 0x8b, 0x00}, + {0x0a, 0x01, 0x8b, 0x00}, {0x0f, 0x01, 0x8b, 0x00}, + {0x18, 0x01, 0x8b, 0x00}, {0x1f, 0x01, 0x8b, 0x00}, + {0x29, 0x01, 0x8b, 0x00}, {0x38, 0x01, 0x8b, 0x01}, + {0x03, 0x01, 0x8c, 0x00}, {0x06, 0x01, 0x8c, 0x00}, + {0x0a, 0x01, 0x8c, 0x00}, {0x0f, 0x01, 0x8c, 0x00}, + {0x18, 0x01, 0x8c, 0x00}, {0x1f, 0x01, 0x8c, 0x00}, + {0x29, 0x01, 0x8c, 0x00}, {0x38, 0x01, 0x8c, 0x01} + }, + { + {0x03, 0x01, 0x8d, 0x00}, {0x06, 0x01, 0x8d, 0x00}, + {0x0a, 0x01, 0x8d, 0x00}, {0x0f, 0x01, 0x8d, 0x00}, + {0x18, 0x01, 0x8d, 0x00}, {0x1f, 0x01, 0x8d, 0x00}, + {0x29, 0x01, 0x8d, 0x00}, {0x38, 0x01, 0x8d, 0x01}, + {0x03, 0x01, 0x8f, 0x00}, {0x06, 0x01, 0x8f, 0x00}, + {0x0a, 0x01, 0x8f, 0x00}, {0x0f, 0x01, 0x8f, 0x00}, + {0x18, 0x01, 0x8f, 0x00}, {0x1f, 0x01, 0x8f, 0x00}, + {0x29, 0x01, 0x8f, 0x00}, {0x38, 0x01, 0x8f, 0x01} + }, + { + {0x9d, 0x00, 0x00, 0x00}, {0x9e, 0x00, 0x00, 0x00}, + {0xa0, 0x00, 0x00, 0x00}, {0xa1, 0x00, 0x00, 0x00}, + {0xa4, 0x00, 0x00, 0x00}, {0xa5, 0x00, 0x00, 0x00}, + {0xa7, 0x00, 0x00, 0x00}, {0xa8, 0x00, 0x00, 0x00}, + {0xac, 0x00, 0x00, 0x00}, {0xad, 0x00, 0x00, 0x00}, + {0xaf, 0x00, 0x00, 0x00}, {0xb1, 0x00, 0x00, 0x00}, + {0xb6, 0x00, 0x00, 0x00}, {0xb9, 0x00, 0x00, 0x00}, + {0xbf, 0x00, 0x00, 0x00}, {0xcf, 0x00, 0x00, 0x01} + }, + { + {0x00, 0x01, 0x93, 0x01}, {0x00, 0x01, 0x95, 0x01}, + {0x00, 0x01, 0x96, 0x01}, {0x00, 0x01, 0x97, 0x01}, + {0x00, 0x01, 0x98, 0x01}, {0x00, 0x01, 0x9b, 0x01}, + {0x00, 0x01, 0x9d, 0x01}, {0x00, 0x01, 0x9e, 0x01}, + {0x00, 0x01, 0xa5, 0x01}, {0x00, 0x01, 0xa6, 0x01}, + {0x00, 0x01, 0xa8, 0x01}, {0x00, 0x01, 0xae, 0x01}, + {0x00, 0x01, 0xaf, 0x01}, {0x00, 0x01, 0xb4, 0x01}, + {0x00, 0x01, 0xb6, 0x01}, {0x00, 0x01, 0xb7, 0x01} + }, + /* 155 */ + { + {0x01, 0x01, 0x93, 0x00}, {0x16, 0x01, 0x93, 0x01}, + {0x01, 0x01, 0x95, 0x00}, {0x16, 0x01, 0x95, 0x01}, + {0x01, 0x01, 0x96, 0x00}, {0x16, 0x01, 0x96, 0x01}, + {0x01, 0x01, 0x97, 0x00}, {0x16, 0x01, 0x97, 0x01}, + {0x01, 0x01, 0x98, 0x00}, {0x16, 0x01, 0x98, 0x01}, + {0x01, 0x01, 0x9b, 0x00}, {0x16, 0x01, 0x9b, 0x01}, + {0x01, 0x01, 0x9d, 0x00}, {0x16, 0x01, 0x9d, 0x01}, + {0x01, 0x01, 0x9e, 0x00}, {0x16, 0x01, 0x9e, 0x01} + }, + { + {0x02, 0x01, 0x93, 0x00}, {0x09, 0x01, 0x93, 0x00}, + {0x17, 0x01, 0x93, 0x00}, {0x28, 0x01, 0x93, 0x01}, + {0x02, 0x01, 0x95, 0x00}, {0x09, 0x01, 0x95, 0x00}, + {0x17, 0x01, 0x95, 0x00}, {0x28, 0x01, 0x95, 0x01}, + {0x02, 0x01, 0x96, 0x00}, {0x09, 0x01, 0x96, 0x00}, + {0x17, 0x01, 0x96, 0x00}, {0x28, 0x01, 0x96, 0x01}, + {0x02, 0x01, 0x97, 0x00}, {0x09, 0x01, 0x97, 0x00}, + {0x17, 0x01, 0x97, 0x00}, {0x28, 0x01, 0x97, 0x01} + }, + { + {0x03, 0x01, 0x93, 0x00}, {0x06, 0x01, 0x93, 0x00}, + {0x0a, 0x01, 0x93, 0x00}, {0x0f, 0x01, 0x93, 0x00}, + {0x18, 0x01, 0x93, 0x00}, {0x1f, 0x01, 0x93, 0x00}, + {0x29, 0x01, 0x93, 0x00}, {0x38, 0x01, 0x93, 0x01}, + {0x03, 0x01, 0x95, 0x00}, {0x06, 0x01, 0x95, 0x00}, + {0x0a, 0x01, 0x95, 0x00}, {0x0f, 0x01, 0x95, 0x00}, + {0x18, 0x01, 0x95, 0x00}, {0x1f, 0x01, 0x95, 0x00}, + {0x29, 0x01, 0x95, 0x00}, {0x38, 0x01, 0x95, 0x01} + }, + { + {0x03, 0x01, 0x96, 0x00}, {0x06, 0x01, 0x96, 0x00}, + {0x0a, 0x01, 0x96, 0x00}, {0x0f, 0x01, 0x96, 0x00}, + {0x18, 0x01, 0x96, 0x00}, {0x1f, 0x01, 0x96, 0x00}, + {0x29, 0x01, 0x96, 0x00}, {0x38, 0x01, 0x96, 0x01}, + {0x03, 0x01, 0x97, 0x00}, {0x06, 0x01, 0x97, 0x00}, + {0x0a, 0x01, 0x97, 0x00}, {0x0f, 0x01, 0x97, 0x00}, + {0x18, 0x01, 0x97, 0x00}, {0x1f, 0x01, 0x97, 0x00}, + {0x29, 0x01, 0x97, 0x00}, {0x38, 0x01, 0x97, 0x01} + }, + { + {0x02, 0x01, 0x98, 0x00}, {0x09, 0x01, 0x98, 0x00}, + {0x17, 0x01, 0x98, 0x00}, {0x28, 0x01, 0x98, 0x01}, + {0x02, 0x01, 0x9b, 0x00}, {0x09, 0x01, 0x9b, 0x00}, + {0x17, 0x01, 0x9b, 0x00}, {0x28, 0x01, 0x9b, 0x01}, + {0x02, 0x01, 0x9d, 0x00}, {0x09, 0x01, 0x9d, 0x00}, + {0x17, 0x01, 0x9d, 0x00}, {0x28, 0x01, 0x9d, 0x01}, + {0x02, 0x01, 0x9e, 0x00}, {0x09, 0x01, 0x9e, 0x00}, + {0x17, 0x01, 0x9e, 0x00}, {0x28, 0x01, 0x9e, 0x01} + }, + /* 160 */ + { + {0x03, 0x01, 0x98, 0x00}, {0x06, 0x01, 0x98, 0x00}, + {0x0a, 0x01, 0x98, 0x00}, {0x0f, 0x01, 0x98, 0x00}, + {0x18, 0x01, 0x98, 0x00}, {0x1f, 0x01, 0x98, 0x00}, + {0x29, 0x01, 0x98, 0x00}, {0x38, 0x01, 0x98, 0x01}, + {0x03, 0x01, 0x9b, 0x00}, {0x06, 0x01, 0x9b, 0x00}, + {0x0a, 0x01, 0x9b, 0x00}, {0x0f, 0x01, 0x9b, 0x00}, + {0x18, 0x01, 0x9b, 0x00}, {0x1f, 0x01, 0x9b, 0x00}, + {0x29, 0x01, 0x9b, 0x00}, {0x38, 0x01, 0x9b, 0x01} + }, + { + {0x03, 0x01, 0x9d, 0x00}, {0x06, 0x01, 0x9d, 0x00}, + {0x0a, 0x01, 0x9d, 0x00}, {0x0f, 0x01, 0x9d, 0x00}, + {0x18, 0x01, 0x9d, 0x00}, {0x1f, 0x01, 0x9d, 0x00}, + {0x29, 0x01, 0x9d, 0x00}, {0x38, 0x01, 0x9d, 0x01}, + {0x03, 0x01, 0x9e, 0x00}, {0x06, 0x01, 0x9e, 0x00}, + {0x0a, 0x01, 0x9e, 0x00}, {0x0f, 0x01, 0x9e, 0x00}, + {0x18, 0x01, 0x9e, 0x00}, {0x1f, 0x01, 0x9e, 0x00}, + {0x29, 0x01, 0x9e, 0x00}, {0x38, 0x01, 0x9e, 0x01} + }, + { + {0x01, 0x01, 0xa5, 0x00}, {0x16, 0x01, 0xa5, 0x01}, + {0x01, 0x01, 0xa6, 0x00}, {0x16, 0x01, 0xa6, 0x01}, + {0x01, 0x01, 0xa8, 0x00}, {0x16, 0x01, 0xa8, 0x01}, + {0x01, 0x01, 0xae, 0x00}, {0x16, 0x01, 0xae, 0x01}, + {0x01, 0x01, 0xaf, 0x00}, {0x16, 0x01, 0xaf, 0x01}, + {0x01, 0x01, 0xb4, 0x00}, {0x16, 0x01, 0xb4, 0x01}, + {0x01, 0x01, 0xb6, 0x00}, {0x16, 0x01, 0xb6, 0x01}, + {0x01, 0x01, 0xb7, 0x00}, {0x16, 0x01, 0xb7, 0x01} + }, + { + {0x02, 0x01, 0xa5, 0x00}, {0x09, 0x01, 0xa5, 0x00}, + {0x17, 0x01, 0xa5, 0x00}, {0x28, 0x01, 0xa5, 0x01}, + {0x02, 0x01, 0xa6, 0x00}, {0x09, 0x01, 0xa6, 0x00}, + {0x17, 0x01, 0xa6, 0x00}, {0x28, 0x01, 0xa6, 0x01}, + {0x02, 0x01, 0xa8, 0x00}, {0x09, 0x01, 0xa8, 0x00}, + {0x17, 0x01, 0xa8, 0x00}, {0x28, 0x01, 0xa8, 0x01}, + {0x02, 0x01, 0xae, 0x00}, {0x09, 0x01, 0xae, 0x00}, + {0x17, 0x01, 0xae, 0x00}, {0x28, 0x01, 0xae, 0x01} + }, + { + {0x03, 0x01, 0xa5, 0x00}, {0x06, 0x01, 0xa5, 0x00}, + {0x0a, 0x01, 0xa5, 0x00}, {0x0f, 0x01, 0xa5, 0x00}, + {0x18, 0x01, 0xa5, 0x00}, {0x1f, 0x01, 0xa5, 0x00}, + {0x29, 0x01, 0xa5, 0x00}, {0x38, 0x01, 0xa5, 0x01}, + {0x03, 0x01, 0xa6, 0x00}, {0x06, 0x01, 0xa6, 0x00}, + {0x0a, 0x01, 0xa6, 0x00}, {0x0f, 0x01, 0xa6, 0x00}, + {0x18, 0x01, 0xa6, 0x00}, {0x1f, 0x01, 0xa6, 0x00}, + {0x29, 0x01, 0xa6, 0x00}, {0x38, 0x01, 0xa6, 0x01} + }, + /* 165 */ + { + {0x03, 0x01, 0xa8, 0x00}, {0x06, 0x01, 0xa8, 0x00}, + {0x0a, 0x01, 0xa8, 0x00}, {0x0f, 0x01, 0xa8, 0x00}, + {0x18, 0x01, 0xa8, 0x00}, {0x1f, 0x01, 0xa8, 0x00}, + {0x29, 0x01, 0xa8, 0x00}, {0x38, 0x01, 0xa8, 0x01}, + {0x03, 0x01, 0xae, 0x00}, {0x06, 0x01, 0xae, 0x00}, + {0x0a, 0x01, 0xae, 0x00}, {0x0f, 0x01, 0xae, 0x00}, + {0x18, 0x01, 0xae, 0x00}, {0x1f, 0x01, 0xae, 0x00}, + {0x29, 0x01, 0xae, 0x00}, {0x38, 0x01, 0xae, 0x01} + }, + { + {0x02, 0x01, 0xaf, 0x00}, {0x09, 0x01, 0xaf, 0x00}, + {0x17, 0x01, 0xaf, 0x00}, {0x28, 0x01, 0xaf, 0x01}, + {0x02, 0x01, 0xb4, 0x00}, {0x09, 0x01, 0xb4, 0x00}, + {0x17, 0x01, 0xb4, 0x00}, {0x28, 0x01, 0xb4, 0x01}, + {0x02, 0x01, 0xb6, 0x00}, {0x09, 0x01, 0xb6, 0x00}, + {0x17, 0x01, 0xb6, 0x00}, {0x28, 0x01, 0xb6, 0x01}, + {0x02, 0x01, 0xb7, 0x00}, {0x09, 0x01, 0xb7, 0x00}, + {0x17, 0x01, 0xb7, 0x00}, {0x28, 0x01, 0xb7, 0x01} + }, + { + {0x03, 0x01, 0xaf, 0x00}, {0x06, 0x01, 0xaf, 0x00}, + {0x0a, 0x01, 0xaf, 0x00}, {0x0f, 0x01, 0xaf, 0x00}, + {0x18, 0x01, 0xaf, 0x00}, {0x1f, 0x01, 0xaf, 0x00}, + {0x29, 0x01, 0xaf, 0x00}, {0x38, 0x01, 0xaf, 0x01}, + {0x03, 0x01, 0xb4, 0x00}, {0x06, 0x01, 0xb4, 0x00}, + {0x0a, 0x01, 0xb4, 0x00}, {0x0f, 0x01, 0xb4, 0x00}, + {0x18, 0x01, 0xb4, 0x00}, {0x1f, 0x01, 0xb4, 0x00}, + {0x29, 0x01, 0xb4, 0x00}, {0x38, 0x01, 0xb4, 0x01} + }, + { + {0x03, 0x01, 0xb6, 0x00}, {0x06, 0x01, 0xb6, 0x00}, + {0x0a, 0x01, 0xb6, 0x00}, {0x0f, 0x01, 0xb6, 0x00}, + {0x18, 0x01, 0xb6, 0x00}, {0x1f, 0x01, 0xb6, 0x00}, + {0x29, 0x01, 0xb6, 0x00}, {0x38, 0x01, 0xb6, 0x01}, + {0x03, 0x01, 0xb7, 0x00}, {0x06, 0x01, 0xb7, 0x00}, + {0x0a, 0x01, 0xb7, 0x00}, {0x0f, 0x01, 0xb7, 0x00}, + {0x18, 0x01, 0xb7, 0x00}, {0x1f, 0x01, 0xb7, 0x00}, + {0x29, 0x01, 0xb7, 0x00}, {0x38, 0x01, 0xb7, 0x01} + }, + { + {0x00, 0x01, 0xbc, 0x01}, {0x00, 0x01, 0xbf, 0x01}, + {0x00, 0x01, 0xc5, 0x01}, {0x00, 0x01, 0xe7, 0x01}, + {0x00, 0x01, 0xef, 0x01}, {0xb0, 0x00, 0x00, 0x00}, + {0xb2, 0x00, 0x00, 0x00}, {0xb3, 0x00, 0x00, 0x00}, + {0xb7, 0x00, 0x00, 0x00}, {0xb8, 0x00, 0x00, 0x00}, + {0xba, 0x00, 0x00, 0x00}, {0xbb, 0x00, 0x00, 0x00}, + {0xc0, 0x00, 0x00, 0x00}, {0xc7, 0x00, 0x00, 0x00}, + {0xd0, 0x00, 0x00, 0x00}, {0xdf, 0x00, 0x00, 0x01} + }, + /* 170 */ + { + {0x01, 0x01, 0xbc, 0x00}, {0x16, 0x01, 0xbc, 0x01}, + {0x01, 0x01, 0xbf, 0x00}, {0x16, 0x01, 0xbf, 0x01}, + {0x01, 0x01, 0xc5, 0x00}, {0x16, 0x01, 0xc5, 0x01}, + {0x01, 0x01, 0xe7, 0x00}, {0x16, 0x01, 0xe7, 0x01}, + {0x01, 0x01, 0xef, 0x00}, {0x16, 0x01, 0xef, 0x01}, + {0x00, 0x01, 0x09, 0x01}, {0x00, 0x01, 0x8e, 0x01}, + {0x00, 0x01, 0x90, 0x01}, {0x00, 0x01, 0x91, 0x01}, + {0x00, 0x01, 0x94, 0x01}, {0x00, 0x01, 0x9f, 0x01} + }, + { + {0x02, 0x01, 0xbc, 0x00}, {0x09, 0x01, 0xbc, 0x00}, + {0x17, 0x01, 0xbc, 0x00}, {0x28, 0x01, 0xbc, 0x01}, + {0x02, 0x01, 0xbf, 0x00}, {0x09, 0x01, 0xbf, 0x00}, + {0x17, 0x01, 0xbf, 0x00}, {0x28, 0x01, 0xbf, 0x01}, + {0x02, 0x01, 0xc5, 0x00}, {0x09, 0x01, 0xc5, 0x00}, + {0x17, 0x01, 0xc5, 0x00}, {0x28, 0x01, 0xc5, 0x01}, + {0x02, 0x01, 0xe7, 0x00}, {0x09, 0x01, 0xe7, 0x00}, + {0x17, 0x01, 0xe7, 0x00}, {0x28, 0x01, 0xe7, 0x01} + }, + { + {0x03, 0x01, 0xbc, 0x00}, {0x06, 0x01, 0xbc, 0x00}, + {0x0a, 0x01, 0xbc, 0x00}, {0x0f, 0x01, 0xbc, 0x00}, + {0x18, 0x01, 0xbc, 0x00}, {0x1f, 0x01, 0xbc, 0x00}, + {0x29, 0x01, 0xbc, 0x00}, {0x38, 0x01, 0xbc, 0x01}, + {0x03, 0x01, 0xbf, 0x00}, {0x06, 0x01, 0xbf, 0x00}, + {0x0a, 0x01, 0xbf, 0x00}, {0x0f, 0x01, 0xbf, 0x00}, + {0x18, 0x01, 0xbf, 0x00}, {0x1f, 0x01, 0xbf, 0x00}, + {0x29, 0x01, 0xbf, 0x00}, {0x38, 0x01, 0xbf, 0x01} + }, + { + {0x03, 0x01, 0xc5, 0x00}, {0x06, 0x01, 0xc5, 0x00}, + {0x0a, 0x01, 0xc5, 0x00}, {0x0f, 0x01, 0xc5, 0x00}, + {0x18, 0x01, 0xc5, 0x00}, {0x1f, 0x01, 0xc5, 0x00}, + {0x29, 0x01, 0xc5, 0x00}, {0x38, 0x01, 0xc5, 0x01}, + {0x03, 0x01, 0xe7, 0x00}, {0x06, 0x01, 0xe7, 0x00}, + {0x0a, 0x01, 0xe7, 0x00}, {0x0f, 0x01, 0xe7, 0x00}, + {0x18, 0x01, 0xe7, 0x00}, {0x1f, 0x01, 0xe7, 0x00}, + {0x29, 0x01, 0xe7, 0x00}, {0x38, 0x01, 0xe7, 0x01} + }, + { + {0x02, 0x01, 0xef, 0x00}, {0x09, 0x01, 0xef, 0x00}, + {0x17, 0x01, 0xef, 0x00}, {0x28, 0x01, 0xef, 0x01}, + {0x01, 0x01, 0x09, 0x00}, {0x16, 0x01, 0x09, 0x01}, + {0x01, 0x01, 0x8e, 0x00}, {0x16, 0x01, 0x8e, 0x01}, + {0x01, 0x01, 0x90, 0x00}, {0x16, 0x01, 0x90, 0x01}, + {0x01, 0x01, 0x91, 0x00}, {0x16, 0x01, 0x91, 0x01}, + {0x01, 0x01, 0x94, 0x00}, {0x16, 0x01, 0x94, 0x01}, + {0x01, 0x01, 0x9f, 0x00}, {0x16, 0x01, 0x9f, 0x01} + }, + /* 175 */ + { + {0x03, 0x01, 0xef, 0x00}, {0x06, 0x01, 0xef, 0x00}, + {0x0a, 0x01, 0xef, 0x00}, {0x0f, 0x01, 0xef, 0x00}, + {0x18, 0x01, 0xef, 0x00}, {0x1f, 0x01, 0xef, 0x00}, + {0x29, 0x01, 0xef, 0x00}, {0x38, 0x01, 0xef, 0x01}, + {0x02, 0x01, 0x09, 0x00}, {0x09, 0x01, 0x09, 0x00}, + {0x17, 0x01, 0x09, 0x00}, {0x28, 0x01, 0x09, 0x01}, + {0x02, 0x01, 0x8e, 0x00}, {0x09, 0x01, 0x8e, 0x00}, + {0x17, 0x01, 0x8e, 0x00}, {0x28, 0x01, 0x8e, 0x01} + }, + { + {0x03, 0x01, 0x09, 0x00}, {0x06, 0x01, 0x09, 0x00}, + {0x0a, 0x01, 0x09, 0x00}, {0x0f, 0x01, 0x09, 0x00}, + {0x18, 0x01, 0x09, 0x00}, {0x1f, 0x01, 0x09, 0x00}, + {0x29, 0x01, 0x09, 0x00}, {0x38, 0x01, 0x09, 0x01}, + {0x03, 0x01, 0x8e, 0x00}, {0x06, 0x01, 0x8e, 0x00}, + {0x0a, 0x01, 0x8e, 0x00}, {0x0f, 0x01, 0x8e, 0x00}, + {0x18, 0x01, 0x8e, 0x00}, {0x1f, 0x01, 0x8e, 0x00}, + {0x29, 0x01, 0x8e, 0x00}, {0x38, 0x01, 0x8e, 0x01} + }, + { + {0x02, 0x01, 0x90, 0x00}, {0x09, 0x01, 0x90, 0x00}, + {0x17, 0x01, 0x90, 0x00}, {0x28, 0x01, 0x90, 0x01}, + {0x02, 0x01, 0x91, 0x00}, {0x09, 0x01, 0x91, 0x00}, + {0x17, 0x01, 0x91, 0x00}, {0x28, 0x01, 0x91, 0x01}, + {0x02, 0x01, 0x94, 0x00}, {0x09, 0x01, 0x94, 0x00}, + {0x17, 0x01, 0x94, 0x00}, {0x28, 0x01, 0x94, 0x01}, + {0x02, 0x01, 0x9f, 0x00}, {0x09, 0x01, 0x9f, 0x00}, + {0x17, 0x01, 0x9f, 0x00}, {0x28, 0x01, 0x9f, 0x01} + }, + { + {0x03, 0x01, 0x90, 0x00}, {0x06, 0x01, 0x90, 0x00}, + {0x0a, 0x01, 0x90, 0x00}, {0x0f, 0x01, 0x90, 0x00}, + {0x18, 0x01, 0x90, 0x00}, {0x1f, 0x01, 0x90, 0x00}, + {0x29, 0x01, 0x90, 0x00}, {0x38, 0x01, 0x90, 0x01}, + {0x03, 0x01, 0x91, 0x00}, {0x06, 0x01, 0x91, 0x00}, + {0x0a, 0x01, 0x91, 0x00}, {0x0f, 0x01, 0x91, 0x00}, + {0x18, 0x01, 0x91, 0x00}, {0x1f, 0x01, 0x91, 0x00}, + {0x29, 0x01, 0x91, 0x00}, {0x38, 0x01, 0x91, 0x01} + }, + { + {0x03, 0x01, 0x94, 0x00}, {0x06, 0x01, 0x94, 0x00}, + {0x0a, 0x01, 0x94, 0x00}, {0x0f, 0x01, 0x94, 0x00}, + {0x18, 0x01, 0x94, 0x00}, {0x1f, 0x01, 0x94, 0x00}, + {0x29, 0x01, 0x94, 0x00}, {0x38, 0x01, 0x94, 0x01}, + {0x03, 0x01, 0x9f, 0x00}, {0x06, 0x01, 0x9f, 0x00}, + {0x0a, 0x01, 0x9f, 0x00}, {0x0f, 0x01, 0x9f, 0x00}, + {0x18, 0x01, 0x9f, 0x00}, {0x1f, 0x01, 0x9f, 0x00}, + {0x29, 0x01, 0x9f, 0x00}, {0x38, 0x01, 0x9f, 0x01} + }, + /* 180 */ + { + {0x00, 0x01, 0xab, 0x01}, {0x00, 0x01, 0xce, 0x01}, + {0x00, 0x01, 0xd7, 0x01}, {0x00, 0x01, 0xe1, 0x01}, + {0x00, 0x01, 0xec, 0x01}, {0x00, 0x01, 0xed, 0x01}, + {0xbc, 0x00, 0x00, 0x00}, {0xbd, 0x00, 0x00, 0x00}, + {0xc1, 0x00, 0x00, 0x00}, {0xc4, 0x00, 0x00, 0x00}, + {0xc8, 0x00, 0x00, 0x00}, {0xcb, 0x00, 0x00, 0x00}, + {0xd1, 0x00, 0x00, 0x00}, {0xd8, 0x00, 0x00, 0x00}, + {0xe0, 0x00, 0x00, 0x00}, {0xee, 0x00, 0x00, 0x01} + }, + { + {0x01, 0x01, 0xab, 0x00}, {0x16, 0x01, 0xab, 0x01}, + {0x01, 0x01, 0xce, 0x00}, {0x16, 0x01, 0xce, 0x01}, + {0x01, 0x01, 0xd7, 0x00}, {0x16, 0x01, 0xd7, 0x01}, + {0x01, 0x01, 0xe1, 0x00}, {0x16, 0x01, 0xe1, 0x01}, + {0x01, 0x01, 0xec, 0x00}, {0x16, 0x01, 0xec, 0x01}, + {0x01, 0x01, 0xed, 0x00}, {0x16, 0x01, 0xed, 0x01}, + {0x00, 0x01, 0xc7, 0x01}, {0x00, 0x01, 0xcf, 0x01}, + {0x00, 0x01, 0xea, 0x01}, {0x00, 0x01, 0xeb, 0x01} + }, + { + {0x02, 0x01, 0xab, 0x00}, {0x09, 0x01, 0xab, 0x00}, + {0x17, 0x01, 0xab, 0x00}, {0x28, 0x01, 0xab, 0x01}, + {0x02, 0x01, 0xce, 0x00}, {0x09, 0x01, 0xce, 0x00}, + {0x17, 0x01, 0xce, 0x00}, {0x28, 0x01, 0xce, 0x01}, + {0x02, 0x01, 0xd7, 0x00}, {0x09, 0x01, 0xd7, 0x00}, + {0x17, 0x01, 0xd7, 0x00}, {0x28, 0x01, 0xd7, 0x01}, + {0x02, 0x01, 0xe1, 0x00}, {0x09, 0x01, 0xe1, 0x00}, + {0x17, 0x01, 0xe1, 0x00}, {0x28, 0x01, 0xe1, 0x01} + }, + { + {0x03, 0x01, 0xab, 0x00}, {0x06, 0x01, 0xab, 0x00}, + {0x0a, 0x01, 0xab, 0x00}, {0x0f, 0x01, 0xab, 0x00}, + {0x18, 0x01, 0xab, 0x00}, {0x1f, 0x01, 0xab, 0x00}, + {0x29, 0x01, 0xab, 0x00}, {0x38, 0x01, 0xab, 0x01}, + {0x03, 0x01, 0xce, 0x00}, {0x06, 0x01, 0xce, 0x00}, + {0x0a, 0x01, 0xce, 0x00}, {0x0f, 0x01, 0xce, 0x00}, + {0x18, 0x01, 0xce, 0x00}, {0x1f, 0x01, 0xce, 0x00}, + {0x29, 0x01, 0xce, 0x00}, {0x38, 0x01, 0xce, 0x01} + }, + { + {0x03, 0x01, 0xd7, 0x00}, {0x06, 0x01, 0xd7, 0x00}, + {0x0a, 0x01, 0xd7, 0x00}, {0x0f, 0x01, 0xd7, 0x00}, + {0x18, 0x01, 0xd7, 0x00}, {0x1f, 0x01, 0xd7, 0x00}, + {0x29, 0x01, 0xd7, 0x00}, {0x38, 0x01, 0xd7, 0x01}, + {0x03, 0x01, 0xe1, 0x00}, {0x06, 0x01, 0xe1, 0x00}, + {0x0a, 0x01, 0xe1, 0x00}, {0x0f, 0x01, 0xe1, 0x00}, + {0x18, 0x01, 0xe1, 0x00}, {0x1f, 0x01, 0xe1, 0x00}, + {0x29, 0x01, 0xe1, 0x00}, {0x38, 0x01, 0xe1, 0x01} + }, + /* 185 */ + { + {0x02, 0x01, 0xec, 0x00}, {0x09, 0x01, 0xec, 0x00}, + {0x17, 0x01, 0xec, 0x00}, {0x28, 0x01, 0xec, 0x01}, + {0x02, 0x01, 0xed, 0x00}, {0x09, 0x01, 0xed, 0x00}, + {0x17, 0x01, 0xed, 0x00}, {0x28, 0x01, 0xed, 0x01}, + {0x01, 0x01, 0xc7, 0x00}, {0x16, 0x01, 0xc7, 0x01}, + {0x01, 0x01, 0xcf, 0x00}, {0x16, 0x01, 0xcf, 0x01}, + {0x01, 0x01, 0xea, 0x00}, {0x16, 0x01, 0xea, 0x01}, + {0x01, 0x01, 0xeb, 0x00}, {0x16, 0x01, 0xeb, 0x01} + }, + { + {0x03, 0x01, 0xec, 0x00}, {0x06, 0x01, 0xec, 0x00}, + {0x0a, 0x01, 0xec, 0x00}, {0x0f, 0x01, 0xec, 0x00}, + {0x18, 0x01, 0xec, 0x00}, {0x1f, 0x01, 0xec, 0x00}, + {0x29, 0x01, 0xec, 0x00}, {0x38, 0x01, 0xec, 0x01}, + {0x03, 0x01, 0xed, 0x00}, {0x06, 0x01, 0xed, 0x00}, + {0x0a, 0x01, 0xed, 0x00}, {0x0f, 0x01, 0xed, 0x00}, + {0x18, 0x01, 0xed, 0x00}, {0x1f, 0x01, 0xed, 0x00}, + {0x29, 0x01, 0xed, 0x00}, {0x38, 0x01, 0xed, 0x01} + }, + { + {0x02, 0x01, 0xc7, 0x00}, {0x09, 0x01, 0xc7, 0x00}, + {0x17, 0x01, 0xc7, 0x00}, {0x28, 0x01, 0xc7, 0x01}, + {0x02, 0x01, 0xcf, 0x00}, {0x09, 0x01, 0xcf, 0x00}, + {0x17, 0x01, 0xcf, 0x00}, {0x28, 0x01, 0xcf, 0x01}, + {0x02, 0x01, 0xea, 0x00}, {0x09, 0x01, 0xea, 0x00}, + {0x17, 0x01, 0xea, 0x00}, {0x28, 0x01, 0xea, 0x01}, + {0x02, 0x01, 0xeb, 0x00}, {0x09, 0x01, 0xeb, 0x00}, + {0x17, 0x01, 0xeb, 0x00}, {0x28, 0x01, 0xeb, 0x01} + }, + { + {0x03, 0x01, 0xc7, 0x00}, {0x06, 0x01, 0xc7, 0x00}, + {0x0a, 0x01, 0xc7, 0x00}, {0x0f, 0x01, 0xc7, 0x00}, + {0x18, 0x01, 0xc7, 0x00}, {0x1f, 0x01, 0xc7, 0x00}, + {0x29, 0x01, 0xc7, 0x00}, {0x38, 0x01, 0xc7, 0x01}, + {0x03, 0x01, 0xcf, 0x00}, {0x06, 0x01, 0xcf, 0x00}, + {0x0a, 0x01, 0xcf, 0x00}, {0x0f, 0x01, 0xcf, 0x00}, + {0x18, 0x01, 0xcf, 0x00}, {0x1f, 0x01, 0xcf, 0x00}, + {0x29, 0x01, 0xcf, 0x00}, {0x38, 0x01, 0xcf, 0x01} + }, + { + {0x03, 0x01, 0xea, 0x00}, {0x06, 0x01, 0xea, 0x00}, + {0x0a, 0x01, 0xea, 0x00}, {0x0f, 0x01, 0xea, 0x00}, + {0x18, 0x01, 0xea, 0x00}, {0x1f, 0x01, 0xea, 0x00}, + {0x29, 0x01, 0xea, 0x00}, {0x38, 0x01, 0xea, 0x01}, + {0x03, 0x01, 0xeb, 0x00}, {0x06, 0x01, 0xeb, 0x00}, + {0x0a, 0x01, 0xeb, 0x00}, {0x0f, 0x01, 0xeb, 0x00}, + {0x18, 0x01, 0xeb, 0x00}, {0x1f, 0x01, 0xeb, 0x00}, + {0x29, 0x01, 0xeb, 0x00}, {0x38, 0x01, 0xeb, 0x01} + }, + /* 190 */ + { + {0xc2, 0x00, 0x00, 0x00}, {0xc3, 0x00, 0x00, 0x00}, + {0xc5, 0x00, 0x00, 0x00}, {0xc6, 0x00, 0x00, 0x00}, + {0xc9, 0x00, 0x00, 0x00}, {0xca, 0x00, 0x00, 0x00}, + {0xcc, 0x00, 0x00, 0x00}, {0xcd, 0x00, 0x00, 0x00}, + {0xd2, 0x00, 0x00, 0x00}, {0xd5, 0x00, 0x00, 0x00}, + {0xd9, 0x00, 0x00, 0x00}, {0xdc, 0x00, 0x00, 0x00}, + {0xe1, 0x00, 0x00, 0x00}, {0xe7, 0x00, 0x00, 0x00}, + {0xef, 0x00, 0x00, 0x00}, {0xf6, 0x00, 0x00, 0x01} + }, + { + {0x00, 0x01, 0xc0, 0x01}, {0x00, 0x01, 0xc1, 0x01}, + {0x00, 0x01, 0xc8, 0x01}, {0x00, 0x01, 0xc9, 0x01}, + {0x00, 0x01, 0xca, 0x01}, {0x00, 0x01, 0xcd, 0x01}, + {0x00, 0x01, 0xd2, 0x01}, {0x00, 0x01, 0xd5, 0x01}, + {0x00, 0x01, 0xda, 0x01}, {0x00, 0x01, 0xdb, 0x01}, + {0x00, 0x01, 0xee, 0x01}, {0x00, 0x01, 0xf0, 0x01}, + {0x00, 0x01, 0xf2, 0x01}, {0x00, 0x01, 0xf3, 0x01}, + {0x00, 0x01, 0xff, 0x01}, {0xce, 0x00, 0x00, 0x00} + }, + { + {0x01, 0x01, 0xc0, 0x00}, {0x16, 0x01, 0xc0, 0x01}, + {0x01, 0x01, 0xc1, 0x00}, {0x16, 0x01, 0xc1, 0x01}, + {0x01, 0x01, 0xc8, 0x00}, {0x16, 0x01, 0xc8, 0x01}, + {0x01, 0x01, 0xc9, 0x00}, {0x16, 0x01, 0xc9, 0x01}, + {0x01, 0x01, 0xca, 0x00}, {0x16, 0x01, 0xca, 0x01}, + {0x01, 0x01, 0xcd, 0x00}, {0x16, 0x01, 0xcd, 0x01}, + {0x01, 0x01, 0xd2, 0x00}, {0x16, 0x01, 0xd2, 0x01}, + {0x01, 0x01, 0xd5, 0x00}, {0x16, 0x01, 0xd5, 0x01} + }, + { + {0x02, 0x01, 0xc0, 0x00}, {0x09, 0x01, 0xc0, 0x00}, + {0x17, 0x01, 0xc0, 0x00}, {0x28, 0x01, 0xc0, 0x01}, + {0x02, 0x01, 0xc1, 0x00}, {0x09, 0x01, 0xc1, 0x00}, + {0x17, 0x01, 0xc1, 0x00}, {0x28, 0x01, 0xc1, 0x01}, + {0x02, 0x01, 0xc8, 0x00}, {0x09, 0x01, 0xc8, 0x00}, + {0x17, 0x01, 0xc8, 0x00}, {0x28, 0x01, 0xc8, 0x01}, + {0x02, 0x01, 0xc9, 0x00}, {0x09, 0x01, 0xc9, 0x00}, + {0x17, 0x01, 0xc9, 0x00}, {0x28, 0x01, 0xc9, 0x01} + }, + { + {0x03, 0x01, 0xc0, 0x00}, {0x06, 0x01, 0xc0, 0x00}, + {0x0a, 0x01, 0xc0, 0x00}, {0x0f, 0x01, 0xc0, 0x00}, + {0x18, 0x01, 0xc0, 0x00}, {0x1f, 0x01, 0xc0, 0x00}, + {0x29, 0x01, 0xc0, 0x00}, {0x38, 0x01, 0xc0, 0x01}, + {0x03, 0x01, 0xc1, 0x00}, {0x06, 0x01, 0xc1, 0x00}, + {0x0a, 0x01, 0xc1, 0x00}, {0x0f, 0x01, 0xc1, 0x00}, + {0x18, 0x01, 0xc1, 0x00}, {0x1f, 0x01, 0xc1, 0x00}, + {0x29, 0x01, 0xc1, 0x00}, {0x38, 0x01, 0xc1, 0x01} + }, + /* 195 */ + { + {0x03, 0x01, 0xc8, 0x00}, {0x06, 0x01, 0xc8, 0x00}, + {0x0a, 0x01, 0xc8, 0x00}, {0x0f, 0x01, 0xc8, 0x00}, + {0x18, 0x01, 0xc8, 0x00}, {0x1f, 0x01, 0xc8, 0x00}, + {0x29, 0x01, 0xc8, 0x00}, {0x38, 0x01, 0xc8, 0x01}, + {0x03, 0x01, 0xc9, 0x00}, {0x06, 0x01, 0xc9, 0x00}, + {0x0a, 0x01, 0xc9, 0x00}, {0x0f, 0x01, 0xc9, 0x00}, + {0x18, 0x01, 0xc9, 0x00}, {0x1f, 0x01, 0xc9, 0x00}, + {0x29, 0x01, 0xc9, 0x00}, {0x38, 0x01, 0xc9, 0x01} + }, + { + {0x02, 0x01, 0xca, 0x00}, {0x09, 0x01, 0xca, 0x00}, + {0x17, 0x01, 0xca, 0x00}, {0x28, 0x01, 0xca, 0x01}, + {0x02, 0x01, 0xcd, 0x00}, {0x09, 0x01, 0xcd, 0x00}, + {0x17, 0x01, 0xcd, 0x00}, {0x28, 0x01, 0xcd, 0x01}, + {0x02, 0x01, 0xd2, 0x00}, {0x09, 0x01, 0xd2, 0x00}, + {0x17, 0x01, 0xd2, 0x00}, {0x28, 0x01, 0xd2, 0x01}, + {0x02, 0x01, 0xd5, 0x00}, {0x09, 0x01, 0xd5, 0x00}, + {0x17, 0x01, 0xd5, 0x00}, {0x28, 0x01, 0xd5, 0x01} + }, + { + {0x03, 0x01, 0xca, 0x00}, {0x06, 0x01, 0xca, 0x00}, + {0x0a, 0x01, 0xca, 0x00}, {0x0f, 0x01, 0xca, 0x00}, + {0x18, 0x01, 0xca, 0x00}, {0x1f, 0x01, 0xca, 0x00}, + {0x29, 0x01, 0xca, 0x00}, {0x38, 0x01, 0xca, 0x01}, + {0x03, 0x01, 0xcd, 0x00}, {0x06, 0x01, 0xcd, 0x00}, + {0x0a, 0x01, 0xcd, 0x00}, {0x0f, 0x01, 0xcd, 0x00}, + {0x18, 0x01, 0xcd, 0x00}, {0x1f, 0x01, 0xcd, 0x00}, + {0x29, 0x01, 0xcd, 0x00}, {0x38, 0x01, 0xcd, 0x01} + }, + { + {0x03, 0x01, 0xd2, 0x00}, {0x06, 0x01, 0xd2, 0x00}, + {0x0a, 0x01, 0xd2, 0x00}, {0x0f, 0x01, 0xd2, 0x00}, + {0x18, 0x01, 0xd2, 0x00}, {0x1f, 0x01, 0xd2, 0x00}, + {0x29, 0x01, 0xd2, 0x00}, {0x38, 0x01, 0xd2, 0x01}, + {0x03, 0x01, 0xd5, 0x00}, {0x06, 0x01, 0xd5, 0x00}, + {0x0a, 0x01, 0xd5, 0x00}, {0x0f, 0x01, 0xd5, 0x00}, + {0x18, 0x01, 0xd5, 0x00}, {0x1f, 0x01, 0xd5, 0x00}, + {0x29, 0x01, 0xd5, 0x00}, {0x38, 0x01, 0xd5, 0x01} + }, + { + {0x01, 0x01, 0xda, 0x00}, {0x16, 0x01, 0xda, 0x01}, + {0x01, 0x01, 0xdb, 0x00}, {0x16, 0x01, 0xdb, 0x01}, + {0x01, 0x01, 0xee, 0x00}, {0x16, 0x01, 0xee, 0x01}, + {0x01, 0x01, 0xf0, 0x00}, {0x16, 0x01, 0xf0, 0x01}, + {0x01, 0x01, 0xf2, 0x00}, {0x16, 0x01, 0xf2, 0x01}, + {0x01, 0x01, 0xf3, 0x00}, {0x16, 0x01, 0xf3, 0x01}, + {0x01, 0x01, 0xff, 0x00}, {0x16, 0x01, 0xff, 0x01}, + {0x00, 0x01, 0xcb, 0x01}, {0x00, 0x01, 0xcc, 0x01} + }, + /* 200 */ + { + {0x02, 0x01, 0xda, 0x00}, {0x09, 0x01, 0xda, 0x00}, + {0x17, 0x01, 0xda, 0x00}, {0x28, 0x01, 0xda, 0x01}, + {0x02, 0x01, 0xdb, 0x00}, {0x09, 0x01, 0xdb, 0x00}, + {0x17, 0x01, 0xdb, 0x00}, {0x28, 0x01, 0xdb, 0x01}, + {0x02, 0x01, 0xee, 0x00}, {0x09, 0x01, 0xee, 0x00}, + {0x17, 0x01, 0xee, 0x00}, {0x28, 0x01, 0xee, 0x01}, + {0x02, 0x01, 0xf0, 0x00}, {0x09, 0x01, 0xf0, 0x00}, + {0x17, 0x01, 0xf0, 0x00}, {0x28, 0x01, 0xf0, 0x01} + }, + { + {0x03, 0x01, 0xda, 0x00}, {0x06, 0x01, 0xda, 0x00}, + {0x0a, 0x01, 0xda, 0x00}, {0x0f, 0x01, 0xda, 0x00}, + {0x18, 0x01, 0xda, 0x00}, {0x1f, 0x01, 0xda, 0x00}, + {0x29, 0x01, 0xda, 0x00}, {0x38, 0x01, 0xda, 0x01}, + {0x03, 0x01, 0xdb, 0x00}, {0x06, 0x01, 0xdb, 0x00}, + {0x0a, 0x01, 0xdb, 0x00}, {0x0f, 0x01, 0xdb, 0x00}, + {0x18, 0x01, 0xdb, 0x00}, {0x1f, 0x01, 0xdb, 0x00}, + {0x29, 0x01, 0xdb, 0x00}, {0x38, 0x01, 0xdb, 0x01} + }, + { + {0x03, 0x01, 0xee, 0x00}, {0x06, 0x01, 0xee, 0x00}, + {0x0a, 0x01, 0xee, 0x00}, {0x0f, 0x01, 0xee, 0x00}, + {0x18, 0x01, 0xee, 0x00}, {0x1f, 0x01, 0xee, 0x00}, + {0x29, 0x01, 0xee, 0x00}, {0x38, 0x01, 0xee, 0x01}, + {0x03, 0x01, 0xf0, 0x00}, {0x06, 0x01, 0xf0, 0x00}, + {0x0a, 0x01, 0xf0, 0x00}, {0x0f, 0x01, 0xf0, 0x00}, + {0x18, 0x01, 0xf0, 0x00}, {0x1f, 0x01, 0xf0, 0x00}, + {0x29, 0x01, 0xf0, 0x00}, {0x38, 0x01, 0xf0, 0x01} + }, + { + {0x02, 0x01, 0xf2, 0x00}, {0x09, 0x01, 0xf2, 0x00}, + {0x17, 0x01, 0xf2, 0x00}, {0x28, 0x01, 0xf2, 0x01}, + {0x02, 0x01, 0xf3, 0x00}, {0x09, 0x01, 0xf3, 0x00}, + {0x17, 0x01, 0xf3, 0x00}, {0x28, 0x01, 0xf3, 0x01}, + {0x02, 0x01, 0xff, 0x00}, {0x09, 0x01, 0xff, 0x00}, + {0x17, 0x01, 0xff, 0x00}, {0x28, 0x01, 0xff, 0x01}, + {0x01, 0x01, 0xcb, 0x00}, {0x16, 0x01, 0xcb, 0x01}, + {0x01, 0x01, 0xcc, 0x00}, {0x16, 0x01, 0xcc, 0x01} + }, + { + {0x03, 0x01, 0xf2, 0x00}, {0x06, 0x01, 0xf2, 0x00}, + {0x0a, 0x01, 0xf2, 0x00}, {0x0f, 0x01, 0xf2, 0x00}, + {0x18, 0x01, 0xf2, 0x00}, {0x1f, 0x01, 0xf2, 0x00}, + {0x29, 0x01, 0xf2, 0x00}, {0x38, 0x01, 0xf2, 0x01}, + {0x03, 0x01, 0xf3, 0x00}, {0x06, 0x01, 0xf3, 0x00}, + {0x0a, 0x01, 0xf3, 0x00}, {0x0f, 0x01, 0xf3, 0x00}, + {0x18, 0x01, 0xf3, 0x00}, {0x1f, 0x01, 0xf3, 0x00}, + {0x29, 0x01, 0xf3, 0x00}, {0x38, 0x01, 0xf3, 0x01} + }, + /* 205 */ + { + {0x03, 0x01, 0xff, 0x00}, {0x06, 0x01, 0xff, 0x00}, + {0x0a, 0x01, 0xff, 0x00}, {0x0f, 0x01, 0xff, 0x00}, + {0x18, 0x01, 0xff, 0x00}, {0x1f, 0x01, 0xff, 0x00}, + {0x29, 0x01, 0xff, 0x00}, {0x38, 0x01, 0xff, 0x01}, + {0x02, 0x01, 0xcb, 0x00}, {0x09, 0x01, 0xcb, 0x00}, + {0x17, 0x01, 0xcb, 0x00}, {0x28, 0x01, 0xcb, 0x01}, + {0x02, 0x01, 0xcc, 0x00}, {0x09, 0x01, 0xcc, 0x00}, + {0x17, 0x01, 0xcc, 0x00}, {0x28, 0x01, 0xcc, 0x01} + }, + { + {0x03, 0x01, 0xcb, 0x00}, {0x06, 0x01, 0xcb, 0x00}, + {0x0a, 0x01, 0xcb, 0x00}, {0x0f, 0x01, 0xcb, 0x00}, + {0x18, 0x01, 0xcb, 0x00}, {0x1f, 0x01, 0xcb, 0x00}, + {0x29, 0x01, 0xcb, 0x00}, {0x38, 0x01, 0xcb, 0x01}, + {0x03, 0x01, 0xcc, 0x00}, {0x06, 0x01, 0xcc, 0x00}, + {0x0a, 0x01, 0xcc, 0x00}, {0x0f, 0x01, 0xcc, 0x00}, + {0x18, 0x01, 0xcc, 0x00}, {0x1f, 0x01, 0xcc, 0x00}, + {0x29, 0x01, 0xcc, 0x00}, {0x38, 0x01, 0xcc, 0x01} + }, + { + {0xd3, 0x00, 0x00, 0x00}, {0xd4, 0x00, 0x00, 0x00}, + {0xd6, 0x00, 0x00, 0x00}, {0xd7, 0x00, 0x00, 0x00}, + {0xda, 0x00, 0x00, 0x00}, {0xdb, 0x00, 0x00, 0x00}, + {0xdd, 0x00, 0x00, 0x00}, {0xde, 0x00, 0x00, 0x00}, + {0xe2, 0x00, 0x00, 0x00}, {0xe4, 0x00, 0x00, 0x00}, + {0xe8, 0x00, 0x00, 0x00}, {0xeb, 0x00, 0x00, 0x00}, + {0xf0, 0x00, 0x00, 0x00}, {0xf3, 0x00, 0x00, 0x00}, + {0xf7, 0x00, 0x00, 0x00}, {0xfa, 0x00, 0x00, 0x01} + }, + { + {0x00, 0x01, 0xd3, 0x01}, {0x00, 0x01, 0xd4, 0x01}, + {0x00, 0x01, 0xd6, 0x01}, {0x00, 0x01, 0xdd, 0x01}, + {0x00, 0x01, 0xde, 0x01}, {0x00, 0x01, 0xdf, 0x01}, + {0x00, 0x01, 0xf1, 0x01}, {0x00, 0x01, 0xf4, 0x01}, + {0x00, 0x01, 0xf5, 0x01}, {0x00, 0x01, 0xf6, 0x01}, + {0x00, 0x01, 0xf7, 0x01}, {0x00, 0x01, 0xf8, 0x01}, + {0x00, 0x01, 0xfa, 0x01}, {0x00, 0x01, 0xfb, 0x01}, + {0x00, 0x01, 0xfc, 0x01}, {0x00, 0x01, 0xfd, 0x01} + }, + { + {0x01, 0x01, 0xd3, 0x00}, {0x16, 0x01, 0xd3, 0x01}, + {0x01, 0x01, 0xd4, 0x00}, {0x16, 0x01, 0xd4, 0x01}, + {0x01, 0x01, 0xd6, 0x00}, {0x16, 0x01, 0xd6, 0x01}, + {0x01, 0x01, 0xdd, 0x00}, {0x16, 0x01, 0xdd, 0x01}, + {0x01, 0x01, 0xde, 0x00}, {0x16, 0x01, 0xde, 0x01}, + {0x01, 0x01, 0xdf, 0x00}, {0x16, 0x01, 0xdf, 0x01}, + {0x01, 0x01, 0xf1, 0x00}, {0x16, 0x01, 0xf1, 0x01}, + {0x01, 0x01, 0xf4, 0x00}, {0x16, 0x01, 0xf4, 0x01} + }, + /* 210 */ + { + {0x02, 0x01, 0xd3, 0x00}, {0x09, 0x01, 0xd3, 0x00}, + {0x17, 0x01, 0xd3, 0x00}, {0x28, 0x01, 0xd3, 0x01}, + {0x02, 0x01, 0xd4, 0x00}, {0x09, 0x01, 0xd4, 0x00}, + {0x17, 0x01, 0xd4, 0x00}, {0x28, 0x01, 0xd4, 0x01}, + {0x02, 0x01, 0xd6, 0x00}, {0x09, 0x01, 0xd6, 0x00}, + {0x17, 0x01, 0xd6, 0x00}, {0x28, 0x01, 0xd6, 0x01}, + {0x02, 0x01, 0xdd, 0x00}, {0x09, 0x01, 0xdd, 0x00}, + {0x17, 0x01, 0xdd, 0x00}, {0x28, 0x01, 0xdd, 0x01} + }, + { + {0x03, 0x01, 0xd3, 0x00}, {0x06, 0x01, 0xd3, 0x00}, + {0x0a, 0x01, 0xd3, 0x00}, {0x0f, 0x01, 0xd3, 0x00}, + {0x18, 0x01, 0xd3, 0x00}, {0x1f, 0x01, 0xd3, 0x00}, + {0x29, 0x01, 0xd3, 0x00}, {0x38, 0x01, 0xd3, 0x01}, + {0x03, 0x01, 0xd4, 0x00}, {0x06, 0x01, 0xd4, 0x00}, + {0x0a, 0x01, 0xd4, 0x00}, {0x0f, 0x01, 0xd4, 0x00}, + {0x18, 0x01, 0xd4, 0x00}, {0x1f, 0x01, 0xd4, 0x00}, + {0x29, 0x01, 0xd4, 0x00}, {0x38, 0x01, 0xd4, 0x01} + }, + { + {0x03, 0x01, 0xd6, 0x00}, {0x06, 0x01, 0xd6, 0x00}, + {0x0a, 0x01, 0xd6, 0x00}, {0x0f, 0x01, 0xd6, 0x00}, + {0x18, 0x01, 0xd6, 0x00}, {0x1f, 0x01, 0xd6, 0x00}, + {0x29, 0x01, 0xd6, 0x00}, {0x38, 0x01, 0xd6, 0x01}, + {0x03, 0x01, 0xdd, 0x00}, {0x06, 0x01, 0xdd, 0x00}, + {0x0a, 0x01, 0xdd, 0x00}, {0x0f, 0x01, 0xdd, 0x00}, + {0x18, 0x01, 0xdd, 0x00}, {0x1f, 0x01, 0xdd, 0x00}, + {0x29, 0x01, 0xdd, 0x00}, {0x38, 0x01, 0xdd, 0x01} + }, + { + {0x02, 0x01, 0xde, 0x00}, {0x09, 0x01, 0xde, 0x00}, + {0x17, 0x01, 0xde, 0x00}, {0x28, 0x01, 0xde, 0x01}, + {0x02, 0x01, 0xdf, 0x00}, {0x09, 0x01, 0xdf, 0x00}, + {0x17, 0x01, 0xdf, 0x00}, {0x28, 0x01, 0xdf, 0x01}, + {0x02, 0x01, 0xf1, 0x00}, {0x09, 0x01, 0xf1, 0x00}, + {0x17, 0x01, 0xf1, 0x00}, {0x28, 0x01, 0xf1, 0x01}, + {0x02, 0x01, 0xf4, 0x00}, {0x09, 0x01, 0xf4, 0x00}, + {0x17, 0x01, 0xf4, 0x00}, {0x28, 0x01, 0xf4, 0x01} + }, + { + {0x03, 0x01, 0xde, 0x00}, {0x06, 0x01, 0xde, 0x00}, + {0x0a, 0x01, 0xde, 0x00}, {0x0f, 0x01, 0xde, 0x00}, + {0x18, 0x01, 0xde, 0x00}, {0x1f, 0x01, 0xde, 0x00}, + {0x29, 0x01, 0xde, 0x00}, {0x38, 0x01, 0xde, 0x01}, + {0x03, 0x01, 0xdf, 0x00}, {0x06, 0x01, 0xdf, 0x00}, + {0x0a, 0x01, 0xdf, 0x00}, {0x0f, 0x01, 0xdf, 0x00}, + {0x18, 0x01, 0xdf, 0x00}, {0x1f, 0x01, 0xdf, 0x00}, + {0x29, 0x01, 0xdf, 0x00}, {0x38, 0x01, 0xdf, 0x01} + }, + /* 215 */ + { + {0x03, 0x01, 0xf1, 0x00}, {0x06, 0x01, 0xf1, 0x00}, + {0x0a, 0x01, 0xf1, 0x00}, {0x0f, 0x01, 0xf1, 0x00}, + {0x18, 0x01, 0xf1, 0x00}, {0x1f, 0x01, 0xf1, 0x00}, + {0x29, 0x01, 0xf1, 0x00}, {0x38, 0x01, 0xf1, 0x01}, + {0x03, 0x01, 0xf4, 0x00}, {0x06, 0x01, 0xf4, 0x00}, + {0x0a, 0x01, 0xf4, 0x00}, {0x0f, 0x01, 0xf4, 0x00}, + {0x18, 0x01, 0xf4, 0x00}, {0x1f, 0x01, 0xf4, 0x00}, + {0x29, 0x01, 0xf4, 0x00}, {0x38, 0x01, 0xf4, 0x01} + }, + { + {0x01, 0x01, 0xf5, 0x00}, {0x16, 0x01, 0xf5, 0x01}, + {0x01, 0x01, 0xf6, 0x00}, {0x16, 0x01, 0xf6, 0x01}, + {0x01, 0x01, 0xf7, 0x00}, {0x16, 0x01, 0xf7, 0x01}, + {0x01, 0x01, 0xf8, 0x00}, {0x16, 0x01, 0xf8, 0x01}, + {0x01, 0x01, 0xfa, 0x00}, {0x16, 0x01, 0xfa, 0x01}, + {0x01, 0x01, 0xfb, 0x00}, {0x16, 0x01, 0xfb, 0x01}, + {0x01, 0x01, 0xfc, 0x00}, {0x16, 0x01, 0xfc, 0x01}, + {0x01, 0x01, 0xfd, 0x00}, {0x16, 0x01, 0xfd, 0x01} + }, + { + {0x02, 0x01, 0xf5, 0x00}, {0x09, 0x01, 0xf5, 0x00}, + {0x17, 0x01, 0xf5, 0x00}, {0x28, 0x01, 0xf5, 0x01}, + {0x02, 0x01, 0xf6, 0x00}, {0x09, 0x01, 0xf6, 0x00}, + {0x17, 0x01, 0xf6, 0x00}, {0x28, 0x01, 0xf6, 0x01}, + {0x02, 0x01, 0xf7, 0x00}, {0x09, 0x01, 0xf7, 0x00}, + {0x17, 0x01, 0xf7, 0x00}, {0x28, 0x01, 0xf7, 0x01}, + {0x02, 0x01, 0xf8, 0x00}, {0x09, 0x01, 0xf8, 0x00}, + {0x17, 0x01, 0xf8, 0x00}, {0x28, 0x01, 0xf8, 0x01} + }, + { + {0x03, 0x01, 0xf5, 0x00}, {0x06, 0x01, 0xf5, 0x00}, + {0x0a, 0x01, 0xf5, 0x00}, {0x0f, 0x01, 0xf5, 0x00}, + {0x18, 0x01, 0xf5, 0x00}, {0x1f, 0x01, 0xf5, 0x00}, + {0x29, 0x01, 0xf5, 0x00}, {0x38, 0x01, 0xf5, 0x01}, + {0x03, 0x01, 0xf6, 0x00}, {0x06, 0x01, 0xf6, 0x00}, + {0x0a, 0x01, 0xf6, 0x00}, {0x0f, 0x01, 0xf6, 0x00}, + {0x18, 0x01, 0xf6, 0x00}, {0x1f, 0x01, 0xf6, 0x00}, + {0x29, 0x01, 0xf6, 0x00}, {0x38, 0x01, 0xf6, 0x01} + }, + { + {0x03, 0x01, 0xf7, 0x00}, {0x06, 0x01, 0xf7, 0x00}, + {0x0a, 0x01, 0xf7, 0x00}, {0x0f, 0x01, 0xf7, 0x00}, + {0x18, 0x01, 0xf7, 0x00}, {0x1f, 0x01, 0xf7, 0x00}, + {0x29, 0x01, 0xf7, 0x00}, {0x38, 0x01, 0xf7, 0x01}, + {0x03, 0x01, 0xf8, 0x00}, {0x06, 0x01, 0xf8, 0x00}, + {0x0a, 0x01, 0xf8, 0x00}, {0x0f, 0x01, 0xf8, 0x00}, + {0x18, 0x01, 0xf8, 0x00}, {0x1f, 0x01, 0xf8, 0x00}, + {0x29, 0x01, 0xf8, 0x00}, {0x38, 0x01, 0xf8, 0x01} + }, + /* 220 */ + { + {0x02, 0x01, 0xfa, 0x00}, {0x09, 0x01, 0xfa, 0x00}, + {0x17, 0x01, 0xfa, 0x00}, {0x28, 0x01, 0xfa, 0x01}, + {0x02, 0x01, 0xfb, 0x00}, {0x09, 0x01, 0xfb, 0x00}, + {0x17, 0x01, 0xfb, 0x00}, {0x28, 0x01, 0xfb, 0x01}, + {0x02, 0x01, 0xfc, 0x00}, {0x09, 0x01, 0xfc, 0x00}, + {0x17, 0x01, 0xfc, 0x00}, {0x28, 0x01, 0xfc, 0x01}, + {0x02, 0x01, 0xfd, 0x00}, {0x09, 0x01, 0xfd, 0x00}, + {0x17, 0x01, 0xfd, 0x00}, {0x28, 0x01, 0xfd, 0x01} + }, + { + {0x03, 0x01, 0xfa, 0x00}, {0x06, 0x01, 0xfa, 0x00}, + {0x0a, 0x01, 0xfa, 0x00}, {0x0f, 0x01, 0xfa, 0x00}, + {0x18, 0x01, 0xfa, 0x00}, {0x1f, 0x01, 0xfa, 0x00}, + {0x29, 0x01, 0xfa, 0x00}, {0x38, 0x01, 0xfa, 0x01}, + {0x03, 0x01, 0xfb, 0x00}, {0x06, 0x01, 0xfb, 0x00}, + {0x0a, 0x01, 0xfb, 0x00}, {0x0f, 0x01, 0xfb, 0x00}, + {0x18, 0x01, 0xfb, 0x00}, {0x1f, 0x01, 0xfb, 0x00}, + {0x29, 0x01, 0xfb, 0x00}, {0x38, 0x01, 0xfb, 0x01} + }, + { + {0x03, 0x01, 0xfc, 0x00}, {0x06, 0x01, 0xfc, 0x00}, + {0x0a, 0x01, 0xfc, 0x00}, {0x0f, 0x01, 0xfc, 0x00}, + {0x18, 0x01, 0xfc, 0x00}, {0x1f, 0x01, 0xfc, 0x00}, + {0x29, 0x01, 0xfc, 0x00}, {0x38, 0x01, 0xfc, 0x01}, + {0x03, 0x01, 0xfd, 0x00}, {0x06, 0x01, 0xfd, 0x00}, + {0x0a, 0x01, 0xfd, 0x00}, {0x0f, 0x01, 0xfd, 0x00}, + {0x18, 0x01, 0xfd, 0x00}, {0x1f, 0x01, 0xfd, 0x00}, + {0x29, 0x01, 0xfd, 0x00}, {0x38, 0x01, 0xfd, 0x01} + }, + { + {0x00, 0x01, 0xfe, 0x01}, {0xe3, 0x00, 0x00, 0x00}, + {0xe5, 0x00, 0x00, 0x00}, {0xe6, 0x00, 0x00, 0x00}, + {0xe9, 0x00, 0x00, 0x00}, {0xea, 0x00, 0x00, 0x00}, + {0xec, 0x00, 0x00, 0x00}, {0xed, 0x00, 0x00, 0x00}, + {0xf1, 0x00, 0x00, 0x00}, {0xf2, 0x00, 0x00, 0x00}, + {0xf4, 0x00, 0x00, 0x00}, {0xf5, 0x00, 0x00, 0x00}, + {0xf8, 0x00, 0x00, 0x00}, {0xf9, 0x00, 0x00, 0x00}, + {0xfb, 0x00, 0x00, 0x00}, {0xfc, 0x00, 0x00, 0x01} + }, + { + {0x01, 0x01, 0xfe, 0x00}, {0x16, 0x01, 0xfe, 0x01}, + {0x00, 0x01, 0x02, 0x01}, {0x00, 0x01, 0x03, 0x01}, + {0x00, 0x01, 0x04, 0x01}, {0x00, 0x01, 0x05, 0x01}, + {0x00, 0x01, 0x06, 0x01}, {0x00, 0x01, 0x07, 0x01}, + {0x00, 0x01, 0x08, 0x01}, {0x00, 0x01, 0x0b, 0x01}, + {0x00, 0x01, 0x0c, 0x01}, {0x00, 0x01, 0x0e, 0x01}, + {0x00, 0x01, 0x0f, 0x01}, {0x00, 0x01, 0x10, 0x01}, + {0x00, 0x01, 0x11, 0x01}, {0x00, 0x01, 0x12, 0x01} + }, + /* 225 */ + { + {0x02, 0x01, 0xfe, 0x00}, {0x09, 0x01, 0xfe, 0x00}, + {0x17, 0x01, 0xfe, 0x00}, {0x28, 0x01, 0xfe, 0x01}, + {0x01, 0x01, 0x02, 0x00}, {0x16, 0x01, 0x02, 0x01}, + {0x01, 0x01, 0x03, 0x00}, {0x16, 0x01, 0x03, 0x01}, + {0x01, 0x01, 0x04, 0x00}, {0x16, 0x01, 0x04, 0x01}, + {0x01, 0x01, 0x05, 0x00}, {0x16, 0x01, 0x05, 0x01}, + {0x01, 0x01, 0x06, 0x00}, {0x16, 0x01, 0x06, 0x01}, + {0x01, 0x01, 0x07, 0x00}, {0x16, 0x01, 0x07, 0x01} + }, + { + {0x03, 0x01, 0xfe, 0x00}, {0x06, 0x01, 0xfe, 0x00}, + {0x0a, 0x01, 0xfe, 0x00}, {0x0f, 0x01, 0xfe, 0x00}, + {0x18, 0x01, 0xfe, 0x00}, {0x1f, 0x01, 0xfe, 0x00}, + {0x29, 0x01, 0xfe, 0x00}, {0x38, 0x01, 0xfe, 0x01}, + {0x02, 0x01, 0x02, 0x00}, {0x09, 0x01, 0x02, 0x00}, + {0x17, 0x01, 0x02, 0x00}, {0x28, 0x01, 0x02, 0x01}, + {0x02, 0x01, 0x03, 0x00}, {0x09, 0x01, 0x03, 0x00}, + {0x17, 0x01, 0x03, 0x00}, {0x28, 0x01, 0x03, 0x01} + }, + { + {0x03, 0x01, 0x02, 0x00}, {0x06, 0x01, 0x02, 0x00}, + {0x0a, 0x01, 0x02, 0x00}, {0x0f, 0x01, 0x02, 0x00}, + {0x18, 0x01, 0x02, 0x00}, {0x1f, 0x01, 0x02, 0x00}, + {0x29, 0x01, 0x02, 0x00}, {0x38, 0x01, 0x02, 0x01}, + {0x03, 0x01, 0x03, 0x00}, {0x06, 0x01, 0x03, 0x00}, + {0x0a, 0x01, 0x03, 0x00}, {0x0f, 0x01, 0x03, 0x00}, + {0x18, 0x01, 0x03, 0x00}, {0x1f, 0x01, 0x03, 0x00}, + {0x29, 0x01, 0x03, 0x00}, {0x38, 0x01, 0x03, 0x01} + }, + { + {0x02, 0x01, 0x04, 0x00}, {0x09, 0x01, 0x04, 0x00}, + {0x17, 0x01, 0x04, 0x00}, {0x28, 0x01, 0x04, 0x01}, + {0x02, 0x01, 0x05, 0x00}, {0x09, 0x01, 0x05, 0x00}, + {0x17, 0x01, 0x05, 0x00}, {0x28, 0x01, 0x05, 0x01}, + {0x02, 0x01, 0x06, 0x00}, {0x09, 0x01, 0x06, 0x00}, + {0x17, 0x01, 0x06, 0x00}, {0x28, 0x01, 0x06, 0x01}, + {0x02, 0x01, 0x07, 0x00}, {0x09, 0x01, 0x07, 0x00}, + {0x17, 0x01, 0x07, 0x00}, {0x28, 0x01, 0x07, 0x01} + }, + { + {0x03, 0x01, 0x04, 0x00}, {0x06, 0x01, 0x04, 0x00}, + {0x0a, 0x01, 0x04, 0x00}, {0x0f, 0x01, 0x04, 0x00}, + {0x18, 0x01, 0x04, 0x00}, {0x1f, 0x01, 0x04, 0x00}, + {0x29, 0x01, 0x04, 0x00}, {0x38, 0x01, 0x04, 0x01}, + {0x03, 0x01, 0x05, 0x00}, {0x06, 0x01, 0x05, 0x00}, + {0x0a, 0x01, 0x05, 0x00}, {0x0f, 0x01, 0x05, 0x00}, + {0x18, 0x01, 0x05, 0x00}, {0x1f, 0x01, 0x05, 0x00}, + {0x29, 0x01, 0x05, 0x00}, {0x38, 0x01, 0x05, 0x01} + }, + /* 230 */ + { + {0x03, 0x01, 0x06, 0x00}, {0x06, 0x01, 0x06, 0x00}, + {0x0a, 0x01, 0x06, 0x00}, {0x0f, 0x01, 0x06, 0x00}, + {0x18, 0x01, 0x06, 0x00}, {0x1f, 0x01, 0x06, 0x00}, + {0x29, 0x01, 0x06, 0x00}, {0x38, 0x01, 0x06, 0x01}, + {0x03, 0x01, 0x07, 0x00}, {0x06, 0x01, 0x07, 0x00}, + {0x0a, 0x01, 0x07, 0x00}, {0x0f, 0x01, 0x07, 0x00}, + {0x18, 0x01, 0x07, 0x00}, {0x1f, 0x01, 0x07, 0x00}, + {0x29, 0x01, 0x07, 0x00}, {0x38, 0x01, 0x07, 0x01} + }, + { + {0x01, 0x01, 0x08, 0x00}, {0x16, 0x01, 0x08, 0x01}, + {0x01, 0x01, 0x0b, 0x00}, {0x16, 0x01, 0x0b, 0x01}, + {0x01, 0x01, 0x0c, 0x00}, {0x16, 0x01, 0x0c, 0x01}, + {0x01, 0x01, 0x0e, 0x00}, {0x16, 0x01, 0x0e, 0x01}, + {0x01, 0x01, 0x0f, 0x00}, {0x16, 0x01, 0x0f, 0x01}, + {0x01, 0x01, 0x10, 0x00}, {0x16, 0x01, 0x10, 0x01}, + {0x01, 0x01, 0x11, 0x00}, {0x16, 0x01, 0x11, 0x01}, + {0x01, 0x01, 0x12, 0x00}, {0x16, 0x01, 0x12, 0x01} + }, + { + {0x02, 0x01, 0x08, 0x00}, {0x09, 0x01, 0x08, 0x00}, + {0x17, 0x01, 0x08, 0x00}, {0x28, 0x01, 0x08, 0x01}, + {0x02, 0x01, 0x0b, 0x00}, {0x09, 0x01, 0x0b, 0x00}, + {0x17, 0x01, 0x0b, 0x00}, {0x28, 0x01, 0x0b, 0x01}, + {0x02, 0x01, 0x0c, 0x00}, {0x09, 0x01, 0x0c, 0x00}, + {0x17, 0x01, 0x0c, 0x00}, {0x28, 0x01, 0x0c, 0x01}, + {0x02, 0x01, 0x0e, 0x00}, {0x09, 0x01, 0x0e, 0x00}, + {0x17, 0x01, 0x0e, 0x00}, {0x28, 0x01, 0x0e, 0x01} + }, + { + {0x03, 0x01, 0x08, 0x00}, {0x06, 0x01, 0x08, 0x00}, + {0x0a, 0x01, 0x08, 0x00}, {0x0f, 0x01, 0x08, 0x00}, + {0x18, 0x01, 0x08, 0x00}, {0x1f, 0x01, 0x08, 0x00}, + {0x29, 0x01, 0x08, 0x00}, {0x38, 0x01, 0x08, 0x01}, + {0x03, 0x01, 0x0b, 0x00}, {0x06, 0x01, 0x0b, 0x00}, + {0x0a, 0x01, 0x0b, 0x00}, {0x0f, 0x01, 0x0b, 0x00}, + {0x18, 0x01, 0x0b, 0x00}, {0x1f, 0x01, 0x0b, 0x00}, + {0x29, 0x01, 0x0b, 0x00}, {0x38, 0x01, 0x0b, 0x01} + }, + { + {0x03, 0x01, 0x0c, 0x00}, {0x06, 0x01, 0x0c, 0x00}, + {0x0a, 0x01, 0x0c, 0x00}, {0x0f, 0x01, 0x0c, 0x00}, + {0x18, 0x01, 0x0c, 0x00}, {0x1f, 0x01, 0x0c, 0x00}, + {0x29, 0x01, 0x0c, 0x00}, {0x38, 0x01, 0x0c, 0x01}, + {0x03, 0x01, 0x0e, 0x00}, {0x06, 0x01, 0x0e, 0x00}, + {0x0a, 0x01, 0x0e, 0x00}, {0x0f, 0x01, 0x0e, 0x00}, + {0x18, 0x01, 0x0e, 0x00}, {0x1f, 0x01, 0x0e, 0x00}, + {0x29, 0x01, 0x0e, 0x00}, {0x38, 0x01, 0x0e, 0x01} + }, + /* 235 */ + { + {0x02, 0x01, 0x0f, 0x00}, {0x09, 0x01, 0x0f, 0x00}, + {0x17, 0x01, 0x0f, 0x00}, {0x28, 0x01, 0x0f, 0x01}, + {0x02, 0x01, 0x10, 0x00}, {0x09, 0x01, 0x10, 0x00}, + {0x17, 0x01, 0x10, 0x00}, {0x28, 0x01, 0x10, 0x01}, + {0x02, 0x01, 0x11, 0x00}, {0x09, 0x01, 0x11, 0x00}, + {0x17, 0x01, 0x11, 0x00}, {0x28, 0x01, 0x11, 0x01}, + {0x02, 0x01, 0x12, 0x00}, {0x09, 0x01, 0x12, 0x00}, + {0x17, 0x01, 0x12, 0x00}, {0x28, 0x01, 0x12, 0x01} + }, + { + {0x03, 0x01, 0x0f, 0x00}, {0x06, 0x01, 0x0f, 0x00}, + {0x0a, 0x01, 0x0f, 0x00}, {0x0f, 0x01, 0x0f, 0x00}, + {0x18, 0x01, 0x0f, 0x00}, {0x1f, 0x01, 0x0f, 0x00}, + {0x29, 0x01, 0x0f, 0x00}, {0x38, 0x01, 0x0f, 0x01}, + {0x03, 0x01, 0x10, 0x00}, {0x06, 0x01, 0x10, 0x00}, + {0x0a, 0x01, 0x10, 0x00}, {0x0f, 0x01, 0x10, 0x00}, + {0x18, 0x01, 0x10, 0x00}, {0x1f, 0x01, 0x10, 0x00}, + {0x29, 0x01, 0x10, 0x00}, {0x38, 0x01, 0x10, 0x01} + }, + { + {0x03, 0x01, 0x11, 0x00}, {0x06, 0x01, 0x11, 0x00}, + {0x0a, 0x01, 0x11, 0x00}, {0x0f, 0x01, 0x11, 0x00}, + {0x18, 0x01, 0x11, 0x00}, {0x1f, 0x01, 0x11, 0x00}, + {0x29, 0x01, 0x11, 0x00}, {0x38, 0x01, 0x11, 0x01}, + {0x03, 0x01, 0x12, 0x00}, {0x06, 0x01, 0x12, 0x00}, + {0x0a, 0x01, 0x12, 0x00}, {0x0f, 0x01, 0x12, 0x00}, + {0x18, 0x01, 0x12, 0x00}, {0x1f, 0x01, 0x12, 0x00}, + {0x29, 0x01, 0x12, 0x00}, {0x38, 0x01, 0x12, 0x01} + }, + { + {0x00, 0x01, 0x13, 0x01}, {0x00, 0x01, 0x14, 0x01}, + {0x00, 0x01, 0x15, 0x01}, {0x00, 0x01, 0x17, 0x01}, + {0x00, 0x01, 0x18, 0x01}, {0x00, 0x01, 0x19, 0x01}, + {0x00, 0x01, 0x1a, 0x01}, {0x00, 0x01, 0x1b, 0x01}, + {0x00, 0x01, 0x1c, 0x01}, {0x00, 0x01, 0x1d, 0x01}, + {0x00, 0x01, 0x1e, 0x01}, {0x00, 0x01, 0x1f, 0x01}, + {0x00, 0x01, 0x7f, 0x01}, {0x00, 0x01, 0xdc, 0x01}, + {0x00, 0x01, 0xf9, 0x01}, {0xfd, 0x00, 0x00, 0x01} + }, + { + {0x01, 0x01, 0x13, 0x00}, {0x16, 0x01, 0x13, 0x01}, + {0x01, 0x01, 0x14, 0x00}, {0x16, 0x01, 0x14, 0x01}, + {0x01, 0x01, 0x15, 0x00}, {0x16, 0x01, 0x15, 0x01}, + {0x01, 0x01, 0x17, 0x00}, {0x16, 0x01, 0x17, 0x01}, + {0x01, 0x01, 0x18, 0x00}, {0x16, 0x01, 0x18, 0x01}, + {0x01, 0x01, 0x19, 0x00}, {0x16, 0x01, 0x19, 0x01}, + {0x01, 0x01, 0x1a, 0x00}, {0x16, 0x01, 0x1a, 0x01}, + {0x01, 0x01, 0x1b, 0x00}, {0x16, 0x01, 0x1b, 0x01} + }, + /* 240 */ + { + {0x02, 0x01, 0x13, 0x00}, {0x09, 0x01, 0x13, 0x00}, + {0x17, 0x01, 0x13, 0x00}, {0x28, 0x01, 0x13, 0x01}, + {0x02, 0x01, 0x14, 0x00}, {0x09, 0x01, 0x14, 0x00}, + {0x17, 0x01, 0x14, 0x00}, {0x28, 0x01, 0x14, 0x01}, + {0x02, 0x01, 0x15, 0x00}, {0x09, 0x01, 0x15, 0x00}, + {0x17, 0x01, 0x15, 0x00}, {0x28, 0x01, 0x15, 0x01}, + {0x02, 0x01, 0x17, 0x00}, {0x09, 0x01, 0x17, 0x00}, + {0x17, 0x01, 0x17, 0x00}, {0x28, 0x01, 0x17, 0x01} + }, + { + {0x03, 0x01, 0x13, 0x00}, {0x06, 0x01, 0x13, 0x00}, + {0x0a, 0x01, 0x13, 0x00}, {0x0f, 0x01, 0x13, 0x00}, + {0x18, 0x01, 0x13, 0x00}, {0x1f, 0x01, 0x13, 0x00}, + {0x29, 0x01, 0x13, 0x00}, {0x38, 0x01, 0x13, 0x01}, + {0x03, 0x01, 0x14, 0x00}, {0x06, 0x01, 0x14, 0x00}, + {0x0a, 0x01, 0x14, 0x00}, {0x0f, 0x01, 0x14, 0x00}, + {0x18, 0x01, 0x14, 0x00}, {0x1f, 0x01, 0x14, 0x00}, + {0x29, 0x01, 0x14, 0x00}, {0x38, 0x01, 0x14, 0x01} + }, + { + {0x03, 0x01, 0x15, 0x00}, {0x06, 0x01, 0x15, 0x00}, + {0x0a, 0x01, 0x15, 0x00}, {0x0f, 0x01, 0x15, 0x00}, + {0x18, 0x01, 0x15, 0x00}, {0x1f, 0x01, 0x15, 0x00}, + {0x29, 0x01, 0x15, 0x00}, {0x38, 0x01, 0x15, 0x01}, + {0x03, 0x01, 0x17, 0x00}, {0x06, 0x01, 0x17, 0x00}, + {0x0a, 0x01, 0x17, 0x00}, {0x0f, 0x01, 0x17, 0x00}, + {0x18, 0x01, 0x17, 0x00}, {0x1f, 0x01, 0x17, 0x00}, + {0x29, 0x01, 0x17, 0x00}, {0x38, 0x01, 0x17, 0x01} + }, + { + {0x02, 0x01, 0x18, 0x00}, {0x09, 0x01, 0x18, 0x00}, + {0x17, 0x01, 0x18, 0x00}, {0x28, 0x01, 0x18, 0x01}, + {0x02, 0x01, 0x19, 0x00}, {0x09, 0x01, 0x19, 0x00}, + {0x17, 0x01, 0x19, 0x00}, {0x28, 0x01, 0x19, 0x01}, + {0x02, 0x01, 0x1a, 0x00}, {0x09, 0x01, 0x1a, 0x00}, + {0x17, 0x01, 0x1a, 0x00}, {0x28, 0x01, 0x1a, 0x01}, + {0x02, 0x01, 0x1b, 0x00}, {0x09, 0x01, 0x1b, 0x00}, + {0x17, 0x01, 0x1b, 0x00}, {0x28, 0x01, 0x1b, 0x01} + }, + { + {0x03, 0x01, 0x18, 0x00}, {0x06, 0x01, 0x18, 0x00}, + {0x0a, 0x01, 0x18, 0x00}, {0x0f, 0x01, 0x18, 0x00}, + {0x18, 0x01, 0x18, 0x00}, {0x1f, 0x01, 0x18, 0x00}, + {0x29, 0x01, 0x18, 0x00}, {0x38, 0x01, 0x18, 0x01}, + {0x03, 0x01, 0x19, 0x00}, {0x06, 0x01, 0x19, 0x00}, + {0x0a, 0x01, 0x19, 0x00}, {0x0f, 0x01, 0x19, 0x00}, + {0x18, 0x01, 0x19, 0x00}, {0x1f, 0x01, 0x19, 0x00}, + {0x29, 0x01, 0x19, 0x00}, {0x38, 0x01, 0x19, 0x01} + }, + /* 245 */ + { + {0x03, 0x01, 0x1a, 0x00}, {0x06, 0x01, 0x1a, 0x00}, + {0x0a, 0x01, 0x1a, 0x00}, {0x0f, 0x01, 0x1a, 0x00}, + {0x18, 0x01, 0x1a, 0x00}, {0x1f, 0x01, 0x1a, 0x00}, + {0x29, 0x01, 0x1a, 0x00}, {0x38, 0x01, 0x1a, 0x01}, + {0x03, 0x01, 0x1b, 0x00}, {0x06, 0x01, 0x1b, 0x00}, + {0x0a, 0x01, 0x1b, 0x00}, {0x0f, 0x01, 0x1b, 0x00}, + {0x18, 0x01, 0x1b, 0x00}, {0x1f, 0x01, 0x1b, 0x00}, + {0x29, 0x01, 0x1b, 0x00}, {0x38, 0x01, 0x1b, 0x01} + }, + { + {0x01, 0x01, 0x1c, 0x00}, {0x16, 0x01, 0x1c, 0x01}, + {0x01, 0x01, 0x1d, 0x00}, {0x16, 0x01, 0x1d, 0x01}, + {0x01, 0x01, 0x1e, 0x00}, {0x16, 0x01, 0x1e, 0x01}, + {0x01, 0x01, 0x1f, 0x00}, {0x16, 0x01, 0x1f, 0x01}, + {0x01, 0x01, 0x7f, 0x00}, {0x16, 0x01, 0x7f, 0x01}, + {0x01, 0x01, 0xdc, 0x00}, {0x16, 0x01, 0xdc, 0x01}, + {0x01, 0x01, 0xf9, 0x00}, {0x16, 0x01, 0xf9, 0x01}, + {0xfe, 0x00, 0x00, 0x00}, {0xff, 0x00, 0x00, 0x01} + }, + { + {0x02, 0x01, 0x1c, 0x00}, {0x09, 0x01, 0x1c, 0x00}, + {0x17, 0x01, 0x1c, 0x00}, {0x28, 0x01, 0x1c, 0x01}, + {0x02, 0x01, 0x1d, 0x00}, {0x09, 0x01, 0x1d, 0x00}, + {0x17, 0x01, 0x1d, 0x00}, {0x28, 0x01, 0x1d, 0x01}, + {0x02, 0x01, 0x1e, 0x00}, {0x09, 0x01, 0x1e, 0x00}, + {0x17, 0x01, 0x1e, 0x00}, {0x28, 0x01, 0x1e, 0x01}, + {0x02, 0x01, 0x1f, 0x00}, {0x09, 0x01, 0x1f, 0x00}, + {0x17, 0x01, 0x1f, 0x00}, {0x28, 0x01, 0x1f, 0x01} + }, + { + {0x03, 0x01, 0x1c, 0x00}, {0x06, 0x01, 0x1c, 0x00}, + {0x0a, 0x01, 0x1c, 0x00}, {0x0f, 0x01, 0x1c, 0x00}, + {0x18, 0x01, 0x1c, 0x00}, {0x1f, 0x01, 0x1c, 0x00}, + {0x29, 0x01, 0x1c, 0x00}, {0x38, 0x01, 0x1c, 0x01}, + {0x03, 0x01, 0x1d, 0x00}, {0x06, 0x01, 0x1d, 0x00}, + {0x0a, 0x01, 0x1d, 0x00}, {0x0f, 0x01, 0x1d, 0x00}, + {0x18, 0x01, 0x1d, 0x00}, {0x1f, 0x01, 0x1d, 0x00}, + {0x29, 0x01, 0x1d, 0x00}, {0x38, 0x01, 0x1d, 0x01} + }, + { + {0x03, 0x01, 0x1e, 0x00}, {0x06, 0x01, 0x1e, 0x00}, + {0x0a, 0x01, 0x1e, 0x00}, {0x0f, 0x01, 0x1e, 0x00}, + {0x18, 0x01, 0x1e, 0x00}, {0x1f, 0x01, 0x1e, 0x00}, + {0x29, 0x01, 0x1e, 0x00}, {0x38, 0x01, 0x1e, 0x01}, + {0x03, 0x01, 0x1f, 0x00}, {0x06, 0x01, 0x1f, 0x00}, + {0x0a, 0x01, 0x1f, 0x00}, {0x0f, 0x01, 0x1f, 0x00}, + {0x18, 0x01, 0x1f, 0x00}, {0x1f, 0x01, 0x1f, 0x00}, + {0x29, 0x01, 0x1f, 0x00}, {0x38, 0x01, 0x1f, 0x01} + }, + /* 250 */ + { + {0x02, 0x01, 0x7f, 0x00}, {0x09, 0x01, 0x7f, 0x00}, + {0x17, 0x01, 0x7f, 0x00}, {0x28, 0x01, 0x7f, 0x01}, + {0x02, 0x01, 0xdc, 0x00}, {0x09, 0x01, 0xdc, 0x00}, + {0x17, 0x01, 0xdc, 0x00}, {0x28, 0x01, 0xdc, 0x01}, + {0x02, 0x01, 0xf9, 0x00}, {0x09, 0x01, 0xf9, 0x00}, + {0x17, 0x01, 0xf9, 0x00}, {0x28, 0x01, 0xf9, 0x01}, + {0x00, 0x01, 0x0a, 0x01}, {0x00, 0x01, 0x0d, 0x01}, + {0x00, 0x01, 0x16, 0x01}, {0xfa, 0x00, 0x00, 0x00} + }, + { + {0x03, 0x01, 0x7f, 0x00}, {0x06, 0x01, 0x7f, 0x00}, + {0x0a, 0x01, 0x7f, 0x00}, {0x0f, 0x01, 0x7f, 0x00}, + {0x18, 0x01, 0x7f, 0x00}, {0x1f, 0x01, 0x7f, 0x00}, + {0x29, 0x01, 0x7f, 0x00}, {0x38, 0x01, 0x7f, 0x01}, + {0x03, 0x01, 0xdc, 0x00}, {0x06, 0x01, 0xdc, 0x00}, + {0x0a, 0x01, 0xdc, 0x00}, {0x0f, 0x01, 0xdc, 0x00}, + {0x18, 0x01, 0xdc, 0x00}, {0x1f, 0x01, 0xdc, 0x00}, + {0x29, 0x01, 0xdc, 0x00}, {0x38, 0x01, 0xdc, 0x01} + }, + { + {0x03, 0x01, 0xf9, 0x00}, {0x06, 0x01, 0xf9, 0x00}, + {0x0a, 0x01, 0xf9, 0x00}, {0x0f, 0x01, 0xf9, 0x00}, + {0x18, 0x01, 0xf9, 0x00}, {0x1f, 0x01, 0xf9, 0x00}, + {0x29, 0x01, 0xf9, 0x00}, {0x38, 0x01, 0xf9, 0x01}, + {0x01, 0x01, 0x0a, 0x00}, {0x16, 0x01, 0x0a, 0x01}, + {0x01, 0x01, 0x0d, 0x00}, {0x16, 0x01, 0x0d, 0x01}, + {0x01, 0x01, 0x16, 0x00}, {0x16, 0x01, 0x16, 0x01}, + {0xfc, 0x00, 0x00, 0x00}, {0xfc, 0x00, 0x00, 0x00} + }, + { + {0x02, 0x01, 0x0a, 0x00}, {0x09, 0x01, 0x0a, 0x00}, + {0x17, 0x01, 0x0a, 0x00}, {0x28, 0x01, 0x0a, 0x01}, + {0x02, 0x01, 0x0d, 0x00}, {0x09, 0x01, 0x0d, 0x00}, + {0x17, 0x01, 0x0d, 0x00}, {0x28, 0x01, 0x0d, 0x01}, + {0x02, 0x01, 0x16, 0x00}, {0x09, 0x01, 0x16, 0x00}, + {0x17, 0x01, 0x16, 0x00}, {0x28, 0x01, 0x16, 0x01}, + {0xfd, 0x00, 0x00, 0x00}, {0xfd, 0x00, 0x00, 0x00}, + {0xfd, 0x00, 0x00, 0x00}, {0xfd, 0x00, 0x00, 0x00} + }, + { + {0x03, 0x01, 0x0a, 0x00}, {0x06, 0x01, 0x0a, 0x00}, + {0x0a, 0x01, 0x0a, 0x00}, {0x0f, 0x01, 0x0a, 0x00}, + {0x18, 0x01, 0x0a, 0x00}, {0x1f, 0x01, 0x0a, 0x00}, + {0x29, 0x01, 0x0a, 0x00}, {0x38, 0x01, 0x0a, 0x01}, + {0x03, 0x01, 0x0d, 0x00}, {0x06, 0x01, 0x0d, 0x00}, + {0x0a, 0x01, 0x0d, 0x00}, {0x0f, 0x01, 0x0d, 0x00}, + {0x18, 0x01, 0x0d, 0x00}, {0x1f, 0x01, 0x0d, 0x00}, + {0x29, 0x01, 0x0d, 0x00}, {0x38, 0x01, 0x0d, 0x01} + }, + /* 255 */ + { + {0x03, 0x01, 0x16, 0x00}, {0x06, 0x01, 0x16, 0x00}, + {0x0a, 0x01, 0x16, 0x00}, {0x0f, 0x01, 0x16, 0x00}, + {0x18, 0x01, 0x16, 0x00}, {0x1f, 0x01, 0x16, 0x00}, + {0x29, 0x01, 0x16, 0x00}, {0x38, 0x01, 0x16, 0x01}, + {0xff, 0x00, 0x00, 0x00}, {0xff, 0x00, 0x00, 0x00}, + {0xff, 0x00, 0x00, 0x00}, {0xff, 0x00, 0x00, 0x00}, + {0xff, 0x00, 0x00, 0x00}, {0xff, 0x00, 0x00, 0x00}, + {0xff, 0x00, 0x00, 0x00}, {0xff, 0x00, 0x00, 0x00} + } +}; + + +ngx_int_t +ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, + ngx_uint_t last, ngx_log_t *log) +{ + u_char *end, ch, ending; + + ch = 0; + ending = 1; + + end = src + len; + + while (src != end) { + ch = *src++; + + if (ngx_http_v2_huff_decode_bits(state, &ending, ch >> 4, dst) + != NGX_OK) + { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, + "http2 huffman decoding error at state %d: " + "bad code 0x%Xd", *state, ch >> 4); + + return NGX_ERROR; + } + + if (ngx_http_v2_huff_decode_bits(state, &ending, ch & 0xf, dst) + != NGX_OK) + { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, + "http2 huffman decoding error at state %d: " + "bad code 0x%Xd", *state, ch & 0xf); + + return NGX_ERROR; + } + } + + if (last) { + if (!ending) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "http2 huffman decoding error: " + "incomplete code 0x%Xd", ch); + + return NGX_ERROR; + } + + *state = 0; + } + + return NGX_OK; +} + + + +static ngx_inline ngx_int_t +ngx_http_v2_huff_decode_bits(u_char *state, u_char *ending, ngx_uint_t bits, + u_char **dst) +{ + ngx_http_v2_huff_decode_code_t code; + + code = ngx_http_v2_huff_decode_codes[*state][bits]; + + if (code.next == *state) { + return NGX_ERROR; + } + + if (code.emit) { + *(*dst)++ = code.sym; + } + + *ending = code.ending; + *state = code.next; + + return NGX_OK; +} diff --git a/src/http/v2/ngx_http_v2_huff_encode.c b/src/http/v2/ngx_http_v2_huff_encode.c new file mode 100644 index 0000000..6c412cf --- /dev/null +++ b/src/http/v2/ngx_http_v2_huff_encode.c @@ -0,0 +1,10 @@ + +/* + * Copyright (C) Nginx, Inc. + * Copyright (C) Valentin V. Bartenev + */ + + +#include +#include +#include diff --git a/src/http/v2/ngx_http_v2_module.c b/src/http/v2/ngx_http_v2_module.c new file mode 100644 index 0000000..d99ac30 --- /dev/null +++ b/src/http/v2/ngx_http_v2_module.c @@ -0,0 +1,469 @@ + +/* + * Copyright (C) Nginx, Inc. + * Copyright (C) Valentin V. Bartenev + */ + + +#include +#include +#include +#include + + +static ngx_int_t ngx_http_v2_add_variables(ngx_conf_t *cf); + +static ngx_int_t ngx_http_v2_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + +static ngx_int_t ngx_http_v2_module_init(ngx_cycle_t *cycle); + +static void *ngx_http_v2_create_main_conf(ngx_conf_t *cf); +static char *ngx_http_v2_init_main_conf(ngx_conf_t *cf, void *conf); +static void *ngx_http_v2_create_srv_conf(ngx_conf_t *cf); +static char *ngx_http_v2_merge_srv_conf(ngx_conf_t *cf, void *parent, + void *child); +static void *ngx_http_v2_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_v2_merge_loc_conf(ngx_conf_t *cf, void *parent, + void *child); + +static char *ngx_http_v2_recv_buffer_size(ngx_conf_t *cf, void *post, + void *data); +static char *ngx_http_v2_pool_size(ngx_conf_t *cf, void *post, void *data); +static char *ngx_http_v2_streams_index_mask(ngx_conf_t *cf, void *post, + void *data); +static char *ngx_http_v2_chunk_size(ngx_conf_t *cf, void *post, void *data); +static char *ngx_http_v2_spdy_deprecated(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_conf_post_t ngx_http_v2_recv_buffer_size_post = + { ngx_http_v2_recv_buffer_size }; +static ngx_conf_post_t ngx_http_v2_pool_size_post = + { ngx_http_v2_pool_size }; +static ngx_conf_post_t ngx_http_v2_streams_index_mask_post = + { ngx_http_v2_streams_index_mask }; +static ngx_conf_post_t ngx_http_v2_chunk_size_post = + { ngx_http_v2_chunk_size }; + + +static ngx_command_t ngx_http_v2_commands[] = { + + { ngx_string("http2_recv_buffer_size"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_v2_main_conf_t, recv_buffer_size), + &ngx_http_v2_recv_buffer_size_post }, + + { ngx_string("http2_pool_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v2_srv_conf_t, pool_size), + &ngx_http_v2_pool_size_post }, + + { ngx_string("http2_max_concurrent_streams"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v2_srv_conf_t, concurrent_streams), + NULL }, + + { ngx_string("http2_max_field_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v2_srv_conf_t, max_field_size), + NULL }, + + { ngx_string("http2_max_header_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v2_srv_conf_t, max_header_size), + NULL }, + + { ngx_string("http2_streams_index_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v2_srv_conf_t, streams_index_mask), + &ngx_http_v2_streams_index_mask_post }, + + { ngx_string("http2_recv_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v2_srv_conf_t, recv_timeout), + NULL }, + + { ngx_string("http2_idle_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v2_srv_conf_t, idle_timeout), + NULL }, + + { ngx_string("http2_chunk_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_v2_loc_conf_t, chunk_size), + &ngx_http_v2_chunk_size_post }, + + { ngx_string("spdy_recv_buffer_size"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_http_v2_spdy_deprecated, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("spdy_pool_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_v2_spdy_deprecated, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("spdy_max_concurrent_streams"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_v2_spdy_deprecated, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("spdy_streams_index_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_v2_spdy_deprecated, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("spdy_recv_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_v2_spdy_deprecated, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("spdy_keepalive_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_v2_spdy_deprecated, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("spdy_headers_comp"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_v2_spdy_deprecated, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("spdy_chunk_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_v2_spdy_deprecated, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_v2_module_ctx = { + ngx_http_v2_add_variables, /* preconfiguration */ + NULL, /* postconfiguration */ + + ngx_http_v2_create_main_conf, /* create main configuration */ + ngx_http_v2_init_main_conf, /* init main configuration */ + + ngx_http_v2_create_srv_conf, /* create server configuration */ + ngx_http_v2_merge_srv_conf, /* merge server configuration */ + + ngx_http_v2_create_loc_conf, /* create location configuration */ + ngx_http_v2_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_v2_module = { + NGX_MODULE_V1, + &ngx_http_v2_module_ctx, /* module context */ + ngx_http_v2_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + ngx_http_v2_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_http_variable_t ngx_http_v2_vars[] = { + + { ngx_string("http2"), NULL, + ngx_http_v2_variable, 0, 0, 0 }, + + { ngx_null_string, NULL, NULL, 0, 0, 0 } +}; + + +static ngx_int_t +ngx_http_v2_add_variables(ngx_conf_t *cf) +{ + ngx_http_variable_t *var, *v; + + for (v = ngx_http_v2_vars; v->name.len; v++) { + var = ngx_http_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = v->get_handler; + var->data = v->data; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v2_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + + if (r->stream) { +#if (NGX_HTTP_SSL) + + if (r->connection->ssl) { + v->len = sizeof("h2") - 1; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = (u_char *) "h2"; + + return NGX_OK; + } + +#endif + v->len = sizeof("h2c") - 1; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = (u_char *) "h2c"; + + return NGX_OK; + } + + *v = ngx_http_variable_null_value; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v2_module_init(ngx_cycle_t *cycle) +{ + return NGX_OK; +} + + +static void * +ngx_http_v2_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_v2_main_conf_t *h2mcf; + + h2mcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_v2_main_conf_t)); + if (h2mcf == NULL) { + return NULL; + } + + h2mcf->recv_buffer_size = NGX_CONF_UNSET_SIZE; + + return h2mcf; +} + + +static char * +ngx_http_v2_init_main_conf(ngx_conf_t *cf, void *conf) +{ + ngx_http_v2_main_conf_t *h2mcf = conf; + + ngx_conf_init_size_value(h2mcf->recv_buffer_size, 256 * 1024); + + return NGX_CONF_OK; +} + + +static void * +ngx_http_v2_create_srv_conf(ngx_conf_t *cf) +{ + ngx_http_v2_srv_conf_t *h2scf; + + h2scf = ngx_pcalloc(cf->pool, sizeof(ngx_http_v2_srv_conf_t)); + if (h2scf == NULL) { + return NULL; + } + + h2scf->pool_size = NGX_CONF_UNSET_SIZE; + + h2scf->concurrent_streams = NGX_CONF_UNSET_UINT; + + h2scf->max_field_size = NGX_CONF_UNSET_SIZE; + h2scf->max_header_size = NGX_CONF_UNSET_SIZE; + + h2scf->streams_index_mask = NGX_CONF_UNSET_UINT; + + h2scf->recv_timeout = NGX_CONF_UNSET_MSEC; + h2scf->idle_timeout = NGX_CONF_UNSET_MSEC; + + return h2scf; +} + + +static char * +ngx_http_v2_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_v2_srv_conf_t *prev = parent; + ngx_http_v2_srv_conf_t *conf = child; + + ngx_conf_merge_size_value(conf->pool_size, prev->pool_size, 4096); + + ngx_conf_merge_uint_value(conf->concurrent_streams, + prev->concurrent_streams, 128); + + ngx_conf_merge_size_value(conf->max_field_size, prev->max_field_size, + 4096); + ngx_conf_merge_size_value(conf->max_header_size, prev->max_header_size, + 16384); + + ngx_conf_merge_uint_value(conf->streams_index_mask, + prev->streams_index_mask, 32 - 1); + + ngx_conf_merge_msec_value(conf->recv_timeout, + prev->recv_timeout, 30000); + ngx_conf_merge_msec_value(conf->idle_timeout, + prev->idle_timeout, 180000); + + return NGX_CONF_OK; +} + + +static void * +ngx_http_v2_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_v2_loc_conf_t *h2lcf; + + h2lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_v2_loc_conf_t)); + if (h2lcf == NULL) { + return NULL; + } + + h2lcf->chunk_size = NGX_CONF_UNSET_SIZE; + + return h2lcf; +} + + +static char * +ngx_http_v2_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_v2_loc_conf_t *prev = parent; + ngx_http_v2_loc_conf_t *conf = child; + + ngx_conf_merge_size_value(conf->chunk_size, prev->chunk_size, 8 * 1024); + + return NGX_CONF_OK; +} + + +static char * +ngx_http_v2_recv_buffer_size(ngx_conf_t *cf, void *post, void *data) +{ + size_t *sp = data; + + if (*sp <= 2 * NGX_HTTP_V2_STATE_BUFFER_SIZE) { + return "value is too small"; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_v2_pool_size(ngx_conf_t *cf, void *post, void *data) +{ + size_t *sp = data; + + if (*sp < NGX_MIN_POOL_SIZE) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the pool size must be no less than %uz", + NGX_MIN_POOL_SIZE); + + return NGX_CONF_ERROR; + } + + if (*sp % NGX_POOL_ALIGNMENT) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the pool size must be a multiple of %uz", + NGX_POOL_ALIGNMENT); + + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_v2_streams_index_mask(ngx_conf_t *cf, void *post, void *data) +{ + ngx_uint_t *np = data; + + ngx_uint_t mask; + + mask = *np - 1; + + if (*np == 0 || (*np & mask)) { + return "must be a power of two"; + } + + *np = mask; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_v2_chunk_size(ngx_conf_t *cf, void *post, void *data) +{ + size_t *sp = data; + + if (*sp == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the http2 chunk size cannot be zero"); + + return NGX_CONF_ERROR; + } + + if (*sp > NGX_HTTP_V2_MAX_FRAME_SIZE) { + *sp = NGX_HTTP_V2_MAX_FRAME_SIZE; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_v2_spdy_deprecated(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "invalid directive \"%V\": ngx_http_spdy_module " + "was superseded by ngx_http_v2_module", &cmd->name); + + return NGX_CONF_OK; +} diff --git a/src/http/ngx_http_spdy_module.h b/src/http/v2/ngx_http_v2_module.h similarity index 58% rename from src/http/ngx_http_spdy_module.h rename to src/http/v2/ngx_http_v2_module.h index 5242322..95cc7d8 100644 --- a/src/http/ngx_http_spdy_module.h +++ b/src/http/v2/ngx_http_v2_module.h @@ -5,8 +5,8 @@ */ -#ifndef _NGX_HTTP_SPDY_MODULE_H_INCLUDED_ -#define _NGX_HTTP_SPDY_MODULE_H_INCLUDED_ +#ifndef _NGX_HTTP_V2_MODULE_H_INCLUDED_ +#define _NGX_HTTP_V2_MODULE_H_INCLUDED_ #include @@ -17,25 +17,26 @@ typedef struct { size_t recv_buffer_size; u_char *recv_buffer; -} ngx_http_spdy_main_conf_t; +} ngx_http_v2_main_conf_t; typedef struct { size_t pool_size; ngx_uint_t concurrent_streams; + size_t max_field_size; + size_t max_header_size; ngx_uint_t streams_index_mask; ngx_msec_t recv_timeout; - ngx_msec_t keepalive_timeout; - ngx_int_t headers_comp; -} ngx_http_spdy_srv_conf_t; + ngx_msec_t idle_timeout; +} ngx_http_v2_srv_conf_t; typedef struct { size_t chunk_size; -} ngx_http_spdy_loc_conf_t; +} ngx_http_v2_loc_conf_t; -extern ngx_module_t ngx_http_spdy_module; +extern ngx_module_t ngx_http_v2_module; -#endif /* _NGX_HTTP_SPDY_MODULE_H_INCLUDED_ */ +#endif /* _NGX_HTTP_V2_MODULE_H_INCLUDED_ */ diff --git a/src/http/v2/ngx_http_v2_table.c b/src/http/v2/ngx_http_v2_table.c new file mode 100644 index 0000000..a73748a --- /dev/null +++ b/src/http/v2/ngx_http_v2_table.c @@ -0,0 +1,349 @@ + +/* + * Copyright (C) Nginx, Inc. + * Copyright (C) Valentin V. Bartenev + */ + + +#include +#include +#include + + +#define NGX_HTTP_V2_TABLE_SIZE 4096 + + +static ngx_int_t ngx_http_v2_table_account(ngx_http_v2_connection_t *h2c, + size_t size); + + +static ngx_http_v2_header_t ngx_http_v2_static_table[] = { + { ngx_string(":authority"), ngx_string("") }, + { ngx_string(":method"), ngx_string("GET") }, + { ngx_string(":method"), ngx_string("POST") }, + { ngx_string(":path"), ngx_string("/") }, + { ngx_string(":path"), ngx_string("/index.html") }, + { ngx_string(":scheme"), ngx_string("http") }, + { ngx_string(":scheme"), ngx_string("https") }, + { ngx_string(":status"), ngx_string("200") }, + { ngx_string(":status"), ngx_string("204") }, + { ngx_string(":status"), ngx_string("206") }, + { ngx_string(":status"), ngx_string("304") }, + { ngx_string(":status"), ngx_string("400") }, + { ngx_string(":status"), ngx_string("404") }, + { ngx_string(":status"), ngx_string("500") }, + { ngx_string("accept-charset"), ngx_string("") }, + { ngx_string("accept-encoding"), ngx_string("gzip, deflate") }, + { ngx_string("accept-language"), ngx_string("") }, + { ngx_string("accept-ranges"), ngx_string("") }, + { ngx_string("accept"), ngx_string("") }, + { ngx_string("access-control-allow-origin"), ngx_string("") }, + { ngx_string("age"), ngx_string("") }, + { ngx_string("allow"), ngx_string("") }, + { ngx_string("authorization"), ngx_string("") }, + { ngx_string("cache-control"), ngx_string("") }, + { ngx_string("content-disposition"), ngx_string("") }, + { ngx_string("content-encoding"), ngx_string("") }, + { ngx_string("content-language"), ngx_string("") }, + { ngx_string("content-length"), ngx_string("") }, + { ngx_string("content-location"), ngx_string("") }, + { ngx_string("content-range"), ngx_string("") }, + { ngx_string("content-type"), ngx_string("") }, + { ngx_string("cookie"), ngx_string("") }, + { ngx_string("date"), ngx_string("") }, + { ngx_string("etag"), ngx_string("") }, + { ngx_string("expect"), ngx_string("") }, + { ngx_string("expires"), ngx_string("") }, + { ngx_string("from"), ngx_string("") }, + { ngx_string("host"), ngx_string("") }, + { ngx_string("if-match"), ngx_string("") }, + { ngx_string("if-modified-since"), ngx_string("") }, + { ngx_string("if-none-match"), ngx_string("") }, + { ngx_string("if-range"), ngx_string("") }, + { ngx_string("if-unmodified-since"), ngx_string("") }, + { ngx_string("last-modified"), ngx_string("") }, + { ngx_string("link"), ngx_string("") }, + { ngx_string("location"), ngx_string("") }, + { ngx_string("max-forwards"), ngx_string("") }, + { ngx_string("proxy-authenticate"), ngx_string("") }, + { ngx_string("proxy-authorization"), ngx_string("") }, + { ngx_string("range"), ngx_string("") }, + { ngx_string("referer"), ngx_string("") }, + { ngx_string("refresh"), ngx_string("") }, + { ngx_string("retry-after"), ngx_string("") }, + { ngx_string("server"), ngx_string("") }, + { ngx_string("set-cookie"), ngx_string("") }, + { ngx_string("strict-transport-security"), ngx_string("") }, + { ngx_string("transfer-encoding"), ngx_string("") }, + { ngx_string("user-agent"), ngx_string("") }, + { ngx_string("vary"), ngx_string("") }, + { ngx_string("via"), ngx_string("") }, + { ngx_string("www-authenticate"), ngx_string("") }, +}; + +#define NGX_HTTP_V2_STATIC_TABLE_ENTRIES \ + (sizeof(ngx_http_v2_static_table) \ + / sizeof(ngx_http_v2_header_t)) + + +ngx_int_t +ngx_http_v2_get_indexed_header(ngx_http_v2_connection_t *h2c, ngx_uint_t index, + ngx_uint_t name_only) +{ + u_char *p; + size_t rest; + ngx_http_v2_header_t *entry; + + if (index == 0) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent invalid hpack table index 0"); + return NGX_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 get indexed %s: %ui", + name_only ? "header" : "header name", index); + + index--; + + if (index < NGX_HTTP_V2_STATIC_TABLE_ENTRIES) { + h2c->state.header = ngx_http_v2_static_table[index]; + return NGX_OK; + } + + index -= NGX_HTTP_V2_STATIC_TABLE_ENTRIES; + + if (index < h2c->hpack.added - h2c->hpack.deleted) { + index = (h2c->hpack.added - index - 1) % h2c->hpack.allocated; + entry = h2c->hpack.entries[index]; + + p = ngx_pnalloc(h2c->state.pool, entry->name.len + 1); + if (p == NULL) { + return NGX_ERROR; + } + + h2c->state.header.name.len = entry->name.len; + h2c->state.header.name.data = p; + + rest = h2c->hpack.storage + NGX_HTTP_V2_TABLE_SIZE - entry->name.data; + + if (entry->name.len > rest) { + p = ngx_cpymem(p, entry->name.data, rest); + p = ngx_cpymem(p, h2c->hpack.storage, entry->name.len - rest); + + } else { + p = ngx_cpymem(p, entry->name.data, entry->name.len); + } + + *p = '\0'; + + if (name_only) { + return NGX_OK; + } + + p = ngx_pnalloc(h2c->state.pool, entry->value.len + 1); + if (p == NULL) { + return NGX_ERROR; + } + + h2c->state.header.value.len = entry->value.len; + h2c->state.header.value.data = p; + + rest = h2c->hpack.storage + NGX_HTTP_V2_TABLE_SIZE - entry->value.data; + + if (entry->value.len > rest) { + p = ngx_cpymem(p, entry->value.data, rest); + p = ngx_cpymem(p, h2c->hpack.storage, entry->value.len - rest); + + } else { + p = ngx_cpymem(p, entry->value.data, entry->value.len); + } + + *p = '\0'; + + return NGX_OK; + } + + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent out of bound hpack table index: %ui", index); + + return NGX_ERROR; +} + + +ngx_int_t +ngx_http_v2_add_header(ngx_http_v2_connection_t *h2c, + ngx_http_v2_header_t *header) +{ + size_t avail; + ngx_uint_t index; + ngx_http_v2_header_t *entry, **entries; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 add header to hpack table: \"%V: %V\"", + &header->name, &header->value); + + if (h2c->hpack.entries == NULL) { + h2c->hpack.allocated = 64; + h2c->hpack.size = NGX_HTTP_V2_TABLE_SIZE; + h2c->hpack.free = NGX_HTTP_V2_TABLE_SIZE; + + h2c->hpack.entries = ngx_palloc(h2c->connection->pool, + sizeof(ngx_http_v2_header_t *) + * h2c->hpack.allocated); + if (h2c->hpack.entries == NULL) { + return NGX_ERROR; + } + + h2c->hpack.storage = ngx_palloc(h2c->connection->pool, + h2c->hpack.free); + if (h2c->hpack.storage == NULL) { + return NGX_ERROR; + } + + h2c->hpack.pos = h2c->hpack.storage; + } + + if (ngx_http_v2_table_account(h2c, header->name.len + header->value.len) + != NGX_OK) + { + return NGX_OK; + } + + if (h2c->hpack.reused == h2c->hpack.deleted) { + entry = ngx_palloc(h2c->connection->pool, sizeof(ngx_http_v2_header_t)); + if (entry == NULL) { + return NGX_ERROR; + } + + } else { + entry = h2c->hpack.entries[h2c->hpack.reused++ % h2c->hpack.allocated]; + } + + avail = h2c->hpack.storage + NGX_HTTP_V2_TABLE_SIZE - h2c->hpack.pos; + + entry->name.len = header->name.len; + entry->name.data = h2c->hpack.pos; + + if (avail >= header->name.len) { + h2c->hpack.pos = ngx_cpymem(h2c->hpack.pos, header->name.data, + header->name.len); + } else { + ngx_memcpy(h2c->hpack.pos, header->name.data, avail); + h2c->hpack.pos = ngx_cpymem(h2c->hpack.storage, + header->name.data + avail, + header->name.len - avail); + avail = NGX_HTTP_V2_TABLE_SIZE; + } + + avail -= header->name.len; + + entry->value.len = header->value.len; + entry->value.data = h2c->hpack.pos; + + if (avail >= header->value.len) { + h2c->hpack.pos = ngx_cpymem(h2c->hpack.pos, header->value.data, + header->value.len); + } else { + ngx_memcpy(h2c->hpack.pos, header->value.data, avail); + h2c->hpack.pos = ngx_cpymem(h2c->hpack.storage, + header->value.data + avail, + header->value.len - avail); + } + + if (h2c->hpack.allocated == h2c->hpack.added - h2c->hpack.deleted) { + + entries = ngx_palloc(h2c->connection->pool, + sizeof(ngx_http_v2_header_t *) + * (h2c->hpack.allocated + 64)); + if (entries == NULL) { + return NGX_ERROR; + } + + index = h2c->hpack.deleted % h2c->hpack.allocated; + + ngx_memcpy(entries, &h2c->hpack.entries[index], + (h2c->hpack.allocated - index) + * sizeof(ngx_http_v2_header_t *)); + + ngx_memcpy(&entries[h2c->hpack.allocated - index], h2c->hpack.entries, + index * sizeof(ngx_http_v2_header_t *)); + + (void) ngx_pfree(h2c->connection->pool, h2c->hpack.entries); + + h2c->hpack.entries = entries; + + h2c->hpack.added = h2c->hpack.allocated; + h2c->hpack.deleted = 0; + h2c->hpack.reused = 0; + h2c->hpack.allocated += 64; + } + + h2c->hpack.entries[h2c->hpack.added++ % h2c->hpack.allocated] = entry; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v2_table_account(ngx_http_v2_connection_t *h2c, size_t size) +{ + ngx_http_v2_header_t *entry; + + size += 32; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 hpack table account: %uz free:%uz", + size, h2c->hpack.free); + + if (size <= h2c->hpack.free) { + h2c->hpack.free -= size; + return NGX_OK; + } + + if (size > h2c->hpack.size) { + h2c->hpack.deleted = h2c->hpack.added; + h2c->hpack.free = h2c->hpack.size; + return NGX_DECLINED; + } + + do { + entry = h2c->hpack.entries[h2c->hpack.deleted++ % h2c->hpack.allocated]; + h2c->hpack.free += 32 + entry->name.len + entry->value.len; + } while (size > h2c->hpack.free); + + h2c->hpack.free -= size; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_v2_table_size(ngx_http_v2_connection_t *h2c, size_t size) +{ + ssize_t needed; + ngx_http_v2_header_t *entry; + + if (size > NGX_HTTP_V2_TABLE_SIZE) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent invalid table size update: %uz", size); + + return NGX_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 new hpack table size: %uz was:%uz", + size, h2c->hpack.size); + + needed = h2c->hpack.size - size; + + while (needed > (ssize_t) h2c->hpack.free) { + entry = h2c->hpack.entries[h2c->hpack.deleted++ % h2c->hpack.allocated]; + h2c->hpack.free += 32 + entry->name.len + entry->value.len; + } + + h2c->hpack.size = size; + h2c->hpack.free -= needed; + + return NGX_OK; +} diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c index 2a3ed2f..417b598 100644 --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -264,6 +264,7 @@ ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, u_char *prev; size_t size; ssize_t total, n; + ngx_err_t err; ngx_array_t vec; struct iovec *iov, iovs[NGX_IOVS]; @@ -335,10 +336,20 @@ ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, file->sys_offset = offset; } +eintr: + n = writev(file->fd, vec.elts, vec.nelts); if (n == -1) { - ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, + err = ngx_errno; + + if (err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, file->log, err, + "writev() was interrupted"); + goto eintr; + } + + ngx_log_error(NGX_LOG_CRIT, file->log, err, "writev() \"%s\" failed", file->name.data); return NGX_ERROR; } From 4e0f0048066088f11656d5764ebe8ca2f4b4d539 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 25 Sep 2015 14:03:48 +0300 Subject: [PATCH 056/651] New upstream release (1.9.5) --- debian/changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index 004eaa2..1fb0f6e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.9.5-1) UNRELEASED; urgency=medium + + [ Christos Trochalakis] + * New upstream release. + + -- Christos Trochalakis Fri, 25 Sep 2015 14:03:10 +0300 + nginx (1.9.4-1) unstable; urgency=medium [ Christos Trochalakis] From baf8feb207a5263be5260c2c5e2d70b958c9077a Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 30 Sep 2015 16:58:41 +0300 Subject: [PATCH 057/651] Enable http2 module --- debian/control | 6 +++--- debian/rules | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/debian/control b/debian/control index b3bfcc3..de705d4 100644 --- a/debian/control +++ b/debian/control @@ -98,7 +98,7 @@ Description: nginx web/proxy server (standard version) Referer, Rewrite, SCGI, Split Clients, UWSGI. . OPTIONAL HTTP MODULES: Addition, Auth Request, Charset, WebDAV, GeoIP, Gunzip, - Gzip, Gzip Precompression, Headers, Image Filter, Index, Log, Real IP, Spdy, + Gzip, Gzip Precompression, Headers, HTTP/2, Image Filter, Index, Log, Real IP, SSI, SSL, Stream, Stub Status, Substitution, Thread Pool, Upstream, User ID, XSLT. . @@ -185,8 +185,8 @@ Description: nginx web/proxy server (extended version) Referer, Rewrite, SCGI, Split Clients, UWSGI. . OPTIONAL HTTP MODULES: Addition, Auth Request, Charset, WebDAV, FLV, GeoIP, - Gunzip, Gzip, Gzip Precompression, Headers, Image Filter, Index, Log, MP4, - Embedded Perl, Random Index, Real IP, Secure Link, Spdy, SSI, SSL, Stream, + Gunzip, Gzip, Gzip Precompression, Headers, HTTP/2, Image Filter, Index, Log, + MP4, Embedded Perl, Random Index, Real IP, Secure Link, SSI, SSL, Stream, Stub Status, Substitution, Thread Pool, Upstream, User ID, XSLT. . MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. diff --git a/debian/rules b/debian/rules index 34223d8..1cdef59 100755 --- a/debian/rules +++ b/debian/rules @@ -73,7 +73,7 @@ full_configure_flags := \ --with-http_gunzip_module \ --with-http_gzip_static_module \ --with-http_image_filter_module \ - --with-http_spdy_module \ + --with-http_v2_module \ --with-http_sub_module \ --with-http_xslt_module \ --with-stream \ @@ -100,7 +100,7 @@ extras_configure_flags := \ --with-http_perl_module \ --with-http_random_index_module \ --with-http_secure_link_module \ - --with-http_spdy_module \ + --with-http_v2_module \ --with-http_sub_module \ --with-http_xslt_module \ --with-mail \ From efe7d922f49e133d66031b58fedbf308690080f6 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 30 Sep 2015 16:50:59 +0300 Subject: [PATCH 058/651] Add a NEWS entry for http2 --- debian/nginx-common.NEWS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/nginx-common.NEWS b/debian/nginx-common.NEWS index edd750f..161d061 100644 --- a/debian/nginx-common.NEWS +++ b/debian/nginx-common.NEWS @@ -1,3 +1,10 @@ +nginx-common (1.9.5-1) UNRELEASED; urgency=medium + + As of nginx 1.9.5 spdy has been replaced by the http2 module. Make sure to + replace "spdy" with "http2" in your config files. + + -- Christos Trochalakis Fri, 25 Sep 2015 14:06:28 +0300 + nginx-common (1.9.1-1) unstable; urgency=medium Starting with this release, we have enabled PIE build features which allows From 6a711b5bd6566b3723657c8e14e5de56079f7c94 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 3 Nov 2015 08:58:01 +0200 Subject: [PATCH 059/651] Imported Upstream version 1.9.6 --- CHANGES | 26 ++ CHANGES.ru | 27 ++ auto/endianness | 9 +- auto/types/uintptr_t | 9 +- src/core/nginx.c | 127 +++++---- src/core/nginx.h | 4 +- src/core/ngx_connection.c | 2 +- src/core/ngx_rwlock.c | 2 +- src/event/ngx_event.c | 9 + src/event/ngx_event_openssl.c | 25 +- src/event/ngx_event_openssl.h | 1 + src/http/ngx_http_core_module.c | 4 +- src/http/ngx_http_variables.c | 38 ++- src/http/v2/ngx_http_v2.c | 69 +++-- src/http/v2/ngx_http_v2.h | 3 +- src/http/v2/ngx_http_v2_filter_module.c | 352 ++++++++++++------------ src/stream/ngx_stream_proxy_module.c | 4 + 17 files changed, 413 insertions(+), 298 deletions(-) diff --git a/CHANGES b/CHANGES index 47d33a4..2b9809c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,30 @@ +Changes with nginx 1.9.6 27 Oct 2015 + + *) Bugfix: a segmentation fault might occur in a worker process when + using HTTP/2. + Thanks to Piotr Sikora and Denis Andzakovic. + + *) Bugfix: the $server_protocol variable was empty when using HTTP/2. + + *) Bugfix: backend SSL connections in the stream module might be timed + out unexpectedly. + + *) Bugfix: a segmentation fault might occur in a worker process if + different ssl_session_cache settings were used in different virtual + servers. + + *) Bugfix: nginx/Windows could not be built with MinGW gcc; the bug had + appeared in 1.9.4. + Thanks to Kouhei Sutou. + + *) Bugfix: time was not updated when the timer_resolution directive was + used on Windows. + + *) Miscellaneous minor fixes and improvements. + Thanks to Markus Linnala, Kurtis Nusbaum and Piotr Sikora. + + Changes with nginx 1.9.5 22 Sep 2015 *) Feature: the ngx_http_v2_module (replaces ngx_http_spdy_module). diff --git a/CHANGES.ru b/CHANGES.ru index b95c33d..3e8c364 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,31 @@ +Изменения в nginx 1.9.6 27.10.2015 + + *) Исправление: при использовании HTTP/2 в рабочем процессе мог + произойти segmentation fault. + Спасибо Piotr Sikora и Denis Andzakovic. + + *) Исправление: при использовании HTTP/2 переменная $server_protocol + была пустой. + + *) Исправление: SSL-соединения к бэкендам в модуле stream могли + неожиданно завершаться по таймауту. + + *) Исправление: при использовании различных настроек ssl_session_cache в + разных виртуальных серверах в рабочем процессе мог произойти + segmentation fault. + + *) Исправление: nginx/Windows не собирался с MinGW gcc; ошибка появилась + в 1.9.4. + Спасибо Kouhei Sutou. + + *) Исправление: при использовании директивы timer_resolution на Windows + время не обновлялось. + + *) Незначительные исправления и улучшения. + Спасибо Markus Linnala, Kurtis Nusbaum и Piotr Sikora. + + Изменения в nginx 1.9.5 22.09.2015 *) Добавление: модуль ngx_http_v2_module (заменяет модуль diff --git a/auto/endianness b/auto/endianness index 93da2f8..70b0a10 100644 --- a/auto/endianness +++ b/auto/endianness @@ -4,8 +4,13 @@ echo $ngx_n "checking for system byte ordering ...$ngx_c" -echo >> $NGX_ERR -echo "checking for system byte ordering" >> $NGX_ERR + +cat << END >> $NGX_AUTOCONF_ERR + +---------------------------------------- +checking for system byte ordering + +END cat << END > $NGX_AUTOTEST.c diff --git a/auto/types/uintptr_t b/auto/types/uintptr_t index f3cdccb..2b7212e 100644 --- a/auto/types/uintptr_t +++ b/auto/types/uintptr_t @@ -4,8 +4,13 @@ echo $ngx_n "checking for uintptr_t ...$ngx_c" -echo >> $NGX_AUTOCONF_ERR -echo "checking for uintptr_t" >> $NGX_AUTOCONF_ERR + +cat << END >> $NGX_AUTOCONF_ERR + +---------------------------------------- +checking for uintptr_t + +END found=no diff --git a/src/core/nginx.c b/src/core/nginx.c index 3213527..3335587 100644 --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -10,6 +10,7 @@ #include +static void ngx_show_version_info(); static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle); static ngx_int_t ngx_get_options(int argc, char *const *argv); static ngx_int_t ngx_process_options(ngx_cycle_t *cycle); @@ -194,64 +195,7 @@ main(int argc, char *const *argv) } if (ngx_show_version) { - ngx_write_stderr("nginx version: " NGINX_VER_BUILD NGX_LINEFEED); - - if (ngx_show_help) { - ngx_write_stderr( - "Usage: nginx [-?hvVtTq] [-s signal] [-c filename] " - "[-p prefix] [-g directives]" NGX_LINEFEED - NGX_LINEFEED - "Options:" NGX_LINEFEED - " -?,-h : this help" NGX_LINEFEED - " -v : show version and exit" NGX_LINEFEED - " -V : show version and configure options then exit" - NGX_LINEFEED - " -t : test configuration and exit" NGX_LINEFEED - " -T : test configuration, dump it and exit" - NGX_LINEFEED - " -q : suppress non-error messages " - "during configuration testing" NGX_LINEFEED - " -s signal : send signal to a master process: " - "stop, quit, reopen, reload" NGX_LINEFEED -#ifdef NGX_PREFIX - " -p prefix : set prefix path (default: " - NGX_PREFIX ")" NGX_LINEFEED -#else - " -p prefix : set prefix path (default: NONE)" NGX_LINEFEED -#endif - " -c filename : set configuration file (default: " - NGX_CONF_PATH ")" NGX_LINEFEED - " -g directives : set global directives out of configuration " - "file" NGX_LINEFEED NGX_LINEFEED - ); - } - - if (ngx_show_configure) { - -#ifdef NGX_COMPILER - ngx_write_stderr("built by " NGX_COMPILER NGX_LINEFEED); -#endif - -#if (NGX_SSL) - if (SSLeay() == SSLEAY_VERSION_NUMBER) { - ngx_write_stderr("built with " OPENSSL_VERSION_TEXT - NGX_LINEFEED); - } else { - ngx_write_stderr("built with " OPENSSL_VERSION_TEXT - " (running with "); - ngx_write_stderr((char *) (uintptr_t) - SSLeay_version(SSLEAY_VERSION)); - ngx_write_stderr(")" NGX_LINEFEED); - } -#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - ngx_write_stderr("TLS SNI support enabled" NGX_LINEFEED); -#else - ngx_write_stderr("TLS SNI support disabled" NGX_LINEFEED); -#endif -#endif - - ngx_write_stderr("configure arguments:" NGX_CONFIGURE NGX_LINEFEED); - } + ngx_show_version_info(); if (!ngx_test_config) { return 0; @@ -419,6 +363,69 @@ main(int argc, char *const *argv) } +static void +ngx_show_version_info() +{ + ngx_write_stderr("nginx version: " NGINX_VER_BUILD NGX_LINEFEED); + + if (ngx_show_help) { + ngx_write_stderr( + "Usage: nginx [-?hvVtTq] [-s signal] [-c filename] " + "[-p prefix] [-g directives]" NGX_LINEFEED + NGX_LINEFEED + "Options:" NGX_LINEFEED + " -?,-h : this help" NGX_LINEFEED + " -v : show version and exit" NGX_LINEFEED + " -V : show version and configure options then exit" + NGX_LINEFEED + " -t : test configuration and exit" NGX_LINEFEED + " -T : test configuration, dump it and exit" + NGX_LINEFEED + " -q : suppress non-error messages " + "during configuration testing" NGX_LINEFEED + " -s signal : send signal to a master process: " + "stop, quit, reopen, reload" NGX_LINEFEED +#ifdef NGX_PREFIX + " -p prefix : set prefix path (default: " NGX_PREFIX ")" + NGX_LINEFEED +#else + " -p prefix : set prefix path (default: NONE)" NGX_LINEFEED +#endif + " -c filename : set configuration file (default: " NGX_CONF_PATH + ")" NGX_LINEFEED + " -g directives : set global directives out of configuration " + "file" NGX_LINEFEED NGX_LINEFEED + ); + } + + if (ngx_show_configure) { + +#ifdef NGX_COMPILER + ngx_write_stderr("built by " NGX_COMPILER NGX_LINEFEED); +#endif + +#if (NGX_SSL) + if (SSLeay() == SSLEAY_VERSION_NUMBER) { + ngx_write_stderr("built with " OPENSSL_VERSION_TEXT NGX_LINEFEED); + } else { + ngx_write_stderr("built with " OPENSSL_VERSION_TEXT + " (running with "); + ngx_write_stderr((char *) (uintptr_t) + SSLeay_version(SSLEAY_VERSION)); + ngx_write_stderr(")" NGX_LINEFEED); + } +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + ngx_write_stderr("TLS SNI support enabled" NGX_LINEFEED); +#else + ngx_write_stderr("TLS SNI support disabled" NGX_LINEFEED); +#endif +#endif + + ngx_write_stderr("configure arguments:" NGX_CONFIGURE NGX_LINEFEED); + } +} + + static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle) { @@ -1139,7 +1146,7 @@ ngx_set_user(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_OK; } - value = (ngx_str_t *) cf->args->elts; + value = cf->args->elts; ccf->username = (char *) value[1].data; @@ -1345,7 +1352,7 @@ ngx_set_worker_processes(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return "is duplicate"; } - value = (ngx_str_t *) cf->args->elts; + value = cf->args->elts; if (ngx_strcmp(value[1].data, "auto") == 0) { ccf->worker_processes = ngx_ncpu; diff --git a/src/core/nginx.h b/src/core/nginx.h index 34a6a80..56e9587 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1009005 -#define NGINX_VERSION "1.9.5" +#define nginx_version 1009006 +#define NGINX_VERSION "1.9.6" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 9f2675b..0c19d5d 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -1175,7 +1175,7 @@ ngx_close_idle_connections(ngx_cycle_t *cycle) /* THREAD: lock */ - if (c[i].fd != -1 && c[i].idle) { + if (c[i].fd != (ngx_socket_t) -1 && c[i].idle) { c[i].close = 1; c[i].read->handler(c[i].read); } diff --git a/src/core/ngx_rwlock.c b/src/core/ngx_rwlock.c index 1404c6e..905de78 100644 --- a/src/core/ngx_rwlock.c +++ b/src/core/ngx_rwlock.c @@ -111,7 +111,7 @@ ngx_rwlock_unlock(ngx_atomic_t *lock) #else -#if (NGX_HTTP_UPSTREAM_ZONE) +#if (NGX_HTTP_UPSTREAM_ZONE || NGX_STREAM_UPSTREAM_ZONE) #error ngx_atomic_cmp_set() is not defined! diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index b8e0607..15da213 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -670,6 +670,15 @@ ngx_event_process_init(ngx_cycle_t *cycle) } } +#else + + if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) { + ngx_log_error(NGX_LOG_WARN, cycle->log, 0, + "the \"timer_resolution\" directive is not supported " + "with the configured event method, ignored"); + ngx_timer_resolution = 0; + } + #endif cycle->connections = diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 1b789e6..57dfc6c 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -1038,6 +1038,8 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags) sc->buffer = ((flags & NGX_SSL_BUFFER) != 0); sc->buffer_size = ssl->buffer_size; + sc->session_ctx = ssl->ctx; + sc->connection = SSL_new(ssl->ctx); if (sc->connection == NULL) { @@ -1158,6 +1160,7 @@ ngx_ssl_handshake(ngx_connection_t *c) c->recv_chain = ngx_ssl_recv_chain; c->send_chain = ngx_ssl_send_chain; +#if OPENSSL_VERSION_NUMBER < 0x10100000L #ifdef SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS /* initial handshake done, disable renegotiation (CVE-2009-3555) */ @@ -1165,6 +1168,7 @@ ngx_ssl_handshake(ngx_connection_t *c) c->ssl->connection->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS; } +#endif #endif return NGX_OK; @@ -2043,7 +2047,7 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...) (void) ERR_get_error(); } - ngx_log_error(level, log, err, "%s)", errstr); + ngx_log_error(level, log, err, "%*s)", p - errstr, errstr); } @@ -2303,7 +2307,7 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) c = ngx_ssl_get_connection(ssl_conn); - ssl_ctx = SSL_get_SSL_CTX(ssl_conn); + ssl_ctx = c->ssl->session_ctx; shm_zone = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_cache_index); cache = shm_zone->data; @@ -2441,21 +2445,17 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, u_char *id, int len, ngx_ssl_sess_id_t *sess_id; ngx_ssl_session_cache_t *cache; u_char buf[NGX_SSL_MAX_SESSION_SIZE]; -#if (NGX_DEBUG) ngx_connection_t *c; -#endif hash = ngx_crc32_short(id, (size_t) len); *copy = 0; -#if (NGX_DEBUG) c = ngx_ssl_get_connection(ssl_conn); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "ssl get session: %08XD:%d", hash, len); -#endif - shm_zone = SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl_conn), + shm_zone = SSL_CTX_get_ex_data(c->ssl->session_ctx, ngx_ssl_session_cache_index); cache = shm_zone->data; @@ -2834,13 +2834,14 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, SSL_CTX *ssl_ctx; ngx_uint_t i; ngx_array_t *keys; + ngx_connection_t *c; ngx_ssl_session_ticket_key_t *key; #if (NGX_DEBUG) u_char buf[32]; - ngx_connection_t *c; #endif - ssl_ctx = SSL_get_SSL_CTX(ssl_conn); + c = ngx_ssl_get_connection(ssl_conn); + ssl_ctx = c->ssl->session_ctx; keys = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_ticket_keys_index); if (keys == NULL) { @@ -2849,10 +2850,6 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, key = keys->elts; -#if (NGX_DEBUG) - c = ngx_ssl_get_connection(ssl_conn); -#endif - if (enc == 1) { /* encrypt session ticket */ @@ -2861,7 +2858,7 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, ngx_hex_dump(buf, key[0].name, 16) - buf, buf, SSL_session_reused(ssl_conn) ? "reused" : "new"); - RAND_pseudo_bytes(iv, 16); + RAND_bytes(iv, 16); EVP_EncryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, key[0].aes_key, iv); HMAC_Init_ex(hctx, key[0].hmac_key, 16, ngx_ssl_session_ticket_md(), NULL); diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 08eff64..c86be2a 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -46,6 +46,7 @@ typedef struct { typedef struct { ngx_ssl_conn_t *connection; + SSL_CTX *session_ctx; ngx_int_t last; ngx_buf_t *buf; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 36f00f6..7a29608 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -4489,7 +4489,9 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) clcf->alias = alias ? clcf->name.len : 0; clcf->root = value[1]; - if (!alias && clcf->root.data[clcf->root.len - 1] == '/') { + if (!alias && clcf->root.len > 0 + && clcf->root.data[clcf->root.len - 1] == '/') + { clcf->root.len--; } diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index c65de35..eaf294a 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -575,7 +575,7 @@ ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key) return NULL; } - if (ngx_strncmp(name->data, "http_", 5) == 0) { + if (name->len >= 5 && ngx_strncmp(name->data, "http_", 5) == 0) { if (ngx_http_variable_unknown_header_in(r, vv, (uintptr_t) name) == NGX_OK) @@ -586,7 +586,7 @@ ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key) return NULL; } - if (ngx_strncmp(name->data, "sent_http_", 10) == 0) { + if (name->len >= 10 && ngx_strncmp(name->data, "sent_http_", 10) == 0) { if (ngx_http_variable_unknown_header_out(r, vv, (uintptr_t) name) == NGX_OK) @@ -597,7 +597,7 @@ ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key) return NULL; } - if (ngx_strncmp(name->data, "upstream_http_", 14) == 0) { + if (name->len >= 14 && ngx_strncmp(name->data, "upstream_http_", 14) == 0) { if (ngx_http_upstream_header_variable(r, vv, (uintptr_t) name) == NGX_OK) @@ -608,7 +608,7 @@ ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key) return NULL; } - if (ngx_strncmp(name->data, "cookie_", 7) == 0) { + if (name->len >= 7 && ngx_strncmp(name->data, "cookie_", 7) == 0) { if (ngx_http_variable_cookie(r, vv, (uintptr_t) name) == NGX_OK) { return vv; @@ -617,7 +617,9 @@ ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key) return NULL; } - if (ngx_strncmp(name->data, "upstream_cookie_", 16) == 0) { + if (name->len >= 16 + && ngx_strncmp(name->data, "upstream_cookie_", 16) == 0) + { if (ngx_http_upstream_cookie_variable(r, vv, (uintptr_t) name) == NGX_OK) @@ -628,7 +630,7 @@ ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key) return NULL; } - if (ngx_strncmp(name->data, "arg_", 4) == 0) { + if (name->len >= 4 && ngx_strncmp(name->data, "arg_", 4) == 0) { if (ngx_http_variable_argument(r, vv, (uintptr_t) name) == NGX_OK) { return vv; @@ -2535,21 +2537,27 @@ ngx_http_variables_init_vars(ngx_conf_t *cf) } } - if (ngx_strncmp(v[i].name.data, "http_", 5) == 0) { + if (v[i].name.len >= 5 + && ngx_strncmp(v[i].name.data, "http_", 5) == 0) + { v[i].get_handler = ngx_http_variable_unknown_header_in; v[i].data = (uintptr_t) &v[i].name; continue; } - if (ngx_strncmp(v[i].name.data, "sent_http_", 10) == 0) { + if (v[i].name.len >= 10 + && ngx_strncmp(v[i].name.data, "sent_http_", 10) == 0) + { v[i].get_handler = ngx_http_variable_unknown_header_out; v[i].data = (uintptr_t) &v[i].name; continue; } - if (ngx_strncmp(v[i].name.data, "upstream_http_", 14) == 0) { + if (v[i].name.len >= 14 + && ngx_strncmp(v[i].name.data, "upstream_http_", 14) == 0) + { v[i].get_handler = ngx_http_upstream_header_variable; v[i].data = (uintptr_t) &v[i].name; v[i].flags = NGX_HTTP_VAR_NOCACHEABLE; @@ -2557,14 +2565,18 @@ ngx_http_variables_init_vars(ngx_conf_t *cf) continue; } - if (ngx_strncmp(v[i].name.data, "cookie_", 7) == 0) { + if (v[i].name.len >= 7 + && ngx_strncmp(v[i].name.data, "cookie_", 7) == 0) + { v[i].get_handler = ngx_http_variable_cookie; v[i].data = (uintptr_t) &v[i].name; continue; } - if (ngx_strncmp(v[i].name.data, "upstream_cookie_", 16) == 0) { + if (v[i].name.len >= 16 + && ngx_strncmp(v[i].name.data, "upstream_cookie_", 16) == 0) + { v[i].get_handler = ngx_http_upstream_cookie_variable; v[i].data = (uintptr_t) &v[i].name; v[i].flags = NGX_HTTP_VAR_NOCACHEABLE; @@ -2572,7 +2584,9 @@ ngx_http_variables_init_vars(ngx_conf_t *cf) continue; } - if (ngx_strncmp(v[i].name.data, "arg_", 4) == 0) { + if (v[i].name.len >= 4 + && ngx_strncmp(v[i].name.data, "arg_", 4) == 0) + { v[i].get_handler = ngx_http_variable_argument; v[i].data = (uintptr_t) &v[i].name; v[i].flags = NGX_HTTP_VAR_NOCACHEABLE; diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index bf07997..10cb727 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -870,6 +870,8 @@ ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) return ngx_http_v2_state_skip_padded(h2c, pos, end); } + stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; + h2c->state.stream = stream; return ngx_http_v2_state_read_data(h2c, pos, end); @@ -897,8 +899,6 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, } if (stream->skip_data) { - stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, "skipping http2 DATA frame, reason: %d", stream->skip_data); @@ -988,9 +988,7 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, ngx_http_v2_state_read_data); } - if (h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG) { - stream->in_closed = 1; - + if (stream->in_closed) { if (r->headers_in.content_length_n < 0) { r->headers_in.content_length_n = rb->rest; @@ -1133,6 +1131,22 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, h2c->last_sid = h2c->state.sid; + if (depend == h2c->state.sid) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent HEADERS frame for stream %ui " + "with incorrect dependency", h2c->state.sid); + + if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, + NGX_HTTP_V2_PROTOCOL_ERROR) + != NGX_OK) + { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + return ngx_http_v2_state_skip_headers(h2c, pos, end); + } + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, ngx_http_v2_module); @@ -1233,7 +1247,7 @@ ngx_http_v2_state_header_block(ngx_http_v2_connection_t *h2c, u_char *pos, } else { /* literal header field without indexing */ - prefix = ngx_http_v2_prefix(3); + prefix = ngx_http_v2_prefix(4); } value = ngx_http_v2_parse_int(h2c, &pos, end, prefix); @@ -2361,12 +2375,6 @@ ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c, ngx_debug_point(); } - if (h2c->state.stream) { - h2c->state.stream->out_closed = 1; - h2c->state.pool = NULL; - ngx_http_v2_close_stream(h2c->state.stream, NGX_HTTP_BAD_REQUEST); - } - ngx_http_v2_finalize_connection(h2c, err); return NULL; @@ -2396,8 +2404,8 @@ ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c, u_char **pos, u_char *end, return value; } - if (end - p > NGX_HTTP_V2_INT_OCTETS - 1) { - end = p + NGX_HTTP_V2_INT_OCTETS - 1; + if (end - start > NGX_HTTP_V2_INT_OCTETS) { + end = start + NGX_HTTP_V2_INT_OCTETS; } for (shift = 0; p != end; shift += 7) { @@ -2417,14 +2425,14 @@ ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c, u_char **pos, u_char *end, } } - if ((size_t) (end - start) >= NGX_HTTP_V2_INT_OCTETS) { - return NGX_DECLINED; - } - if ((size_t) (end - start) >= h2c->state.length) { return NGX_ERROR; } + if (end == start + NGX_HTTP_V2_INT_OCTETS) { + return NGX_DECLINED; + } + return NGX_AGAIN; } @@ -2762,6 +2770,8 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c) return NULL; } + ngx_str_set(&r->http_protocol, "HTTP/2.0"); + r->http_version = NGX_HTTP_VERSION_20; r->valid_location = 1; @@ -2896,11 +2906,14 @@ ngx_http_v2_get_closed_node(ngx_http_v2_connection_t *h2c) weight += child->weight; } + parent = node->parent; + for (q = ngx_queue_head(&node->children); q != ngx_queue_sentinel(&node->children); q = ngx_queue_next(q)) { child = ngx_queue_data(q, ngx_http_v2_node_t, queue); + child->parent = parent; child->weight = node->weight * child->weight / weight; if (child->weight == 0) { @@ -2908,8 +2921,6 @@ ngx_http_v2_get_closed_node(ngx_http_v2_connection_t *h2c) } } - parent = node->parent; - if (parent == NGX_HTTP_V2_ROOT) { node->rank = 0; node->rel_weight = 1.0; @@ -3795,6 +3806,12 @@ ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c, c = h2c->connection; + if (h2c->state.stream) { + h2c->state.stream->out_closed = 1; + h2c->state.pool = NULL; + ngx_http_v2_close_stream(h2c->state.stream, NGX_HTTP_BAD_REQUEST); + } + h2c->blocked = 1; if (!c->error && ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) { @@ -3922,8 +3939,8 @@ static void ngx_http_v2_set_dependency(ngx_http_v2_connection_t *h2c, ngx_http_v2_node_t *node, ngx_uint_t depend, ngx_uint_t exclusive) { - ngx_queue_t *children; - ngx_http_v2_node_t *parent, *next; + ngx_queue_t *children, *q; + ngx_http_v2_node_t *parent, *child, *next; parent = depend ? ngx_http_v2_get_node_by_id(h2c, depend, 0) : NULL; @@ -3985,6 +4002,14 @@ ngx_http_v2_set_dependency(ngx_http_v2_connection_t *h2c, } if (exclusive) { + for (q = ngx_queue_head(children); + q != ngx_queue_sentinel(children); + q = ngx_queue_next(q)) + { + child = ngx_queue_data(q, ngx_http_v2_node_t, queue); + child->parent = node; + } + ngx_queue_add(&node->children, children); ngx_queue_init(children); } diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index b7e73c9..462d254 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -21,7 +21,8 @@ #define NGX_HTTP_V2_MAX_FRAME_SIZE ((1 << 24) - 1) #define NGX_HTTP_V2_INT_OCTETS 4 -#define NGX_HTTP_V2_MAX_FIELD ((1 << NGX_HTTP_V2_INT_OCTETS * 7) - 1) +#define NGX_HTTP_V2_MAX_FIELD \ + (127 + (1 << (NGX_HTTP_V2_INT_OCTETS - 1) * 7) - 1) #define NGX_HTTP_V2_DATA_DISCARD 1 #define NGX_HTTP_V2_DATA_ERROR 2 diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index 17cfcd8..a866cde 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -12,7 +12,12 @@ #include -#define ngx_http_v2_integer_octets(v) (((v) + 127) / 128) +/* + * This returns precise number of octets for values in range 0..253 + * and estimate number for the rest, but not smaller than required. + */ + +#define ngx_http_v2_integer_octets(v) (1 + (v) / 127) #define ngx_http_v2_literal_size(h) \ (ngx_http_v2_integer_octets(sizeof(h) - 1) + sizeof(h) - 1) @@ -20,6 +25,8 @@ #define ngx_http_v2_indexed(i) (128 + (i)) #define ngx_http_v2_inc_indexed(i) (64 + (i)) +#define NGX_HTTP_V2_ENCODE_RAW 0 +#define NGX_HTTP_V2_ENCODE_HUFF 0x80 #define NGX_HTTP_V2_STATUS_INDEX 8 #define NGX_HTTP_V2_STATUS_200_INDEX 8 @@ -41,10 +48,8 @@ static u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, ngx_uint_t value); -static void ngx_http_v2_write_headers_head(u_char *pos, size_t length, - ngx_uint_t sid, ngx_uint_t end_headers, ngx_uint_t end_stream); -static void ngx_http_v2_write_continuation_head(u_char *pos, size_t length, - ngx_uint_t sid, ngx_uint_t end_headers); +static ngx_http_v2_out_frame_t *ngx_http_v2_create_headers_frame( + ngx_http_request_t *r, u_char *pos, u_char *end); static ngx_chain_t *ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit); @@ -114,17 +119,14 @@ static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static ngx_int_t ngx_http_v2_header_filter(ngx_http_request_t *r) { - u_char status, *p, *head; - size_t len, rest, frame_size; - ngx_buf_t *b; + u_char status, *pos, *start, *p; + size_t len; ngx_str_t host, location; - ngx_uint_t i, port, continuation; - ngx_chain_t *cl; + ngx_uint_t i, port; ngx_list_part_t *part; ngx_table_elt_t *header; ngx_connection_t *fc; ngx_http_cleanup_t *cln; - ngx_http_v2_stream_t *stream; ngx_http_v2_out_frame_t *frame; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; @@ -222,7 +224,7 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) } if (r->headers_out.content_type.len) { - len += NGX_HTTP_V2_INT_OCTETS + r->headers_out.content_type.len; + len += 1 + NGX_HTTP_V2_INT_OCTETS + r->headers_out.content_type.len; if (r->headers_out.content_type_len == r->headers_out.content_type.len && r->headers_out.charset.len) @@ -386,134 +388,117 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) + NGX_HTTP_V2_INT_OCTETS + header[i].value.len; } - stream = r->stream; - frame_size = stream->connection->frame_size; - - len += NGX_HTTP_V2_FRAME_HEADER_SIZE - * ((len + frame_size - 1) / frame_size); - - b = ngx_create_temp_buf(r->pool, len); - if (b == NULL) { + pos = ngx_palloc(r->pool, len); + if (pos == NULL) { return NGX_ERROR; } - b->last_buf = r->header_only; - - b->last += NGX_HTTP_V2_FRAME_HEADER_SIZE; + start = pos; if (status) { - *b->last++ = status; + *pos++ = status; } else { - *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_STATUS_INDEX); - *b->last++ = 3; - b->last = ngx_sprintf(b->last, "%03ui", r->headers_out.status); + *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_STATUS_INDEX); + *pos++ = NGX_HTTP_V2_ENCODE_RAW | 3; + pos = ngx_sprintf(pos, "%03ui", r->headers_out.status); } if (r->headers_out.server == NULL) { - *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_SERVER_INDEX); + *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_SERVER_INDEX); if (clcf->server_tokens) { - *b->last++ = sizeof(NGINX_VER) - 1; - b->last = ngx_cpymem(b->last, NGINX_VER, sizeof(NGINX_VER) - 1); + *pos++ = NGX_HTTP_V2_ENCODE_RAW | (sizeof(NGINX_VER) - 1); + pos = ngx_cpymem(pos, NGINX_VER, sizeof(NGINX_VER) - 1); } else { - *b->last++ = sizeof("nginx") - 1; - b->last = ngx_cpymem(b->last, "nginx", sizeof("nginx") - 1); + *pos++ = NGX_HTTP_V2_ENCODE_RAW | (sizeof("nginx") - 1); + pos = ngx_cpymem(pos, "nginx", sizeof("nginx") - 1); } } if (r->headers_out.date == NULL) { - *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_DATE_INDEX); - *b->last++ = (u_char) ngx_cached_http_time.len; + *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_DATE_INDEX); + *pos++ = (u_char) ngx_cached_http_time.len; - b->last = ngx_cpymem(b->last, ngx_cached_http_time.data, - ngx_cached_http_time.len); + pos = ngx_cpymem(pos, ngx_cached_http_time.data, + ngx_cached_http_time.len); } if (r->headers_out.content_type.len) { - *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_CONTENT_TYPE_INDEX); + *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_CONTENT_TYPE_INDEX); if (r->headers_out.content_type_len == r->headers_out.content_type.len && r->headers_out.charset.len) { - *b->last = 0; - b->last = ngx_http_v2_write_int(b->last, ngx_http_v2_prefix(7), - r->headers_out.content_type.len - + sizeof("; charset=") - 1 - + r->headers_out.charset.len); + *pos = NGX_HTTP_V2_ENCODE_RAW; + pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(7), + r->headers_out.content_type.len + + sizeof("; charset=") - 1 + + r->headers_out.charset.len); - p = b->last; + p = pos; - b->last = ngx_cpymem(p, r->headers_out.content_type.data, - r->headers_out.content_type.len); + pos = ngx_cpymem(pos, r->headers_out.content_type.data, + r->headers_out.content_type.len); - b->last = ngx_cpymem(b->last, "; charset=", - sizeof("; charset=") - 1); + pos = ngx_cpymem(pos, "; charset=", sizeof("; charset=") - 1); - b->last = ngx_cpymem(b->last, r->headers_out.charset.data, - r->headers_out.charset.len); + pos = ngx_cpymem(pos, r->headers_out.charset.data, + r->headers_out.charset.len); /* update r->headers_out.content_type for possible logging */ - r->headers_out.content_type.len = b->last - p; + r->headers_out.content_type.len = pos - p; r->headers_out.content_type.data = p; } else { - *b->last = 0; - b->last = ngx_http_v2_write_int(b->last, ngx_http_v2_prefix(7), - r->headers_out.content_type.len); - b->last = ngx_cpymem(b->last, r->headers_out.content_type.data, - r->headers_out.content_type.len); + *pos = NGX_HTTP_V2_ENCODE_RAW; + pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(7), + r->headers_out.content_type.len); + pos = ngx_cpymem(pos, r->headers_out.content_type.data, + r->headers_out.content_type.len); } } if (r->headers_out.content_length == NULL && r->headers_out.content_length_n >= 0) { - *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_CONTENT_LENGTH_INDEX); + *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_CONTENT_LENGTH_INDEX); - p = b->last; - b->last = ngx_sprintf(b->last + 1, "%O", - r->headers_out.content_length_n); - *p = (u_char) (b->last - p - 1); + p = pos; + pos = ngx_sprintf(pos + 1, "%O", r->headers_out.content_length_n); + *p = NGX_HTTP_V2_ENCODE_RAW | (u_char) (pos - p - 1); } if (r->headers_out.last_modified == NULL && r->headers_out.last_modified_time != -1) { - *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_LAST_MODIFIED_INDEX); + *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_LAST_MODIFIED_INDEX); - p = b->last; - b->last = ngx_http_time(b->last + 1, r->headers_out.last_modified_time); - *p = (u_char) (b->last - p - 1); + *pos++ = NGX_HTTP_V2_ENCODE_RAW + | (sizeof("Wed, 31 Dec 1986 18:00:00 GMT") - 1); + pos = ngx_http_time(pos, r->headers_out.last_modified_time); } if (r->headers_out.location && r->headers_out.location->value.len) { - *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_LOCATION_INDEX); + *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_LOCATION_INDEX); - *b->last = 0; - b->last = ngx_http_v2_write_int(b->last, ngx_http_v2_prefix(7), - r->headers_out.location->value.len); - b->last = ngx_cpymem(b->last, r->headers_out.location->value.data, - r->headers_out.location->value.len); + *pos = NGX_HTTP_V2_ENCODE_RAW; + pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(7), + r->headers_out.location->value.len); + pos = ngx_cpymem(pos, r->headers_out.location->value.data, + r->headers_out.location->value.len); } #if (NGX_HTTP_GZIP) if (r->gzip_vary) { - *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_VARY_INDEX); - *b->last++ = sizeof("Accept-Encoding") - 1; - b->last = ngx_cpymem(b->last, "Accept-Encoding", - sizeof("Accept-Encoding") - 1); + *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_VARY_INDEX); + *pos++ = NGX_HTTP_V2_ENCODE_RAW | (sizeof("Accept-Encoding") - 1); + pos = ngx_cpymem(pos, "Accept-Encoding", sizeof("Accept-Encoding") - 1); } #endif - continuation = 0; - head = b->pos; - - len = b->last - head - NGX_HTTP_V2_FRAME_HEADER_SIZE; - rest = frame_size - len; - part = &r->headers_out.headers.part; header = part->elts; @@ -533,82 +518,26 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) continue; } - len = 1 + NGX_HTTP_V2_INT_OCTETS * 2 - + header[i].key.len - + header[i].value.len; + *pos++ = 0; - if (len > rest) { - len = b->last - head - NGX_HTTP_V2_FRAME_HEADER_SIZE; + *pos = NGX_HTTP_V2_ENCODE_RAW; + pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(7), + header[i].key.len); + ngx_strlow(pos, header[i].key.data, header[i].key.len); + pos += header[i].key.len; - if (continuation) { - ngx_http_v2_write_continuation_head(head, len, - stream->node->id, 0); - } else { - continuation = 1; - ngx_http_v2_write_headers_head(head, len, stream->node->id, 0, - r->header_only); - } - - rest = frame_size; - head = b->last; - - b->last += NGX_HTTP_V2_FRAME_HEADER_SIZE; - } - - p = b->last; - - *p++ = 0; - - *p = 0; - p = ngx_http_v2_write_int(p, ngx_http_v2_prefix(7), header[i].key.len); - ngx_strlow(p, header[i].key.data, header[i].key.len); - p += header[i].key.len; - - *p = 0; - p = ngx_http_v2_write_int(p, ngx_http_v2_prefix(7), - header[i].value.len); - p = ngx_cpymem(p, header[i].value.data, header[i].value.len); - - rest -= p - b->last; - b->last = p; + *pos = NGX_HTTP_V2_ENCODE_RAW; + pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(7), + header[i].value.len); + pos = ngx_cpymem(pos, header[i].value.data, header[i].value.len); } - len = b->last - head - NGX_HTTP_V2_FRAME_HEADER_SIZE; - - if (continuation) { - ngx_http_v2_write_continuation_head(head, len, stream->node->id, 1); - - } else { - ngx_http_v2_write_headers_head(head, len, stream->node->id, 1, - r->header_only); - } - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - cl->next = NULL; - - frame = ngx_palloc(r->pool, sizeof(ngx_http_v2_out_frame_t)); + frame = ngx_http_v2_create_headers_frame(r, start, pos); if (frame == NULL) { return NGX_ERROR; } - frame->first = cl; - frame->last = cl; - frame->handler = ngx_http_v2_headers_frame_handler; - frame->stream = stream; - frame->length = b->last - b->pos - NGX_HTTP_V2_FRAME_HEADER_SIZE; - frame->blocked = 1; - frame->fin = r->header_only; - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0, - "http2:%ui create HEADERS frame %p: len:%uz", - stream->node->id, frame, frame->length); - - ngx_http_v2_queue_blocked_frame(stream->connection, frame); + ngx_http_v2_queue_blocked_frame(r->stream->connection, frame); cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { @@ -616,14 +545,14 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) } cln->handler = ngx_http_v2_filter_cleanup; - cln->data = stream; + cln->data = r->stream; - stream->queued = 1; + r->stream->queued = 1; fc->send_chain = ngx_http_v2_send_chain; fc->need_last_buf = 1; - return ngx_http_v2_filter_send(fc, stream); + return ngx_http_v2_filter_send(fc, r->stream); } @@ -649,41 +578,104 @@ ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, ngx_uint_t value) } -static void -ngx_http_v2_write_headers_head(u_char *pos, size_t length, ngx_uint_t sid, - ngx_uint_t end_headers, ngx_uint_t end_stream) +static ngx_http_v2_out_frame_t * +ngx_http_v2_create_headers_frame(ngx_http_request_t *r, u_char *pos, + u_char *end) { - u_char flags; + u_char type, flags; + size_t rest, frame_size; + ngx_buf_t *b; + ngx_chain_t *cl, **ll; + ngx_http_v2_stream_t *stream; + ngx_http_v2_out_frame_t *frame; - pos = ngx_http_v2_write_len_and_type(pos, length, - NGX_HTTP_V2_HEADERS_FRAME); + stream = r->stream; + rest = end - pos; - flags = NGX_HTTP_V2_NO_FLAG; - - if (end_headers) { - flags |= NGX_HTTP_V2_END_HEADERS_FLAG; + frame = ngx_palloc(r->pool, sizeof(ngx_http_v2_out_frame_t)); + if (frame == NULL) { + return NULL; } - if (end_stream) { - flags |= NGX_HTTP_V2_END_STREAM_FLAG; + frame->handler = ngx_http_v2_headers_frame_handler; + frame->stream = stream; + frame->length = rest; + frame->blocked = 1; + frame->fin = r->header_only; + + ll = &frame->first; + + type = NGX_HTTP_V2_HEADERS_FRAME; + flags = r->header_only ? NGX_HTTP_V2_END_STREAM_FLAG : NGX_HTTP_V2_NO_FLAG; + frame_size = stream->connection->frame_size; + + for ( ;; ) { + if (rest <= frame_size) { + frame_size = rest; + flags |= NGX_HTTP_V2_END_HEADERS_FLAG; + } + + b = ngx_create_temp_buf(r->pool, NGX_HTTP_V2_FRAME_HEADER_SIZE); + if (b == NULL) { + return NULL; + } + + b->last = ngx_http_v2_write_len_and_type(b->last, frame_size, type); + *b->last++ = flags; + b->last = ngx_http_v2_write_sid(b->last, stream->node->id); + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NULL; + } + + cl->buf = b; + + *ll = cl; + ll = &cl->next; + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NULL; + } + + b->pos = pos; + + pos += frame_size; + + b->last = pos; + b->start = b->pos; + b->end = b->last; + b->temporary = 1; + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NULL; + } + + cl->buf = b; + + *ll = cl; + ll = &cl->next; + + rest -= frame_size; + + if (rest) { + type = NGX_HTTP_V2_CONTINUATION_FRAME; + flags = NGX_HTTP_V2_NO_FLAG; + continue; + } + + b->last_buf = r->header_only; + cl->next = NULL; + frame->last = cl; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http2:%ui create HEADERS frame %p: len:%uz", + stream->node->id, frame, frame->length); + + return frame; } - - *pos++ = flags; - - (void) ngx_http_v2_write_sid(pos, sid); -} - - -static void -ngx_http_v2_write_continuation_head(u_char *pos, size_t length, ngx_uint_t sid, - ngx_uint_t end_headers) -{ - pos = ngx_http_v2_write_len_and_type(pos, length, - NGX_HTTP_V2_CONTINUATION_FRAME); - - *pos++ = end_headers ? NGX_HTTP_V2_END_HEADERS_FLAG : NGX_HTTP_V2_NO_FLAG; - - (void) ngx_http_v2_write_sid(pos, sid); } diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index ea142e7..6800500 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -759,6 +759,10 @@ ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc) u->peer.save_session(&u->peer, u->peer.data); } + if (pc->write->timer_set) { + ngx_del_timer(pc->write); + } + ngx_stream_proxy_init_upstream(s); return; From b37dfd906aaea875b38630ee2383cd5a2e17cad8 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 3 Nov 2015 08:59:14 +0200 Subject: [PATCH 060/651] New upsteam release (1.9.6) --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 1fb0f6e..10811de 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.9.5-1) UNRELEASED; urgency=medium +nginx (1.9.6-1) UNRELEASED; urgency=medium [ Christos Trochalakis] * New upstream release. From 6f5cefd11e961c884fcb0bea4cd9334c0f979007 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 3 Nov 2015 08:59:30 +0200 Subject: [PATCH 061/651] 1.9.6-1 --- debian/changelog | 5 +++-- debian/nginx-common.NEWS | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 10811de..d01c0c2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,9 +1,10 @@ -nginx (1.9.6-1) UNRELEASED; urgency=medium +nginx (1.9.6-1) unstable; urgency=medium [ Christos Trochalakis] * New upstream release. + * Enable http2 module in nginx-full & nginx-extras - -- Christos Trochalakis Fri, 25 Sep 2015 14:03:10 +0300 + -- Christos Trochalakis Tue, 03 Nov 2015 08:59:21 +0200 nginx (1.9.4-1) unstable; urgency=medium diff --git a/debian/nginx-common.NEWS b/debian/nginx-common.NEWS index 161d061..46a6f14 100644 --- a/debian/nginx-common.NEWS +++ b/debian/nginx-common.NEWS @@ -1,4 +1,4 @@ -nginx-common (1.9.5-1) UNRELEASED; urgency=medium +nginx-common (1.9.6-1) unstable; urgency=medium As of nginx 1.9.5 spdy has been replaced by the http2 module. Make sure to replace "spdy" with "http2" in your config files. From 7a486795eb9b1e2a441a4035cb8854f7d2e2d9cf Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 13 Nov 2015 16:07:02 +0200 Subject: [PATCH 062/651] Update nginx-lua 0.9.19 Fixes http/2 issues o https://github.com/openresty/lua-nginx-module/issues/566 --- debian/changelog | 8 + debian/modules/README.Modules-versions | 2 +- debian/modules/nginx-lua/.gitignore | 164 - debian/modules/nginx-lua/README.markdown | 484 +- debian/modules/nginx-lua/config | 105 +- .../modules/nginx-lua/doc/HttpLuaModule.wiki | 437 +- .../nginx-lua/src/api/ngx_http_lua_api.h | 2 +- debian/modules/nginx-lua/src/ddebug.h | 6 +- .../nginx-lua/src/ngx_http_lua_directive.c | 612 ++ .../nginx-lua/src/ngx_http_lua_directive.h | 18 + .../nginx-lua/src/ngx_http_lua_headers_in.c | 76 +- .../nginx-lua/src/ngx_http_lua_headers_out.c | 12 + .../nginx-lua/src/ngx_http_lua_initworkerby.c | 8 +- .../modules/nginx-lua/src/ngx_http_lua_lex.c | 8251 +++++++++++++++++ .../modules/nginx-lua/src/ngx_http_lua_lex.h | 17 + .../nginx-lua/src/ngx_http_lua_module.c | 86 +- .../nginx-lua/src/ngx_http_lua_shdict.c | 59 +- .../nginx-lua/src/ngx_http_lua_socket_tcp.c | 10 +- .../nginx-lua/src/ngx_http_lua_socket_udp.c | 2 +- .../nginx-lua/src/ngx_http_lua_subrequest.c | 8 +- debian/modules/nginx-lua/t/000--init.t | 1 - debian/modules/nginx-lua/t/000-sanity.t | 1 - debian/modules/nginx-lua/t/001-set.t | 1 - debian/modules/nginx-lua/t/002-content.t | 2 +- debian/modules/nginx-lua/t/003-errors.t | 1 - debian/modules/nginx-lua/t/004-require.t | 2 +- debian/modules/nginx-lua/t/005-exit.t | 1 - debian/modules/nginx-lua/t/006-escape.t | 1 - debian/modules/nginx-lua/t/007-md5.t | 2 +- debian/modules/nginx-lua/t/008-today.t | 2 +- debian/modules/nginx-lua/t/009-log.t | 2 +- debian/modules/nginx-lua/t/010-request_body.t | 2 +- debian/modules/nginx-lua/t/011-md5_bin.t | 1 - debian/modules/nginx-lua/t/012-now.t | 2 +- debian/modules/nginx-lua/t/013-base64.t | 1 - debian/modules/nginx-lua/t/014-bugs.t | 1 - debian/modules/nginx-lua/t/015-status.t | 1 - debian/modules/nginx-lua/t/016-resp-header.t | 46 +- debian/modules/nginx-lua/t/017-exec.t | 1 - debian/modules/nginx-lua/t/018-ndk.t | 1 - debian/modules/nginx-lua/t/019-const.t | 1 - debian/modules/nginx-lua/t/020-subrequest.t | 76 +- debian/modules/nginx-lua/t/021-cookie-time.t | 2 +- debian/modules/nginx-lua/t/022-redirect.t | 1 - .../nginx-lua/t/023-rewrite/client-abort.t | 1 - debian/modules/nginx-lua/t/023-rewrite/exec.t | 1 - debian/modules/nginx-lua/t/023-rewrite/exit.t | 1 - .../modules/nginx-lua/t/023-rewrite/mixed.t | 1 - .../nginx-lua/t/023-rewrite/multi-capture.t | 1 - .../nginx-lua/t/023-rewrite/on-abort.t | 1 - .../nginx-lua/t/023-rewrite/redirect.t | 1 - .../nginx-lua/t/023-rewrite/req-body.t | 2 +- .../nginx-lua/t/023-rewrite/req-socket.t | 1 - .../nginx-lua/t/023-rewrite/request_body.t | 1 - .../modules/nginx-lua/t/023-rewrite/sanity.t | 1 - .../modules/nginx-lua/t/023-rewrite/sleep.t | 1 - .../t/023-rewrite/socket-keepalive.t | 1 - .../nginx-lua/t/023-rewrite/subrequest.t | 1 - .../t/023-rewrite/tcp-socket-timeout.t | 1 - .../nginx-lua/t/023-rewrite/tcp-socket.t | 1 - .../nginx-lua/t/023-rewrite/unix-socket.t | 1 - .../nginx-lua/t/023-rewrite/uthread-exec.t | 1 - .../nginx-lua/t/023-rewrite/uthread-exit.t | 1 - .../t/023-rewrite/uthread-redirect.t | 1 - .../nginx-lua/t/023-rewrite/uthread-spawn.t | 1 - debian/modules/nginx-lua/t/024-access/auth.t | 1 - .../nginx-lua/t/024-access/client-abort.t | 1 - debian/modules/nginx-lua/t/024-access/exec.t | 1 - debian/modules/nginx-lua/t/024-access/exit.t | 1 - debian/modules/nginx-lua/t/024-access/mixed.t | 1 - .../nginx-lua/t/024-access/multi-capture.t | 1 - .../modules/nginx-lua/t/024-access/on-abort.t | 1 - .../modules/nginx-lua/t/024-access/redirect.t | 1 - .../modules/nginx-lua/t/024-access/req-body.t | 2 +- .../nginx-lua/t/024-access/request_body.t | 1 - .../modules/nginx-lua/t/024-access/sanity.t | 1 - .../modules/nginx-lua/t/024-access/satisfy.t | 1 - debian/modules/nginx-lua/t/024-access/sleep.t | 1 - .../nginx-lua/t/024-access/subrequest.t | 1 - .../nginx-lua/t/024-access/uthread-exec.t | 1 - .../nginx-lua/t/024-access/uthread-exit.t | 1 - .../nginx-lua/t/024-access/uthread-redirect.t | 1 - .../nginx-lua/t/024-access/uthread-spawn.t | 1 - debian/modules/nginx-lua/t/025-codecache.t | 1 - debian/modules/nginx-lua/t/026-mysql.t | 1 - .../modules/nginx-lua/t/027-multi-capture.t | 1 - debian/modules/nginx-lua/t/028-req-header.t | 96 +- debian/modules/nginx-lua/t/029-http-time.t | 1 - debian/modules/nginx-lua/t/030-uri-args.t | 1 - debian/modules/nginx-lua/t/031-post-args.t | 1 - debian/modules/nginx-lua/t/032-iolist.t | 1 - debian/modules/nginx-lua/t/033-ctx.t | 1 - debian/modules/nginx-lua/t/035-gmatch.t | 1 - debian/modules/nginx-lua/t/036-sub.t | 1 - debian/modules/nginx-lua/t/037-gsub.t | 1 - debian/modules/nginx-lua/t/038-match-o.t | 1 - debian/modules/nginx-lua/t/039-sub-o.t | 1 - debian/modules/nginx-lua/t/040-gsub-o.t | 1 - .../modules/nginx-lua/t/041-header-filter.t | 1 - debian/modules/nginx-lua/t/042-crc32.t | 1 - debian/modules/nginx-lua/t/043-shdict.t | 135 +- debian/modules/nginx-lua/t/044-req-body.t | 1 - debian/modules/nginx-lua/t/045-ngx-var.t | 1 - debian/modules/nginx-lua/t/046-hmac.t | 1 - debian/modules/nginx-lua/t/047-match-jit.t | 1 - debian/modules/nginx-lua/t/048-match-dfa.t | 1 - debian/modules/nginx-lua/t/049-gmatch-jit.t | 1 - debian/modules/nginx-lua/t/050-gmatch-dfa.t | 1 - debian/modules/nginx-lua/t/051-sub-jit.t | 1 - debian/modules/nginx-lua/t/052-sub-dfa.t | 1 - debian/modules/nginx-lua/t/053-gsub-jit.t | 1 - debian/modules/nginx-lua/t/054-gsub-dfa.t | 1 - debian/modules/nginx-lua/t/055-subreq-vars.t | 1 - debian/modules/nginx-lua/t/056-flush.t | 1 - .../modules/nginx-lua/t/057-flush-timeout.t | 1 - debian/modules/nginx-lua/t/058-tcp-socket.t | 1 - debian/modules/nginx-lua/t/059-unix-socket.t | 1 - .../modules/nginx-lua/t/060-lua-memcached.t | 1 - debian/modules/nginx-lua/t/061-lua-redis.t | 1 - debian/modules/nginx-lua/t/062-count.t | 66 +- debian/modules/nginx-lua/t/063-abort.t | 1 - debian/modules/nginx-lua/t/064-pcall.t | 1 - .../nginx-lua/t/065-tcp-socket-timeout.t | 1 - .../nginx-lua/t/066-socket-receiveuntil.t | 1 - debian/modules/nginx-lua/t/067-req-socket.t | 1 - .../nginx-lua/t/068-socket-keepalive.t | 1 - debian/modules/nginx-lua/t/069-null.t | 1 - debian/modules/nginx-lua/t/070-sha1.t | 1 - debian/modules/nginx-lua/t/071-idle-socket.t | 1 - .../modules/nginx-lua/t/072-conditional-get.t | 1 - debian/modules/nginx-lua/t/073-backtrace.t | 1 - debian/modules/nginx-lua/t/074-prefix-var.t | 1 - debian/modules/nginx-lua/t/075-logby.t | 1 - debian/modules/nginx-lua/t/076-no-postpone.t | 1 - debian/modules/nginx-lua/t/077-sleep.t | 1 - debian/modules/nginx-lua/t/078-hup-vars.t | 1 - .../nginx-lua/t/079-unused-directives.t | 12 +- debian/modules/nginx-lua/t/080-hup-shdict.t | 1 - debian/modules/nginx-lua/t/081-bytecode.t | 1 - debian/modules/nginx-lua/t/082-body-filter.t | 1 - .../modules/nginx-lua/t/083-bad-sock-self.t | 1 - .../nginx-lua/t/084-inclusive-receiveuntil.t | 1 - debian/modules/nginx-lua/t/085-if.t | 1 - debian/modules/nginx-lua/t/086-init-by.t | 1 - debian/modules/nginx-lua/t/087-udp-socket.t | 1 - debian/modules/nginx-lua/t/088-req-method.t | 1 - .../nginx-lua/t/090-log-socket-errors.t | 1 - debian/modules/nginx-lua/t/091-coroutine.t | 1 - debian/modules/nginx-lua/t/092-eof.t | 1 - .../modules/nginx-lua/t/093-uthread-spawn.t | 1 - debian/modules/nginx-lua/t/094-uthread-exit.t | 1 - debian/modules/nginx-lua/t/095-uthread-exec.t | 1 - .../nginx-lua/t/096-uthread-redirect.t | 1 - .../modules/nginx-lua/t/097-uthread-rewrite.t | 1 - debian/modules/nginx-lua/t/098-uthread-wait.t | 1 - debian/modules/nginx-lua/t/099-c-api.t | 36 +- debian/modules/nginx-lua/t/100-client-abort.t | 1 - debian/modules/nginx-lua/t/101-on-abort.t | 1 - .../modules/nginx-lua/t/102-req-start-time.t | 1 - debian/modules/nginx-lua/t/103-req-http-ver.t | 1 - .../modules/nginx-lua/t/104-req-raw-header.t | 1 - debian/modules/nginx-lua/t/105-pressure.t | 1 - debian/modules/nginx-lua/t/106-timer.t | 1 - debian/modules/nginx-lua/t/107-timer-errors.t | 1 - debian/modules/nginx-lua/t/108-timer-safe.t | 1 - debian/modules/nginx-lua/t/109-timer-hup.t | 1 - debian/modules/nginx-lua/t/110-etag.t | 1 - .../modules/nginx-lua/t/111-req-header-ua.t | 1 - .../modules/nginx-lua/t/112-req-header-conn.t | 1 - .../nginx-lua/t/113-req-header-cookie.t | 1 - debian/modules/nginx-lua/t/114-config.t | 1 - .../modules/nginx-lua/t/115-quote-sql-str.t | 1 - .../modules/nginx-lua/t/116-raw-req-socket.t | 1 - .../nginx-lua/t/117-raw-req-socket-timeout.t | 1 - .../nginx-lua/t/118-use-default-type.t | 1 - .../modules/nginx-lua/t/119-config-prefix.t | 1 - debian/modules/nginx-lua/t/121-version.t | 1 - debian/modules/nginx-lua/t/123-lua-path.t | 1 - debian/modules/nginx-lua/t/124-init-worker.t | 18 +- .../modules/nginx-lua/t/125-configure-args.t | 1 - debian/modules/nginx-lua/t/126-shdict-frag.t | 2 +- debian/modules/nginx-lua/t/127-uthread-kill.t | 1 - .../nginx-lua/t/128-duplex-tcp-socket.t | 1 - debian/modules/nginx-lua/t/129-ssl-socket.t | 17 +- debian/modules/nginx-lua/t/130-internal-api.t | 2 +- debian/modules/nginx-lua/t/132-lua-blocks.t | 490 + .../nginx-lua/t/data/fake-module/config | 3 + .../t/data/fake-module/ngx_http_fake_module.c | 121 + debian/modules/nginx-lua/util/build.sh | 39 - debian/modules/nginx-lua/util/build2.sh | 8 +- debian/modules/nginx-lua/util/gen-lexer-c | 18 + debian/modules/nginx-lua/valgrind.suppress | 7 + 192 files changed, 11008 insertions(+), 715 deletions(-) delete mode 100644 debian/modules/nginx-lua/.gitignore create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_lex.c create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_lex.h create mode 100644 debian/modules/nginx-lua/t/132-lua-blocks.t create mode 100644 debian/modules/nginx-lua/t/data/fake-module/config create mode 100644 debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c delete mode 100755 debian/modules/nginx-lua/util/build.sh create mode 100755 debian/modules/nginx-lua/util/gen-lexer-c diff --git a/debian/changelog b/debian/changelog index d01c0c2..08dd22b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +nginx (1.9.6-2) UNRELEASED; urgency=medium + + [ Christos Trochalakis] + * debian/modules/nginx-lua: + + Update nginx-lua to v0.9.19 fixing HTTP/2 compatibility. + + -- Christos Trochalakis Fri, 13 Nov 2015 16:04:32 +0200 + nginx (1.9.6-1) unstable; urgency=medium [ Christos Trochalakis] diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index 435eaab..3690858 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -22,7 +22,7 @@ README for Modules versions nginx-lua Homepage: https://github.com/openresty/lua-nginx-module - Version: v0.9.16 + Version: v0.9.19 nginx-upstream-fair Homepage: https://github.com/gnosek/nginx-upstream-fair diff --git a/debian/modules/nginx-lua/.gitignore b/debian/modules/nginx-lua/.gitignore deleted file mode 100644 index 61613b2..0000000 --- a/debian/modules/nginx-lua/.gitignore +++ /dev/null @@ -1,164 +0,0 @@ -build/ -work/ -tags -cscope.* -*.mobi -genmobi.sh -.libs -*.swp -*.slo -*.la -*.swo -*.lo -*~ -*.o -print.txt -.rsync -*.tar.gz -dist -build[789] -build -tags -update-readme -*.tmp -test/Makefile -test/blib -test.sh -t.sh -t/t.sh -test/t/servroot/ -releng -reset -*.t_ -src/handler.h -src/util.c -src/module.h -src/module.c -src/drizzle.c -src/processor.h -src/handler.c -src/util.h -src/drizzle.h -src/processor.c -src/output.c -src/output.h -libdrizzle -ctags -src/stream.h -nginx -keepalive -reindex -src/keepalive.c -src/keepalive.h -src/checker.h -src/checker.c -src/quoting.h -src/quoting.c -src/module.h -src/module.c -src/util.h -src/util.c -src/processor.h -src/processor.c -src/rds.h -src/utils.h -src/handler.c -src/handler.h -util/bench -*.html -trace.out* -try.sh -src/cache.c -src/cache.h -src/common.h -src/directive.c -src/directive.h -src/consts.[ch] -src/contentby.[ch] -src/pcrefix.[ch] -src/util.c -src/clfactory.c -src/directive.c -src/conf.h -src/setby.h -src/cache.h -src/hook.c -src/util.h -src/hook.h -src/common.h -src/directive.h -src/conf.c -src/setby.c -src/cache.c -src/module.c -src/clfactory.h -src/capturefilter.[ch] -src/contentby.c -pack -b.sh -src/in.[ch] -src/out.[ch] -go -all.sh -src/accessby.[ch] -src/rewriteby.[ch] -src/patch.[ch] -src/ndk.[ch] -src/control.[ch] -src/output.[ch] -src/variable.[ch] -src/string.[ch] -src/misc.[ch] -src/log.[ch] -src/exception.[ch] -src/subrequest.[ch] -src/time.[ch] -src/regex.[ch] -src/ctx.[ch] -src/args.[ch] -src/headers.[ch] -src/script.[ch] -src/filter.[ch] -src/shdict.[ch] -src/body.[ch] -src/uri.[ch] -src/api.[ch] -src/coroutine.[ch] -src/logby.[ch] -src/sleep.[ch] -a.patch -all -build1[0-9] -g -buildroot/ -src/headerfilterby.[ch] -*.patch -analyze -tsock -a.c -test.lua -build12 -ERRORS -src/bodyfilterby.[ch] -src/tcp.[ch] -src/initby.[ch] -src/initworkerby.[ch] -src/socket.[ch] -src/udp.[ch] -src/method.[ch] -tre -src/phase.[ch] -src/probe.h -src/uthread.[ch] -src/timer.[ch] -src/config.[ch] -src/worker.[ch] -*.plist -lua -ttimer -Makefile -tsubreq -tthread -addr2line -hup -theaders diff --git a/debian/modules/nginx-lua/README.markdown b/debian/modules/nginx-lua/README.markdown index 248c47f..da06da6 100644 --- a/debian/modules/nginx-lua/README.markdown +++ b/debian/modules/nginx-lua/README.markdown @@ -6,7 +6,7 @@ Don't edit this file manually! Instead you should generate it by using: Name ==== -ngx_lua - Embed the power of Lua into Nginx +ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers. *This module is not distributed with the Nginx source.* See [the installation instructions](#installation). @@ -61,7 +61,7 @@ Production ready. Version ======= -This document describes ngx_lua [v0.9.16](https://github.com/openresty/lua-nginx-module/tags) released on 22 June 2015. +This document describes ngx_lua [v0.9.19](https://github.com/openresty/lua-nginx-module/tags) released on 11 November 2015. Synopsis ======== @@ -74,42 +74,13 @@ Synopsis lua_package_cpath '/bar/baz/?.so;/blah/blah/?.so;;'; server { - location /inline_concat { - # MIME type determined by default_type: - default_type 'text/plain'; - - set $a "hello"; - set $b "world"; - # inline Lua script - set_by_lua $res "return ngx.arg[1]..ngx.arg[2]" $a $b; - echo $res; - } - - location /rel_file_concat { - set $a "foo"; - set $b "bar"; - # script path relative to nginx prefix - # $ngx_prefix/conf/concat.lua contents: - # - # return ngx.arg[1]..ngx.arg[2] - # - set_by_lua_file $res conf/concat.lua $a $b; - echo $res; - } - - location /abs_file_concat { - set $a "fee"; - set $b "baz"; - # absolute script path not modified - set_by_lua_file $res /usr/nginx/conf/concat.lua $a $b; - echo $res; - } - location /lua_content { # MIME type determined by default_type: default_type 'text/plain'; - content_by_lua "ngx.say('Hello,world!')"; + content_by_lua_block { + ngx.say('Hello,world!') + } } location /nginx_var { @@ -117,84 +88,61 @@ Synopsis default_type 'text/plain'; # try access /nginx_var?a=hello,world - content_by_lua "ngx.print(ngx.var['arg_a'], '\\n')"; + content_by_lua_block { + ngx.say(ngx.var.arg_a) + } } - location /request_body { - # force reading request body (default off) - lua_need_request_body on; - client_max_body_size 50k; - client_body_buffer_size 50k; + location = /request_body { + client_max_body_size 50k; + client_body_buffer_size 50k; - content_by_lua 'ngx.print(ngx.var.request_body)'; + content_by_lua_block { + ngx.req.read_body() -- explicitly read the req body + local data = ngx.req.get_body_data() + if data then + ngx.say("body data:") + ngx.print(data) + return + end + + -- body may get buffered in a temp file: + local file = ngx.req.get_body_file() + if file then + ngx.say("body is in file ", file) + else + ngx.say("no body found") + end + } } # transparent non-blocking I/O in Lua via subrequests - location /lua { + # (well, a better way is to use cosockets) + location = /lua { # MIME type determined by default_type: default_type 'text/plain'; - content_by_lua ' + content_by_lua_block { local res = ngx.location.capture("/some_other_location") - if res.status == 200 then + if res then + ngx.say("status: ", res.status) + ngx.say("body:") ngx.print(res.body) end'; + } } - # GET /recur?num=5 - location /recur { - # MIME type determined by default_type: - default_type 'text/plain'; - - content_by_lua ' - local num = tonumber(ngx.var.arg_num) or 0 - - if num > 50 then - ngx.say("num too big") - return - end - - ngx.say("num is: ", num) - - if num > 0 then - res = ngx.location.capture("/recur?num=" .. tostring(num - 1)) - ngx.print("status=", res.status, " ") - ngx.print("body=", res.body) - else - ngx.say("end") - end - '; - } - - location /foo { - rewrite_by_lua ' + location = /foo { + rewrite_by_lua_block { res = ngx.location.capture("/memc", { args = { cmd = "incr", key = ngx.var.uri } } ) - '; + } proxy_pass http://blah.blah.com; } - location /blah { - access_by_lua ' - local res = ngx.location.capture("/auth") - - if res.status == ngx.HTTP_OK then - return - end - - if res.status == ngx.HTTP_FORBIDDEN then - ngx.exit(res.status) - end - - ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) - '; - - # proxy_pass/fastcgi_pass/postgres_pass/... - } - - location /mixed { + location = /mixed { rewrite_by_lua_file /path/to/rewrite.lua; access_by_lua_file /path/to/access.lua; content_by_lua_file /path/to/content.lua; @@ -209,26 +157,24 @@ Synopsis } location / { - lua_need_request_body on; - client_max_body_size 100k; client_body_buffer_size 100k; - access_by_lua ' + access_by_lua_block { -- check the client IP address is in our black list if ngx.var.remote_addr == "132.5.72.3" then ngx.exit(ngx.HTTP_FORBIDDEN) end - -- check if the request body contains bad words - if ngx.var.request_body and - string.match(ngx.var.request_body, "fsck") + -- check if the URI contains bad words + if ngx.var.uri and + string.match(ngx.var.request_body, "evil") then return ngx.redirect("/terms_of_use.html") end -- tests passed - '; + } # proxy_pass/fastcgi_pass/etc settings } @@ -254,6 +200,8 @@ At least the following Lua libraries and Nginx modules can be used with this ngx * [lua-resty-upload](https://github.com/openresty/lua-resty-upload) * [lua-resty-websocket](https://github.com/openresty/lua-resty-websocket) * [lua-resty-lock](https://github.com/openresty/lua-resty-lock) +* [lua-resty-logger-socket](https://github.com/cloudflare/lua-resty-logger-socket) +* [lua-resty-lrucache](https://github.com/openresty/lua-resty-lrucache) * [lua-resty-string](https://github.com/openresty/lua-resty-string) * [ngx_memc](http://github.com/openresty/memc-nginx-module) * [ngx_postgres](https://github.com/FRiCKLE/ngx_postgres) @@ -295,6 +243,7 @@ Nginx Compatibility =================== The latest module is compatible with the following versions of Nginx: +* 1.9.x (last tested: 1.9.3) * 1.7.x (last tested: 1.7.10) * 1.6.x * 1.5.x (last tested: 1.5.12) @@ -315,7 +264,7 @@ It is highly recommended to use the [ngx_openresty bundle](http://openresty.org) Alternatively, ngx_lua can be manually compiled into Nginx: -1. Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuaJIT can be downloaded from the [the LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuajIT and/or Lua. +1. Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuaJIT can be downloaded from the [the LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuaJIT and/or Lua. 1. Download the latest version of the ngx_devel_kit (NDK) module [HERE](https://github.com/simpl/ngx_devel_kit/tags). 1. Download the latest version of ngx_lua [HERE](https://github.com/openresty/lua-nginx-module/tags). 1. Download the latest version of Nginx [HERE](http://nginx.org/) (See [Nginx Compatibility](#nginx-compatibility)) @@ -324,9 +273,9 @@ Build the source with this module: ```bash - wget 'http://nginx.org/download/nginx-1.7.10.tar.gz' - tar -xzvf nginx-1.7.10.tar.gz - cd nginx-1.7.10/ + wget 'http://nginx.org/download/nginx-1.9.3.tar.gz' + tar -xzvf nginx-1.9.3.tar.gz + cd nginx-1.9.3/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib @@ -342,7 +291,7 @@ Build the source with this module: # Here we assume Nginx is to be installed under /opt/nginx/. ./configure --prefix=/opt/nginx \ - --with-ld-opt='-Wl,-rpath,/path/to/luajit-or-lua/lib" \ + --with-ld-opt="-Wl,-rpath,/path/to/luajit-or-lua/lib" \ --add-module=/path/to/ngx_devel_kit \ --add-module=/path/to/lua-nginx-module @@ -753,6 +702,10 @@ There exists a work-around, however, when the original context does *not* need t Special Escaping Sequences -------------------------- + +**WARNING** We no longer suffer from this pitfall since the introduction of the +`*_by_lua_block {}` configuration directives. + PCRE sequences such as `\d`, `\s`, or `\w`, require special attention because in string literals, the backslash character, `\`, is stripped out by both the Lua language parser and by the Nginx config file parser before processing. So the following snippet will not work as expected: ```nginx @@ -881,21 +834,6 @@ phases. TODO ==== -* add `*_by_lua_block` directives for existing `*_by_lua` directives so that we put literal Lua code directly in curly braces instead of an nginx literal string. For example, -```nginx - - content_by_lua_block { - ngx.say("hello, world\r\n") - } -``` - which is equivalent to -```nginx - - content_by_lua ' - ngx.say("hello, world\\r\\n") - '; -``` - but the former is much cleaner and nicer. * cosocket: implement LuaSocket's unconnected UDP API. * add support for implementing general TCP servers instead of HTTP servers in Lua. For example, ```lua @@ -1064,22 +1002,31 @@ Directives * [lua_package_path](#lua_package_path) * [lua_package_cpath](#lua_package_cpath) * [init_by_lua](#init_by_lua) +* [init_by_lua_block](#init_by_lua_block) * [init_by_lua_file](#init_by_lua_file) * [init_worker_by_lua](#init_worker_by_lua) +* [init_worker_by_lua_block](#init_worker_by_lua_block) * [init_worker_by_lua_file](#init_worker_by_lua_file) * [set_by_lua](#set_by_lua) +* [set_by_lua_block](#set_by_lua_block) * [set_by_lua_file](#set_by_lua_file) * [content_by_lua](#content_by_lua) +* [content_by_lua_block](#content_by_lua_block) * [content_by_lua_file](#content_by_lua_file) * [rewrite_by_lua](#rewrite_by_lua) +* [rewrite_by_lua_block](#rewrite_by_lua_block) * [rewrite_by_lua_file](#rewrite_by_lua_file) * [access_by_lua](#access_by_lua) +* [access_by_lua_block](#access_by_lua_block) * [access_by_lua_file](#access_by_lua_file) * [header_filter_by_lua](#header_filter_by_lua) +* [header_filter_by_lua_block](#header_filter_by_lua_block) * [header_filter_by_lua_file](#header_filter_by_lua_file) * [body_filter_by_lua](#body_filter_by_lua) +* [body_filter_by_lua_block](#body_filter_by_lua_block) * [body_filter_by_lua_file](#body_filter_by_lua_file) * [log_by_lua](#log_by_lua) +* [log_by_lua_block](#log_by_lua_block) * [log_by_lua_file](#log_by_lua_file) * [lua_need_request_body](#lua_need_request_body) * [lua_shared_dict](#lua_shared_dict) @@ -1241,6 +1188,9 @@ init_by_lua **phase:** *loading-config* +**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; +use the new [init_by_lua_block](#init_by_lua_block) directive instead. + Runs the Lua code specified by the argument `` on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file. When Nginx receives the `HUP` signal and starts reloading the config file, the Lua VM will also be re-created and `init_by_lua` will run again on the new Lua VM. In case that the [lua_code_cache](#lua_code_cache) directive is turned off (default on), the `init_by_lua` handler will run upon every request because in this special mode a standalone Lua VM is always created for each request. @@ -1302,6 +1252,33 @@ This directive was first introduced in the `v0.5.5` release. [Back to TOC](#directives) +init_by_lua_block +----------------- + +**syntax:** *init_by_lua_block { lua-script }* + +**context:** *http* + +**phase:** *loading-config* + +Similar to the [init_by_lua](#init_by_lua) directive except that this directive inlines +the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping). + +For instance, + +```nginx + + init_by_lua_block { + print("I need no extra escaping here, for example: \r\nblah") + } +``` + +This directive was first introduced in the `v0.9.17` release. + +[Back to TOC](#directives) + init_by_lua_file ---------------- @@ -1328,9 +1305,11 @@ init_worker_by_lua **phase:** *starting-worker* +**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; use the new [init_worker_by_lua_block](#init_worker_by_lua_block) directive instead. + Runs the specified Lua code upon every Nginx worker process's startup when the master process is enabled. When the master process is disabled, this hook will just run after [init_by_lua*](#init_by_lua). -This hook is often used to create per-worker reoccurring timers (via the [ngx.timer.at](#ngxtimerat) Lua API), either for backend healthcheck or other timed routine work. Below is an example, +This hook is often used to create per-worker reoccurring timers (via the [ngx.timer.at](#ngxtimerat) Lua API), either for backend health-check or other timed routine work. Below is an example, ```nginx @@ -1364,6 +1343,33 @@ This directive was first introduced in the `v0.9.5` release. [Back to TOC](#directives) +init_worker_by_lua_block +------------------------ + +**syntax:** *init_worker_by_lua_block { lua-script }* + +**context:** *http* + +**phase:** *starting-worker* + +Similar to the [init_worker_by_lua](#init_worker_by_lua) directive except that this directive inlines +the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping). + +For instance, + +```nginx + + init_worker_by_lua_block { + print("I need no extra escaping here, for example: \r\nblah") + } +``` + +This directive was first introduced in the `v0.9.17` release. + +[Back to TOC](#directives) + init_worker_by_lua_file ----------------------- @@ -1388,7 +1394,9 @@ set_by_lua **phase:** *rewrite* -Executes code specified in `` with optional input arguments `$arg1 $arg2 ...`, and returns string output to `$res`. +**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; use the new [set_by_lua_block](#set_by_lua_block) directive instead. + +Executes code specified in `` with optional input arguments `$arg1 $arg2 ...`, and returns string output to `$res`. The code in `` can make [API calls](#nginx-api-for-lua) and can retrieve input arguments from the `ngx.arg` table (index starts from `1` and increases sequentially). This directive is designed to execute short, fast running code blocks as the Nginx event loop is blocked during code execution. Time consuming code sequences should therefore be avoided. @@ -1398,7 +1406,7 @@ This directive is implemented by injecting custom commands into the standard [ng At least the following API functions are currently disabled within the context of `set_by_lua`: * Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.exit](#ngxexit)) +* Control API functions (e.g., [ngx.exit](#ngxexit)) * Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) * Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). * Sleeping API function [ngx.sleep](#ngxsleep). @@ -1428,7 +1436,7 @@ This directive can be freely mixed with all directives of the [ngx_http_rewrite_ ```nginx set $foo 32; - set_by_lua $bar 'tonumber(ngx.var.foo) + 1'; + set_by_lua $bar 'return tonumber(ngx.var.foo) + 1'; set $baz "bar: $bar"; # $baz == "bar: 33" ``` @@ -1438,6 +1446,36 @@ This directive requires the [ngx_devel_kit](https://github.com/simpl/ngx_devel_k [Back to TOC](#directives) +set_by_lua_block +---------------- + +**syntax:** *set_by_lua_block $res { lua-script }* + +**context:** *server, server if, location, location if* + +**phase:** *rewrite* + +Similar to the [set_by_lua](#set_by_lua) directive except that + +1. this directive inlines the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping), and +1. this directive does not support extra arguments after the Lua script as in [set_by_lua](#set_by_lua). + +For example, + +```nginx + + set_by_lua_block $res { return 32 + math.cos(32) } + # $res now has the value "32.834223360507" or alike. +``` + +No special escaping is required in the Lua code block. + +This directive was first introduced in the `v0.9.17` release. + +[Back to TOC](#directives) + set_by_lua_file --------------- **syntax:** *set_by_lua_file $res <path-to-lua-script-file> [$arg1 $arg2 ...]* @@ -1470,6 +1508,9 @@ content_by_lua **phase:** *content* +**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; +use the new [content_by_lua_block](#content_by_lua_block) directive instead. + Acts as a "content handler" and executes Lua code string specified in `` for every request. The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). @@ -1477,6 +1518,33 @@ Do not use this directive and other content handler directives in the same locat [Back to TOC](#directives) +content_by_lua_block +-------------------- + +**syntax:** *content_by_lua_block { lua-script }* + +**context:** *location, location if* + +**phase:** *content* + +Similar to the [content_by_lua](#content_by_lua) directive except that this directive inlines +the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping). + +For instance, + +```nginx + + content_by_lua_block { + ngx.say("I need no extra escaping here, for example: \r\nblah") + } +``` + +This directive was first introduced in the `v0.9.17` release. + +[Back to TOC](#directives) + content_by_lua_file ------------------- @@ -1522,6 +1590,9 @@ rewrite_by_lua **phase:** *rewrite tail* +**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; +use the new [rewrite_by_lua_block](#rewrite_by_lua_block) directive instead. + Acts as a rewrite phase handler and executes Lua code string specified in `` for every request. The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). @@ -1637,6 +1708,33 @@ The `rewrite_by_lua` code will always run at the end of the `rewrite` request-pr [Back to TOC](#directives) +rewrite_by_lua_block +-------------------- + +**syntax:** *rewrite_by_lua_block { lua-script }* + +**context:** *http, server, location, location if* + +**phase:** *rewrite tail* + +Similar to the [rewrite_by_lua](#rewrite_by_lua) directive except that this directive inlines +the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping). + +For instance, + +```nginx + + rewrite_by_lua_block { + do_something("hello, world!\nhiya\n") + } +``` + +This directive was first introduced in the `v0.9.17` release. + +[Back to TOC](#directives) + rewrite_by_lua_file ------------------- @@ -1669,6 +1767,9 @@ access_by_lua **phase:** *access tail* +**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; +use the new [access_by_lua_block](#access_by_lua_block) directive instead. + Acts as an access phase handler and executes Lua code string specified in `` for every request. The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). @@ -1733,6 +1834,33 @@ Note that when calling `ngx.exit(ngx.OK)` within a [access_by_lua](#access_by_lu [Back to TOC](#directives) +access_by_lua_block +------------------- + +**syntax:** *access_by_lua_block { lua-script }* + +**context:** *http, server, location, location if* + +**phase:** *access tail* + +Similar to the [access_by_lua](#access_by_lua) directive except that this directive inlines +the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping). + +For instance, + +```nginx + + access_by_lua_block { + do_something("hello, world!\nhiya\n") + } +``` + +This directive was first introduced in the `v0.9.17` release. + +[Back to TOC](#directives) + access_by_lua_file ------------------ @@ -1765,12 +1893,15 @@ header_filter_by_lua **phase:** *output-header-filter* +**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; +use the new [header_filter_by_lua_block](#header_filter_by_lua_block) directive instead. + Uses Lua code specified in `` to define an output header filter. Note that the following API functions are currently disabled within this context: * Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.exit](#ngxexit) and [ngx.exec](#ngxexec)) +* Control API functions (e.g., [ngx.redirect](#ngxredirect) and [ngx.exec](#ngxexec)) * Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) * Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). @@ -1788,6 +1919,33 @@ This directive was first introduced in the `v0.2.1rc20` release. [Back to TOC](#directives) +header_filter_by_lua_block +-------------------------- + +**syntax:** *header_filter_by_lua_block { lua-script }* + +**context:** *http, server, location, location if* + +**phase:** *output-header-filter* + +Similar to the [header_filter_by_lua](#header_filter_by_lua) directive except that this directive inlines +the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping). + +For instance, + +```nginx + + header_filter_by_lua_block { + ngx.header["content-length"] = nil + } +``` + +This directive was first introduced in the `v0.9.17` release. + +[Back to TOC](#directives) + header_filter_by_lua_file ------------------------- @@ -1814,6 +1972,9 @@ body_filter_by_lua **phase:** *output-body-filter* +**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; +use the new [body_filter_by_lua_block](#body_filter_by_lua_block) directive instead. + Uses Lua code specified in `` to define an output body filter. The input data chunk is passed via [ngx.arg](#ngxarg)\[1\] (as a Lua string value) and the "eof" flag indicating the end of the response body data stream is passed via [ngx.arg](#ngxarg)\[2\] (as a Lua boolean value). @@ -1895,6 +2056,33 @@ This directive was first introduced in the `v0.5.0rc32` release. [Back to TOC](#directives) +body_filter_by_lua_block +------------------------ + +**syntax:** *body_filter_by_lua_block { lua-script-str }* + +**context:** *http, server, location, location if* + +**phase:** *output-body-filter* + +Similar to the [body_filter_by_lua](#body_filter_by_lua) directive except that this directive inlines +the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping). + +For instance, + +```nginx + + body_filter_by_lua_block { + local data, eof = ngx.arg[1], ngx.arg[2] + } +``` + +This directive was first introduced in the `v0.9.17` release. + +[Back to TOC](#directives) + body_filter_by_lua_file ----------------------- @@ -1921,7 +2109,10 @@ log_by_lua **phase:** *log* -Run the Lua source code inlined as the `` at the `log` request processing phase. This does not replace the current access logs, but runs after. +**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; +use the new [log_by_lua_block](#log_by_lua_block) directive instead. + +Runs the Lua source code inlined as the `` at the `log` request processing phase. This does not replace the current access logs, but runs after. Note that the following API functions are currently disabled within this context: @@ -1977,6 +2168,33 @@ This directive was first introduced in the `v0.5.0rc31` release. [Back to TOC](#directives) +log_by_lua_block +---------------- + +**syntax:** *log_by_lua_block { lua-script }* + +**context:** *http, server, location, location if* + +**phase:** *log* + +Similar to the [log_by_lua](#log_by_lua) directive except that this directive inlines +the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping). + +For instance, + +```nginx + + log_by_lua_block { + print("I need no extra escaping here, for example: \r\nblah") + } +``` + +This directive was first introduced in the `v0.9.17` release. + +[Back to TOC](#directives) + log_by_lua_file --------------- @@ -2637,7 +2855,7 @@ many others are not, like `$query_string`, `$arg_PARAMETER`, and `$http_NAME`. Nginx regex group capturing variables `$1`, `$2`, `$3`, and etc, can be read by this interface as well, by writing `ngx.var[1]`, `ngx.var[2]`, `ngx.var[3]`, and etc. -Setting `ngx.var.Foo` to a `nil` value will unset the `$Foo` Nginx variable. +Setting `ngx.var.Foo` to a `nil` value will unset the `$Foo` Nginx variable. ```lua @@ -2654,6 +2872,8 @@ Setting `ngx.var.Foo` to a `nil` value will unset the `$Foo` Nginx variable. to prevent (temporary) memory leaking within the current request's lifetime. Another way of caching the result is to use the [ngx.ctx](#ngxctx) table. +Undefined NGINX variables are evaluated to `nil` while uninitialized (but defined) NGINX variables are evaluated to an empty Lua string. + This API requires a relatively expensive metamethod call and it is recommended to avoid using it on hot code paths. [Back to TOC](#nginx-api-for-lua) @@ -2912,7 +3132,7 @@ Here is a basic example: res = ngx.location.capture(uri) ``` -Returns a Lua table with three slots (`res.status`, `res.header`, `res.body`, and `res.truncated`). +Returns a Lua table with 4 slots: `res.status`, `res.header`, `res.body`, and `res.truncated`. `res.status` holds the response status code for the subrequest response. @@ -3502,7 +3722,7 @@ ngx.req.set_method **context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua** -Overrides the current request's request method with the `request_id` argument. Currently only numerical [method constants](#http-method-constants) are supported, like `ngx.HTTP_POST` and `ngx.HTTP_GET`. +Overrides the current request's request method with the `method_id` argument. Currently only numerical [method constants](#http-method-constants) are supported, like `ngx.HTTP_POST` and `ngx.HTTP_GET`. If the current request is an Nginx subrequest, then the subrequest's method will be overridden. @@ -3559,7 +3779,7 @@ or equivalently, ngx.req.set_uri("/foo") ``` -The `jump` can only be set to `true` in [rewrite_by_lua](#rewrite_by_lua) and [rewrite_by_lua_file](#rewrite_by_lua_file). Use of jump in other contexts is prohibited and will throw out a Lua exception. +The `jump` argument can only be set to `true` in [rewrite_by_lua](#rewrite_by_lua) and [rewrite_by_lua_file](#rewrite_by_lua_file). Use of jump in other contexts is prohibited and will throw out a Lua exception. A more sophisticated example involving regex substitutions is as follows @@ -3567,7 +3787,7 @@ A more sophisticated example involving regex substitutions is as follows location /test { rewrite_by_lua ' - local uri = ngx.re.sub(ngx.var.uri, "^/test/(.*)", "$1", "o") + local uri = ngx.re.sub(ngx.var.uri, "^/test/(.*)", "/$1", "o") ngx.req.set_uri(uri) '; proxy_pass http://my_backend; @@ -3808,7 +4028,7 @@ will yield: a b: 1a 2 ``` -Arguments without the `=` parts are treated as boolean arguments. `GET /test?foo&bar` will yield: +Arguments without the `=` parts are treated as boolean arguments. `POST /test` with the request body `foo&bar` will yield: ```bash @@ -3893,14 +4113,14 @@ However, the optional `max_headers` function argument can be used to override th ```lua - local args = ngx.req.get_headers(10) + local headers = ngx.req.get_headers(10) ``` This argument can be set to zero to remove the limit and to process all request headers received: ```lua - local args = ngx.req.get_headers(0) + local headers = ngx.req.get_headers(0) ``` Removing the `max_headers` cap is strongly discouraged. diff --git a/debian/modules/nginx-lua/config b/debian/modules/nginx-lua/config index 28b4078..4b770d7 100644 --- a/debian/modules/nginx-lua/config +++ b/debian/modules/nginx-lua/config @@ -14,32 +14,77 @@ ngx_lua_opt_L= if [ -n "$LUAJIT_INC" -o -n "$LUAJIT_LIB" ]; then # explicitly set LuaJIT paths - # attempt to link with -ldl, static linking on Linux requires it. - ngx_feature="LuaJIT library in $LUAJIT_LIB and $LUAJIT_INC (specified by the LUAJIT_LIB and LUAJIT_INC env, with -ldl)" - ngx_feature_path="$LUAJIT_INC" - ngx_lua_opt_I="-I$LUAJIT_INC" - ngx_lua_opt_L="-L$LUAJIT_LIB" - if [ $NGX_RPATH = YES ]; then - ngx_feature_libs="-R$LUAJIT_LIB $ngx_lua_opt_L -lluajit-5.1 -lm -ldl" - else - ngx_feature_libs="$ngx_lua_opt_L -lluajit-5.1 -lm -ldl" - fi - - . auto/feature - - if [ $ngx_found = no ]; then - # retry without -ldl - ngx_feature="LuaJIT library in $LUAJIT_LIB and $LUAJIT_INC (specified by the LUAJIT_LIB and LUAJIT_INC env)" + if [ "$NGX_PLATFORM" = win32 ]; then + ngx_feature="LuaJIT library in $LUAJIT_LIB and $LUAJIT_INC (win32)" ngx_feature_path="$LUAJIT_INC" ngx_lua_opt_I="-I$LUAJIT_INC" ngx_lua_opt_L="-L$LUAJIT_LIB" + + # ensure that our -I$LUAJIT_INC and -L$LUAJIT_LIB is at the first. + SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" + CC_TEST_FLAGS="$ngx_lua_opt_I $CC_TEST_FLAGS" + SAVED_NGX_TEST_LD_OPT="$NGX_TEST_LD_OPT" + NGX_TEST_LD_OPT="$ngx_lua_opt_L $NGX_TEST_LD_OPT" + + # LuaJIT's win32 build uses the library file name lua51.dll. + ngx_feature_libs="$ngx_lua_opt_L -llua51" + + . auto/feature + + # clean up + CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" + NGX_TEST_LD_OPT="$SAVED_NGX_TEST_LD_OPT" + else + + # attempt to link with -ldl, static linking on Linux requires it. + ngx_feature="LuaJIT library in $LUAJIT_LIB and $LUAJIT_INC (specified by the LUAJIT_LIB and LUAJIT_INC env, with -ldl)" + ngx_feature_path="$LUAJIT_INC" + ngx_lua_opt_I="-I$LUAJIT_INC" + ngx_lua_opt_L="-L$LUAJIT_LIB" + + # ensure that our -I$LUAJIT_INC and -L$LUAJIT_LIB is at the first. + SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" + CC_TEST_FLAGS="$ngx_lua_opt_I $CC_TEST_FLAGS" + SAVED_NGX_TEST_LD_OPT="$NGX_TEST_LD_OPT" + NGX_TEST_LD_OPT="$ngx_lua_opt_L $NGX_TEST_LD_OPT" + if [ $NGX_RPATH = YES ]; then - ngx_feature_libs="-R$LUAJIT_LIB $ngx_lua_opt_L -lluajit-5.1 -lm" + ngx_feature_libs="-R$LUAJIT_LIB $ngx_lua_opt_L -lluajit-5.1 -lm -ldl" else - ngx_feature_libs="$ngx_lua_opt_L -lluajit-5.1 -lm" + ngx_feature_libs="$ngx_lua_opt_L -lluajit-5.1 -lm -ldl" fi . auto/feature + + # clean up + CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" + NGX_TEST_LD_OPT="$SAVED_NGX_TEST_LD_OPT" + + if [ $ngx_found = no ]; then + # retry without -ldl + ngx_feature="LuaJIT library in $LUAJIT_LIB and $LUAJIT_INC (specified by the LUAJIT_LIB and LUAJIT_INC env)" + ngx_feature_path="$LUAJIT_INC" + ngx_lua_opt_I="-I$LUAJIT_INC" + ngx_lua_opt_L="-L$LUAJIT_LIB" + + # ensure that our -I$LUAJIT_INC and -L$LUAJIT_LIB is at the first. + SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" + CC_TEST_FLAGS="$ngx_lua_opt_I $CC_TEST_FLAGS" + SAVED_NGX_TEST_LD_OPT="$NGX_TEST_LD_OPT" + NGX_TEST_LD_OPT="$ngx_lua_opt_L $NGX_TEST_LD_OPT" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R$LUAJIT_LIB $ngx_lua_opt_L -lluajit-5.1 -lm" + else + ngx_feature_libs="$ngx_lua_opt_L -lluajit-5.1 -lm" + fi + + . auto/feature + + # clean up + CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" + NGX_TEST_LD_OPT="$SAVED_NGX_TEST_LD_OPT" + fi fi if [ $ngx_found = no ]; then @@ -72,6 +117,13 @@ else ngx_feature_path="$LUA_INC" ngx_lua_opt_I="-I$LUA_INC" ngx_lua_opt_L="-L$LUA_LIB" + + # ensure that our -I$LUA_INC and -L$LUA_LIB is at the first. + SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" + CC_TEST_FLAGS="$ngx_lua_opt_I $CC_TEST_FLAGS" + SAVED_NGX_TEST_LD_OPT="$NGX_TEST_LD_OPT" + NGX_TEST_LD_OPT="$ngx_lua_opt_L $NGX_TEST_LD_OPT" + if [ $NGX_RPATH = YES ]; then ngx_feature_libs="-R$LUA_LIB $ngx_lua_opt_L -llua -lm -ldl" else @@ -80,12 +132,23 @@ else . auto/feature + # clean up + CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" + NGX_TEST_LD_OPT="$SAVED_NGX_TEST_LD_OPT" + if [ $ngx_found = no ]; then # retry without -ldl ngx_feature_path="$LUA_INC" ngx_lua_opt_I="-I$LUA_INC" ngx_lua_opt_L="-L$LUA_LIB" + + # ensure that our -I$LUA_INC and -L$LUA_LIB is at the first. + SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" + CC_TEST_FLAGS="$ngx_lua_opt_I $CC_TEST_FLAGS" + SAVED_NGX_TEST_LD_OPT="$NGX_TEST_LD_OPT" + NGX_TEST_LD_OPT="$ngx_lua_opt_L $NGX_TEST_LD_OPT" + if [ $NGX_RPATH = YES ]; then ngx_feature_libs="-R$LUA_LIB $ngx_lua_opt_L -llua -lm" else @@ -93,6 +156,10 @@ else fi . auto/feature + + # clean up + CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" + NGX_TEST_LD_OPT="$SAVED_NGX_TEST_LD_OPT" fi if [ $ngx_found = no ]; then @@ -283,6 +350,7 @@ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ $ngx_addon_dir/src/ngx_http_lua_timer.c \ $ngx_addon_dir/src/ngx_http_lua_config.c \ $ngx_addon_dir/src/ngx_http_lua_worker.c \ + $ngx_addon_dir/src/ngx_http_lua_lex.c \ " NGX_ADDON_DEPS="$NGX_ADDON_DEPS \ @@ -336,6 +404,7 @@ NGX_ADDON_DEPS="$NGX_ADDON_DEPS \ $ngx_addon_dir/src/ngx_http_lua_timer.h \ $ngx_addon_dir/src/ngx_http_lua_config.h \ $ngx_addon_dir/src/ngx_http_lua_worker.h \ + $ngx_addon_dir/src/ngx_http_lua_lex.h \ " CFLAGS="$CFLAGS -DNDK_SET_VAR" diff --git a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki index 7e72449..3726509 100644 --- a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki @@ -1,6 +1,6 @@ = Name = -ngx_lua - Embed the power of Lua into Nginx +ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers. ''This module is not distributed with the Nginx source.'' See [[#Installation|the installation instructions]]. @@ -10,7 +10,7 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.9.16] released on 22 June 2015. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.9.19] released on 11 November 2015. = Synopsis = @@ -21,42 +21,13 @@ This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/t lua_package_cpath '/bar/baz/?.so;/blah/blah/?.so;;'; server { - location /inline_concat { - # MIME type determined by default_type: - default_type 'text/plain'; - - set $a "hello"; - set $b "world"; - # inline Lua script - set_by_lua $res "return ngx.arg[1]..ngx.arg[2]" $a $b; - echo $res; - } - - location /rel_file_concat { - set $a "foo"; - set $b "bar"; - # script path relative to nginx prefix - # $ngx_prefix/conf/concat.lua contents: - # - # return ngx.arg[1]..ngx.arg[2] - # - set_by_lua_file $res conf/concat.lua $a $b; - echo $res; - } - - location /abs_file_concat { - set $a "fee"; - set $b "baz"; - # absolute script path not modified - set_by_lua_file $res /usr/nginx/conf/concat.lua $a $b; - echo $res; - } - location /lua_content { # MIME type determined by default_type: default_type 'text/plain'; - content_by_lua "ngx.say('Hello,world!')"; + content_by_lua_block { + ngx.say('Hello,world!') + } } location /nginx_var { @@ -64,84 +35,61 @@ This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/t default_type 'text/plain'; # try access /nginx_var?a=hello,world - content_by_lua "ngx.print(ngx.var['arg_a'], '\\n')"; + content_by_lua_block { + ngx.say(ngx.var.arg_a) + } } - location /request_body { - # force reading request body (default off) - lua_need_request_body on; - client_max_body_size 50k; - client_body_buffer_size 50k; + location = /request_body { + client_max_body_size 50k; + client_body_buffer_size 50k; - content_by_lua 'ngx.print(ngx.var.request_body)'; + content_by_lua_block { + ngx.req.read_body() -- explicitly read the req body + local data = ngx.req.get_body_data() + if data then + ngx.say("body data:") + ngx.print(data) + return + end + + -- body may get buffered in a temp file: + local file = ngx.req.get_body_file() + if file then + ngx.say("body is in file ", file) + else + ngx.say("no body found") + end + } } # transparent non-blocking I/O in Lua via subrequests - location /lua { + # (well, a better way is to use cosockets) + location = /lua { # MIME type determined by default_type: default_type 'text/plain'; - content_by_lua ' + content_by_lua_block { local res = ngx.location.capture("/some_other_location") - if res.status == 200 then + if res then + ngx.say("status: ", res.status) + ngx.say("body:") ngx.print(res.body) end'; + } } - # GET /recur?num=5 - location /recur { - # MIME type determined by default_type: - default_type 'text/plain'; - - content_by_lua ' - local num = tonumber(ngx.var.arg_num) or 0 - - if num > 50 then - ngx.say("num too big") - return - end - - ngx.say("num is: ", num) - - if num > 0 then - res = ngx.location.capture("/recur?num=" .. tostring(num - 1)) - ngx.print("status=", res.status, " ") - ngx.print("body=", res.body) - else - ngx.say("end") - end - '; - } - - location /foo { - rewrite_by_lua ' + location = /foo { + rewrite_by_lua_block { res = ngx.location.capture("/memc", { args = { cmd = "incr", key = ngx.var.uri } } ) - '; + } proxy_pass http://blah.blah.com; } - location /blah { - access_by_lua ' - local res = ngx.location.capture("/auth") - - if res.status == ngx.HTTP_OK then - return - end - - if res.status == ngx.HTTP_FORBIDDEN then - ngx.exit(res.status) - end - - ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) - '; - - # proxy_pass/fastcgi_pass/postgres_pass/... - } - - location /mixed { + location = /mixed { rewrite_by_lua_file /path/to/rewrite.lua; access_by_lua_file /path/to/access.lua; content_by_lua_file /path/to/content.lua; @@ -156,26 +104,24 @@ This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/t } location / { - lua_need_request_body on; - client_max_body_size 100k; client_body_buffer_size 100k; - access_by_lua ' + access_by_lua_block { -- check the client IP address is in our black list if ngx.var.remote_addr == "132.5.72.3" then ngx.exit(ngx.HTTP_FORBIDDEN) end - -- check if the request body contains bad words - if ngx.var.request_body and - string.match(ngx.var.request_body, "fsck") + -- check if the URI contains bad words + if ngx.var.uri and + string.match(ngx.var.request_body, "evil") then return ngx.redirect("/terms_of_use.html") end -- tests passed - '; + } # proxy_pass/fastcgi_pass/etc settings } @@ -198,6 +144,8 @@ At least the following Lua libraries and Nginx modules can be used with this ngx * [https://github.com/openresty/lua-resty-upload lua-resty-upload] * [https://github.com/openresty/lua-resty-websocket lua-resty-websocket] * [https://github.com/openresty/lua-resty-lock lua-resty-lock] +* [https://github.com/cloudflare/lua-resty-logger-socket lua-resty-logger-socket] +* [https://github.com/openresty/lua-resty-lrucache lua-resty-lrucache] * [https://github.com/openresty/lua-resty-string lua-resty-string] * [[HttpMemcModule|ngx_memc]] * [https://github.com/FRiCKLE/ngx_postgres ngx_postgres] @@ -233,6 +181,7 @@ The Lua state (Lua VM instance) is shared across all the requests handled by a s = Nginx Compatibility = The latest module is compatible with the following versions of Nginx: +* 1.9.x (last tested: 1.9.3) * 1.7.x (last tested: 1.7.10) * 1.6.x * 1.5.x (last tested: 1.5.12) @@ -250,7 +199,7 @@ It is highly recommended to use the [http://openresty.org ngx_openresty bundle] Alternatively, ngx_lua can be manually compiled into Nginx: -# Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is ''not'' supported yet). LuaJIT can be downloaded from the [http://luajit.org/download.html the LuaJIT project website] and Lua 5.1, from the [http://www.lua.org/ Lua project website]. Some distribution package managers also distribute LuajIT and/or Lua. +# Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is ''not'' supported yet). LuaJIT can be downloaded from the [http://luajit.org/download.html the LuaJIT project website] and Lua 5.1, from the [http://www.lua.org/ Lua project website]. Some distribution package managers also distribute LuaJIT and/or Lua. # Download the latest version of the ngx_devel_kit (NDK) module [https://github.com/simpl/ngx_devel_kit/tags HERE]. # Download the latest version of ngx_lua [https://github.com/openresty/lua-nginx-module/tags HERE]. # Download the latest version of Nginx [http://nginx.org/ HERE] (See [[#Nginx Compatibility|Nginx Compatibility]]) @@ -258,9 +207,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.7.10.tar.gz' - tar -xzvf nginx-1.7.10.tar.gz - cd nginx-1.7.10/ + wget 'http://nginx.org/download/nginx-1.9.3.tar.gz' + tar -xzvf nginx-1.9.3.tar.gz + cd nginx-1.9.3/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib @@ -276,7 +225,7 @@ Build the source with this module: # Here we assume Nginx is to be installed under /opt/nginx/. ./configure --prefix=/opt/nginx \ - --with-ld-opt='-Wl,-rpath,/path/to/luajit-or-lua/lib" \ + --with-ld-opt="-Wl,-rpath,/path/to/luajit-or-lua/lib" \ --add-module=/path/to/ngx_devel_kit \ --add-module=/path/to/lua-nginx-module @@ -610,6 +559,10 @@ The cosockets are currently also disabled in the [[#init_by_lua|init_by_lua*]] a There exists a work-around, however, when the original context does *not* need to wait for the cosocket results. That is, creating a 0-delay timer via the [[#ngx.timer.at|ngx.timer.at]] API and do the cosocket results in the timer handler, which runs asynchronously as to the original context creating the timer. == Special Escaping Sequences == + +'''WARNING''' We no longer suffer from this pitfall since the introduction of the +*_by_lua_block {} configuration directives. + PCRE sequences such as \d, \s, or \w, require special attention because in string literals, the backslash character, \, is stripped out by both the Lua language parser and by the Nginx config file parser before processing. So the following snippet will not work as expected: @@ -720,19 +673,6 @@ phases. = TODO = -* add *_by_lua_block directives for existing *_by_lua directives so that we put literal Lua code directly in curly braces instead of an nginx literal string. For example, - - content_by_lua_block { - ngx.say("hello, world\r\n") - } - -: which is equivalent to - - content_by_lua ' - ngx.say("hello, world\\r\\n") - '; - -: but the former is much cleaner and nicer. * cosocket: implement LuaSocket's unconnected UDP API. * add support for implementing general TCP servers instead of HTTP servers in Lua. For example, @@ -995,6 +935,9 @@ As from the v0.5.0rc29 release, the special notation $prefix< '''phase:''' ''loading-config'' +'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; +use the new [[#init_by_lua_block|init_by_lua_block]] directive instead. + Runs the Lua code specified by the argument on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file. When Nginx receives the HUP signal and starts reloading the config file, the Lua VM will also be re-created and init_by_lua will run again on the new Lua VM. In case that the [[#lua_code_cache|lua_code_cache]] directive is turned off (default on), the init_by_lua handler will run upon every request because in this special mode a standalone Lua VM is always created for each request. @@ -1052,6 +995,29 @@ You should be very careful about potential security vulnerabilities in your Lua This directive was first introduced in the v0.5.5 release. +== init_by_lua_block == + +'''syntax:''' ''init_by_lua_block { lua-script }'' + +'''context:''' ''http'' + +'''phase:''' ''loading-config'' + +Similar to the [[#init_by_lua|init_by_lua]] directive except that this directive inlines +the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping). + +For instance, + + + init_by_lua_block { + print("I need no extra escaping here, for example: \r\nblah") + } + + +This directive was first introduced in the v0.9.17 release. + == init_by_lua_file == '''syntax:''' ''init_by_lua_file '' @@ -1074,9 +1040,11 @@ This directive was first introduced in the v0.5.5 release. '''phase:''' ''starting-worker'' +'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; use the new [[#init_worker_by_lua_block|init_worker_by_lua_block]] directive instead. + Runs the specified Lua code upon every Nginx worker process's startup when the master process is enabled. When the master process is disabled, this hook will just run after [[#init_by_lua|init_by_lua*]]. -This hook is often used to create per-worker reoccurring timers (via the [[#ngx.timer.at|ngx.timer.at]] Lua API), either for backend healthcheck or other timed routine work. Below is an example, +This hook is often used to create per-worker reoccurring timers (via the [[#ngx.timer.at|ngx.timer.at]] Lua API), either for backend health-check or other timed routine work. Below is an example, init_worker_by_lua ' @@ -1107,6 +1075,29 @@ This hook is often used to create per-worker reoccurring timers (via the [[#ngx. This directive was first introduced in the v0.9.5 release. +== init_worker_by_lua_block == + +'''syntax:''' ''init_worker_by_lua_block { lua-script }'' + +'''context:''' ''http'' + +'''phase:''' ''starting-worker'' + +Similar to the [[#init_worker_by_lua|init_worker_by_lua]] directive except that this directive inlines +the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping). + +For instance, + + + init_worker_by_lua_block { + print("I need no extra escaping here, for example: \r\nblah") + } + + +This directive was first introduced in the v0.9.17 release. + == init_worker_by_lua_file == '''syntax:''' ''init_worker_by_lua_file '' @@ -1127,7 +1118,9 @@ This directive was first introduced in the v0.9.5 release. '''phase:''' ''rewrite'' -Executes code specified in with optional input arguments $arg1 $arg2 ..., and returns string output to $res. +'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; use the new [[#set_by_lua_block|set_by_lua_block]] directive instead. + +Executes code specified in with optional input arguments $arg1 $arg2 ..., and returns string output to $res. The code in can make [[#Nginx API for Lua|API calls]] and can retrieve input arguments from the ngx.arg table (index starts from 1 and increases sequentially). This directive is designed to execute short, fast running code blocks as the Nginx event loop is blocked during code execution. Time consuming code sequences should therefore be avoided. @@ -1137,7 +1130,7 @@ This directive is implemented by injecting custom commands into the standard [[H At least the following API functions are currently disabled within the context of set_by_lua: * Output API functions (e.g., [[#ngx.say|ngx.say]] and [[#ngx.send_headers|ngx.send_headers]]) -* Control API functions (e.g., [[#ngx.exit|ngx.exit]]) +* Control API functions (e.g., [[#ngx.exit|ngx.exit]]) * Subrequest API functions (e.g., [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]]) * Cosocket API functions (e.g., [[#ngx.socket.tcp|ngx.socket.tcp]] and [[#ngx.req.socket|ngx.req.socket]]). * Sleeping API function [[#ngx.sleep|ngx.sleep]]. @@ -1165,7 +1158,7 @@ This directive can be freely mixed with all directives of the [[HttpRewriteModul set $foo 32; - set_by_lua $bar 'tonumber(ngx.var.foo) + 1'; + set_by_lua $bar 'return tonumber(ngx.var.foo) + 1'; set $baz "bar: $bar"; # $baz == "bar: 33" @@ -1173,6 +1166,32 @@ As from the v0.5.0rc29 release, Nginx variable interpolation is dis This directive requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_kit] module. +== set_by_lua_block == + +'''syntax:''' ''set_by_lua_block $res { lua-script }'' + +'''context:''' ''server, server if, location, location if'' + +'''phase:''' ''rewrite'' + +Similar to the [[#set_by_lua|set_by_lua]] directive except that + +# this directive inlines the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping), and +# this directive does not support extra arguments after the Lua script as in [[#set_by_lua|set_by_lua]]. + +For example, + + + set_by_lua_block $res { return 32 + math.cos(32) } + # $res now has the value "32.834223360507" or alike. + + +No special escaping is required in the Lua code block. + +This directive was first introduced in the v0.9.17 release. + == set_by_lua_file == '''syntax:''' ''set_by_lua_file $res [$arg1 $arg2 ...]'' @@ -1201,11 +1220,37 @@ This directive requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_ki '''phase:''' ''content'' +'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; +use the new [[#content_by_lua_block|content_by_lua_block]] directive instead. + Acts as a "content handler" and executes Lua code string specified in for every request. The Lua code may make [[#Nginx API for Lua|API calls]] and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). Do not use this directive and other content handler directives in the same location. For example, this directive and the [[HttpProxyModule#proxy_pass|proxy_pass]] directive should not be used in the same location. +== content_by_lua_block == + +'''syntax:''' ''content_by_lua_block { lua-script }'' + +'''context:''' ''location, location if'' + +'''phase:''' ''content'' + +Similar to the [[#content_by_lua|content_by_lua]] directive except that this directive inlines +the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping). + +For instance, + + + content_by_lua_block { + ngx.say("I need no extra escaping here, for example: \r\nblah") + } + + +This directive was first introduced in the v0.9.17 release. + == content_by_lua_file == '''syntax:''' ''content_by_lua_file '' @@ -1246,6 +1291,9 @@ But be very careful about malicious user inputs and always carefully validate or '''phase:''' ''rewrite tail'' +'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; +use the new [[#rewrite_by_lua_block|rewrite_by_lua_block]] directive instead. + Acts as a rewrite phase handler and executes Lua code string specified in for every request. The Lua code may make [[#Nginx API for Lua|API calls]] and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). @@ -1353,6 +1401,29 @@ Here the Lua code ngx.exit(503) will never run. This will be the ca The rewrite_by_lua code will always run at the end of the rewrite request-processing phase unless [[#rewrite_by_lua_no_postpone|rewrite_by_lua_no_postpone]] is turned on. +== rewrite_by_lua_block == + +'''syntax:''' ''rewrite_by_lua_block { lua-script }'' + +'''context:''' ''http, server, location, location if'' + +'''phase:''' ''rewrite tail'' + +Similar to the [[#rewrite_by_lua|rewrite_by_lua]] directive except that this directive inlines +the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping). + +For instance, + + + rewrite_by_lua_block { + do_something("hello, world!\nhiya\n") + } + + +This directive was first introduced in the v0.9.17 release. + == rewrite_by_lua_file == '''syntax:''' ''rewrite_by_lua_file '' @@ -1381,6 +1452,9 @@ Nginx variables are supported in the file path for dynamic dispatch just as in [ '''phase:''' ''access tail'' +'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; +use the new [[#access_by_lua_block|access_by_lua_block]] directive instead. + Acts as an access phase handler and executes Lua code string specified in for every request. The Lua code may make [[#Nginx API for Lua|API calls]] and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). @@ -1440,6 +1514,29 @@ As with other access phase handlers, [[#access_by_lua|access_by_lua]] will ''not Note that when calling ngx.exit(ngx.OK) within a [[#access_by_lua|access_by_lua]] handler, the nginx request processing control flow will still continue to the content handler. To terminate the current request from within a [[#access_by_lua|access_by_lua]] handler, calling [[#ngx.exit|ngx.exit]] with status >= 200 (ngx.HTTP_OK) and status < 300 (ngx.HTTP_SPECIAL_RESPONSE) for successful quits and ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) (or its friends) for failures. +== access_by_lua_block == + +'''syntax:''' ''access_by_lua_block { lua-script }'' + +'''context:''' ''http, server, location, location if'' + +'''phase:''' ''access tail'' + +Similar to the [[#access_by_lua|access_by_lua]] directive except that this directive inlines +the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping). + +For instance, + + + access_by_lua_block { + do_something("hello, world!\nhiya\n") + } + + +This directive was first introduced in the v0.9.17 release. + == access_by_lua_file == '''syntax:''' ''access_by_lua_file '' @@ -1468,12 +1565,15 @@ Nginx variables are supported in the file path for dynamic dispatch just as in [ '''phase:''' ''output-header-filter'' +'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; +use the new [[#header_filter_by_lua_block|header_filter_by_lua_block]] directive instead. + Uses Lua code specified in to define an output header filter. Note that the following API functions are currently disabled within this context: * Output API functions (e.g., [[#ngx.say|ngx.say]] and [[#ngx.send_headers|ngx.send_headers]]) -* Control API functions (e.g., [[#ngx.exit|ngx.exit]] and [[#ngx.exec|ngx.exec]]) +* Control API functions (e.g., [[#ngx.redirect|ngx.redirect]] and [[#ngx.exec|ngx.exec]]) * Subrequest API functions (e.g., [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]]) * Cosocket API functions (e.g., [[#ngx.socket.tcp|ngx.socket.tcp]] and [[#ngx.req.socket|ngx.req.socket]]). @@ -1488,6 +1588,29 @@ Here is an example of overriding a response header (or adding one if absent) in This directive was first introduced in the v0.2.1rc20 release. +== header_filter_by_lua_block == + +'''syntax:''' ''header_filter_by_lua_block { lua-script }'' + +'''context:''' ''http, server, location, location if'' + +'''phase:''' ''output-header-filter'' + +Similar to the [[#header_filter_by_lua|header_filter_by_lua]] directive except that this directive inlines +the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping). + +For instance, + + + header_filter_by_lua_block { + ngx.header["content-length"] = nil + } + + +This directive was first introduced in the v0.9.17 release. + == header_filter_by_lua_file == '''syntax:''' ''header_filter_by_lua_file '' @@ -1510,6 +1633,9 @@ This directive was first introduced in the v0.2.1rc20 release. '''phase:''' ''output-body-filter'' +'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; +use the new [[#body_filter_by_lua_block|body_filter_by_lua_block]] directive instead. + Uses Lua code specified in to define an output body filter. The input data chunk is passed via [[#ngx.arg|ngx.arg]][1] (as a Lua string value) and the "eof" flag indicating the end of the response body data stream is passed via [[#ngx.arg|ngx.arg]][2] (as a Lua boolean value). @@ -1585,6 +1711,29 @@ Nginx output filters may be called multiple times for a single request because r This directive was first introduced in the v0.5.0rc32 release. +== body_filter_by_lua_block == + +'''syntax:''' ''body_filter_by_lua_block { lua-script-str }'' + +'''context:''' ''http, server, location, location if'' + +'''phase:''' ''output-body-filter'' + +Similar to the [[#body_filter_by_lua|body_filter_by_lua]] directive except that this directive inlines +the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping). + +For instance, + + + body_filter_by_lua_block { + local data, eof = ngx.arg[1], ngx.arg[2] + } + + +This directive was first introduced in the v0.9.17 release. + == body_filter_by_lua_file == '''syntax:''' ''body_filter_by_lua_file '' @@ -1607,7 +1756,10 @@ This directive was first introduced in the v0.5.0rc32 release. '''phase:''' ''log'' -Run the Lua source code inlined as the at the log request processing phase. This does not replace the current access logs, but runs after. +'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; +use the new [[#log_by_lua_block|log_by_lua_block]] directive instead. + +Runs the Lua source code inlined as the at the log request processing phase. This does not replace the current access logs, but runs after. Note that the following API functions are currently disabled within this context: @@ -1660,6 +1812,29 @@ Here is an example of gathering average data for [[HttpUpstreamModule#$upstream_ This directive was first introduced in the v0.5.0rc31 release. +== log_by_lua_block == + +'''syntax:''' ''log_by_lua_block { lua-script }'' + +'''context:''' ''http, server, location, location if'' + +'''phase:''' ''log'' + +Similar to the [[#log_by_lua|log_by_lua]] directive except that this directive inlines +the Lua source directly +inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +special character escaping). + +For instance, + + + log_by_lua_block { + print("I need no extra escaping here, for example: \r\nblah") + } + + +This directive was first introduced in the v0.9.17 release. + == log_by_lua_file == '''syntax:''' ''log_by_lua_file '' @@ -2110,7 +2285,7 @@ many others are not, like $query_string, $arg_PARAMETER$1, $2, $3, and etc, can be read by this interface as well, by writing ngx.var[1], ngx.var[2], ngx.var[3], and etc. -Setting ngx.var.Foo to a nil value will unset the $Foo Nginx variable. +Setting ngx.var.Foo to a nil value will unset the $Foo Nginx variable. ngx.var.args = nil @@ -2125,6 +2300,8 @@ Setting ngx.var.Foo to a nil value will unset the -Returns a Lua table with three slots (res.status, res.header, res.body, and res.truncated). +Returns a Lua table with 4 slots: res.status, res.header, res.body, and res.truncated. res.status holds the response status code for the subrequest response. @@ -2884,7 +3061,7 @@ See also [[#ngx.req.set_method|ngx.req.set_method]]. '''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*'' -Overrides the current request's request method with the request_id argument. Currently only numerical [[#HTTP method constants|method constants]] are supported, like ngx.HTTP_POST and ngx.HTTP_GET. +Overrides the current request's request method with the method_id argument. Currently only numerical [[#HTTP method constants|method constants]] are supported, like ngx.HTTP_POST and ngx.HTTP_GET. If the current request is an Nginx subrequest, then the subrequest's method will be overridden. @@ -2933,14 +3110,14 @@ or equivalently, ngx.req.set_uri("/foo") -The jump can only be set to true in [[#rewrite_by_lua|rewrite_by_lua]] and [[#rewrite_by_lua_file|rewrite_by_lua_file]]. Use of jump in other contexts is prohibited and will throw out a Lua exception. +The jump argument can only be set to true in [[#rewrite_by_lua|rewrite_by_lua]] and [[#rewrite_by_lua_file|rewrite_by_lua_file]]. Use of jump in other contexts is prohibited and will throw out a Lua exception. A more sophisticated example involving regex substitutions is as follows location /test { rewrite_by_lua ' - local uri = ngx.re.sub(ngx.var.uri, "^/test/(.*)", "$1", "o") + local uri = ngx.re.sub(ngx.var.uri, "^/test/(.*)", "/$1", "o") ngx.req.set_uri(uri) '; proxy_pass http://my_backend; @@ -3151,7 +3328,7 @@ will yield: a b: 1a 2 -Arguments without the = parts are treated as boolean arguments. GET /test?foo&bar will yield: +Arguments without the = parts are treated as boolean arguments. POST /test with the request body foo&bar will yield: foo: true @@ -3224,13 +3401,13 @@ Note that a maximum of 100 request headers are parsed by default (including thos However, the optional max_headers function argument can be used to override this limit: - local args = ngx.req.get_headers(10) + local headers = ngx.req.get_headers(10) This argument can be set to zero to remove the limit and to process all request headers received: - local args = ngx.req.get_headers(0) + local headers = ngx.req.get_headers(0) Removing the max_headers cap is strongly discouraged. diff --git a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h index c9e3e66..962c651 100644 --- a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 9016 +#define ngx_http_lua_version 9019 typedef struct { diff --git a/debian/modules/nginx-lua/src/ddebug.h b/debian/modules/nginx-lua/src/ddebug.h index d0f3d1b..f2d4b73 100644 --- a/debian/modules/nginx-lua/src/ddebug.h +++ b/debian/modules/nginx-lua/src/ddebug.h @@ -28,7 +28,8 @@ #include -static void dd(const char *fmt, ...) { +static ngx_inline void +dd(const char *fmt, ...) { } # endif @@ -43,7 +44,8 @@ static void dd(const char *fmt, ...) { #include -static void dd(const char *fmt, ...) { +static ngx_inline void +dd(const char *fmt, ...) { } # endif diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c b/debian/modules/nginx-lua/src/ngx_http_lua_directive.c index dc9a12c..ae8b09f 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_directive.c @@ -24,6 +24,11 @@ #include "ngx_http_lua_initby.h" #include "ngx_http_lua_initworkerby.h" #include "ngx_http_lua_shdict.h" +#include "ngx_http_lua_lex.h" + + +typedef struct ngx_http_lua_block_parser_ctx_s + ngx_http_lua_block_parser_ctx_t; #if defined(NDK) && NDK @@ -35,6 +40,32 @@ static ngx_int_t ngx_http_lua_set_by_lua_init(ngx_http_request_t *r); static u_char *ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len); +static char *ngx_http_lua_conf_lua_block_parse(ngx_conf_t *cf, + ngx_command_t *cmd); +static ngx_int_t ngx_http_lua_conf_read_lua_token(ngx_conf_t *cf, + ngx_http_lua_block_parser_ctx_t *ctx); +static u_char *ngx_http_lua_strlstrn(u_char *s1, u_char *last, u_char *s2, + size_t n); + + +struct ngx_http_lua_block_parser_ctx_s { + ngx_uint_t start_line; + int token_len; +}; + + +enum { + FOUND_LEFT_CURLY = 0, + FOUND_RIGHT_CURLY, + FOUND_LEFT_LBRACKET_STR, + FOUND_LBRACKET_STR = FOUND_LEFT_LBRACKET_STR, + FOUND_LEFT_LBRACKET_CMT, + FOUND_LBRACKET_CMT = FOUND_LEFT_LBRACKET_CMT, + FOUND_RIGHT_LBRACKET, + FOUND_COMMENT_LINE, + FOUND_DOUBLE_QUOTED, + FOUND_SINGLE_QUOTED +}; char * @@ -189,6 +220,25 @@ ngx_http_lua_package_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #if defined(NDK) && NDK +char * +ngx_http_lua_set_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_set_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + char * ngx_http_lua_set_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { @@ -372,6 +422,25 @@ ngx_http_lua_filter_set_by_lua_file(ngx_http_request_t *r, ngx_str_t *val, #endif /* defined(NDK) && NDK */ +char * +ngx_http_lua_rewrite_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_rewrite_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + char * ngx_http_lua_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { @@ -467,6 +536,25 @@ ngx_http_lua_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +char * +ngx_http_lua_access_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_access_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + char * ngx_http_lua_access_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { @@ -558,6 +646,25 @@ ngx_http_lua_access_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +char * +ngx_http_lua_content_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_content_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + char * ngx_http_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { @@ -583,6 +690,9 @@ ngx_http_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) value = cf->args->elts; + dd("value[0]: %.*s", (int) value[0].len, value[0].data); + dd("value[1]: %.*s", (int) value[1].len, value[1].data); + if (value[1].len == 0) { /* Oops...Invalid location conf */ ngx_conf_log_error(NGX_LOG_ERR, cf, 0, @@ -659,6 +769,25 @@ ngx_http_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +char * +ngx_http_lua_log_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_log_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + char * ngx_http_lua_log_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { @@ -749,6 +878,25 @@ ngx_http_lua_log_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +char * +ngx_http_lua_header_filter_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_header_filter_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + char * ngx_http_lua_header_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) @@ -830,6 +978,25 @@ ngx_http_lua_header_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, } +char * +ngx_http_lua_body_filter_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_body_filter_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + char * ngx_http_lua_body_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) @@ -912,6 +1079,25 @@ ngx_http_lua_body_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, } +char * +ngx_http_lua_init_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_init_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + char * ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) @@ -960,6 +1146,25 @@ ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, } +char * +ngx_http_lua_init_worker_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_init_worker_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + char * ngx_http_lua_init_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) @@ -1078,4 +1283,411 @@ found: } +/* a specialized version of the standard ngx_conf_parse() function */ +static char * +ngx_http_lua_conf_lua_block_parse(ngx_conf_t *cf, ngx_command_t *cmd) +{ + ngx_http_lua_block_parser_ctx_t ctx; + + int level = 1; + char *rv; + u_char *p; + size_t len; + ngx_str_t *src, *dst; + ngx_int_t rc; + ngx_uint_t i, start_line; + ngx_array_t *saved; + enum { + parse_block = 0, + parse_param + } type; + + if (cf->conf_file->file.fd != NGX_INVALID_FILE) { + + type = parse_block; + + } else { + type = parse_param; + } + + saved = cf->args; + + cf->args = ngx_array_create(cf->temp_pool, 4, sizeof(ngx_str_t)); + if (cf->args == NULL) { + return NGX_CONF_ERROR; + } + + ctx.token_len = 0; + start_line = cf->conf_file->line; + + dd("init start line: %d", (int) start_line); + + ctx.start_line = start_line; + + for ( ;; ) { + rc = ngx_http_lua_conf_read_lua_token(cf, &ctx); + + dd("parser start line: %d", (int) start_line); + + switch (rc) { + + case NGX_ERROR: + goto done; + + case FOUND_LEFT_CURLY: + + ctx.start_line = cf->conf_file->line; + + if (type == parse_param) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "block directives are not supported " + "in -g option"); + goto failed; + } + + level++; + dd("seen block start: level=%d", (int) level); + break; + + case FOUND_RIGHT_CURLY: + + level--; + dd("seen block done: level=%d", (int) level); + + if (type != parse_block || level < 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unexpected \"}\": level %d, " + "starting at line %ui", level, + start_line); + goto failed; + } + + if (level == 0) { + ngx_http_lua_assert(cf->handler); + + src = cf->args->elts; + + for (len = 0, i = 0; i < cf->args->nelts; i++) { + len += src[i].len; + } + + dd("saved nelts: %d", (int) saved->nelts); + dd("temp nelts: %d", (int) cf->args->nelts); +#if 0 + ngx_http_lua_assert(saved->nelts == 1); +#endif + + dst = ngx_array_push(saved); + if (dst == NULL) { + return NGX_CONF_ERROR; + } + dst->len = len; + dst->len--; /* skip the trailing '}' block terminator */ + + p = ngx_palloc(cf->pool, len); + if (p == NULL) { + return NGX_CONF_ERROR; + } + dst->data = p; + + for (i = 0; i < cf->args->nelts; i++) { + p = ngx_copy(p, src[i].data, src[i].len); + } + + p[-1] = '\0'; /* override the last '}' char to null */ + + cf->args = saved; + + rv = (*cf->handler)(cf, cmd, cf->handler_conf); + if (rv == NGX_CONF_OK) { + goto done; + } + + if (rv == NGX_CONF_ERROR) { + goto failed; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv); + + goto failed; + } + + break; + + case FOUND_LBRACKET_STR: + + break; + + case FOUND_LBRACKET_CMT: + + break; + + case FOUND_RIGHT_LBRACKET: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unexpected lua closing long-bracket"); + goto failed; + + break; + + case FOUND_COMMENT_LINE: + case FOUND_DOUBLE_QUOTED: + case FOUND_SINGLE_QUOTED: + break; + + default: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unknown return value from the lexer: %i", rc); + goto failed; + } + } + +failed: + + rc = NGX_ERROR; + +done: + + if (rc == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_lua_conf_read_lua_token(ngx_conf_t *cf, + ngx_http_lua_block_parser_ctx_t *ctx) +{ + enum { + OVEC_SIZE = 2 + }; + int i, rc; + int ovec[OVEC_SIZE]; + u_char *start, *p, *q, ch; + off_t file_size; + size_t len, buf_size; + ssize_t n, size; + ngx_uint_t start_line; + ngx_str_t *word; + ngx_buf_t *b; +#if nginx_version >= 1009002 + ngx_buf_t *dump; +#endif + + b = cf->conf_file->buffer; +#if nginx_version >= 1009002 + dump = cf->conf_file->dump; +#endif + start = b->pos; + start_line = cf->conf_file->line; + buf_size = b->end - b->start; + + dd("lexer start line: %d", (int) start_line); + + file_size = ngx_file_size(&cf->conf_file->file.info); + + for ( ;; ) { + + if (b->pos >= b->last) { + + if (cf->conf_file->file.offset >= file_size) { + + cf->conf_file->line = ctx->start_line; + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unexpected end of file, expecting " + "terminating characters for lua code " + "block"); + return NGX_ERROR; + } + + len = b->pos - start; + + if (len == buf_size) { + + cf->conf_file->line = start_line; + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "too long lua code block, probably " + "missing terminating characters"); + + return NGX_ERROR; + } + + if (len) { + ngx_memmove(b->start, start, len); + } + + size = (ssize_t) (file_size - cf->conf_file->file.offset); + + if (size > b->end - (b->start + len)) { + size = b->end - (b->start + len); + } + + n = ngx_read_file(&cf->conf_file->file, b->start + len, size, + cf->conf_file->file.offset); + + if (n == NGX_ERROR) { + return NGX_ERROR; + } + + if (n != size) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + ngx_read_file_n " returned " + "only %z bytes instead of %z", + n, size); + return NGX_ERROR; + } + + b->pos = b->start + len; + b->last = b->pos + n; + start = b->start; + +#if nginx_version >= 1009002 + if (dump) { + dump->last = ngx_cpymem(dump->last, b->pos, size); + } +#endif + } + + rc = ngx_http_lua_lex(b->pos, b->last - b->pos, ovec); + + if (rc < 0) { /* no match */ + cf->conf_file->line = start_line; + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "Lua code block missing the \"}\" " + "character"); + + return NGX_ERROR; + } + + if (rc == FOUND_LEFT_LBRACKET_STR || rc == FOUND_LEFT_LBRACKET_CMT) { + + /* we update the line numbers for best error messages when the + * closing long bracket is missing */ + + for (i = 0; i < ovec[0]; i++) { + ch = b->pos[i]; + if (ch == LF) { + cf->conf_file->line++; + } + } + + b->pos += ovec[0]; + ovec[1] -= ovec[0]; + ovec[0] = 0; + + if (rc == FOUND_LEFT_LBRACKET_CMT) { + p = &b->pos[2]; /* we skip the leading "--" prefix */ + rc = FOUND_LBRACKET_CMT; + + } else { + p = b->pos; + rc = FOUND_LBRACKET_STR; + } + + /* we temporarily rewrite [=*[ in the input buffer to ]=*] to + * construct the pattern for the corresponding closing long + * bracket without additional buffers. */ + + ngx_http_lua_assert(p[0] == '['); + p[0] = ']'; + + ngx_http_lua_assert(b->pos[ovec[1] - 1] == '['); + b->pos[ovec[1] - 1] = ']'; + + /* search for the corresponding closing bracket */ + + dd("search pattern for the closing long bracket: \"%.*s\" (len=%d)", + (int) (b->pos + ovec[1] - p), p, (int) (b->pos + ovec[1] - p)); + + q = ngx_http_lua_strlstrn(b->pos + ovec[1], b->last, p, + b->pos + ovec[1] - p - 1); + + if (q == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "Lua code block missing the closing " + "long bracket \"%*s\"", + b->pos + ovec[1] - p, p); + return NGX_ERROR; + } + + /* restore the original opening long bracket */ + + p[0] = '['; + b->pos[ovec[1] - 1] = '['; + + ovec[1] = q - b->pos + b->pos + ovec[1] - p; + + dd("found long bracket token: \"%.*s\"", + (int) (ovec[1] - ovec[0]), b->pos + ovec[0]); + } + + for (i = 0; i < ovec[1]; i++) { + ch = b->pos[i]; + if (ch == LF) { + cf->conf_file->line++; + } + } + + b->pos += ovec[1]; + ctx->token_len = ovec[1] - ovec[0]; + + break; + } + + word = ngx_array_push(cf->args); + if (word == NULL) { + return NGX_ERROR; + } + + word->data = ngx_pnalloc(cf->temp_pool, b->pos - start); + if (word->data == NULL) { + return NGX_ERROR; + } + + len = b->pos - start; + ngx_memcpy(word->data, start, len); + word->len = len; + + return rc; +} + + +/* + * ngx_http_lua_strlstrn() is intended to search for static substring + * with known length in string until the argument last. The argument n + * must be length of the second substring - 1. + */ + +static u_char * +ngx_http_lua_strlstrn(u_char *s1, u_char *last, u_char *s2, size_t n) +{ + ngx_uint_t c1, c2; + + c2 = (ngx_uint_t) *s2++; + last -= n; + + do { + do { + if (s1 >= last) { + return NULL; + } + + c1 = (ngx_uint_t) *s1++; + + dd("testing char '%c' vs '%c'", (int) c1, (int) c2); + + } while (c1 != c2); + + dd("testing against pattern \"%.*s\"", (int) n, s2); + + } while (ngx_strncmp(s1, s2, n) != 0); + + return --s1; +} + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_directive.h b/debian/modules/nginx-lua/src/ngx_http_lua_directive.h index 5d5540c..5a8d93b 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_directive.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_directive.h @@ -17,26 +17,44 @@ char *ngx_http_lua_package_cpath(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); char *ngx_http_lua_package_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_lua_content_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); char *ngx_http_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_lua_rewrite_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); char *ngx_http_lua_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_lua_access_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); char *ngx_http_lua_access_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_lua_log_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); char *ngx_http_lua_log_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_lua_header_filter_by_lua_block(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); char *ngx_http_lua_header_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_lua_body_filter_by_lua_block(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); char *ngx_http_lua_body_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_lua_init_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); char *ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_lua_init_worker_by_lua_block(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); char *ngx_http_lua_init_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); char *ngx_http_lua_code_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); #if defined(NDK) && NDK +char *ngx_http_lua_set_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); char *ngx_http_lua_set_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); char *ngx_http_lua_set_by_lua_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers_in.c b/debian/modules/nginx-lua/src/ngx_http_lua_headers_in.c index f2f805c..abce458 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headers_in.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headers_in.c @@ -44,17 +44,6 @@ static ngx_int_t ngx_http_lua_rm_header_helper(ngx_list_t *l, static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { - -#if (NGX_HTTP_GZIP) - { ngx_string("Accept-Encoding"), - offsetof(ngx_http_headers_in_t, accept_encoding), - ngx_http_set_builtin_header }, - - { ngx_string("Via"), - offsetof(ngx_http_headers_in_t, via), - ngx_http_set_builtin_header }, -#endif - { ngx_string("Host"), offsetof(ngx_http_headers_in_t, host), ngx_http_set_host_header }, @@ -67,6 +56,22 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { offsetof(ngx_http_headers_in_t, if_modified_since), ngx_http_set_builtin_header }, +#if defined(nginx_version) && nginx_version >= 9002 + { ngx_string("If-Unmodified-Since"), + offsetof(ngx_http_headers_in_t, if_unmodified_since), + ngx_http_set_builtin_header }, +#endif + +#if defined(nginx_version) && nginx_version >= 1003003 + { ngx_string("If-Match"), + offsetof(ngx_http_headers_in_t, if_match), + ngx_http_set_builtin_header }, + + { ngx_string("If-None-Match"), + offsetof(ngx_http_headers_in_t, if_none_match), + ngx_http_set_builtin_header }, +#endif + { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent), ngx_http_set_user_agent_header }, @@ -75,6 +80,10 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { offsetof(ngx_http_headers_in_t, referer), ngx_http_set_builtin_header }, + { ngx_string("Content-Length"), + offsetof(ngx_http_headers_in_t, content_length), + ngx_http_set_content_length_header }, + { ngx_string("Content-Type"), offsetof(ngx_http_headers_in_t, content_type), ngx_http_set_builtin_header }, @@ -95,6 +104,22 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { offsetof(ngx_http_headers_in_t, expect), ngx_http_set_builtin_header }, +#if defined(nginx_version) && nginx_version >= 1003013 + { ngx_string("Upgrade"), + offsetof(ngx_http_headers_in_t, upgrade), + ngx_http_set_builtin_header }, +#endif + +#if (NGX_HTTP_GZIP) + { ngx_string("Accept-Encoding"), + offsetof(ngx_http_headers_in_t, accept_encoding), + ngx_http_set_builtin_header }, + + { ngx_string("Via"), + offsetof(ngx_http_headers_in_t, via), + ngx_http_set_builtin_header }, +#endif + { ngx_string("Authorization"), offsetof(ngx_http_headers_in_t, authorization), ngx_http_set_builtin_header }, @@ -103,20 +128,33 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { offsetof(ngx_http_headers_in_t, keep_alive), ngx_http_set_builtin_header }, - { ngx_string("Content-Length"), - offsetof(ngx_http_headers_in_t, content_length), - ngx_http_set_content_length_header }, - - { ngx_string("Cookie"), - 0, - ngx_http_set_cookie_header }, - #if (NGX_HTTP_REALIP) { ngx_string("X-Real-IP"), offsetof(ngx_http_headers_in_t, x_real_ip), ngx_http_set_builtin_header }, #endif +#if (NGX_HTTP_DAV) + { ngx_string("Depth"), + offsetof(ngx_http_headers_in_t, depth), + ngx_http_set_builtin_header }, + + { ngx_string("Destination"), + offsetof(ngx_http_headers_in_t, destination), + ngx_http_set_builtin_header }, + + { ngx_string("Overwrite"), + offsetof(ngx_http_headers_in_t, overwrite), + ngx_http_set_builtin_header }, + + { ngx_string("Date"), offsetof(ngx_http_headers_in_t, date), + ngx_http_set_builtin_header }, +#endif + + { ngx_string("Cookie"), + 0, + ngx_http_set_cookie_header }, + { ngx_null_string, 0, ngx_http_set_header } }; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c b/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c index 5039c27..5fd077f 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c @@ -385,7 +385,19 @@ static ngx_int_t ngx_http_set_content_type_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value) { + ngx_uint_t i; + r->headers_out.content_type_len = value->len; + +#if 1 + for (i = 0; i < value->len; i++) { + if (value->data[i] == ';') { + r->headers_out.content_type_len = i; + break; + } + } +#endif + r->headers_out.content_type = *value; r->headers_out.content_type_hash = hv->hash; r->headers_out.content_type_lowcase = NULL; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c b/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c index 6aa1a33..0876f26 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c @@ -167,6 +167,8 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) return NGX_ERROR; } + http_ctx.srv_conf[ngx_modules[i]->ctx_index] = cur; + if (module->merge_srv_conf) { prev = module->create_srv_conf(&conf); if (prev == NULL) { @@ -178,8 +180,6 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) goto failed; } } - - http_ctx.srv_conf[ngx_modules[i]->ctx_index] = cur; } if (module->create_loc_conf) { @@ -188,6 +188,8 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) return NGX_ERROR; } + http_ctx.loc_conf[ngx_modules[i]->ctx_index] = cur; + if (module->merge_loc_conf) { prev = module->create_loc_conf(&conf); if (prev == NULL) { @@ -199,8 +201,6 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) goto failed; } } - - http_ctx.loc_conf[ngx_modules[i]->ctx_index] = cur; } } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_lex.c b/debian/modules/nginx-lua/src/ngx_http_lua_lex.c new file mode 100644 index 0000000..45cf754 --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_lex.c @@ -0,0 +1,8251 @@ +/* + * Copyright (C) Yichun Zhang (agentzh) + * + * WARNING: DO NOT EVER EDIT THIS FILE!! + * + * This file was automatically generated by the re.pl script of sregex's + * "dfa-multi-re" git branch. + */ + + +#include "ngx_http_lua_lex.h" +#include +#include +#include +#include +#include +#include + + +#if __GNUC__ > 3 +# define likely(x) __builtin_expect((x),1) +# define unlikely(x) __builtin_expect((x),0) +#else +# define likely(x) (x) +# define unlikely(x) (x) +#endif + + +#ifndef u_char +#define u_char unsigned char +#endif + + +enum { + NO_MATCH = -1, +}; + + +/* + * ngx_http_lua_lex: the "ovec" array should be allocated by the caller with at + * least 2 elements. + */ +int +ngx_http_lua_lex(const u_char *const s, size_t len, int *const ovec) +{ + unsigned i = 0; + int matched_0 = -1; + int matched_1 = -1; + int matched_id = NO_MATCH; /* (pending) matched regex ID */ + int c; + int caps0_0 = -1; + int caps0_10 = -1; + int caps0_12 = -1; + int caps0_14 = -1; + int caps0_2 = -1; + int caps0_4 = -1; + int caps0_6 = -1; + int caps0_8 = -1; + int caps1_0 = -1; + int caps1_10 = -1; + int caps1_12 = -1; + int caps1_14 = -1; + int caps1_2 = -1; + int caps1_4 = -1; + int caps1_6 = -1; + int caps1_8 = -1; + int caps2_0 = -1; + int caps2_10 = -1; + int caps2_2 = -1; + int caps2_4 = -1; + int caps2_6 = -1; + int caps2_8 = -1; + int caps3_10 = -1; + + { /* DFA node {0} 0 */ + if (unlikely(i >= len)) { + i++; + goto st0_error; + } + + c = s[i]; + i++; + switch (c) { + case 34: { + /* transfer caps from row 0 to row 1 */ + /* capture stores */ + caps0_12 = i - 1; + goto st2; + break; + } + case 39: { + /* transfer caps from row 0 to row 1 */ + /* capture stores */ + caps0_14 = i - 1; + goto st3; + break; + } + case 45: { + /* transfer caps from row 0 to row 1 */ + /* transfer caps from row 0 to row 2 */ + /* capture stores */ + caps0_6 = i - 1; + caps1_10 = i - 1; + goto st4; + break; + } + case 91: { + /* transfer caps from row 0 to row 1 */ + /* capture stores */ + caps0_4 = i - 1; + goto st5; + break; + } + case 93: { + /* transfer caps from row 0 to row 1 */ + /* capture stores */ + caps0_8 = i - 1; + goto st6; + break; + } + case 123: { + /* transfer caps from row 0 to row 1 */ + /* capture stores */ + caps0_0 = i - 1; + goto st7; + break; + } + case 125: { + /* transfer caps from row 0 to row 1 */ + /* capture stores */ + caps0_2 = i - 1; + goto st8; + break; + } + default: + break; + } + /* (c >= 0 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c == 92) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st1; + } /* end state */ + + goto st0_error; + +st1: { /* DFA node {1} 1 */ + if (unlikely(i >= len)) { + i++; + goto st1_error; + } + + c = s[i]; + i++; + switch (c) { + case 34: { + /* transfer caps from row 0 to row 1 */ + /* capture stores */ + caps0_12 = i - 1; + goto st2; + break; + } + case 39: { + /* transfer caps from row 0 to row 1 */ + /* capture stores */ + caps0_14 = i - 1; + goto st3; + break; + } + case 45: { + /* transfer caps from row 0 to row 1 */ + /* transfer caps from row 0 to row 2 */ + /* capture stores */ + caps0_6 = i - 1; + caps1_10 = i - 1; + goto st4; + break; + } + case 91: { + /* transfer caps from row 0 to row 1 */ + /* capture stores */ + caps0_4 = i - 1; + goto st5; + break; + } + case 93: { + /* transfer caps from row 0 to row 1 */ + /* capture stores */ + caps0_8 = i - 1; + goto st6; + break; + } + case 123: { + /* transfer caps from row 0 to row 1 */ + /* capture stores */ + caps0_0 = i - 1; + goto st7; + break; + } + case 125: { + /* transfer caps from row 0 to row 1 */ + /* capture stores */ + caps0_2 = i - 1; + goto st8; + break; + } + default: + break; + } + /* (c >= 0 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c == 92) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st1; + } /* end state */ + + goto st1_error; + +st2: { /* DFA node {59,1} 2 */ + if (unlikely(i >= len)) { + i++; + goto st2_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 1 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_12 = i - 1; + goto st10; + break; + } + case 39: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_14 = i - 1; + goto st11; + break; + } + case 45: { + /* transfer caps from row 1 to row 2 */ + /* transfer caps from row 1 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st12; + break; + } + case 91: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_4 = i - 1; + goto st13; + break; + } + case 92: { + goto st14; + break; + } + case 93: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_8 = i - 1; + goto st15; + break; + } + case 123: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_0 = i - 1; + goto st16; + break; + } + case 125: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_2 = i - 1; + goto st17; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st9; + } /* end state */ + + goto st2_error; + +st3: { /* DFA node {72,1} 3 */ + if (unlikely(i >= len)) { + i++; + goto st3_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 1 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_12 = i - 1; + goto st19; + break; + } + case 39: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_14 = i - 1; + goto st20; + break; + } + case 45: { + /* transfer caps from row 1 to row 2 */ + /* transfer caps from row 1 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st21; + break; + } + case 91: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_4 = i - 1; + goto st22; + break; + } + case 92: { + goto st23; + break; + } + case 93: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_8 = i - 1; + goto st24; + break; + } + case 123: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_0 = i - 1; + goto st25; + break; + } + case 125: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_2 = i - 1; + goto st26; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st18; + } /* end state */ + + goto st3_error; + +st4: { /* DFA node {30,50,1} 4 */ + if (unlikely(i >= len)) { + i++; + goto st4_error; + } + + c = s[i]; + i++; + switch (c) { + case 34: { + /* transfer caps from row 2 to row 0 */ + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps0_12 = i - 1; + goto st2; + break; + } + case 39: { + /* transfer caps from row 2 to row 0 */ + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps0_14 = i - 1; + goto st3; + break; + } + case 45: { + /* transfer caps from row 2 to row 3 */ + /* transfer caps from row 2 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st27; + break; + } + case 91: { + /* transfer caps from row 2 to row 0 */ + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps0_4 = i - 1; + goto st5; + break; + } + case 93: { + /* transfer caps from row 2 to row 0 */ + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps0_8 = i - 1; + goto st6; + break; + } + case 123: { + /* transfer caps from row 2 to row 0 */ + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps0_0 = i - 1; + goto st7; + break; + } + case 125: { + /* transfer caps from row 2 to row 0 */ + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps0_2 = i - 1; + goto st8; + break; + } + default: + break; + } + /* (c >= 0 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c == 92) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 2 to row 0 */ + goto st1; + } /* end state */ + + goto st4_error; + +st5: { /* DFA node {21,1} 5 */ + if (unlikely(i >= len)) { + i++; + goto st5_error; + } + + c = s[i]; + i++; + switch (c) { + case 34: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_12 = i - 1; + goto st2; + break; + } + case 39: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_14 = i - 1; + goto st3; + break; + } + case 45: { + /* transfer caps from row 1 to row 0 */ + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps0_6 = i - 1; + caps1_10 = i - 1; + goto st4; + break; + } + case 61: { + goto st28; + break; + } + case 91: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_4 = i - 1; + goto st29; + break; + } + case 93: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_8 = i - 1; + goto st6; + break; + } + case 123: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_0 = i - 1; + goto st7; + break; + } + case 125: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_2 = i - 1; + goto st8; + break; + } + default: + break; + } + /* (c >= 0 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c == 92) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 1 to row 0 */ + goto st1; + } /* end state */ + + goto st5_error; + +st6: { /* DFA node {41,1} 6 */ + if (unlikely(i >= len)) { + i++; + goto st6_error; + } + + c = s[i]; + i++; + switch (c) { + case 34: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_12 = i - 1; + goto st2; + break; + } + case 39: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_14 = i - 1; + goto st3; + break; + } + case 45: { + /* transfer caps from row 1 to row 0 */ + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps0_6 = i - 1; + caps1_10 = i - 1; + goto st4; + break; + } + case 61: { + goto st30; + break; + } + case 91: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_4 = i - 1; + goto st5; + break; + } + case 93: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_8 = i - 1; + goto st31; + break; + } + case 123: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_0 = i - 1; + goto st7; + break; + } + case 125: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_2 = i - 1; + goto st8; + break; + } + default: + break; + } + /* (c >= 0 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c == 92) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 1 to row 0 */ + goto st1; + } /* end state */ + + goto st6_error; + +st7: { /* DFA node {11,1} 7 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_0; + /* capture stores */ + matched_1 = i - 1; + matched_id = 0; + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st8: { /* DFA node {16,1} 8 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_2; + /* capture stores */ + matched_1 = i - 1; + matched_id = 1; + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st9: { /* DFA node {65,1} 9 */ + if (unlikely(i >= len)) { + i++; + goto st9_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 1 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_12 = i - 1; + goto st10; + break; + } + case 39: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_14 = i - 1; + goto st11; + break; + } + case 45: { + /* transfer caps from row 1 to row 2 */ + /* transfer caps from row 1 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st12; + break; + } + case 91: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_4 = i - 1; + goto st13; + break; + } + case 92: { + goto st14; + break; + } + case 93: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_8 = i - 1; + goto st15; + break; + } + case 123: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_0 = i - 1; + goto st16; + break; + } + case 125: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_2 = i - 1; + goto st17; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st9; + } /* end state */ + + goto st9_error; + +st10: { /* DFA node {67,59,1} 10 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_12; + /* capture stores */ + matched_1 = i - 1; + matched_id = 6; + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st11: { /* DFA node {65,72,1} 11 */ + if (unlikely(i >= len)) { + i++; + goto st11_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st36; + break; + } + case 39: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st37; + break; + } + case 45: { + /* transfer caps from row 2 to row 3 */ + /* transfer caps from row 2 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st38; + break; + } + case 91: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st39; + break; + } + case 92: { + goto st40; + break; + } + case 93: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st41; + break; + } + case 123: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_0 = i - 1; + goto st42; + break; + } + case 125: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_2 = i - 1; + goto st43; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st35; + } /* end state */ + + goto st11_error; + +st12: { /* DFA node {65,30,50,1} 12 */ + if (unlikely(i >= len)) { + i++; + goto st12_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_12 = i - 1; + goto st10; + break; + } + case 39: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_14 = i - 1; + goto st11; + break; + } + case 45: { + /* transfer caps from row 3 to row 4 */ + /* transfer caps from row 3 to row 5 */ + /* capture stores */ + goto st44; + break; + } + case 91: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_4 = i - 1; + goto st13; + break; + } + case 92: { + /* transfer caps from row 3 to row 1 */ + goto st14; + break; + } + case 93: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_8 = i - 1; + goto st15; + break; + } + case 123: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_0 = i - 1; + goto st16; + break; + } + case 125: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_2 = i - 1; + goto st17; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 1 */ + goto st9; + } /* end state */ + + goto st12_error; + +st13: { /* DFA node {65,21,1} 13 */ + if (unlikely(i >= len)) { + i++; + goto st13_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_12 = i - 1; + goto st10; + break; + } + case 39: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_14 = i - 1; + goto st11; + break; + } + case 45: { + /* transfer caps from row 2 to row 1 */ + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st12; + break; + } + case 61: { + goto st45; + break; + } + case 91: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st46; + break; + } + case 92: { + /* transfer caps from row 2 to row 1 */ + goto st14; + break; + } + case 93: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_8 = i - 1; + goto st15; + break; + } + case 123: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_0 = i - 1; + goto st16; + break; + } + case 125: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_2 = i - 1; + goto st17; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 2 to row 1 */ + goto st9; + } /* end state */ + + goto st13_error; + +st14: { /* DFA node {62,1} 14 */ + if (unlikely(i >= len)) { + i++; + goto st14_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 1 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_12 = i - 1; + goto st48; + break; + } + case 39: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_14 = i - 1; + goto st49; + break; + } + case 45: { + /* transfer caps from row 1 to row 2 */ + /* transfer caps from row 1 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st50; + break; + } + case 91: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_4 = i - 1; + goto st51; + break; + } + case 93: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_8 = i - 1; + goto st52; + break; + } + case 123: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_0 = i - 1; + goto st53; + break; + } + case 125: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_2 = i - 1; + goto st54; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c == 92) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st47; + } /* end state */ + + goto st14_error; + +st15: { /* DFA node {65,41,1} 15 */ + if (unlikely(i >= len)) { + i++; + goto st15_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_12 = i - 1; + goto st10; + break; + } + case 39: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_14 = i - 1; + goto st11; + break; + } + case 45: { + /* transfer caps from row 2 to row 1 */ + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st12; + break; + } + case 61: { + goto st55; + break; + } + case 91: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_4 = i - 1; + goto st13; + break; + } + case 92: { + /* transfer caps from row 2 to row 1 */ + goto st14; + break; + } + case 93: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st56; + break; + } + case 123: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_0 = i - 1; + goto st16; + break; + } + case 125: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_2 = i - 1; + goto st17; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 2 to row 1 */ + goto st9; + } /* end state */ + + goto st15_error; + +st16: { /* DFA node {65,11,1} 16 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_0; + /* capture stores */ + matched_1 = i - 1; + matched_id = 0; + if (c != -1) { + if (c == 34) { + goto st58; + } + if (c == 92) { + goto st59; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st57; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st17: { /* DFA node {65,16,1} 17 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_2; + /* capture stores */ + matched_1 = i - 1; + matched_id = 1; + if (c != -1) { + if (c == 34) { + goto st58; + } + if (c == 92) { + goto st59; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st57; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st18: { /* DFA node {78,1} 18 */ + if (unlikely(i >= len)) { + i++; + goto st18_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 1 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_12 = i - 1; + goto st19; + break; + } + case 39: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_14 = i - 1; + goto st20; + break; + } + case 45: { + /* transfer caps from row 1 to row 2 */ + /* transfer caps from row 1 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st21; + break; + } + case 91: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_4 = i - 1; + goto st22; + break; + } + case 92: { + goto st23; + break; + } + case 93: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_8 = i - 1; + goto st24; + break; + } + case 123: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_0 = i - 1; + goto st25; + break; + } + case 125: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_2 = i - 1; + goto st26; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st18; + } /* end state */ + + goto st18_error; + +st19: { /* DFA node {78,59,1} 19 */ + if (unlikely(i >= len)) { + i++; + goto st19_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st61; + break; + } + case 39: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st62; + break; + } + case 45: { + /* transfer caps from row 2 to row 3 */ + /* transfer caps from row 2 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st63; + break; + } + case 91: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st64; + break; + } + case 92: { + goto st65; + break; + } + case 93: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st66; + break; + } + case 123: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_0 = i - 1; + goto st67; + break; + } + case 125: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_2 = i - 1; + goto st68; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st60; + } /* end state */ + + goto st19_error; + +st20: { /* DFA node {80,72,1} 20 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_14; + /* capture stores */ + matched_1 = i - 1; + matched_id = 7; + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st21: { /* DFA node {78,30,50,1} 21 */ + if (unlikely(i >= len)) { + i++; + goto st21_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_12 = i - 1; + goto st19; + break; + } + case 39: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_14 = i - 1; + goto st20; + break; + } + case 45: { + /* transfer caps from row 3 to row 4 */ + /* transfer caps from row 3 to row 5 */ + /* capture stores */ + goto st70; + break; + } + case 91: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_4 = i - 1; + goto st22; + break; + } + case 92: { + /* transfer caps from row 3 to row 1 */ + goto st23; + break; + } + case 93: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_8 = i - 1; + goto st24; + break; + } + case 123: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_0 = i - 1; + goto st25; + break; + } + case 125: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_2 = i - 1; + goto st26; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 1 */ + goto st18; + } /* end state */ + + goto st21_error; + +st22: { /* DFA node {78,21,1} 22 */ + if (unlikely(i >= len)) { + i++; + goto st22_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_12 = i - 1; + goto st19; + break; + } + case 39: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_14 = i - 1; + goto st20; + break; + } + case 45: { + /* transfer caps from row 2 to row 1 */ + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st21; + break; + } + case 61: { + goto st71; + break; + } + case 91: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st72; + break; + } + case 92: { + /* transfer caps from row 2 to row 1 */ + goto st23; + break; + } + case 93: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_8 = i - 1; + goto st24; + break; + } + case 123: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_0 = i - 1; + goto st25; + break; + } + case 125: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_2 = i - 1; + goto st26; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 2 to row 1 */ + goto st18; + } /* end state */ + + goto st22_error; + +st23: { /* DFA node {75,1} 23 */ + if (unlikely(i >= len)) { + i++; + goto st23_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 1 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_12 = i - 1; + goto st74; + break; + } + case 39: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_14 = i - 1; + goto st75; + break; + } + case 45: { + /* transfer caps from row 1 to row 2 */ + /* transfer caps from row 1 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st76; + break; + } + case 91: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_4 = i - 1; + goto st77; + break; + } + case 93: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_8 = i - 1; + goto st78; + break; + } + case 123: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_0 = i - 1; + goto st79; + break; + } + case 125: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_2 = i - 1; + goto st80; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c == 92) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st73; + } /* end state */ + + goto st23_error; + +st24: { /* DFA node {78,41,1} 24 */ + if (unlikely(i >= len)) { + i++; + goto st24_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_12 = i - 1; + goto st19; + break; + } + case 39: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_14 = i - 1; + goto st20; + break; + } + case 45: { + /* transfer caps from row 2 to row 1 */ + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st21; + break; + } + case 61: { + goto st81; + break; + } + case 91: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_4 = i - 1; + goto st22; + break; + } + case 92: { + /* transfer caps from row 2 to row 1 */ + goto st23; + break; + } + case 93: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st82; + break; + } + case 123: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_0 = i - 1; + goto st25; + break; + } + case 125: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_2 = i - 1; + goto st26; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 2 to row 1 */ + goto st18; + } /* end state */ + + goto st24_error; + +st25: { /* DFA node {78,11,1} 25 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_0; + /* capture stores */ + matched_1 = i - 1; + matched_id = 0; + if (c != -1) { + if (c == 39) { + goto st84; + } + if (c == 92) { + goto st85; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st83; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st26: { /* DFA node {78,16,1} 26 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_2; + /* capture stores */ + matched_1 = i - 1; + matched_id = 1; + if (c != -1) { + if (c == 39) { + goto st84; + } + if (c == 92) { + goto st85; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st83; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st27: { /* DFA node {31,51,30,50,1} 27 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 91) { + goto st88; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 90) + || (c >= 92 && c <= 255)) + { + /* transfer caps from row 1 to row 0 */ + caps0_10 = caps1_10; + goto st87; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st28: { /* DFA node {23,1} 28 */ + if (unlikely(i >= len)) { + i++; + goto st28_error; + } + + c = s[i]; + i++; + switch (c) { + case 34: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_12 = i - 1; + goto st2; + break; + } + case 39: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_14 = i - 1; + goto st3; + break; + } + case 45: { + /* transfer caps from row 1 to row 0 */ + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps0_6 = i - 1; + caps1_10 = i - 1; + goto st4; + break; + } + case 61: { + goto st28; + break; + } + case 91: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_4 = i - 1; + goto st29; + break; + } + case 93: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_8 = i - 1; + goto st6; + break; + } + case 123: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_0 = i - 1; + goto st7; + break; + } + case 125: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_2 = i - 1; + goto st8; + break; + } + default: + break; + } + /* (c >= 0 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c == 92) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 1 to row 0 */ + goto st1; + } /* end state */ + + goto st28_error; + +st29: { /* DFA node {25,21,1} 29 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_4; + /* capture stores */ + matched_1 = i - 1; + matched_id = 2; + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st30: { /* DFA node {43,1} 30 */ + if (unlikely(i >= len)) { + i++; + goto st30_error; + } + + c = s[i]; + i++; + switch (c) { + case 34: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_12 = i - 1; + goto st2; + break; + } + case 39: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_14 = i - 1; + goto st3; + break; + } + case 45: { + /* transfer caps from row 1 to row 0 */ + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps0_6 = i - 1; + caps1_10 = i - 1; + goto st4; + break; + } + case 61: { + goto st30; + break; + } + case 91: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_4 = i - 1; + goto st5; + break; + } + case 93: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_8 = i - 1; + goto st31; + break; + } + case 123: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_0 = i - 1; + goto st7; + break; + } + case 125: { + /* transfer caps from row 1 to row 0 */ + /* capture stores */ + caps0_2 = i - 1; + goto st8; + break; + } + default: + break; + } + /* (c >= 0 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c == 92) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 1 to row 0 */ + goto st1; + } /* end state */ + + goto st30_error; + +st31: { /* DFA node {45,41,1} 31 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_8; + /* capture stores */ + matched_1 = i - 1; + matched_id = 4; + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st35: { /* DFA node {65,78,1} 35 */ + if (unlikely(i >= len)) { + i++; + goto st35_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st36; + break; + } + case 39: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st37; + break; + } + case 45: { + /* transfer caps from row 2 to row 3 */ + /* transfer caps from row 2 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st38; + break; + } + case 91: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st39; + break; + } + case 92: { + goto st40; + break; + } + case 93: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st41; + break; + } + case 123: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_0 = i - 1; + goto st42; + break; + } + case 125: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_2 = i - 1; + goto st43; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st35; + } /* end state */ + + goto st35_error; + +st36: { /* DFA node {67,78,59,1} 36 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_12; + /* capture stores */ + matched_1 = i - 1; + matched_id = 6; + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st37: { /* DFA node {65,80,72,1} 37 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_14; + /* capture stores */ + matched_1 = i - 1; + matched_id = 7; + if (c != -1) { + if (c == 34) { + goto st58; + } + if (c == 92) { + goto st59; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st57; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st38: { /* DFA node {65,78,30,50,1} 38 */ + if (unlikely(i >= len)) { + i++; + goto st38_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 4 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + goto st36; + break; + } + case 39: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + goto st37; + break; + } + case 45: { + /* transfer caps from row 4 to row 5 */ + /* transfer caps from row 4 to row 6 */ + /* capture stores */ + goto st91; + break; + } + case 91: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st39; + break; + } + case 92: { + /* transfer caps from row 4 to row 2 */ + goto st40; + break; + } + case 93: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st41; + break; + } + case 123: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + caps2_0 = i - 1; + goto st42; + break; + } + case 125: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + caps2_2 = i - 1; + goto st43; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 4 to row 2 */ + goto st35; + } /* end state */ + + goto st38_error; + +st39: { /* DFA node {65,78,21,1} 39 */ + if (unlikely(i >= len)) { + i++; + goto st39_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st36; + break; + } + case 39: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st37; + break; + } + case 45: { + /* transfer caps from row 3 to row 2 */ + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st38; + break; + } + case 61: { + goto st92; + break; + } + case 91: { + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + goto st93; + break; + } + case 92: { + /* transfer caps from row 3 to row 2 */ + goto st40; + break; + } + case 93: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_8 = i - 1; + goto st41; + break; + } + case 123: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_0 = i - 1; + goto st42; + break; + } + case 125: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_2 = i - 1; + goto st43; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 2 */ + goto st35; + } /* end state */ + + goto st39_error; + +st40: { /* DFA node {62,75,1} 40 */ + if (unlikely(i >= len)) { + i++; + goto st40_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st95; + break; + } + case 39: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st96; + break; + } + case 45: { + /* transfer caps from row 2 to row 3 */ + /* transfer caps from row 2 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st97; + break; + } + case 91: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st98; + break; + } + case 93: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st99; + break; + } + case 123: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_0 = i - 1; + goto st100; + break; + } + case 125: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_2 = i - 1; + goto st101; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c == 92) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st94; + } /* end state */ + + goto st40_error; + +st41: { /* DFA node {65,78,41,1} 41 */ + if (unlikely(i >= len)) { + i++; + goto st41_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st36; + break; + } + case 39: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st37; + break; + } + case 45: { + /* transfer caps from row 3 to row 2 */ + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st38; + break; + } + case 61: { + goto st102; + break; + } + case 91: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_4 = i - 1; + goto st39; + break; + } + case 92: { + /* transfer caps from row 3 to row 2 */ + goto st40; + break; + } + case 93: { + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + goto st103; + break; + } + case 123: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_0 = i - 1; + goto st42; + break; + } + case 125: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_2 = i - 1; + goto st43; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 2 */ + goto st35; + } /* end state */ + + goto st41_error; + +st42: { /* DFA node {65,78,11,1} 42 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_0; + /* capture stores */ + matched_1 = i - 1; + matched_id = 0; + if (c != -1) { + if (c == 34) { + goto st105; + } + if (c == 39) { + goto st106; + } + if (c == 92) { + goto st107; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st104; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st43: { /* DFA node {65,78,16,1} 43 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_2; + /* capture stores */ + matched_1 = i - 1; + matched_id = 1; + if (c != -1) { + if (c == 34) { + goto st105; + } + if (c == 39) { + goto st106; + } + if (c == 92) { + goto st107; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st104; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st44: { /* DFA node {65,31,51,30,50,1} 44 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 34) { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st109; + } + if (c == 91) { + goto st110; + } + if (c == 92) { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st111; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 90) + || (c >= 93 && c <= 255)) + { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st108; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st45: { /* DFA node {65,23,1} 45 */ + if (unlikely(i >= len)) { + i++; + goto st45_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_12 = i - 1; + goto st10; + break; + } + case 39: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_14 = i - 1; + goto st11; + break; + } + case 45: { + /* transfer caps from row 2 to row 1 */ + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st12; + break; + } + case 61: { + goto st45; + break; + } + case 91: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st46; + break; + } + case 92: { + /* transfer caps from row 2 to row 1 */ + goto st14; + break; + } + case 93: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_8 = i - 1; + goto st15; + break; + } + case 123: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_0 = i - 1; + goto st16; + break; + } + case 125: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_2 = i - 1; + goto st17; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 2 to row 1 */ + goto st9; + } /* end state */ + + goto st45_error; + +st46: { /* DFA node {65,25,21,1} 46 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_4; + /* capture stores */ + matched_1 = i - 1; + matched_id = 2; + if (c != -1) { + if (c == 34) { + goto st58; + } + if (c == 92) { + goto st59; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st57; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st47: { /* DFA node {63,1} 47 */ + if (unlikely(i >= len)) { + i++; + goto st47_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 1 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_12 = i - 1; + goto st10; + break; + } + case 39: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_14 = i - 1; + goto st11; + break; + } + case 45: { + /* transfer caps from row 1 to row 2 */ + /* transfer caps from row 1 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st12; + break; + } + case 91: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_4 = i - 1; + goto st13; + break; + } + case 92: { + goto st14; + break; + } + case 93: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_8 = i - 1; + goto st15; + break; + } + case 123: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_0 = i - 1; + goto st16; + break; + } + case 125: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_2 = i - 1; + goto st17; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st9; + } /* end state */ + + goto st47_error; + +st48: { /* DFA node {63,59,1} 48 */ + if (unlikely(i >= len)) { + i++; + goto st48_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_12 = i - 1; + goto st10; + break; + } + case 39: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_14 = i - 1; + goto st11; + break; + } + case 45: { + /* transfer caps from row 2 to row 1 */ + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st12; + break; + } + case 91: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_4 = i - 1; + goto st13; + break; + } + case 92: { + /* transfer caps from row 2 to row 1 */ + goto st14; + break; + } + case 93: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_8 = i - 1; + goto st15; + break; + } + case 123: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_0 = i - 1; + goto st16; + break; + } + case 125: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_2 = i - 1; + goto st17; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 2 to row 1 */ + goto st9; + } /* end state */ + + goto st48_error; + +st49: { /* DFA node {63,72,1} 49 */ + if (unlikely(i >= len)) { + i++; + goto st49_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st36; + break; + } + case 39: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st37; + break; + } + case 45: { + /* transfer caps from row 2 to row 3 */ + /* transfer caps from row 2 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st38; + break; + } + case 91: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st39; + break; + } + case 92: { + goto st40; + break; + } + case 93: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st41; + break; + } + case 123: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_0 = i - 1; + goto st42; + break; + } + case 125: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_2 = i - 1; + goto st43; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st35; + } /* end state */ + + goto st49_error; + +st50: { /* DFA node {63,30,50,1} 50 */ + if (unlikely(i >= len)) { + i++; + goto st50_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_12 = i - 1; + goto st10; + break; + } + case 39: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_14 = i - 1; + goto st11; + break; + } + case 45: { + /* transfer caps from row 3 to row 4 */ + /* transfer caps from row 3 to row 5 */ + /* capture stores */ + goto st44; + break; + } + case 91: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_4 = i - 1; + goto st13; + break; + } + case 92: { + /* transfer caps from row 3 to row 1 */ + goto st14; + break; + } + case 93: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_8 = i - 1; + goto st15; + break; + } + case 123: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_0 = i - 1; + goto st16; + break; + } + case 125: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_2 = i - 1; + goto st17; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 1 */ + goto st9; + } /* end state */ + + goto st50_error; + +st51: { /* DFA node {63,21,1} 51 */ + if (unlikely(i >= len)) { + i++; + goto st51_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_12 = i - 1; + goto st10; + break; + } + case 39: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_14 = i - 1; + goto st11; + break; + } + case 45: { + /* transfer caps from row 2 to row 1 */ + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st12; + break; + } + case 61: { + goto st45; + break; + } + case 91: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st46; + break; + } + case 92: { + /* transfer caps from row 2 to row 1 */ + goto st14; + break; + } + case 93: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_8 = i - 1; + goto st15; + break; + } + case 123: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_0 = i - 1; + goto st16; + break; + } + case 125: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_2 = i - 1; + goto st17; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 2 to row 1 */ + goto st9; + } /* end state */ + + goto st51_error; + +st52: { /* DFA node {63,41,1} 52 */ + if (unlikely(i >= len)) { + i++; + goto st52_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_12 = i - 1; + goto st10; + break; + } + case 39: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_14 = i - 1; + goto st11; + break; + } + case 45: { + /* transfer caps from row 2 to row 1 */ + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st12; + break; + } + case 61: { + goto st55; + break; + } + case 91: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_4 = i - 1; + goto st13; + break; + } + case 92: { + /* transfer caps from row 2 to row 1 */ + goto st14; + break; + } + case 93: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st56; + break; + } + case 123: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_0 = i - 1; + goto st16; + break; + } + case 125: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_2 = i - 1; + goto st17; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 2 to row 1 */ + goto st9; + } /* end state */ + + goto st52_error; + +st53: { /* DFA node {63,11,1} 53 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_0; + /* capture stores */ + matched_1 = i - 1; + matched_id = 0; + if (c != -1) { + if (c == 34) { + goto st58; + } + if (c == 92) { + goto st59; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st57; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st54: { /* DFA node {63,16,1} 54 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_2; + /* capture stores */ + matched_1 = i - 1; + matched_id = 1; + if (c != -1) { + if (c == 34) { + goto st58; + } + if (c == 92) { + goto st59; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st57; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st55: { /* DFA node {65,43,1} 55 */ + if (unlikely(i >= len)) { + i++; + goto st55_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_12 = i - 1; + goto st10; + break; + } + case 39: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_14 = i - 1; + goto st11; + break; + } + case 45: { + /* transfer caps from row 2 to row 1 */ + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st12; + break; + } + case 61: { + goto st55; + break; + } + case 91: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_4 = i - 1; + goto st13; + break; + } + case 92: { + /* transfer caps from row 2 to row 1 */ + goto st14; + break; + } + case 93: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st56; + break; + } + case 123: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_0 = i - 1; + goto st16; + break; + } + case 125: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_2 = i - 1; + goto st17; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 2 to row 1 */ + goto st9; + } /* end state */ + + goto st55_error; + +st56: { /* DFA node {65,45,41,1} 56 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_8; + /* capture stores */ + matched_1 = i - 1; + matched_id = 4; + if (c != -1) { + if (c == 34) { + goto st58; + } + if (c == 92) { + goto st59; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st57; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st57: { /* DFA node {65} 57 */ + if (unlikely(i >= len)) { + i++; + goto st57_error; + } + + c = s[i]; + i++; + switch (c) { + case 34: { + goto st58; + break; + } + case 92: { + goto st59; + break; + } + default: + break; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st57; + } + } /* end state */ + + goto st57_error; + +st58: { /* DFA node {67} 58 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_12; + /* capture stores */ + matched_1 = i - 1; + matched_id = 6; + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st59: { /* DFA node {62} 59 */ + if (unlikely(i >= len)) { + i++; + goto st59_error; + } + + c = s[i]; + i++; + if ((c >= 0 && c <= 9) || (c >= 11 && c <= 255)) { + goto st112; + } + } /* end state */ + + goto st59_error; + +st60: { /* DFA node {78,65,1} 60 */ + if (unlikely(i >= len)) { + i++; + goto st60_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st61; + break; + } + case 39: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st62; + break; + } + case 45: { + /* transfer caps from row 2 to row 3 */ + /* transfer caps from row 2 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st63; + break; + } + case 91: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st64; + break; + } + case 92: { + goto st65; + break; + } + case 93: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st66; + break; + } + case 123: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_0 = i - 1; + goto st67; + break; + } + case 125: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_2 = i - 1; + goto st68; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st60; + } /* end state */ + + goto st60_error; + +st61: { /* DFA node {78,67,59,1} 61 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_12; + /* capture stores */ + matched_1 = i - 1; + matched_id = 6; + if (c != -1) { + if (c == 39) { + goto st84; + } + if (c == 92) { + goto st85; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st83; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st62: { /* DFA node {80,65,72,1} 62 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_14; + /* capture stores */ + matched_1 = i - 1; + matched_id = 7; + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st63: { /* DFA node {78,65,30,50,1} 63 */ + if (unlikely(i >= len)) { + i++; + goto st63_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 4 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + goto st61; + break; + } + case 39: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + goto st62; + break; + } + case 45: { + /* transfer caps from row 4 to row 5 */ + /* transfer caps from row 4 to row 6 */ + /* capture stores */ + goto st113; + break; + } + case 91: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st64; + break; + } + case 92: { + /* transfer caps from row 4 to row 2 */ + goto st65; + break; + } + case 93: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st66; + break; + } + case 123: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + caps2_0 = i - 1; + goto st67; + break; + } + case 125: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + caps2_2 = i - 1; + goto st68; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 4 to row 2 */ + goto st60; + } /* end state */ + + goto st63_error; + +st64: { /* DFA node {78,65,21,1} 64 */ + if (unlikely(i >= len)) { + i++; + goto st64_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st61; + break; + } + case 39: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st62; + break; + } + case 45: { + /* transfer caps from row 3 to row 2 */ + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st63; + break; + } + case 61: { + goto st114; + break; + } + case 91: { + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + goto st115; + break; + } + case 92: { + /* transfer caps from row 3 to row 2 */ + goto st65; + break; + } + case 93: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_8 = i - 1; + goto st66; + break; + } + case 123: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_0 = i - 1; + goto st67; + break; + } + case 125: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_2 = i - 1; + goto st68; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 2 */ + goto st60; + } /* end state */ + + goto st64_error; + +st65: { /* DFA node {75,62,1} 65 */ + if (unlikely(i >= len)) { + i++; + goto st65_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st117; + break; + } + case 39: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st118; + break; + } + case 45: { + /* transfer caps from row 2 to row 3 */ + /* transfer caps from row 2 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st119; + break; + } + case 91: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st120; + break; + } + case 93: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st121; + break; + } + case 123: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_0 = i - 1; + goto st122; + break; + } + case 125: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_2 = i - 1; + goto st123; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c == 92) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st116; + } /* end state */ + + goto st65_error; + +st66: { /* DFA node {78,65,41,1} 66 */ + if (unlikely(i >= len)) { + i++; + goto st66_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st61; + break; + } + case 39: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st62; + break; + } + case 45: { + /* transfer caps from row 3 to row 2 */ + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st63; + break; + } + case 61: { + goto st124; + break; + } + case 91: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_4 = i - 1; + goto st64; + break; + } + case 92: { + /* transfer caps from row 3 to row 2 */ + goto st65; + break; + } + case 93: { + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + goto st125; + break; + } + case 123: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_0 = i - 1; + goto st67; + break; + } + case 125: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_2 = i - 1; + goto st68; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 2 */ + goto st60; + } /* end state */ + + goto st66_error; + +st67: { /* DFA node {78,65,11,1} 67 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_0; + /* capture stores */ + matched_1 = i - 1; + matched_id = 0; + if (c != -1) { + if (c == 34) { + goto st127; + } + if (c == 39) { + goto st128; + } + if (c == 92) { + goto st129; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st126; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st68: { /* DFA node {78,65,16,1} 68 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_2; + /* capture stores */ + matched_1 = i - 1; + matched_id = 1; + if (c != -1) { + if (c == 34) { + goto st127; + } + if (c == 39) { + goto st128; + } + if (c == 92) { + goto st129; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st126; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st70: { /* DFA node {78,31,51,30,50,1} 70 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 39) { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st131; + } + if (c == 91) { + goto st132; + } + if (c == 92) { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st133; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 38) + || (c >= 40 && c <= 90) + || (c >= 93 && c <= 255)) + { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st130; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st71: { /* DFA node {78,23,1} 71 */ + if (unlikely(i >= len)) { + i++; + goto st71_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_12 = i - 1; + goto st19; + break; + } + case 39: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_14 = i - 1; + goto st20; + break; + } + case 45: { + /* transfer caps from row 2 to row 1 */ + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st21; + break; + } + case 61: { + goto st71; + break; + } + case 91: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st72; + break; + } + case 92: { + /* transfer caps from row 2 to row 1 */ + goto st23; + break; + } + case 93: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_8 = i - 1; + goto st24; + break; + } + case 123: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_0 = i - 1; + goto st25; + break; + } + case 125: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_2 = i - 1; + goto st26; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 2 to row 1 */ + goto st18; + } /* end state */ + + goto st71_error; + +st72: { /* DFA node {78,25,21,1} 72 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_4; + /* capture stores */ + matched_1 = i - 1; + matched_id = 2; + if (c != -1) { + if (c == 39) { + goto st84; + } + if (c == 92) { + goto st85; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st83; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st73: { /* DFA node {76,1} 73 */ + if (unlikely(i >= len)) { + i++; + goto st73_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 1 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_12 = i - 1; + goto st19; + break; + } + case 39: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_14 = i - 1; + goto st20; + break; + } + case 45: { + /* transfer caps from row 1 to row 2 */ + /* transfer caps from row 1 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st21; + break; + } + case 91: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_4 = i - 1; + goto st22; + break; + } + case 92: { + goto st23; + break; + } + case 93: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_8 = i - 1; + goto st24; + break; + } + case 123: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_0 = i - 1; + goto st25; + break; + } + case 125: { + /* transfer caps from row 1 to row 2 */ + /* capture stores */ + caps1_2 = i - 1; + goto st26; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st18; + } /* end state */ + + goto st73_error; + +st74: { /* DFA node {76,59,1} 74 */ + if (unlikely(i >= len)) { + i++; + goto st74_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st61; + break; + } + case 39: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st62; + break; + } + case 45: { + /* transfer caps from row 2 to row 3 */ + /* transfer caps from row 2 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st63; + break; + } + case 91: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st64; + break; + } + case 92: { + goto st65; + break; + } + case 93: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st66; + break; + } + case 123: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_0 = i - 1; + goto st67; + break; + } + case 125: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_2 = i - 1; + goto st68; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st60; + } /* end state */ + + goto st74_error; + +st75: { /* DFA node {76,72,1} 75 */ + if (unlikely(i >= len)) { + i++; + goto st75_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_12 = i - 1; + goto st19; + break; + } + case 39: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_14 = i - 1; + goto st20; + break; + } + case 45: { + /* transfer caps from row 2 to row 1 */ + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st21; + break; + } + case 91: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_4 = i - 1; + goto st22; + break; + } + case 92: { + /* transfer caps from row 2 to row 1 */ + goto st23; + break; + } + case 93: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_8 = i - 1; + goto st24; + break; + } + case 123: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_0 = i - 1; + goto st25; + break; + } + case 125: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_2 = i - 1; + goto st26; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 2 to row 1 */ + goto st18; + } /* end state */ + + goto st75_error; + +st76: { /* DFA node {76,30,50,1} 76 */ + if (unlikely(i >= len)) { + i++; + goto st76_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_12 = i - 1; + goto st19; + break; + } + case 39: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_14 = i - 1; + goto st20; + break; + } + case 45: { + /* transfer caps from row 3 to row 4 */ + /* transfer caps from row 3 to row 5 */ + /* capture stores */ + goto st70; + break; + } + case 91: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_4 = i - 1; + goto st22; + break; + } + case 92: { + /* transfer caps from row 3 to row 1 */ + goto st23; + break; + } + case 93: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_8 = i - 1; + goto st24; + break; + } + case 123: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_0 = i - 1; + goto st25; + break; + } + case 125: { + /* transfer caps from row 3 to row 1 */ + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps1_2 = i - 1; + goto st26; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 1 */ + goto st18; + } /* end state */ + + goto st76_error; + +st77: { /* DFA node {76,21,1} 77 */ + if (unlikely(i >= len)) { + i++; + goto st77_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_12 = i - 1; + goto st19; + break; + } + case 39: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_14 = i - 1; + goto st20; + break; + } + case 45: { + /* transfer caps from row 2 to row 1 */ + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st21; + break; + } + case 61: { + goto st71; + break; + } + case 91: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st72; + break; + } + case 92: { + /* transfer caps from row 2 to row 1 */ + goto st23; + break; + } + case 93: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_8 = i - 1; + goto st24; + break; + } + case 123: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_0 = i - 1; + goto st25; + break; + } + case 125: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_2 = i - 1; + goto st26; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 2 to row 1 */ + goto st18; + } /* end state */ + + goto st77_error; + +st78: { /* DFA node {76,41,1} 78 */ + if (unlikely(i >= len)) { + i++; + goto st78_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_12 = i - 1; + goto st19; + break; + } + case 39: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_14 = i - 1; + goto st20; + break; + } + case 45: { + /* transfer caps from row 2 to row 1 */ + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st21; + break; + } + case 61: { + goto st81; + break; + } + case 91: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_4 = i - 1; + goto st22; + break; + } + case 92: { + /* transfer caps from row 2 to row 1 */ + goto st23; + break; + } + case 93: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st82; + break; + } + case 123: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_0 = i - 1; + goto st25; + break; + } + case 125: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_2 = i - 1; + goto st26; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 2 to row 1 */ + goto st18; + } /* end state */ + + goto st78_error; + +st79: { /* DFA node {76,11,1} 79 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_0; + /* capture stores */ + matched_1 = i - 1; + matched_id = 0; + if (c != -1) { + if (c == 39) { + goto st84; + } + if (c == 92) { + goto st85; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st83; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st80: { /* DFA node {76,16,1} 80 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_2; + /* capture stores */ + matched_1 = i - 1; + matched_id = 1; + if (c != -1) { + if (c == 39) { + goto st84; + } + if (c == 92) { + goto st85; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st83; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st81: { /* DFA node {78,43,1} 81 */ + if (unlikely(i >= len)) { + i++; + goto st81_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_12 = i - 1; + goto st19; + break; + } + case 39: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_14 = i - 1; + goto st20; + break; + } + case 45: { + /* transfer caps from row 2 to row 1 */ + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps1_6 = i - 1; + caps2_10 = i - 1; + goto st21; + break; + } + case 61: { + goto st81; + break; + } + case 91: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_4 = i - 1; + goto st22; + break; + } + case 92: { + /* transfer caps from row 2 to row 1 */ + goto st23; + break; + } + case 93: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st82; + break; + } + case 123: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_0 = i - 1; + goto st25; + break; + } + case 125: { + /* transfer caps from row 2 to row 1 */ + /* capture stores */ + caps1_2 = i - 1; + goto st26; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 2 to row 1 */ + goto st18; + } /* end state */ + + goto st81_error; + +st82: { /* DFA node {78,45,41,1} 82 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_8; + /* capture stores */ + matched_1 = i - 1; + matched_id = 4; + if (c != -1) { + if (c == 39) { + goto st84; + } + if (c == 92) { + goto st85; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st83; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st83: { /* DFA node {78} 83 */ + if (unlikely(i >= len)) { + i++; + goto st83_error; + } + + c = s[i]; + i++; + switch (c) { + case 39: { + goto st84; + break; + } + case 92: { + goto st85; + break; + } + default: + break; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st83; + } + } /* end state */ + + goto st83_error; + +st84: { /* DFA node {80} 84 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_14; + /* capture stores */ + matched_1 = i - 1; + matched_id = 7; + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st85: { /* DFA node {75} 85 */ + if (unlikely(i >= len)) { + i++; + goto st85_error; + } + + c = s[i]; + i++; + if ((c >= 0 && c <= 9) || (c >= 11 && c <= 255)) { + goto st134; + } + } /* end state */ + + goto st85_error; + +st87: { /* DFA node {53} 87 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if ((c >= 0 && c <= 9) || (c >= 11 && c <= 255)) { + goto st87; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st88: { /* DFA node {32,53} 88 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 61) { + goto st135; + } + if (c == 91) { + goto st136; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 60) + || (c >= 62 && c <= 90) + || (c >= 92 && c <= 255)) + { + /* transfer caps from row 1 to row 0 */ + caps0_10 = caps1_10; + goto st87; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st91: { /* DFA node {65,78,31,51,30,50,1} 91 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 3 to matched */ + matched_0 = caps3_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 34) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st138; + } + if (c == 39) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st139; + } + if (c == 91) { + goto st140; + } + if (c == 92) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st141; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 90) + || (c >= 93 && c <= 255)) + { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st137; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st92: { /* DFA node {65,78,23,1} 92 */ + if (unlikely(i >= len)) { + i++; + goto st92_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st36; + break; + } + case 39: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st37; + break; + } + case 45: { + /* transfer caps from row 3 to row 2 */ + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st38; + break; + } + case 61: { + goto st92; + break; + } + case 91: { + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + goto st93; + break; + } + case 92: { + /* transfer caps from row 3 to row 2 */ + goto st40; + break; + } + case 93: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_8 = i - 1; + goto st41; + break; + } + case 123: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_0 = i - 1; + goto st42; + break; + } + case 125: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_2 = i - 1; + goto st43; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 2 */ + goto st35; + } /* end state */ + + goto st92_error; + +st93: { /* DFA node {65,78,25,21,1} 93 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_4; + /* capture stores */ + matched_1 = i - 1; + matched_id = 2; + if (c != -1) { + if (c == 34) { + goto st105; + } + if (c == 39) { + goto st106; + } + if (c == 92) { + goto st107; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st104; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st94: { /* DFA node {63,76,1} 94 */ + if (unlikely(i >= len)) { + i++; + goto st94_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st36; + break; + } + case 39: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st37; + break; + } + case 45: { + /* transfer caps from row 2 to row 3 */ + /* transfer caps from row 2 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st38; + break; + } + case 91: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st39; + break; + } + case 92: { + goto st40; + break; + } + case 93: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st41; + break; + } + case 123: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_0 = i - 1; + goto st42; + break; + } + case 125: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_2 = i - 1; + goto st43; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st35; + } /* end state */ + + goto st94_error; + +st95: { /* DFA node {63,76,59,1} 95 */ + if (unlikely(i >= len)) { + i++; + goto st95_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st36; + break; + } + case 39: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st37; + break; + } + case 45: { + /* transfer caps from row 3 to row 2 */ + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st38; + break; + } + case 91: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_4 = i - 1; + goto st39; + break; + } + case 92: { + /* transfer caps from row 3 to row 2 */ + goto st40; + break; + } + case 93: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_8 = i - 1; + goto st41; + break; + } + case 123: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_0 = i - 1; + goto st42; + break; + } + case 125: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_2 = i - 1; + goto st43; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 2 */ + goto st35; + } /* end state */ + + goto st95_error; + +st96: { /* DFA node {63,76,72,1} 96 */ + if (unlikely(i >= len)) { + i++; + goto st96_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st36; + break; + } + case 39: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st37; + break; + } + case 45: { + /* transfer caps from row 3 to row 2 */ + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st38; + break; + } + case 91: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_4 = i - 1; + goto st39; + break; + } + case 92: { + /* transfer caps from row 3 to row 2 */ + goto st40; + break; + } + case 93: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_8 = i - 1; + goto st41; + break; + } + case 123: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_0 = i - 1; + goto st42; + break; + } + case 125: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_2 = i - 1; + goto st43; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 2 */ + goto st35; + } /* end state */ + + goto st96_error; + +st97: { /* DFA node {63,76,30,50,1} 97 */ + if (unlikely(i >= len)) { + i++; + goto st97_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 4 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + goto st36; + break; + } + case 39: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + goto st37; + break; + } + case 45: { + /* transfer caps from row 4 to row 5 */ + /* transfer caps from row 4 to row 6 */ + /* capture stores */ + goto st91; + break; + } + case 91: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st39; + break; + } + case 92: { + /* transfer caps from row 4 to row 2 */ + goto st40; + break; + } + case 93: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st41; + break; + } + case 123: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + caps2_0 = i - 1; + goto st42; + break; + } + case 125: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + caps2_2 = i - 1; + goto st43; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 4 to row 2 */ + goto st35; + } /* end state */ + + goto st97_error; + +st98: { /* DFA node {63,76,21,1} 98 */ + if (unlikely(i >= len)) { + i++; + goto st98_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st36; + break; + } + case 39: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st37; + break; + } + case 45: { + /* transfer caps from row 3 to row 2 */ + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st38; + break; + } + case 61: { + goto st92; + break; + } + case 91: { + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + goto st93; + break; + } + case 92: { + /* transfer caps from row 3 to row 2 */ + goto st40; + break; + } + case 93: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_8 = i - 1; + goto st41; + break; + } + case 123: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_0 = i - 1; + goto st42; + break; + } + case 125: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_2 = i - 1; + goto st43; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 2 */ + goto st35; + } /* end state */ + + goto st98_error; + +st99: { /* DFA node {63,76,41,1} 99 */ + if (unlikely(i >= len)) { + i++; + goto st99_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st36; + break; + } + case 39: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st37; + break; + } + case 45: { + /* transfer caps from row 3 to row 2 */ + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st38; + break; + } + case 61: { + goto st102; + break; + } + case 91: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_4 = i - 1; + goto st39; + break; + } + case 92: { + /* transfer caps from row 3 to row 2 */ + goto st40; + break; + } + case 93: { + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + goto st103; + break; + } + case 123: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_0 = i - 1; + goto st42; + break; + } + case 125: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_2 = i - 1; + goto st43; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 2 */ + goto st35; + } /* end state */ + + goto st99_error; + +st100: { /* DFA node {63,76,11,1} 100 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_0; + /* capture stores */ + matched_1 = i - 1; + matched_id = 0; + if (c != -1) { + if (c == 34) { + goto st105; + } + if (c == 39) { + goto st106; + } + if (c == 92) { + goto st107; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st104; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st101: { /* DFA node {63,76,16,1} 101 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_2; + /* capture stores */ + matched_1 = i - 1; + matched_id = 1; + if (c != -1) { + if (c == 34) { + goto st105; + } + if (c == 39) { + goto st106; + } + if (c == 92) { + goto st107; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st104; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st102: { /* DFA node {65,78,43,1} 102 */ + if (unlikely(i >= len)) { + i++; + goto st102_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st36; + break; + } + case 39: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st37; + break; + } + case 45: { + /* transfer caps from row 3 to row 2 */ + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st38; + break; + } + case 61: { + goto st102; + break; + } + case 91: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_4 = i - 1; + goto st39; + break; + } + case 92: { + /* transfer caps from row 3 to row 2 */ + goto st40; + break; + } + case 93: { + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + goto st103; + break; + } + case 123: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_0 = i - 1; + goto st42; + break; + } + case 125: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_2 = i - 1; + goto st43; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 2 */ + goto st35; + } /* end state */ + + goto st102_error; + +st103: { /* DFA node {65,78,45,41,1} 103 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_8; + /* capture stores */ + matched_1 = i - 1; + matched_id = 4; + if (c != -1) { + if (c == 34) { + goto st105; + } + if (c == 39) { + goto st106; + } + if (c == 92) { + goto st107; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st104; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st104: { /* DFA node {65,78} 104 */ + if (unlikely(i >= len)) { + i++; + goto st104_error; + } + + c = s[i]; + i++; + switch (c) { + case 34: { + goto st105; + break; + } + case 39: { + goto st106; + break; + } + case 92: { + goto st107; + break; + } + default: + break; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st104; + } + } /* end state */ + + goto st104_error; + +st105: { /* DFA node {67,78} 105 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_12; + /* capture stores */ + matched_1 = i - 1; + matched_id = 6; + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st106: { /* DFA node {65,80} 106 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_14; + /* capture stores */ + matched_1 = i - 1; + matched_id = 7; + if (c != -1) { + if (c == 34) { + goto st58; + } + if (c == 92) { + goto st59; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st57; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st107: { /* DFA node {62,75} 107 */ + if (unlikely(i >= len)) { + i++; + goto st107_error; + } + + c = s[i]; + i++; + if ((c >= 0 && c <= 9) || (c >= 11 && c <= 255)) { + goto st142; + } + } /* end state */ + + goto st107_error; + +st108: { /* DFA node {65,53} 108 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 34) { + goto st109; + } + if (c == 92) { + goto st111; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st108; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st109: { /* DFA node {67,53} 109 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_12; + /* capture stores */ + matched_1 = i - 1; + matched_id = 6; + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st110: { /* DFA node {65,32,53} 110 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 34) { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st109; + } + if (c == 61) { + goto st143; + } + if (c == 91) { + goto st144; + } + if (c == 92) { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st111; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 60) + || (c >= 62 && c <= 90) + || (c >= 93 && c <= 255)) + { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st108; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st111: { /* DFA node {62,53} 111 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if ((c >= 0 && c <= 9) || (c >= 11 && c <= 255)) { + goto st145; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st112: { /* DFA node {63} 112 */ + if (unlikely(i >= len)) { + i++; + goto st112_error; + } + + c = s[i]; + i++; + switch (c) { + case 34: { + goto st58; + break; + } + case 92: { + goto st59; + break; + } + default: + break; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st57; + } + } /* end state */ + + goto st112_error; + +st113: { /* DFA node {78,65,31,51,30,50,1} 113 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 3 to matched */ + matched_0 = caps3_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 34) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st147; + } + if (c == 39) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st148; + } + if (c == 91) { + goto st149; + } + if (c == 92) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st150; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 90) + || (c >= 93 && c <= 255)) + { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st146; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st114: { /* DFA node {78,65,23,1} 114 */ + if (unlikely(i >= len)) { + i++; + goto st114_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st61; + break; + } + case 39: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st62; + break; + } + case 45: { + /* transfer caps from row 3 to row 2 */ + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st63; + break; + } + case 61: { + goto st114; + break; + } + case 91: { + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + goto st115; + break; + } + case 92: { + /* transfer caps from row 3 to row 2 */ + goto st65; + break; + } + case 93: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_8 = i - 1; + goto st66; + break; + } + case 123: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_0 = i - 1; + goto st67; + break; + } + case 125: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_2 = i - 1; + goto st68; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 2 */ + goto st60; + } /* end state */ + + goto st114_error; + +st115: { /* DFA node {78,65,25,21,1} 115 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_4; + /* capture stores */ + matched_1 = i - 1; + matched_id = 2; + if (c != -1) { + if (c == 34) { + goto st127; + } + if (c == 39) { + goto st128; + } + if (c == 92) { + goto st129; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st126; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st116: { /* DFA node {76,63,1} 116 */ + if (unlikely(i >= len)) { + i++; + goto st116_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 2 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st61; + break; + } + case 39: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + goto st62; + break; + } + case 45: { + /* transfer caps from row 2 to row 3 */ + /* transfer caps from row 2 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st63; + break; + } + case 91: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st64; + break; + } + case 92: { + goto st65; + break; + } + case 93: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st66; + break; + } + case 123: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_0 = i - 1; + goto st67; + break; + } + case 125: { + /* transfer caps from row 2 to row 3 */ + /* capture stores */ + caps2_2 = i - 1; + goto st68; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + goto st60; + } /* end state */ + + goto st116_error; + +st117: { /* DFA node {76,63,59,1} 117 */ + if (unlikely(i >= len)) { + i++; + goto st117_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st61; + break; + } + case 39: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st62; + break; + } + case 45: { + /* transfer caps from row 3 to row 2 */ + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st63; + break; + } + case 91: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_4 = i - 1; + goto st64; + break; + } + case 92: { + /* transfer caps from row 3 to row 2 */ + goto st65; + break; + } + case 93: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_8 = i - 1; + goto st66; + break; + } + case 123: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_0 = i - 1; + goto st67; + break; + } + case 125: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_2 = i - 1; + goto st68; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 2 */ + goto st60; + } /* end state */ + + goto st117_error; + +st118: { /* DFA node {76,63,72,1} 118 */ + if (unlikely(i >= len)) { + i++; + goto st118_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st61; + break; + } + case 39: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st62; + break; + } + case 45: { + /* transfer caps from row 3 to row 2 */ + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st63; + break; + } + case 91: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_4 = i - 1; + goto st64; + break; + } + case 92: { + /* transfer caps from row 3 to row 2 */ + goto st65; + break; + } + case 93: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_8 = i - 1; + goto st66; + break; + } + case 123: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_0 = i - 1; + goto st67; + break; + } + case 125: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_2 = i - 1; + goto st68; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 2 */ + goto st60; + } /* end state */ + + goto st118_error; + +st119: { /* DFA node {76,63,30,50,1} 119 */ + if (unlikely(i >= len)) { + i++; + goto st119_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 4 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + goto st61; + break; + } + case 39: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + goto st62; + break; + } + case 45: { + /* transfer caps from row 4 to row 5 */ + /* transfer caps from row 4 to row 6 */ + /* capture stores */ + goto st113; + break; + } + case 91: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + caps2_4 = i - 1; + goto st64; + break; + } + case 92: { + /* transfer caps from row 4 to row 2 */ + goto st65; + break; + } + case 93: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + caps2_8 = i - 1; + goto st66; + break; + } + case 123: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + caps2_0 = i - 1; + goto st67; + break; + } + case 125: { + /* transfer caps from row 4 to row 2 */ + /* transfer caps from row 4 to row 3 */ + /* capture stores */ + caps2_2 = i - 1; + goto st68; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 4 to row 2 */ + goto st60; + } /* end state */ + + goto st119_error; + +st120: { /* DFA node {76,63,21,1} 120 */ + if (unlikely(i >= len)) { + i++; + goto st120_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st61; + break; + } + case 39: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st62; + break; + } + case 45: { + /* transfer caps from row 3 to row 2 */ + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st63; + break; + } + case 61: { + goto st114; + break; + } + case 91: { + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + goto st115; + break; + } + case 92: { + /* transfer caps from row 3 to row 2 */ + goto st65; + break; + } + case 93: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_8 = i - 1; + goto st66; + break; + } + case 123: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_0 = i - 1; + goto st67; + break; + } + case 125: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_2 = i - 1; + goto st68; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 2 */ + goto st60; + } /* end state */ + + goto st120_error; + +st121: { /* DFA node {76,63,41,1} 121 */ + if (unlikely(i >= len)) { + i++; + goto st121_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st61; + break; + } + case 39: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st62; + break; + } + case 45: { + /* transfer caps from row 3 to row 2 */ + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st63; + break; + } + case 61: { + goto st124; + break; + } + case 91: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_4 = i - 1; + goto st64; + break; + } + case 92: { + /* transfer caps from row 3 to row 2 */ + goto st65; + break; + } + case 93: { + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + goto st125; + break; + } + case 123: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_0 = i - 1; + goto st67; + break; + } + case 125: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_2 = i - 1; + goto st68; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 2 */ + goto st60; + } /* end state */ + + goto st121_error; + +st122: { /* DFA node {76,63,11,1} 122 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_0; + /* capture stores */ + matched_1 = i - 1; + matched_id = 0; + if (c != -1) { + if (c == 34) { + goto st127; + } + if (c == 39) { + goto st128; + } + if (c == 92) { + goto st129; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st126; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st123: { /* DFA node {76,63,16,1} 123 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_2; + /* capture stores */ + matched_1 = i - 1; + matched_id = 1; + if (c != -1) { + if (c == 34) { + goto st127; + } + if (c == 39) { + goto st128; + } + if (c == 92) { + goto st129; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st126; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st124: { /* DFA node {78,65,43,1} 124 */ + if (unlikely(i >= len)) { + i++; + goto st124_error; + } + + c = s[i]; + i++; + switch (c) { + case 10: { + /* transfer caps from row 3 to row 0 */ + goto st1; + break; + } + case 34: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st61; + break; + } + case 39: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + goto st62; + break; + } + case 45: { + /* transfer caps from row 3 to row 2 */ + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + caps2_6 = i - 1; + caps3_10 = i - 1; + goto st63; + break; + } + case 61: { + goto st124; + break; + } + case 91: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_4 = i - 1; + goto st64; + break; + } + case 92: { + /* transfer caps from row 3 to row 2 */ + goto st65; + break; + } + case 93: { + /* transfer caps from row 3 to row 4 */ + /* capture stores */ + goto st125; + break; + } + case 123: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_0 = i - 1; + goto st67; + break; + } + case 125: { + /* transfer caps from row 3 to row 2 */ + /* capture stores */ + caps2_2 = i - 1; + goto st68; + break; + } + default: + break; + } + /* (c >= 0 && c <= 9) + * || (c >= 11 && c <= 33) + * || (c >= 35 && c <= 38) + * || (c >= 40 && c <= 44) + * || (c >= 46 && c <= 60) + * || (c >= 62 && c <= 90) + * || (c >= 94 && c <= 122) + * || (c == 124) + * || (c >= 126 && c <= 255) + */ + /* transfer caps from row 3 to row 2 */ + goto st60; + } /* end state */ + + goto st124_error; + +st125: { /* DFA node {78,65,45,41,1} 125 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_8; + /* capture stores */ + matched_1 = i - 1; + matched_id = 4; + if (c != -1) { + if (c == 34) { + goto st127; + } + if (c == 39) { + goto st128; + } + if (c == 92) { + goto st129; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st126; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st126: { /* DFA node {78,65} 126 */ + if (unlikely(i >= len)) { + i++; + goto st126_error; + } + + c = s[i]; + i++; + switch (c) { + case 34: { + goto st127; + break; + } + case 39: { + goto st128; + break; + } + case 92: { + goto st129; + break; + } + default: + break; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st126; + } + } /* end state */ + + goto st126_error; + +st127: { /* DFA node {78,67} 127 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_12; + /* capture stores */ + matched_1 = i - 1; + matched_id = 6; + if (c != -1) { + if (c == 39) { + goto st84; + } + if (c == 92) { + goto st85; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st83; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st128: { /* DFA node {80,65} 128 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_14; + /* capture stores */ + matched_1 = i - 1; + matched_id = 7; + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st129: { /* DFA node {75,62} 129 */ + if (unlikely(i >= len)) { + i++; + goto st129_error; + } + + c = s[i]; + i++; + if ((c >= 0 && c <= 9) || (c >= 11 && c <= 255)) { + goto st151; + } + } /* end state */ + + goto st129_error; + +st130: { /* DFA node {78,53} 130 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 39) { + goto st131; + } + if (c == 92) { + goto st133; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st130; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st131: { /* DFA node {80,53} 131 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_14; + /* capture stores */ + matched_1 = i - 1; + matched_id = 7; + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st132: { /* DFA node {78,32,53} 132 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 39) { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st131; + } + if (c == 61) { + goto st152; + } + if (c == 91) { + goto st153; + } + if (c == 92) { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st133; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 38) + || (c >= 40 && c <= 60) + || (c >= 62 && c <= 90) + || (c >= 93 && c <= 255)) + { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st130; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st133: { /* DFA node {75,53} 133 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if ((c >= 0 && c <= 9) || (c >= 11 && c <= 255)) { + goto st154; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st134: { /* DFA node {76} 134 */ + if (unlikely(i >= len)) { + i++; + goto st134_error; + } + + c = s[i]; + i++; + switch (c) { + case 39: { + goto st84; + break; + } + case 92: { + goto st85; + break; + } + default: + break; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st83; + } + } /* end state */ + + goto st134_error; + +st135: { /* DFA node {34,53} 135 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 61) { + goto st135; + } + if (c == 91) { + goto st136; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 60) + || (c >= 62 && c <= 90) + || (c >= 92 && c <= 255)) + { + /* transfer caps from row 1 to row 0 */ + caps0_10 = caps1_10; + goto st87; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st136: { /* DFA node {36,53} 136 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_6; + /* capture stores */ + matched_1 = i - 1; + matched_id = 3; + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st137: { /* DFA node {65,78,53} 137 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 34) { + goto st138; + } + if (c == 39) { + goto st139; + } + if (c == 92) { + goto st141; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st137; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st138: { /* DFA node {67,78,53} 138 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_12; + /* capture stores */ + matched_1 = i - 1; + matched_id = 6; + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st139: { /* DFA node {65,80,53} 139 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_14; + /* capture stores */ + matched_1 = i - 1; + matched_id = 7; + if (c != -1) { + if (c == 34) { + goto st58; + } + if (c == 92) { + goto st59; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st57; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st140: { /* DFA node {65,78,32,53} 140 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 3 to matched */ + matched_0 = caps3_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 34) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st138; + } + if (c == 39) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st139; + } + if (c == 61) { + goto st156; + } + if (c == 91) { + goto st157; + } + if (c == 92) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st141; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 60) + || (c >= 62 && c <= 90) + || (c >= 93 && c <= 255)) + { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st137; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st141: { /* DFA node {62,75,53} 141 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if ((c >= 0 && c <= 9) || (c >= 11 && c <= 255)) { + goto st158; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st142: { /* DFA node {63,76} 142 */ + if (unlikely(i >= len)) { + i++; + goto st142_error; + } + + c = s[i]; + i++; + switch (c) { + case 34: { + goto st105; + break; + } + case 39: { + goto st106; + break; + } + case 92: { + goto st107; + break; + } + default: + break; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st104; + } + } /* end state */ + + goto st142_error; + +st143: { /* DFA node {65,34,53} 143 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 34) { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st109; + } + if (c == 61) { + goto st143; + } + if (c == 91) { + goto st144; + } + if (c == 92) { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st111; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 60) + || (c >= 62 && c <= 90) + || (c >= 93 && c <= 255)) + { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st108; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st144: { /* DFA node {65,36,53} 144 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_6; + /* capture stores */ + matched_1 = i - 1; + matched_id = 3; + if (c != -1) { + if (c == 34) { + goto st58; + } + if (c == 92) { + goto st59; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st57; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st145: { /* DFA node {63,53} 145 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 34) { + goto st109; + } + if (c == 92) { + goto st111; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st108; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st146: { /* DFA node {78,65,53} 146 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 34) { + goto st147; + } + if (c == 39) { + goto st148; + } + if (c == 92) { + goto st150; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st146; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st147: { /* DFA node {78,67,53} 147 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_12; + /* capture stores */ + matched_1 = i - 1; + matched_id = 6; + if (c != -1) { + if (c == 39) { + goto st84; + } + if (c == 92) { + goto st85; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st83; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st148: { /* DFA node {80,65,53} 148 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 0 to matched */ + matched_0 = caps0_14; + /* capture stores */ + matched_1 = i - 1; + matched_id = 7; + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st149: { /* DFA node {78,65,32,53} 149 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 3 to matched */ + matched_0 = caps3_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 34) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st147; + } + if (c == 39) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st148; + } + if (c == 61) { + goto st159; + } + if (c == 91) { + goto st160; + } + if (c == 92) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st150; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 60) + || (c >= 62 && c <= 90) + || (c >= 93 && c <= 255)) + { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st146; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st150: { /* DFA node {75,62,53} 150 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if ((c >= 0 && c <= 9) || (c >= 11 && c <= 255)) { + goto st161; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st151: { /* DFA node {76,63} 151 */ + if (unlikely(i >= len)) { + i++; + goto st151_error; + } + + c = s[i]; + i++; + switch (c) { + case 34: { + goto st127; + break; + } + case 39: { + goto st128; + break; + } + case 92: { + goto st129; + break; + } + default: + break; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st126; + } + } /* end state */ + + goto st151_error; + +st152: { /* DFA node {78,34,53} 152 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 39) { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st131; + } + if (c == 61) { + goto st152; + } + if (c == 91) { + goto st153; + } + if (c == 92) { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st133; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 38) + || (c >= 40 && c <= 60) + || (c >= 62 && c <= 90) + || (c >= 93 && c <= 255)) + { + /* transfer caps from row 2 to row 1 */ + caps1_10 = caps2_10; + goto st130; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st153: { /* DFA node {78,36,53} 153 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_6; + /* capture stores */ + matched_1 = i - 1; + matched_id = 3; + if (c != -1) { + if (c == 39) { + goto st84; + } + if (c == 92) { + goto st85; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st83; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st154: { /* DFA node {76,53} 154 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 1 to matched */ + matched_0 = caps1_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 39) { + goto st131; + } + if (c == 92) { + goto st133; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st130; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st156: { /* DFA node {65,78,34,53} 156 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 3 to matched */ + matched_0 = caps3_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 34) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st138; + } + if (c == 39) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st139; + } + if (c == 61) { + goto st156; + } + if (c == 91) { + goto st157; + } + if (c == 92) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st141; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 60) + || (c >= 62 && c <= 90) + || (c >= 93 && c <= 255)) + { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st137; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st157: { /* DFA node {65,78,36,53} 157 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_6; + /* capture stores */ + matched_1 = i - 1; + matched_id = 3; + if (c != -1) { + if (c == 34) { + goto st105; + } + if (c == 39) { + goto st106; + } + if (c == 92) { + goto st107; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st104; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st158: { /* DFA node {63,76,53} 158 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 34) { + goto st138; + } + if (c == 39) { + goto st139; + } + if (c == 92) { + goto st141; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st137; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st159: { /* DFA node {78,65,34,53} 159 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 3 to matched */ + matched_0 = caps3_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 34) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st147; + } + if (c == 39) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st148; + } + if (c == 61) { + goto st159; + } + if (c == 91) { + goto st160; + } + if (c == 92) { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st150; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 60) + || (c >= 62 && c <= 90) + || (c >= 93 && c <= 255)) + { + /* transfer caps from row 3 to row 2 */ + caps2_10 = caps3_10; + goto st146; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st160: { /* DFA node {78,65,36,53} 160 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_6; + /* capture stores */ + matched_1 = i - 1; + matched_id = 3; + if (c != -1) { + if (c == 34) { + goto st127; + } + if (c == 39) { + goto st128; + } + if (c == 92) { + goto st129; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st126; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st161: { /* DFA node {76,63,53} 161 */ + c = i < len ? s[i] : -1; + i++; + /* transfer caps from row 2 to matched */ + matched_0 = caps2_10; + /* capture stores */ + matched_1 = i - 1; + matched_id = 5; + if (c != -1) { + if (c == 34) { + goto st147; + } + if (c == 39) { + goto st148; + } + if (c == 92) { + goto st150; + } + if ((c >= 0 && c <= 9) + || (c >= 11 && c <= 33) + || (c >= 35 && c <= 38) + || (c >= 40 && c <= 91) + || (c >= 93 && c <= 255)) + { + goto st146; + } + } + } /* end state */ + + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + +st0_error: +st1_error: +st2_error: +st3_error: +st4_error: +st5_error: +st6_error: +st9_error: +st11_error: +st12_error: +st13_error: +st14_error: +st15_error: +st18_error: +st19_error: +st21_error: +st22_error: +st23_error: +st24_error: +st28_error: +st30_error: +st35_error: +st38_error: +st39_error: +st40_error: +st41_error: +st45_error: +st47_error: +st48_error: +st49_error: +st50_error: +st51_error: +st52_error: +st55_error: +st57_error: +st59_error: +st60_error: +st63_error: +st64_error: +st65_error: +st66_error: +st71_error: +st73_error: +st74_error: +st75_error: +st76_error: +st77_error: +st78_error: +st81_error: +st83_error: +st85_error: +st92_error: +st94_error: +st95_error: +st96_error: +st97_error: +st98_error: +st99_error: +st102_error: +st104_error: +st107_error: +st112_error: +st114_error: +st116_error: +st117_error: +st118_error: +st119_error: +st120_error: +st121_error: +st124_error: +st126_error: +st129_error: +st134_error: +st142_error: +st151_error: + + if (matched_0 != -1) { + ovec[0] = matched_0; + ovec[1] = matched_1; + return matched_id; /* fallback */ + } + return NO_MATCH; +} diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_lex.h b/debian/modules/nginx-lua/src/ngx_http_lua_lex.h new file mode 100644 index 0000000..11f102c --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_lex.h @@ -0,0 +1,17 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_LEX_H_INCLUDED_ +#define _NGX_HTTP_LUA_LEX_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +int ngx_http_lua_lex(const u_char *const s, size_t len, int *const ovec); + + +#endif diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_module.c b/debian/modules/nginx-lua/src/ngx_http_lua_module.c index 6f43b23..3bf50c2 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_module.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_module.c @@ -149,6 +149,13 @@ static ngx_command_t ngx_http_lua_cmds[] = { offsetof(ngx_http_lua_loc_conf_t, log_socket_errors), NULL }, + { ngx_string("init_by_lua_block"), + NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_http_lua_init_by_lua_block, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + (void *) ngx_http_lua_init_by_inline }, + { ngx_string("init_by_lua"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, ngx_http_lua_init_by_lua, @@ -163,6 +170,13 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, (void *) ngx_http_lua_init_by_file }, + { ngx_string("init_worker_by_lua_block"), + NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_http_lua_init_worker_by_lua_block, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + (void *) ngx_http_lua_init_worker_by_inline }, + { ngx_string("init_worker_by_lua"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, ngx_http_lua_init_worker_by_lua, @@ -178,6 +192,15 @@ static ngx_command_t ngx_http_lua_cmds[] = { (void *) ngx_http_lua_init_worker_by_file }, #if defined(NDK) && NDK + /* set_by_lua $res { inline Lua code } [$arg1 [$arg2 [...]]] */ + { ngx_string("set_by_lua_block"), + NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_1MORE|NGX_CONF_BLOCK, + ngx_http_lua_set_by_lua_block, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + (void *) ngx_http_lua_filter_set_by_lua_inline }, + /* set_by_lua $res [$arg1 [$arg2 [...]]] */ { ngx_string("set_by_lua"), NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF @@ -197,7 +220,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { (void *) ngx_http_lua_filter_set_by_lua_file }, #endif - /* rewrite_by_lua */ + /* rewrite_by_lua "" */ { ngx_string("rewrite_by_lua"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_TAKE1, @@ -206,7 +229,16 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, (void *) ngx_http_lua_rewrite_handler_inline }, - /* access_by_lua */ + /* rewrite_by_lua_block { } */ + { ngx_string("rewrite_by_lua_block"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_http_lua_rewrite_by_lua_block, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + (void *) ngx_http_lua_rewrite_handler_inline }, + + /* access_by_lua "" */ { ngx_string("access_by_lua"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_TAKE1, @@ -215,7 +247,16 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, (void *) ngx_http_lua_access_handler_inline }, - /* content_by_lua */ + /* access_by_lua_block { } */ + { ngx_string("access_by_lua_block"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_http_lua_access_by_lua_block, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + (void *) ngx_http_lua_access_handler_inline }, + + /* content_by_lua "" */ { ngx_string("content_by_lua"), NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, ngx_http_lua_content_by_lua, @@ -223,6 +264,14 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, (void *) ngx_http_lua_content_handler_inline }, + /* content_by_lua_block { } */ + { ngx_string("content_by_lua_block"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_http_lua_content_by_lua_block, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + (void *) ngx_http_lua_content_handler_inline }, + /* log_by_lua */ { ngx_string("log_by_lua"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF @@ -232,6 +281,15 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, (void *) ngx_http_lua_log_handler_inline }, + /* log_by_lua_block { } */ + { ngx_string("log_by_lua_block"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_http_lua_log_by_lua_block, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + (void *) ngx_http_lua_log_handler_inline }, + { ngx_string("rewrite_by_lua_file"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_TAKE1, @@ -280,6 +338,15 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, (void *) ngx_http_lua_header_filter_inline }, + /* header_filter_by_lua_block { } */ + { ngx_string("header_filter_by_lua_block"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_http_lua_header_filter_by_lua_block, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + (void *) ngx_http_lua_header_filter_inline }, + { ngx_string("header_filter_by_lua_file"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_TAKE1, @@ -296,6 +363,15 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, (void *) ngx_http_lua_body_filter_inline }, + /* body_filter_by_lua_block { } */ + { ngx_string("body_filter_by_lua_block"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_http_lua_body_filter_by_lua_block, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + (void *) ngx_http_lua_body_filter_inline }, + { ngx_string("body_filter_by_lua_file"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_TAKE1, @@ -582,7 +658,7 @@ ngx_http_lua_lowat_check(ngx_conf_t *cf, void *post, void *data) if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"fastcgi_send_lowat\" must be less than %d " + "\"lua_send_lowat\" must be less than %d " "(sysctl net.inet.tcp.sendspace)", ngx_freebsd_net_inet_tcp_sendspace); @@ -593,7 +669,7 @@ ngx_http_lua_lowat_check(ngx_conf_t *cf, void *post, void *data) ssize_t *np = data; ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "\"fastcgi_send_lowat\" is not supported, ignored"); + "\"lua_send_lowat\" is not supported, ignored"); *np = 0; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c b/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c index 8c666f7..a72f9da 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c @@ -36,11 +36,20 @@ static int ngx_http_lua_shdict_flush_expired(lua_State *L); static int ngx_http_lua_shdict_get_keys(lua_State *L); +static ngx_inline ngx_shm_zone_t *ngx_http_lua_shdict_get_zone(lua_State *L, + int index); + + #define NGX_HTTP_LUA_SHDICT_ADD 0x0001 #define NGX_HTTP_LUA_SHDICT_REPLACE 0x0002 #define NGX_HTTP_LUA_SHDICT_SAFE_STORE 0x0004 +enum { + SHDICT_USERDATA_INDEX = 1, +}; + + ngx_int_t ngx_http_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data) { @@ -347,7 +356,10 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) lua_pushlstring(L, (char *) ctx->name.data, ctx->name.len); /* shared mt key */ + lua_createtable(L, 1 /* narr */, 0 /* nrec */); + /* table of zone[i] */ lua_pushlightuserdata(L, zone[i]); /* shared mt key ud */ + lua_rawseti(L, -2, SHDICT_USERDATA_INDEX); /* {zone[i]} */ lua_pushvalue(L, -3); /* shared mt key ud mt */ lua_setmetatable(L, -2); /* shared mt key ud */ lua_rawset(L, -4); /* shared mt */ @@ -377,6 +389,19 @@ ngx_http_lua_shdict_get_stale(lua_State *L) } +static ngx_inline ngx_shm_zone_t * +ngx_http_lua_shdict_get_zone(lua_State *L, int index) +{ + ngx_shm_zone_t *zone; + + lua_rawgeti(L, index, SHDICT_USERDATA_INDEX); + zone = lua_touserdata(L, -1); + lua_pop(L, 1); + + return zone; +} + + static int ngx_http_lua_shdict_get_helper(lua_State *L, int get_stale) { @@ -401,7 +426,11 @@ ngx_http_lua_shdict_get_helper(lua_State *L, int get_stale) "but only seen %d", n); } - zone = lua_touserdata(L, 1); + if (lua_type(L, 1) != LUA_TTABLE) { + return luaL_error(L, "bad \"zone\" argument"); + } + + zone = ngx_http_lua_shdict_get_zone(L, 1); if (zone == NULL) { return luaL_error(L, "bad \"zone\" argument"); } @@ -572,9 +601,9 @@ ngx_http_lua_shdict_flush_all(lua_State *L) return luaL_error(L, "expecting 1 argument, but seen %d", n); } - luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); + luaL_checktype(L, 1, LUA_TTABLE); - zone = lua_touserdata(L, 1); + zone = ngx_http_lua_shdict_get_zone(L, 1); if (zone == NULL) { return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); } @@ -619,9 +648,9 @@ ngx_http_lua_shdict_flush_expired(lua_State *L) return luaL_error(L, "expecting 1 or 2 argument(s), but saw %d", n); } - luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); + luaL_checktype(L, 1, LUA_TTABLE); - zone = lua_touserdata(L, 1); + zone = ngx_http_lua_shdict_get_zone(L, 1); if (zone == NULL) { return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); } @@ -700,9 +729,9 @@ ngx_http_lua_shdict_get_keys(lua_State *L) "but saw %d", n); } - luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); + luaL_checktype(L, 1, LUA_TTABLE); - zone = lua_touserdata(L, 1); + zone = ngx_http_lua_shdict_get_zone(L, 1); if (zone == NULL) { return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); } @@ -840,7 +869,11 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) "but only seen %d", n); } - zone = lua_touserdata(L, 1); + if (lua_type(L, 1) != LUA_TTABLE) { + return luaL_error(L, "bad \"zone\" argument"); + } + + zone = ngx_http_lua_shdict_get_zone(L, 1); if (zone == NULL) { return luaL_error(L, "bad \"zone\" argument"); } @@ -1013,7 +1046,7 @@ replace: } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, - "lua shared dict set: found old entry bug value size " + "lua shared dict set: found old entry but value size " "NOT matched, removing it first"); remove: @@ -1147,11 +1180,11 @@ ngx_http_lua_shdict_incr(lua_State *L) return luaL_error(L, "expecting 3 arguments, but only seen %d", n); } - if (lua_type(L, 1) != LUA_TLIGHTUSERDATA) { + if (lua_type(L, 1) != LUA_TTABLE) { return luaL_error(L, "bad \"zone\" argument"); } - zone = lua_touserdata(L, 1); + zone = ngx_http_lua_shdict_get_zone(L, 1); if (zone == NULL) { return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); } @@ -1366,7 +1399,7 @@ ngx_http_lua_find_zone(u_char *name_data, size_t name_len) if (name->len == name_len && ngx_strncmp(name->data, name_data, name_len) == 0) { - return zone; + return &zone[i]; } } @@ -1522,7 +1555,7 @@ replace: } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, - "lua shared dict set: found old entry bug value size " + "lua shared dict set: found old entry but value size " "NOT matched, removing it first"); remove: diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c index 804c854..4640f87 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c @@ -223,7 +223,7 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* {{{req socket object metatable */ lua_pushlightuserdata(L, &ngx_http_lua_req_socket_metatable_key); - lua_createtable(L, 0 /* narr */, 3 /* nrec */); + lua_createtable(L, 0 /* narr */, 4 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); lua_setfield(L, -2, "receive"); @@ -242,7 +242,7 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* {{{raw req socket object metatable */ lua_pushlightuserdata(L, &ngx_http_lua_raw_req_socket_metatable_key); - lua_createtable(L, 0 /* narr */, 4 /* nrec */); + lua_createtable(L, 0 /* narr */, 5 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); lua_setfield(L, -2, "receive"); @@ -4084,6 +4084,12 @@ ngx_http_lua_req_socket(lua_State *L) } #endif +#if (NGX_HTTP_V2) + if (r->stream) { + return luaL_error(L, "http v2 not supported yet"); + } +#endif + #if nginx_version >= 1003009 if (!raw && r->headers_in.chunked) { lua_pushnil(L); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c b/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c index 6c846f5..23cc69a 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c @@ -82,7 +82,7 @@ ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L) /* udp socket object metatable */ lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key); - lua_createtable(L, 0 /* narr */, 4 /* nrec */); + lua_createtable(L, 0 /* narr */, 6 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_udp_setpeername); lua_setfield(L, -2, "setpeername"); /* ngx socket mt */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_subrequest.c b/debian/modules/nginx-lua/src/ngx_http_lua_subrequest.c index 87fc74c..4ac801b 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_subrequest.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_subrequest.c @@ -116,7 +116,7 @@ static int ngx_http_lua_ngx_location_capture_multi(lua_State *L) { ngx_http_request_t *r; - ngx_http_request_t *sr; /* subrequest object */ + ngx_http_request_t *sr = NULL; /* subrequest object */ ngx_http_post_subrequest_t *psr; ngx_http_lua_ctx_t *sr_ctx; ngx_http_lua_ctx_t *ctx; @@ -1004,7 +1004,7 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) rc = NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + if (rc >= 100) { pr_coctx->sr_statuses[ctx->index] = rc; } } @@ -1489,6 +1489,10 @@ ngx_http_lua_subrequest(ngx_http_request_t *r, sr->spdy_stream = r->spdy_stream; #endif +#if (NGX_HTTP_V2) + sr->stream = r->stream; +#endif + #ifdef HAVE_ALLOW_REQUEST_BODY_UPDATING_PATCH sr->content_length_n = -1; #endif diff --git a/debian/modules/nginx-lua/t/000--init.t b/debian/modules/nginx-lua/t/000--init.t index bb57e81..364334f 100644 --- a/debian/modules/nginx-lua/t/000--init.t +++ b/debian/modules/nginx-lua/t/000--init.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(1); diff --git a/debian/modules/nginx-lua/t/000-sanity.t b/debian/modules/nginx-lua/t/000-sanity.t index e390bf6..3f66752 100644 --- a/debian/modules/nginx-lua/t/000-sanity.t +++ b/debian/modules/nginx-lua/t/000-sanity.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/001-set.t b/debian/modules/nginx-lua/t/001-set.t index 73bc3a7..2295a2d 100644 --- a/debian/modules/nginx-lua/t/001-set.t +++ b/debian/modules/nginx-lua/t/001-set.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/002-content.t b/debian/modules/nginx-lua/t/002-content.t index 706083a..e6cb62d 100644 --- a/debian/modules/nginx-lua/t/002-content.t +++ b/debian/modules/nginx-lua/t/002-content.t @@ -1,5 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; + use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/003-errors.t b/debian/modules/nginx-lua/t/003-errors.t index 1b92266..764300a 100644 --- a/debian/modules/nginx-lua/t/003-errors.t +++ b/debian/modules/nginx-lua/t/003-errors.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(1); diff --git a/debian/modules/nginx-lua/t/004-require.t b/debian/modules/nginx-lua/t/004-require.t index 64b61be..3250b2f 100644 --- a/debian/modules/nginx-lua/t/004-require.t +++ b/debian/modules/nginx-lua/t/004-require.t @@ -1,5 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; + use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/005-exit.t b/debian/modules/nginx-lua/t/005-exit.t index 3ba5c58..781531f 100644 --- a/debian/modules/nginx-lua/t/005-exit.t +++ b/debian/modules/nginx-lua/t/005-exit.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #repeat_each(20000); diff --git a/debian/modules/nginx-lua/t/006-escape.t b/debian/modules/nginx-lua/t/006-escape.t index 5b801da..7b26bba 100644 --- a/debian/modules/nginx-lua/t/006-escape.t +++ b/debian/modules/nginx-lua/t/006-escape.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/007-md5.t b/debian/modules/nginx-lua/t/007-md5.t index 6d851e7..501e3af 100644 --- a/debian/modules/nginx-lua/t/007-md5.t +++ b/debian/modules/nginx-lua/t/007-md5.t @@ -1,5 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; + use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/008-today.t b/debian/modules/nginx-lua/t/008-today.t index a8199df..02169c8 100644 --- a/debian/modules/nginx-lua/t/008-today.t +++ b/debian/modules/nginx-lua/t/008-today.t @@ -1,5 +1,5 @@ # vim:set ft=perl ts=4 sw=4 et fdm=marker: -use lib 'lib'; + use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/009-log.t b/debian/modules/nginx-lua/t/009-log.t index 70202ee..e06c799 100644 --- a/debian/modules/nginx-lua/t/009-log.t +++ b/debian/modules/nginx-lua/t/009-log.t @@ -1,5 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; + use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/010-request_body.t b/debian/modules/nginx-lua/t/010-request_body.t index 65f7ccb..d200495 100644 --- a/debian/modules/nginx-lua/t/010-request_body.t +++ b/debian/modules/nginx-lua/t/010-request_body.t @@ -1,5 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; + use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/011-md5_bin.t b/debian/modules/nginx-lua/t/011-md5_bin.t index 50e0762..48b8c61 100644 --- a/debian/modules/nginx-lua/t/011-md5_bin.t +++ b/debian/modules/nginx-lua/t/011-md5_bin.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/012-now.t b/debian/modules/nginx-lua/t/012-now.t index ae14a12..abcb735 100644 --- a/debian/modules/nginx-lua/t/012-now.t +++ b/debian/modules/nginx-lua/t/012-now.t @@ -1,5 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; + use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/013-base64.t b/debian/modules/nginx-lua/t/013-base64.t index 95db9a1..6903218 100644 --- a/debian/modules/nginx-lua/t/013-base64.t +++ b/debian/modules/nginx-lua/t/013-base64.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/014-bugs.t b/debian/modules/nginx-lua/t/014-bugs.t index 6461783..44337e3 100644 --- a/debian/modules/nginx-lua/t/014-bugs.t +++ b/debian/modules/nginx-lua/t/014-bugs.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/015-status.t b/debian/modules/nginx-lua/t/015-status.t index ba14e70..2e026f1 100644 --- a/debian/modules/nginx-lua/t/015-status.t +++ b/debian/modules/nginx-lua/t/015-status.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/016-resp-header.t b/debian/modules/nginx-lua/t/016-resp-header.t index 38765dc..e23b48f 100644 --- a/debian/modules/nginx-lua/t/016-resp-header.t +++ b/debian/modules/nginx-lua/t/016-resp-header.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); @@ -9,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 34); +plan tests => repeat_each() * (blocks() * 3 + 38); #no_diff(); no_long_string(); @@ -1404,3 +1403,46 @@ Location: http://test.com/foo/bar --- no_error_log [error] + + +=== TEST 67: ngx.header["Content-Type"] with ngx_gzip +--- config + gzip on; + gzip_min_length 1; + location = /test2 { + content_by_lua ' + ngx.header["Content-Type"] = "text/html; charset=utf-8" + ngx.say("test") + '; + } +--- request +GET /test2 +--- more_headers +Accept-Encoding: gzip +--- response_headers +Content-Encoding: gzip +Content-Type: text/html; charset=utf-8 +--- response_body_like chomp +[^[:ascii:]]+ +--- no_error_log +[error] + + + +=== TEST 68: ngx.header["Content-Type"] with "; blah" +--- config + location = /test2 { + content_by_lua ' + ngx.header["Content-Type"] = "; blah" + ngx.say("test") + '; + } +--- request +GET /test2 +--- response_headers +!Content-Encoding +Content-Type: ; blah +--- response_body +test +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/017-exec.t b/debian/modules/nginx-lua/t/017-exec.t index 94defa2..4c7a918 100644 --- a/debian/modules/nginx-lua/t/017-exec.t +++ b/debian/modules/nginx-lua/t/017-exec.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/018-ndk.t b/debian/modules/nginx-lua/t/018-ndk.t index 677e908..d68306b 100644 --- a/debian/modules/nginx-lua/t/018-ndk.t +++ b/debian/modules/nginx-lua/t/018-ndk.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/019-const.t b/debian/modules/nginx-lua/t/019-const.t index 9ac0ce9..fe79bfb 100644 --- a/debian/modules/nginx-lua/t/019-const.t +++ b/debian/modules/nginx-lua/t/019-const.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/020-subrequest.t b/debian/modules/nginx-lua/t/020-subrequest.t index e3357be..21e728d 100644 --- a/debian/modules/nginx-lua/t/020-subrequest.t +++ b/debian/modules/nginx-lua/t/020-subrequest.t @@ -1,5 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; + use Test::Nginx::Socket::Lua; #master_on(); @@ -8,6 +8,7 @@ use Test::Nginx::Socket::Lua; #log_level('warn'); #master_process_enabled(1); +no_root_location; repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 22); @@ -2797,3 +2798,76 @@ image header filter --- no_error_log [error] + + +=== TEST 75: WebDAV + MOVE +--- config + location = /t { + content_by_lua_block { + local file1 = "/file1.txt" + local file2 = "/file2.txt" + ngx.req.set_header( "Destination", file2 ) + local res = ngx.location.capture( + file1, { method = ngx.HTTP_MOVE } + ) + + ngx.say( + "MOVE ", file1, " -> ", file2, + ", response status: ", res.status + ) + } + } + + location / { + dav_methods MOVE; + } + +--- user_files +>>> file1.txt +hello, world! + +--- request +GET /t + +--- response_body +MOVE /file1.txt -> /file2.txt, response status: 204 + +--- no_error_log +[error] +--- error_code: 200 + + + +=== TEST 76: WebDAV + DELETE +--- config + location = /t { + content_by_lua_block { + local file = "/file.txt" + local res = ngx.location.capture( + file, { method = ngx.HTTP_DELETE } + ) + + ngx.say( + "DELETE ", file, + ", response status: ", res.status + ) + } + } + + location / { + dav_methods DELETE; + } + +--- user_files +>>> file.txt +hello, world! + +--- request +GET /t + +--- response_body +DELETE /file.txt, response status: 204 + +--- no_error_log +[error] +--- error_code: 200 diff --git a/debian/modules/nginx-lua/t/021-cookie-time.t b/debian/modules/nginx-lua/t/021-cookie-time.t index fb24d30..c00bbea 100644 --- a/debian/modules/nginx-lua/t/021-cookie-time.t +++ b/debian/modules/nginx-lua/t/021-cookie-time.t @@ -1,5 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; + use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/022-redirect.t b/debian/modules/nginx-lua/t/022-redirect.t index 1f874ec..0e2a107 100644 --- a/debian/modules/nginx-lua/t/022-redirect.t +++ b/debian/modules/nginx-lua/t/022-redirect.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/023-rewrite/client-abort.t b/debian/modules/nginx-lua/t/023-rewrite/client-abort.t index 3b3f242..e970802 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/client-abort.t +++ b/debian/modules/nginx-lua/t/023-rewrite/client-abort.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/023-rewrite/exec.t b/debian/modules/nginx-lua/t/023-rewrite/exec.t index 1186c14..a063b5b 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/exec.t +++ b/debian/modules/nginx-lua/t/023-rewrite/exec.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/023-rewrite/exit.t b/debian/modules/nginx-lua/t/023-rewrite/exit.t index 280602b..9d292f7 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/exit.t +++ b/debian/modules/nginx-lua/t/023-rewrite/exit.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #repeat_each(20000); diff --git a/debian/modules/nginx-lua/t/023-rewrite/mixed.t b/debian/modules/nginx-lua/t/023-rewrite/mixed.t index 17e38c7..1156567 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/mixed.t +++ b/debian/modules/nginx-lua/t/023-rewrite/mixed.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/023-rewrite/multi-capture.t b/debian/modules/nginx-lua/t/023-rewrite/multi-capture.t index 7f1a923..44629b0 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/multi-capture.t +++ b/debian/modules/nginx-lua/t/023-rewrite/multi-capture.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(10); diff --git a/debian/modules/nginx-lua/t/023-rewrite/on-abort.t b/debian/modules/nginx-lua/t/023-rewrite/on-abort.t index f5a5ef8..aca2ab6 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/on-abort.t +++ b/debian/modules/nginx-lua/t/023-rewrite/on-abort.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/023-rewrite/redirect.t b/debian/modules/nginx-lua/t/023-rewrite/redirect.t index e4a46cc..8843f1a 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/redirect.t +++ b/debian/modules/nginx-lua/t/023-rewrite/redirect.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/023-rewrite/req-body.t b/debian/modules/nginx-lua/t/023-rewrite/req-body.t index c085c0f..2f42e0a 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/req-body.t +++ b/debian/modules/nginx-lua/t/023-rewrite/req-body.t @@ -1,5 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; + use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/023-rewrite/req-socket.t b/debian/modules/nginx-lua/t/023-rewrite/req-socket.t index 59dac5d..34aedaa 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/req-socket.t +++ b/debian/modules/nginx-lua/t/023-rewrite/req-socket.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/023-rewrite/request_body.t b/debian/modules/nginx-lua/t/023-rewrite/request_body.t index db87e5f..665d6de 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/request_body.t +++ b/debian/modules/nginx-lua/t/023-rewrite/request_body.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/023-rewrite/sanity.t b/debian/modules/nginx-lua/t/023-rewrite/sanity.t index f213f53..20b00e2 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/sanity.t +++ b/debian/modules/nginx-lua/t/023-rewrite/sanity.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/023-rewrite/sleep.t b/debian/modules/nginx-lua/t/023-rewrite/sleep.t index e8d88f0..1719784 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/sleep.t +++ b/debian/modules/nginx-lua/t/023-rewrite/sleep.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/023-rewrite/socket-keepalive.t b/debian/modules/nginx-lua/t/023-rewrite/socket-keepalive.t index 85a9b53..50de0b3 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/socket-keepalive.t +++ b/debian/modules/nginx-lua/t/023-rewrite/socket-keepalive.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/023-rewrite/subrequest.t b/debian/modules/nginx-lua/t/023-rewrite/subrequest.t index 12321e6..3c206a8 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/subrequest.t +++ b/debian/modules/nginx-lua/t/023-rewrite/subrequest.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket-timeout.t b/debian/modules/nginx-lua/t/023-rewrite/tcp-socket-timeout.t index 129f711..79cd0b9 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket-timeout.t +++ b/debian/modules/nginx-lua/t/023-rewrite/tcp-socket-timeout.t @@ -20,7 +20,6 @@ BEGIN { $ENV{MOCKEAGAIN_WRITE_TIMEOUT_PATTERN} = 'get helloworld'; } -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t b/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t index fdac782..9b39ba1 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t +++ b/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/023-rewrite/unix-socket.t b/debian/modules/nginx-lua/t/023-rewrite/unix-socket.t index d19ba8c..098dd67 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/unix-socket.t +++ b/debian/modules/nginx-lua/t/023-rewrite/unix-socket.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-exec.t b/debian/modules/nginx-lua/t/023-rewrite/uthread-exec.t index d929670..2bea7e7 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/uthread-exec.t +++ b/debian/modules/nginx-lua/t/023-rewrite/uthread-exec.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-exit.t b/debian/modules/nginx-lua/t/023-rewrite/uthread-exit.t index f17c9c3..266d5ab 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/uthread-exit.t +++ b/debian/modules/nginx-lua/t/023-rewrite/uthread-exit.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t b/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t index 6d4f0a1..0f125e0 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t +++ b/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t b/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t index b65e748..58af7d0 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t +++ b/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/024-access/auth.t b/debian/modules/nginx-lua/t/024-access/auth.t index 4b7927c..5da09cb 100644 --- a/debian/modules/nginx-lua/t/024-access/auth.t +++ b/debian/modules/nginx-lua/t/024-access/auth.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/024-access/client-abort.t b/debian/modules/nginx-lua/t/024-access/client-abort.t index 528838e..a94f822 100644 --- a/debian/modules/nginx-lua/t/024-access/client-abort.t +++ b/debian/modules/nginx-lua/t/024-access/client-abort.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/024-access/exec.t b/debian/modules/nginx-lua/t/024-access/exec.t index f6e3e76..8bf638f 100644 --- a/debian/modules/nginx-lua/t/024-access/exec.t +++ b/debian/modules/nginx-lua/t/024-access/exec.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/024-access/exit.t b/debian/modules/nginx-lua/t/024-access/exit.t index 39d39ea..8470ab9 100644 --- a/debian/modules/nginx-lua/t/024-access/exit.t +++ b/debian/modules/nginx-lua/t/024-access/exit.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #repeat_each(20000); diff --git a/debian/modules/nginx-lua/t/024-access/mixed.t b/debian/modules/nginx-lua/t/024-access/mixed.t index 1644c6c..d801216 100644 --- a/debian/modules/nginx-lua/t/024-access/mixed.t +++ b/debian/modules/nginx-lua/t/024-access/mixed.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/024-access/multi-capture.t b/debian/modules/nginx-lua/t/024-access/multi-capture.t index caa6755..368d401 100644 --- a/debian/modules/nginx-lua/t/024-access/multi-capture.t +++ b/debian/modules/nginx-lua/t/024-access/multi-capture.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(10); diff --git a/debian/modules/nginx-lua/t/024-access/on-abort.t b/debian/modules/nginx-lua/t/024-access/on-abort.t index 638c644..0c17b55 100644 --- a/debian/modules/nginx-lua/t/024-access/on-abort.t +++ b/debian/modules/nginx-lua/t/024-access/on-abort.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/024-access/redirect.t b/debian/modules/nginx-lua/t/024-access/redirect.t index b8c3519..c7ce512 100644 --- a/debian/modules/nginx-lua/t/024-access/redirect.t +++ b/debian/modules/nginx-lua/t/024-access/redirect.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/024-access/req-body.t b/debian/modules/nginx-lua/t/024-access/req-body.t index 4d8eb78..fd33aff 100644 --- a/debian/modules/nginx-lua/t/024-access/req-body.t +++ b/debian/modules/nginx-lua/t/024-access/req-body.t @@ -1,5 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; + use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/024-access/request_body.t b/debian/modules/nginx-lua/t/024-access/request_body.t index 0e83801..e4ac161 100644 --- a/debian/modules/nginx-lua/t/024-access/request_body.t +++ b/debian/modules/nginx-lua/t/024-access/request_body.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/024-access/sanity.t b/debian/modules/nginx-lua/t/024-access/sanity.t index f5b9f70..de63a68 100644 --- a/debian/modules/nginx-lua/t/024-access/sanity.t +++ b/debian/modules/nginx-lua/t/024-access/sanity.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/024-access/satisfy.t b/debian/modules/nginx-lua/t/024-access/satisfy.t index 55724a6..10d3ece 100644 --- a/debian/modules/nginx-lua/t/024-access/satisfy.t +++ b/debian/modules/nginx-lua/t/024-access/satisfy.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/024-access/sleep.t b/debian/modules/nginx-lua/t/024-access/sleep.t index cbf2362..2eb0822 100644 --- a/debian/modules/nginx-lua/t/024-access/sleep.t +++ b/debian/modules/nginx-lua/t/024-access/sleep.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/024-access/subrequest.t b/debian/modules/nginx-lua/t/024-access/subrequest.t index 0347d51..00c56b8 100644 --- a/debian/modules/nginx-lua/t/024-access/subrequest.t +++ b/debian/modules/nginx-lua/t/024-access/subrequest.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/024-access/uthread-exec.t b/debian/modules/nginx-lua/t/024-access/uthread-exec.t index b8d01e0..d7c2321 100644 --- a/debian/modules/nginx-lua/t/024-access/uthread-exec.t +++ b/debian/modules/nginx-lua/t/024-access/uthread-exec.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/024-access/uthread-exit.t b/debian/modules/nginx-lua/t/024-access/uthread-exit.t index a843d3b..c08fefc 100644 --- a/debian/modules/nginx-lua/t/024-access/uthread-exit.t +++ b/debian/modules/nginx-lua/t/024-access/uthread-exit.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/024-access/uthread-redirect.t b/debian/modules/nginx-lua/t/024-access/uthread-redirect.t index 620fcc0..8b030ac 100644 --- a/debian/modules/nginx-lua/t/024-access/uthread-redirect.t +++ b/debian/modules/nginx-lua/t/024-access/uthread-redirect.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/024-access/uthread-spawn.t b/debian/modules/nginx-lua/t/024-access/uthread-spawn.t index 4f52019..415e4c0 100644 --- a/debian/modules/nginx-lua/t/024-access/uthread-spawn.t +++ b/debian/modules/nginx-lua/t/024-access/uthread-spawn.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/025-codecache.t b/debian/modules/nginx-lua/t/025-codecache.t index f708286..f33452a 100644 --- a/debian/modules/nginx-lua/t/025-codecache.t +++ b/debian/modules/nginx-lua/t/025-codecache.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/026-mysql.t b/debian/modules/nginx-lua/t/026-mysql.t index 72622c9..e14ffb6 100644 --- a/debian/modules/nginx-lua/t/026-mysql.t +++ b/debian/modules/nginx-lua/t/026-mysql.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/027-multi-capture.t b/debian/modules/nginx-lua/t/027-multi-capture.t index 06873c1..3588c69 100644 --- a/debian/modules/nginx-lua/t/027-multi-capture.t +++ b/debian/modules/nginx-lua/t/027-multi-capture.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(10); diff --git a/debian/modules/nginx-lua/t/028-req-header.t b/debian/modules/nginx-lua/t/028-req-header.t index 1d18c39..77c0b06 100644 --- a/debian/modules/nginx-lua/t/028-req-header.t +++ b/debian/modules/nginx-lua/t/028-req-header.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); @@ -9,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (2 * blocks() + 21); +plan tests => repeat_each() * (2 * blocks() + 26); #no_diff(); #no_long_string(); @@ -1440,3 +1439,96 @@ AAA: 678 --- no_error_log [error] + + +=== TEST 46: clear If-Match req header +--- config + location /t { + content_by_lua ' + ngx.req.clear_header("if-match") + if not ngx.send_headers() then + return + end + ngx.say("test") + '; + } +--- request +GET /t +--- more_headers +If-Match: abc +--- response_body +test +--- no_error_log +[error] + + + +=== TEST 47: clear If-Unmodified-Since req header +--- config + location /t { + content_by_lua ' + ngx.req.clear_header("if-unmodified-since") + ngx.header["Last-Modified"] = "Tue, 30 Jun 2011 12:16:36 GMT" + if not ngx.send_headers() then + return + end + ngx.say("test") + '; + } +--- request +GET /t +--- more_headers +If-Unmodified-Since: Tue, 28 Jun 2011 12:16:36 GMT +--- response_body +test +--- no_error_log +[error] + + + +=== TEST 48: clear If-None-Match req header +--- config + location /t { + content_by_lua ' + ngx.req.clear_header("if-none-match") + -- ngx.header["etags"] = "abc" + if not ngx.send_headers() then + return + end + ngx.say("test") + '; + } +--- request +GET /t +--- more_headers +If-None-Match: * +--- response_body +test +--- no_error_log +[error] + + + +=== TEST 49: set the Destination request header for WebDav +--- config + location = /a.txt { + rewrite_by_lua_block { + ngx.req.set_header("Destination", "/b.txt") + } + dav_methods MOVE; + dav_access all:rw; + root html; + } + +--- user_files +>>> a.txt +hello, world! + +--- request +MOVE /a.txt + +--- response_body +--- no_error_log +client sent no "Destination" header +[error] +--- error_code: 204 diff --git a/debian/modules/nginx-lua/t/029-http-time.t b/debian/modules/nginx-lua/t/029-http-time.t index 8ac1725..71a7758 100644 --- a/debian/modules/nginx-lua/t/029-http-time.t +++ b/debian/modules/nginx-lua/t/029-http-time.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/030-uri-args.t b/debian/modules/nginx-lua/t/030-uri-args.t index 83b3842..2f18ba7 100644 --- a/debian/modules/nginx-lua/t/030-uri-args.t +++ b/debian/modules/nginx-lua/t/030-uri-args.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/031-post-args.t b/debian/modules/nginx-lua/t/031-post-args.t index 209af69..29d6057 100644 --- a/debian/modules/nginx-lua/t/031-post-args.t +++ b/debian/modules/nginx-lua/t/031-post-args.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/032-iolist.t b/debian/modules/nginx-lua/t/032-iolist.t index 12c9635..ddf3d7f 100644 --- a/debian/modules/nginx-lua/t/032-iolist.t +++ b/debian/modules/nginx-lua/t/032-iolist.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/033-ctx.t b/debian/modules/nginx-lua/t/033-ctx.t index 8301bac..eefb216 100644 --- a/debian/modules/nginx-lua/t/033-ctx.t +++ b/debian/modules/nginx-lua/t/033-ctx.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/035-gmatch.t b/debian/modules/nginx-lua/t/035-gmatch.t index b6e3110..04a06ed 100644 --- a/debian/modules/nginx-lua/t/035-gmatch.t +++ b/debian/modules/nginx-lua/t/035-gmatch.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/036-sub.t b/debian/modules/nginx-lua/t/036-sub.t index ad8638c..88dc8d6 100644 --- a/debian/modules/nginx-lua/t/036-sub.t +++ b/debian/modules/nginx-lua/t/036-sub.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/037-gsub.t b/debian/modules/nginx-lua/t/037-gsub.t index fb4a706..b3bb04e 100644 --- a/debian/modules/nginx-lua/t/037-gsub.t +++ b/debian/modules/nginx-lua/t/037-gsub.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/038-match-o.t b/debian/modules/nginx-lua/t/038-match-o.t index 7da2c72..4ccd73a 100644 --- a/debian/modules/nginx-lua/t/038-match-o.t +++ b/debian/modules/nginx-lua/t/038-match-o.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/039-sub-o.t b/debian/modules/nginx-lua/t/039-sub-o.t index 05fc0ba..a861b6c 100644 --- a/debian/modules/nginx-lua/t/039-sub-o.t +++ b/debian/modules/nginx-lua/t/039-sub-o.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/040-gsub-o.t b/debian/modules/nginx-lua/t/040-gsub-o.t index a371526..90619b0 100644 --- a/debian/modules/nginx-lua/t/040-gsub-o.t +++ b/debian/modules/nginx-lua/t/040-gsub-o.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/041-header-filter.t b/debian/modules/nginx-lua/t/041-header-filter.t index c3d495c..553ee43 100644 --- a/debian/modules/nginx-lua/t/041-header-filter.t +++ b/debian/modules/nginx-lua/t/041-header-filter.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/042-crc32.t b/debian/modules/nginx-lua/t/042-crc32.t index 1725435..86d9201 100644 --- a/debian/modules/nginx-lua/t/042-crc32.t +++ b/debian/modules/nginx-lua/t/042-crc32.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/043-shdict.t b/debian/modules/nginx-lua/t/043-shdict.t index 22ab0d8..4c4d121 100644 --- a/debian/modules/nginx-lua/t/043-shdict.t +++ b/debian/modules/nginx-lua/t/043-shdict.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); @@ -8,7 +7,7 @@ use Test::Nginx::Socket::Lua; #repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 17); +plan tests => repeat_each() * (blocks() * 3 + 18); #no_diff(); no_long_string(); @@ -2298,3 +2297,135 @@ foo = nil --- no_error_log [error] + + +=== TEST 86: the lightuserdata ngx.null has no methods of shared dicts. +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua ' + local lightuserdata = ngx.null + lightuserdata:set("foo", 1) + '; + } +--- request +GET /test +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- grep_error_log chop +attempt to index local 'lightuserdata' (a userdata value) +--- grep_error_log_out +attempt to index local 'lightuserdata' (a userdata value) +--- error_log +[error] +--- no_error_log +bad "zone" argument + + + +=== TEST 87: set bad zone table +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua ' + local dogs = ngx.shared.dogs + dogs.set({1}, "foo", 1) + '; + } +--- request +GET /test +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log +bad "zone" argument + + + +=== TEST 88: get bad zone table +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua ' + local dogs = ngx.shared.dogs + dogs.get({1}, "foo") + '; + } +--- request +GET /test +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log +bad "zone" argument + + + +=== TEST 89: incr bad zone table +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua ' + local dogs = ngx.shared.dogs + dogs.incr({1}, "foo", 32) + '; + } +--- request +GET /test +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log + + + +=== TEST 90: check the type of the shdict object +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua ' + ngx.say("type: ", type(ngx.shared.dogs)) + '; + } +--- request +GET /test +--- response_body +type: table +--- no_error_log +[error] + + + +=== TEST 91: dogs, cat mixing +--- http_config + lua_shared_dict dogs 1m; + lua_shared_dict cats 1m; +--- config + location = /test { + content_by_lua ' + local dogs = ngx.shared.dogs + dogs:set("foo", 32) + dogs:set("bah", 10502) + local val = dogs:get("foo") + ngx.say(val, " ", type(val)) + val = dogs:get("bah") + ngx.say(val, " ", type(val)) + + local cats = ngx.shared.cats + val = cats:get("foo") + ngx.say(val or "nil") + val = cats:get("bah") + ngx.say(val or "nil") + '; + } +--- request +GET /test +--- response_body +32 number +10502 number +nil +nil +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/044-req-body.t b/debian/modules/nginx-lua/t/044-req-body.t index 0246265..f0d0a4d 100644 --- a/debian/modules/nginx-lua/t/044-req-body.t +++ b/debian/modules/nginx-lua/t/044-req-body.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/045-ngx-var.t b/debian/modules/nginx-lua/t/045-ngx-var.t index a909040..8f2dcb3 100644 --- a/debian/modules/nginx-lua/t/045-ngx-var.t +++ b/debian/modules/nginx-lua/t/045-ngx-var.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/046-hmac.t b/debian/modules/nginx-lua/t/046-hmac.t index d8280e4..686b479 100644 --- a/debian/modules/nginx-lua/t/046-hmac.t +++ b/debian/modules/nginx-lua/t/046-hmac.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/047-match-jit.t b/debian/modules/nginx-lua/t/047-match-jit.t index ef5970b..077ebb6 100644 --- a/debian/modules/nginx-lua/t/047-match-jit.t +++ b/debian/modules/nginx-lua/t/047-match-jit.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/048-match-dfa.t b/debian/modules/nginx-lua/t/048-match-dfa.t index 6860532..8350a73 100644 --- a/debian/modules/nginx-lua/t/048-match-dfa.t +++ b/debian/modules/nginx-lua/t/048-match-dfa.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/049-gmatch-jit.t b/debian/modules/nginx-lua/t/049-gmatch-jit.t index 51e268a..614c440 100644 --- a/debian/modules/nginx-lua/t/049-gmatch-jit.t +++ b/debian/modules/nginx-lua/t/049-gmatch-jit.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/050-gmatch-dfa.t b/debian/modules/nginx-lua/t/050-gmatch-dfa.t index 15295ba..c6b87e1 100644 --- a/debian/modules/nginx-lua/t/050-gmatch-dfa.t +++ b/debian/modules/nginx-lua/t/050-gmatch-dfa.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/051-sub-jit.t b/debian/modules/nginx-lua/t/051-sub-jit.t index 038fa83..789e897 100644 --- a/debian/modules/nginx-lua/t/051-sub-jit.t +++ b/debian/modules/nginx-lua/t/051-sub-jit.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/052-sub-dfa.t b/debian/modules/nginx-lua/t/052-sub-dfa.t index 93c29b6..f4de4d2 100644 --- a/debian/modules/nginx-lua/t/052-sub-dfa.t +++ b/debian/modules/nginx-lua/t/052-sub-dfa.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/053-gsub-jit.t b/debian/modules/nginx-lua/t/053-gsub-jit.t index e2c2e22..3a2a1aa 100644 --- a/debian/modules/nginx-lua/t/053-gsub-jit.t +++ b/debian/modules/nginx-lua/t/053-gsub-jit.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/054-gsub-dfa.t b/debian/modules/nginx-lua/t/054-gsub-dfa.t index 912fe3a..9c471a9 100644 --- a/debian/modules/nginx-lua/t/054-gsub-dfa.t +++ b/debian/modules/nginx-lua/t/054-gsub-dfa.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/055-subreq-vars.t b/debian/modules/nginx-lua/t/055-subreq-vars.t index e2b0658..2fc6960 100644 --- a/debian/modules/nginx-lua/t/055-subreq-vars.t +++ b/debian/modules/nginx-lua/t/055-subreq-vars.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/056-flush.t b/debian/modules/nginx-lua/t/056-flush.t index 8b8ee0d..260e39a 100644 --- a/debian/modules/nginx-lua/t/056-flush.t +++ b/debian/modules/nginx-lua/t/056-flush.t @@ -4,7 +4,6 @@ BEGIN { $ENV{TEST_NGINX_POSTPONE_OUTPUT} = 1; } -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/057-flush-timeout.t b/debian/modules/nginx-lua/t/057-flush-timeout.t index 7420e8e..d6e0f86 100644 --- a/debian/modules/nginx-lua/t/057-flush-timeout.t +++ b/debian/modules/nginx-lua/t/057-flush-timeout.t @@ -21,7 +21,6 @@ BEGIN { $ENV{TEST_NGINX_POSTPONE_OUTPUT} = 1; } -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/058-tcp-socket.t b/debian/modules/nginx-lua/t/058-tcp-socket.t index a4e6a56..145a07b 100644 --- a/debian/modules/nginx-lua/t/058-tcp-socket.t +++ b/debian/modules/nginx-lua/t/058-tcp-socket.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/059-unix-socket.t b/debian/modules/nginx-lua/t/059-unix-socket.t index 3c5f93e..9e9e6df 100644 --- a/debian/modules/nginx-lua/t/059-unix-socket.t +++ b/debian/modules/nginx-lua/t/059-unix-socket.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/060-lua-memcached.t b/debian/modules/nginx-lua/t/060-lua-memcached.t index d7fc68f..e1ebb92 100644 --- a/debian/modules/nginx-lua/t/060-lua-memcached.t +++ b/debian/modules/nginx-lua/t/060-lua-memcached.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/061-lua-redis.t b/debian/modules/nginx-lua/t/061-lua-redis.t index abde988..d7b1876 100644 --- a/debian/modules/nginx-lua/t/061-lua-redis.t +++ b/debian/modules/nginx-lua/t/061-lua-redis.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/062-count.t b/debian/modules/nginx-lua/t/062-count.t index 38c4faf..120d131 100644 --- a/debian/modules/nginx-lua/t/062-count.t +++ b/debian/modules/nginx-lua/t/062-count.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); @@ -240,20 +239,25 @@ n = 10 -=== TEST 11: entries under ngx._reqsock_meta ---- SKIP +=== TEST 11: entries under the metatable of req sockets --- config location = /test { content_by_lua ' local n = 0 - for k, v in pairs(ngx._reqsock_meta) do + local sock, err = ngx.req.socket() + if not sock then + ngx.say("failed to get the request socket: ", err) + end + + for k, v in pairs(getmetatable(sock)) do n = n + 1 end ngx.say("n = ", n) '; } --- request -GET /test +POST /test +hello world --- response_body n = 4 --- no_error_log @@ -438,3 +442,55 @@ worker: 2 --- no_error_log [error] + + +=== TEST 20: entries under the metatable of udp sockets +--- config + location = /test { + content_by_lua ' + local n = 0 + local sock = ngx.socket.udp() + for k, v in pairs(getmetatable(sock)) do + n = n + 1 + end + ngx.say("n = ", n) + '; + } +--- request +GET /test +--- response_body +n = 6 +--- no_error_log +[error] + + + +=== TEST 21: entries under the metatable of req raw sockets +--- config + location = /test { + content_by_lua ' + local n = 0 + ngx.req.read_body() + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) + return + end + + for k, v in pairs(getmetatable(sock)) do + n = n + 1 + end + + local ok, err = sock:send("HTTP/1.1 200 OK\\r\\nContent-Length: 6\\r\\n\\r\\nn = "..n.."\\n") + if not ok then + ngx.log(ngx.ERR, "failed to send: ", err) + return + end + '; + } +--- request +GET /test +--- response_body +n = 5 +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/063-abort.t b/debian/modules/nginx-lua/t/063-abort.t index 2019639..c112ee1 100644 --- a/debian/modules/nginx-lua/t/063-abort.t +++ b/debian/modules/nginx-lua/t/063-abort.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/064-pcall.t b/debian/modules/nginx-lua/t/064-pcall.t index cfa344d..cf90a07 100644 --- a/debian/modules/nginx-lua/t/064-pcall.t +++ b/debian/modules/nginx-lua/t/064-pcall.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/065-tcp-socket-timeout.t b/debian/modules/nginx-lua/t/065-tcp-socket-timeout.t index b330019..ec79891 100644 --- a/debian/modules/nginx-lua/t/065-tcp-socket-timeout.t +++ b/debian/modules/nginx-lua/t/065-tcp-socket-timeout.t @@ -20,7 +20,6 @@ BEGIN { $ENV{MOCKEAGAIN_WRITE_TIMEOUT_PATTERN} = 'get helloworld'; } -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/066-socket-receiveuntil.t b/debian/modules/nginx-lua/t/066-socket-receiveuntil.t index 23fe8a0..3bf5229 100644 --- a/debian/modules/nginx-lua/t/066-socket-receiveuntil.t +++ b/debian/modules/nginx-lua/t/066-socket-receiveuntil.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/067-req-socket.t b/debian/modules/nginx-lua/t/067-req-socket.t index 7797521..30a653a 100644 --- a/debian/modules/nginx-lua/t/067-req-socket.t +++ b/debian/modules/nginx-lua/t/067-req-socket.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/068-socket-keepalive.t b/debian/modules/nginx-lua/t/068-socket-keepalive.t index 21f9631..a005620 100644 --- a/debian/modules/nginx-lua/t/068-socket-keepalive.t +++ b/debian/modules/nginx-lua/t/068-socket-keepalive.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #repeat_each(2); diff --git a/debian/modules/nginx-lua/t/069-null.t b/debian/modules/nginx-lua/t/069-null.t index 6133545..7761c91 100644 --- a/debian/modules/nginx-lua/t/069-null.t +++ b/debian/modules/nginx-lua/t/069-null.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/070-sha1.t b/debian/modules/nginx-lua/t/070-sha1.t index e6fe687..8648a8c 100644 --- a/debian/modules/nginx-lua/t/070-sha1.t +++ b/debian/modules/nginx-lua/t/070-sha1.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/071-idle-socket.t b/debian/modules/nginx-lua/t/071-idle-socket.t index 049e291..55d25c6 100644 --- a/debian/modules/nginx-lua/t/071-idle-socket.t +++ b/debian/modules/nginx-lua/t/071-idle-socket.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/072-conditional-get.t b/debian/modules/nginx-lua/t/072-conditional-get.t index 10a5370..4bb567a 100644 --- a/debian/modules/nginx-lua/t/072-conditional-get.t +++ b/debian/modules/nginx-lua/t/072-conditional-get.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/073-backtrace.t b/debian/modules/nginx-lua/t/073-backtrace.t index 914fa15..aae4bae 100644 --- a/debian/modules/nginx-lua/t/073-backtrace.t +++ b/debian/modules/nginx-lua/t/073-backtrace.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/074-prefix-var.t b/debian/modules/nginx-lua/t/074-prefix-var.t index c95517f..3cc4587 100644 --- a/debian/modules/nginx-lua/t/074-prefix-var.t +++ b/debian/modules/nginx-lua/t/074-prefix-var.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/075-logby.t b/debian/modules/nginx-lua/t/075-logby.t index 5dadb9f..f987c8e 100644 --- a/debian/modules/nginx-lua/t/075-logby.t +++ b/debian/modules/nginx-lua/t/075-logby.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/076-no-postpone.t b/debian/modules/nginx-lua/t/076-no-postpone.t index 655650e..d19bb77 100644 --- a/debian/modules/nginx-lua/t/076-no-postpone.t +++ b/debian/modules/nginx-lua/t/076-no-postpone.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/077-sleep.t b/debian/modules/nginx-lua/t/077-sleep.t index c4d7c0c..a7c251a 100644 --- a/debian/modules/nginx-lua/t/077-sleep.t +++ b/debian/modules/nginx-lua/t/077-sleep.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/078-hup-vars.t b/debian/modules/nginx-lua/t/078-hup-vars.t index d6667c7..8acc346 100644 --- a/debian/modules/nginx-lua/t/078-hup-vars.t +++ b/debian/modules/nginx-lua/t/078-hup-vars.t @@ -12,7 +12,6 @@ BEGIN { } } -use lib 'lib'; use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/079-unused-directives.t b/debian/modules/nginx-lua/t/079-unused-directives.t index c06d228..cba0e41 100644 --- a/debian/modules/nginx-lua/t/079-unused-directives.t +++ b/debian/modules/nginx-lua/t/079-unused-directives.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); @@ -10,7 +9,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * 120; +plan tests => repeat_each() * 110; #no_diff(); #no_long_string(); @@ -264,6 +263,9 @@ lua log handler, uri:"/t" === TEST 11: header_filter_by_lua with multiple http blocks (github issue #294) +This test case won't run with nginx 1.9.3+ since duplicate http {} blocks +have been prohibited since then. +--- SKIP --- config location = /t { echo ok; @@ -289,6 +291,9 @@ ok === TEST 12: body_filter_by_lua in multiple http blocks (github issue #294) +This test case won't run with nginx 1.9.3+ since duplicate http {} blocks +have been prohibited since then. +--- SKIP --- config location = /t { echo -n ok; @@ -312,6 +317,9 @@ okay === TEST 13: capture filter with multiple http blocks (github issue #294) +This test case won't run with nginx 1.9.3+ since duplicate http {} blocks +have been prohibited since then. +--- SKIP --- config location = /t { content_by_lua ' diff --git a/debian/modules/nginx-lua/t/080-hup-shdict.t b/debian/modules/nginx-lua/t/080-hup-shdict.t index ac3ee00..f9a0278 100644 --- a/debian/modules/nginx-lua/t/080-hup-shdict.t +++ b/debian/modules/nginx-lua/t/080-hup-shdict.t @@ -12,7 +12,6 @@ BEGIN { } } -use lib 'lib'; use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/081-bytecode.t b/debian/modules/nginx-lua/t/081-bytecode.t index 6612235..93139e2 100644 --- a/debian/modules/nginx-lua/t/081-bytecode.t +++ b/debian/modules/nginx-lua/t/081-bytecode.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/082-body-filter.t b/debian/modules/nginx-lua/t/082-body-filter.t index 3f7b6da..c0a7c23 100644 --- a/debian/modules/nginx-lua/t/082-body-filter.t +++ b/debian/modules/nginx-lua/t/082-body-filter.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/083-bad-sock-self.t b/debian/modules/nginx-lua/t/083-bad-sock-self.t index eb4f215..b93849f 100644 --- a/debian/modules/nginx-lua/t/083-bad-sock-self.t +++ b/debian/modules/nginx-lua/t/083-bad-sock-self.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/084-inclusive-receiveuntil.t b/debian/modules/nginx-lua/t/084-inclusive-receiveuntil.t index a86afd5..c966015 100644 --- a/debian/modules/nginx-lua/t/084-inclusive-receiveuntil.t +++ b/debian/modules/nginx-lua/t/084-inclusive-receiveuntil.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/085-if.t b/debian/modules/nginx-lua/t/085-if.t index c82085f..e08b43c 100644 --- a/debian/modules/nginx-lua/t/085-if.t +++ b/debian/modules/nginx-lua/t/085-if.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/086-init-by.t b/debian/modules/nginx-lua/t/086-init-by.t index f9ed12c..3a474fe 100644 --- a/debian/modules/nginx-lua/t/086-init-by.t +++ b/debian/modules/nginx-lua/t/086-init-by.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/087-udp-socket.t b/debian/modules/nginx-lua/t/087-udp-socket.t index fd07ff9..39ff54f 100644 --- a/debian/modules/nginx-lua/t/087-udp-socket.t +++ b/debian/modules/nginx-lua/t/087-udp-socket.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/088-req-method.t b/debian/modules/nginx-lua/t/088-req-method.t index aceb877..9ced40c 100644 --- a/debian/modules/nginx-lua/t/088-req-method.t +++ b/debian/modules/nginx-lua/t/088-req-method.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/090-log-socket-errors.t b/debian/modules/nginx-lua/t/090-log-socket-errors.t index 1e41491..a5943c2 100644 --- a/debian/modules/nginx-lua/t/090-log-socket-errors.t +++ b/debian/modules/nginx-lua/t/090-log-socket-errors.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/091-coroutine.t b/debian/modules/nginx-lua/t/091-coroutine.t index c7c5922..b047ccb 100644 --- a/debian/modules/nginx-lua/t/091-coroutine.t +++ b/debian/modules/nginx-lua/t/091-coroutine.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/092-eof.t b/debian/modules/nginx-lua/t/092-eof.t index 7b852b3..a75711f 100644 --- a/debian/modules/nginx-lua/t/092-eof.t +++ b/debian/modules/nginx-lua/t/092-eof.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/093-uthread-spawn.t b/debian/modules/nginx-lua/t/093-uthread-spawn.t index e6dba5f..772e866 100644 --- a/debian/modules/nginx-lua/t/093-uthread-spawn.t +++ b/debian/modules/nginx-lua/t/093-uthread-spawn.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/094-uthread-exit.t b/debian/modules/nginx-lua/t/094-uthread-exit.t index 1bd970c..4d1d316 100644 --- a/debian/modules/nginx-lua/t/094-uthread-exit.t +++ b/debian/modules/nginx-lua/t/094-uthread-exit.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/095-uthread-exec.t b/debian/modules/nginx-lua/t/095-uthread-exec.t index 2309fbe..4459360 100644 --- a/debian/modules/nginx-lua/t/095-uthread-exec.t +++ b/debian/modules/nginx-lua/t/095-uthread-exec.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/096-uthread-redirect.t b/debian/modules/nginx-lua/t/096-uthread-redirect.t index 177e071..b0258fb 100644 --- a/debian/modules/nginx-lua/t/096-uthread-redirect.t +++ b/debian/modules/nginx-lua/t/096-uthread-redirect.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/097-uthread-rewrite.t b/debian/modules/nginx-lua/t/097-uthread-rewrite.t index bf88864..178a374 100644 --- a/debian/modules/nginx-lua/t/097-uthread-rewrite.t +++ b/debian/modules/nginx-lua/t/097-uthread-rewrite.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/098-uthread-wait.t b/debian/modules/nginx-lua/t/098-uthread-wait.t index 1f064f3..aaf020a 100644 --- a/debian/modules/nginx-lua/t/098-uthread-wait.t +++ b/debian/modules/nginx-lua/t/098-uthread-wait.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/099-c-api.t b/debian/modules/nginx-lua/t/099-c-api.t index a61b8f4..a0b375c 100644 --- a/debian/modules/nginx-lua/t/099-c-api.t +++ b/debian/modules/nginx-lua/t/099-c-api.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); @@ -361,3 +360,38 @@ foo: rc=-5 --- no_error_log [error] + + +=== TEST 7: find zone (multiple zones) +--- http_config + lua_shared_dict dogs 1m; + lua_shared_dict cats 1m; +--- config + location = /test { + content_by_lua ' + local ffi = require "ffi" + + ffi.cdef[[ + void *ngx_http_lua_find_zone(char *data, size_t len); + ]] + + local buf = ffi.new("char[?]", 4) + ffi.copy(buf, "cats", 4) + local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + local cats = tostring(zone) + + ffi.copy(buf, "dogs", 4) + zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + local dogs = tostring(zone) + + ngx.say("dogs == cats ? ", dogs == cats) + -- ngx.say("dogs: ", dogs) + -- ngx.say("cats ", cats) + '; + } +--- request +GET /test +--- response_body +dogs == cats ? false +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/100-client-abort.t b/debian/modules/nginx-lua/t/100-client-abort.t index 2428388..cd46859 100644 --- a/debian/modules/nginx-lua/t/100-client-abort.t +++ b/debian/modules/nginx-lua/t/100-client-abort.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/101-on-abort.t b/debian/modules/nginx-lua/t/101-on-abort.t index 6eed29d..bb74204 100644 --- a/debian/modules/nginx-lua/t/101-on-abort.t +++ b/debian/modules/nginx-lua/t/101-on-abort.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/102-req-start-time.t b/debian/modules/nginx-lua/t/102-req-start-time.t index 6ce6196..1d5fe28 100644 --- a/debian/modules/nginx-lua/t/102-req-start-time.t +++ b/debian/modules/nginx-lua/t/102-req-start-time.t @@ -1,7 +1,6 @@ # -*- mode: conf -*- # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/103-req-http-ver.t b/debian/modules/nginx-lua/t/103-req-http-ver.t index 89b491f..6ded75a 100644 --- a/debian/modules/nginx-lua/t/103-req-http-ver.t +++ b/debian/modules/nginx-lua/t/103-req-http-ver.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/104-req-raw-header.t b/debian/modules/nginx-lua/t/104-req-raw-header.t index 5fe326b..439b9de 100644 --- a/debian/modules/nginx-lua/t/104-req-raw-header.t +++ b/debian/modules/nginx-lua/t/104-req-raw-header.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/105-pressure.t b/debian/modules/nginx-lua/t/105-pressure.t index ce9d8b4..10f495e 100644 --- a/debian/modules/nginx-lua/t/105-pressure.t +++ b/debian/modules/nginx-lua/t/105-pressure.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/106-timer.t b/debian/modules/nginx-lua/t/106-timer.t index 497ffa2..5cfc01b 100644 --- a/debian/modules/nginx-lua/t/106-timer.t +++ b/debian/modules/nginx-lua/t/106-timer.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/107-timer-errors.t b/debian/modules/nginx-lua/t/107-timer-errors.t index 5e9b664..9ed1334 100644 --- a/debian/modules/nginx-lua/t/107-timer-errors.t +++ b/debian/modules/nginx-lua/t/107-timer-errors.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/108-timer-safe.t b/debian/modules/nginx-lua/t/108-timer-safe.t index 94c322d..19c9f6d 100644 --- a/debian/modules/nginx-lua/t/108-timer-safe.t +++ b/debian/modules/nginx-lua/t/108-timer-safe.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/109-timer-hup.t b/debian/modules/nginx-lua/t/109-timer-hup.t index 5cdf75b..15aaa0e 100644 --- a/debian/modules/nginx-lua/t/109-timer-hup.t +++ b/debian/modules/nginx-lua/t/109-timer-hup.t @@ -12,7 +12,6 @@ BEGIN { } } -use lib 'lib'; use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); diff --git a/debian/modules/nginx-lua/t/110-etag.t b/debian/modules/nginx-lua/t/110-etag.t index d6f2864..351fec4 100644 --- a/debian/modules/nginx-lua/t/110-etag.t +++ b/debian/modules/nginx-lua/t/110-etag.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/111-req-header-ua.t b/debian/modules/nginx-lua/t/111-req-header-ua.t index 7d395c8..7c980d0 100644 --- a/debian/modules/nginx-lua/t/111-req-header-ua.t +++ b/debian/modules/nginx-lua/t/111-req-header-ua.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/112-req-header-conn.t b/debian/modules/nginx-lua/t/112-req-header-conn.t index 4926a01..51df730 100644 --- a/debian/modules/nginx-lua/t/112-req-header-conn.t +++ b/debian/modules/nginx-lua/t/112-req-header-conn.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/113-req-header-cookie.t b/debian/modules/nginx-lua/t/113-req-header-cookie.t index df08205..b26b709 100644 --- a/debian/modules/nginx-lua/t/113-req-header-cookie.t +++ b/debian/modules/nginx-lua/t/113-req-header-cookie.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/114-config.t b/debian/modules/nginx-lua/t/114-config.t index fa97eb1..e6d75fc 100644 --- a/debian/modules/nginx-lua/t/114-config.t +++ b/debian/modules/nginx-lua/t/114-config.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/115-quote-sql-str.t b/debian/modules/nginx-lua/t/115-quote-sql-str.t index e473b21..0c20dfb 100644 --- a/debian/modules/nginx-lua/t/115-quote-sql-str.t +++ b/debian/modules/nginx-lua/t/115-quote-sql-str.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/116-raw-req-socket.t b/debian/modules/nginx-lua/t/116-raw-req-socket.t index 81b84bd..c2ff8f7 100644 --- a/debian/modules/nginx-lua/t/116-raw-req-socket.t +++ b/debian/modules/nginx-lua/t/116-raw-req-socket.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/117-raw-req-socket-timeout.t b/debian/modules/nginx-lua/t/117-raw-req-socket-timeout.t index 46e7d71..4e3929b 100644 --- a/debian/modules/nginx-lua/t/117-raw-req-socket-timeout.t +++ b/debian/modules/nginx-lua/t/117-raw-req-socket-timeout.t @@ -21,7 +21,6 @@ BEGIN { $ENV{TEST_NGINX_POSTPONE_OUTPUT} = 1; } -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/118-use-default-type.t b/debian/modules/nginx-lua/t/118-use-default-type.t index fd77cff..6008d65 100644 --- a/debian/modules/nginx-lua/t/118-use-default-type.t +++ b/debian/modules/nginx-lua/t/118-use-default-type.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/119-config-prefix.t b/debian/modules/nginx-lua/t/119-config-prefix.t index 047c68e..4581aa1 100644 --- a/debian/modules/nginx-lua/t/119-config-prefix.t +++ b/debian/modules/nginx-lua/t/119-config-prefix.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/121-version.t b/debian/modules/nginx-lua/t/121-version.t index 4ddd263..2b7a306 100644 --- a/debian/modules/nginx-lua/t/121-version.t +++ b/debian/modules/nginx-lua/t/121-version.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/123-lua-path.t b/debian/modules/nginx-lua/t/123-lua-path.t index 964b48b..da97909 100644 --- a/debian/modules/nginx-lua/t/123-lua-path.t +++ b/debian/modules/nginx-lua/t/123-lua-path.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/124-init-worker.t b/debian/modules/nginx-lua/t/124-init-worker.t index ce86fee..d6ea675 100644 --- a/debian/modules/nginx-lua/t/124-init-worker.t +++ b/debian/modules/nginx-lua/t/124-init-worker.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket::Lua; repeat_each(1); -plan tests => repeat_each() * (blocks() * 4 + 1); +plan tests => repeat_each() * (blocks() * 4); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; @@ -740,3 +740,19 @@ ok Bad bad bad --- skip_nginx: 4: < 1.7.1 + + +=== TEST 19: fake module calls ngx_http_conf_get_module_srv_conf in its merge_srv_conf callback (GitHub issue #554) +This also affects merge_loc_conf +--- http_config + init_worker_by_lua return; +--- config + location = /t { + return 200 ok; + } +--- request +GET /t +--- response_body chomp +ok +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/125-configure-args.t b/debian/modules/nginx-lua/t/125-configure-args.t index d37a218..adec129 100644 --- a/debian/modules/nginx-lua/t/125-configure-args.t +++ b/debian/modules/nginx-lua/t/125-configure-args.t @@ -1,5 +1,4 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/126-shdict-frag.t b/debian/modules/nginx-lua/t/126-shdict-frag.t index 8c1ad75..94422fb 100644 --- a/debian/modules/nginx-lua/t/126-shdict-frag.t +++ b/debian/modules/nginx-lua/t/126-shdict-frag.t @@ -1,5 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; + use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/127-uthread-kill.t b/debian/modules/nginx-lua/t/127-uthread-kill.t index a5afc2b..2ab8abe 100644 --- a/debian/modules/nginx-lua/t/127-uthread-kill.t +++ b/debian/modules/nginx-lua/t/127-uthread-kill.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; use t::StapThread; diff --git a/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t b/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t index 571bdc8..0bf38d0 100644 --- a/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t +++ b/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); diff --git a/debian/modules/nginx-lua/t/129-ssl-socket.t b/debian/modules/nginx-lua/t/129-ssl-socket.t index bb04110..45eaa82 100644 --- a/debian/modules/nginx-lua/t/129-ssl-socket.t +++ b/debian/modules/nginx-lua/t/129-ssl-socket.t @@ -1,6 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; use Test::Nginx::Socket::Lua; repeat_each(2); @@ -102,13 +101,13 @@ __DATA__ --- request GET /t ---- response_body -connected: 1 +--- response_body_like chop +\Aconnected: 1 ssl handshake: userdata sent http request: 59 bytes. -received: HTTP/1.1 200 OK +received: HTTP/1.1 (?:200 OK|302 Found) close: 1 nil - +\z --- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ --- grep_error_log_out eval qr/^lua ssl save session: ([0-9A-F]+):2 @@ -920,13 +919,13 @@ $::EquifaxRootCertificate" --- request GET /t ---- response_body -connected: 1 +--- response_body_like chop +\Aconnected: 1 ssl handshake: userdata sent http request: 59 bytes. -received: HTTP/1.1 200 OK +received: HTTP/1.1 (?:200 OK|302 Found) close: 1 nil - +\z --- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ --- grep_error_log_out eval qr/^lua ssl save session: ([0-9A-F]+):2 diff --git a/debian/modules/nginx-lua/t/130-internal-api.t b/debian/modules/nginx-lua/t/130-internal-api.t index c40bf13..d641ab5 100644 --- a/debian/modules/nginx-lua/t/130-internal-api.t +++ b/debian/modules/nginx-lua/t/130-internal-api.t @@ -1,5 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; + use Test::Nginx::Socket::Lua; #worker_connections(1014); diff --git a/debian/modules/nginx-lua/t/132-lua-blocks.t b/debian/modules/nginx-lua/t/132-lua-blocks.t new file mode 100644 index 0000000..874d017 --- /dev/null +++ b/debian/modules/nginx-lua/t/132-lua-blocks.t @@ -0,0 +1,490 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); +#repeat_each(1); + +plan tests => repeat_each() * (blocks() * 3 + 4); + +#no_diff(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: content_by_lua_block (simplest) +--- config + location = /t { + content_by_lua_block { + ngx.say("hello, world") + } + } +--- request +GET /t +--- response_body +hello, world +--- no_error_log +[error] + + + +=== TEST 2: content_by_lua_block (nested curly braces) +--- config + location = /t { + content_by_lua_block { + local a = { + dogs = {32, 78, 96}, + cat = "kitty", + } + ngx.say("a.dogs[1] = ", a.dogs[1]) + ngx.say("a.dogs[2] = ", a.dogs[2]) + ngx.say("a.dogs[3] = ", a.dogs[3]) + ngx.say("a.cat = ", a.cat) + } + } +--- request +GET /t +--- response_body +a.dogs[1] = 32 +a.dogs[2] = 78 +a.dogs[3] = 96 +a.cat = kitty + +--- no_error_log +[error] + + + +=== TEST 3: content_by_lua_block (curly braces in strings) +--- config + location = /t { + content_by_lua_block { + ngx.say("}1, 2)") + ngx.say('{1, 2)') + } + } +--- request +GET /t +--- response_body +}1, 2) +{1, 2) + +--- no_error_log +[error] + + + +=== TEST 4: content_by_lua_block (curly braces in strings, with escaped terminators) +--- config + location = /t { + content_by_lua_block { + ngx.say("\"}1, 2)") + ngx.say('\'{1, 2)') + } + } +--- request +GET /t +--- response_body +"}1, 2) +'{1, 2) + +--- no_error_log +[error] + + + +=== TEST 5: content_by_lua_block (curly braces in long brackets) +--- config + location = /t { + content_by_lua_block { + --[[ + {{{ + + } + ]] + --[==[ + }}} + + { + ]==] + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +ok +--- no_error_log +[error] + + + +=== TEST 6: content_by_lua_block ("nested" long brackets) +--- config + location = /t { + content_by_lua_block { + --[[ + ]=] + ' " + } + ]] + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +ok +--- no_error_log +[error] + + + +=== TEST 7: content_by_lua_block (curly braces in line comments) +--- config + location = /t { + content_by_lua_block { + --}} {} + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +ok +--- no_error_log +[error] + + + +=== TEST 8: content_by_lua_block (cosockets) +--- config + server_tokens off; + location = /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + local port = ngx.var.port + local ok, err = sock:connect('127.0.0.1', tonumber(ngx.var.server_port)) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say('connected: ', ok) + + local req = "GET /foo HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n" + -- req = "OK" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + ngx.say("request sent: ", bytes) + + while true do + local line, err, part = sock:receive() + if line then + ngx.say("received: ", line) + + else + ngx.say("failed to receive a line: ", err, " [", part, "]") + break + end + end + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + } + } + + location /foo { + content_by_lua_block { ngx.say("foo") } + more_clear_headers Date; + } + +--- request +GET /t +--- response_body +connected: 1 +request sent: 57 +received: HTTP/1.1 200 OK +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +failed to receive a line: closed [] +close: 1 nil +--- no_error_log +[error] + + + +=== TEST 9: all in one +--- http_config + init_by_lua_block { + glob = "init by lua }here{" + } + + init_worker_by_lua_block { + glob = glob .. ", init worker }here{" + } +--- config + location = /t { + set $a ''; + rewrite_by_lua_block { + local s = ngx.var.a + s = s .. "}rewrite{\n" + ngx.var.a = s + } + access_by_lua_block { + local s = ngx.var.a + s = s .. '}access{\n' + ngx.var.a = s + } + content_by_lua_block { + local s = ngx.var.a + s = s .. [[}content{]] + ngx.say(s) + ngx.say("glob: ", glob) + } + log_by_lua_block { + print("log by lua running \"}{!\"") + } + header_filter_by_lua_block { + ngx.header["Foo"] = "\"Hello, world\"" + ngx.header["Content-Length"] = nil + } + body_filter_by_lua_block { + local data, eof = ngx.arg[1], ngx.arg[2] + print("eof = ", eof) + if eof then + if not data then + data = "" + end + data = data .. "}body filter{\n" + print("data: ", data) + ngx.arg[1] = data + end + } + } +--- request +GET /t +--- response_body +}rewrite{ +}access{ +}content{ +glob: init by lua }here{, init worker }here{ +}body filter{ + +--- response_headers +Foo: "Hello, world" +--- error_log +log by lua running "}{!" +--- no_error_log +[error] + + + +=== TEST 10: missing ]] (string) +--- config + location = /t { + content_by_lua_block { + ngx.say([[hello, world") + } + } +--- request +GET /t +--- response_body +hello, world +--- no_error_log +[error] +--- must_die +--- error_log eval +qr/\[emerg\] .*? Lua code block missing the closing long bracket "]]" in .*?\bnginx\.conf:41/ + + + +=== TEST 11: missing ]==] (string) +--- config + location = /t { + content_by_lua_block { + ngx.say([==[hello, world") + } + } +--- request +GET /t +--- response_body +hello, world +--- no_error_log +[error] +--- must_die +--- error_log eval +qr/\[emerg\] .*? Lua code block missing the closing long bracket "]==]" in .*?\bnginx\.conf:41/ + + + +=== TEST 12: missing ]] (comment) +--- config + location = /t { + content_by_lua_block { + ngx.say(--[[hello, world") + } + } +--- request +GET /t +--- response_body +hello, world +--- no_error_log +[error] +--- must_die +--- error_log eval +qr/\[emerg\] .*? Lua code block missing the closing long bracket "]]" in .*?\bnginx\.conf:41/ + + + +=== TEST 13: missing ]=] (comment) +--- config + location = /t { + content_by_lua_block { + ngx.say(--[=[hello, world") + } + } +--- request +GET /t +--- response_body +hello, world +--- no_error_log +[error] +--- must_die +--- error_log eval +qr/\[emerg\] .*? Lua code block missing the closing long bracket "]=]" in .*?\bnginx\.conf:41/ + + + +=== TEST 14: missing } +FIXME: we need better diagnostics by actually loading the inlined Lua code while parsing +the *_by_lua_block directive. + +--- config + location = /t { + content_by_lua_block { + ngx.say("hello") +--- request +GET /t +--- response_body +hello, world +--- no_error_log +[error] +--- error_log +"events" directive is not allowed here +--- must_die + + + +=== TEST 15: content_by_lua_block (compact) +--- config + location = /t { + content_by_lua_block {ngx.say("hello, world", {"!"})} + } +--- request +GET /t +--- response_body +hello, world! +--- no_error_log +[error] + + + +=== TEST 16: content_by_lua_block (unexpected closing long brackets) +--- config + location = /t { + content_by_lua_block { + ]=] + } + } +--- request +GET /t +--- no_error_log +[error] +--- error_log eval +qr{\[emerg\] .*? unexpected lua closing long-bracket in .*?/nginx\.conf:41} +--- must_die + + + +=== TEST 17: simple set_by_lua_block (integer) +--- config + location /lua { + set_by_lua_block $res { return 1+1 } + echo $res; + } +--- request +GET /lua +--- response_body +2 +--- no_error_log +[error] + + + +=== TEST 18: ambiguous line comments inside a long bracket string (GitHub #596) +--- config + location = /t { + content_by_lua_block { + ngx.say([[ok--]]) + ngx.say([==[ok--]==]) + ngx.say([==[ok-- ]==]) + --[[ --]] ngx.say("done") + } + } +--- request +GET /t +--- response_body +ok-- +ok-- +ok-- +done +--- no_error_log +[error] + + + +=== TEST 19: double quotes in long brackets +--- config + location = /t { + rewrite_by_lua_block { print([[Hey, it is "!]]) } content_by_lua_block { ngx.say([["]]) } + } +--- request +GET /t +--- response_body +" +--- error_log +Hey, it is "! +--- no_error_log +[error] + + + +=== TEST 20: single quotes in long brackets +--- config + location = /t { + rewrite_by_lua_block { print([[Hey, it is '!]]) } content_by_lua_block { ngx.say([[']]) } + } +--- request +GET /t +--- response_body +' +--- error_log +Hey, it is '! +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/data/fake-module/config b/debian/modules/nginx-lua/t/data/fake-module/config new file mode 100644 index 0000000..00cc8e8 --- /dev/null +++ b/debian/modules/nginx-lua/t/data/fake-module/config @@ -0,0 +1,3 @@ +ngx_addon_name=ngx_http_fake_module +HTTP_MODULES="$HTTP_MODULES ngx_http_fake_module" +NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_fake_module.c" diff --git a/debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c b/debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c new file mode 100644 index 0000000..ec74aa4 --- /dev/null +++ b/debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c @@ -0,0 +1,121 @@ +/* Copyright (C) ZHANG Heng (chiyouhen) + * + * This fake module was used to reproduce a bug in ngx_lua's + * init_worker_by_lua implementation. + */ + + +#include +#include +#include +#include + + +typedef struct { + ngx_int_t a; +} ngx_http_fake_srv_conf_t; + + +typedef struct { + ngx_int_t a; +} ngx_http_fake_loc_conf_t; + + +static void *ngx_http_fake_create_srv_conf(ngx_conf_t *cf); +static char *ngx_http_fake_merge_srv_conf(ngx_conf_t *cf, void *prev, void *conf); +static void *ngx_http_fake_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_fake_merge_loc_conf(ngx_conf_t *cf, void *prev, void *conf); + + +/* flow identify module configure struct */ +static ngx_http_module_t ngx_http_fake_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_http_fake_create_srv_conf, /* create server configuration */ + ngx_http_fake_merge_srv_conf, /* merge server configuration */ + + ngx_http_fake_create_loc_conf, /* create location configuration */ + ngx_http_fake_merge_loc_conf /* merge location configuration */ +}; + +/* flow identify module struct */ +ngx_module_t ngx_http_fake_module = { + NGX_MODULE_V1, + &ngx_http_fake_module_ctx, /* module context */ + NULL, /* 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 +}; + + +/* create server configure */ +static void *ngx_http_fake_create_srv_conf(ngx_conf_t *cf) +{ + ngx_http_fake_srv_conf_t *fscf; + + fscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fake_srv_conf_t)); + if (fscf == NULL) { + return NULL; + } + + return fscf; +} + + +/* merge server configure */ +static char *ngx_http_fake_merge_srv_conf(ngx_conf_t *cf, void *prev, void *conf) +{ + ngx_http_fake_srv_conf_t *fscf; + + fscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_fake_module); + if (fscf == NULL) { + ngx_conf_log_error(NGX_LOG_ALERT, cf, 0, + "get module srv conf failed in merge srv conf"); + return NGX_CONF_ERROR; + } + + ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "merge srv conf ok"); + return NGX_CONF_OK; +} + + +/* create location configure */ +static void *ngx_http_fake_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_fake_loc_conf_t *flcf; + + flcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fake_loc_conf_t)); + if (flcf == NULL) { + return NULL; + } + + return flcf; +} + + +/* merge location configure */ +static char *ngx_http_fake_merge_loc_conf(ngx_conf_t *cf, void *prev, void *conf) +{ + ngx_http_fake_loc_conf_t *flcf; + + flcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_fake_module); + if (flcf == NULL) { + ngx_conf_log_error(NGX_LOG_ALERT, cf, 0, + "get module loc conf failed in merge loc conf"); + return NGX_CONF_ERROR; + } + + ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "merge loc conf ok"); + return NGX_CONF_OK; +} diff --git a/debian/modules/nginx-lua/util/build.sh b/debian/modules/nginx-lua/util/build.sh deleted file mode 100755 index 6617817..0000000 --- a/debian/modules/nginx-lua/util/build.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -# this file is mostly meant to be used by the author himself. - -version=${1:-0.8.54} -opts=$2 - -root=$(cd ${0%/*}/.. && echo $PWD) -mkdir -p $root/{build,work} - -cd $root -git submodule update --init - -cd $root/build -if [ ! -s nginx-$version.tar.gz ]; then - wget "http://sysoev.ru/nginx/nginx-$version.tar.gz" -O nginx-$version.tar.gz -fi -tar -xzvf nginx-$version.tar.gz - -cd nginx-$version/ -if [[ "$BUILD_CLEAN" -eq 1 || ! -f Makefile || "$root/config" -nt Makefile || "$root/util/build.sh" -nt Makefile ]]; then - ./configure --prefix=$root/work \ - --add-module=$root \ - --add-module=$root/deps/ngx_devel_kit \ - $opts \ - --with-debug -fi - -if [ -f $root/work/sbin/nginx ]; then - rm -f $root/work/sbin/nginx -fi - -if [ -f $root/work/logs/nginx.pid ]; then - kill `cat $root/work/logs/nginx.pid` -fi - -make -j2 -make install - diff --git a/debian/modules/nginx-lua/util/build2.sh b/debian/modules/nginx-lua/util/build2.sh index 21caf1f..5a89c29 100755 --- a/debian/modules/nginx-lua/util/build2.sh +++ b/debian/modules/nginx-lua/util/build2.sh @@ -1,6 +1,9 @@ #!/usr/bin/env bash -# this file is mostly meant to be used by the author himself. +# this script is for developers only. +# dependent on the ngx-build script from the nginx-devel-utils repostory: +# https://github.com/openresty/nginx-devel-utils/blob/master/ngx-build +# the resulting nginx is located at ./work/nginx/sbin/nginx root=`pwd` version=${1:-1.4.1} @@ -17,6 +20,7 @@ force=$2 #--with-cc=gcc46 \ #--with-cc=clang \ #--without-http_referer_module \ + #--with-http_v2_module \ time ngx-build $force $version \ --with-ipv6 \ @@ -46,7 +50,9 @@ time ngx-build $force $version \ --add-module=$root/../rds-json-nginx-module \ --add-module=$root/../coolkit-nginx-module \ --add-module=$root/../redis2-nginx-module \ + --add-module=$root/t/data/fake-module \ --with-http_gunzip_module \ + --with-http_dav_module \ --with-select_module \ --with-poll_module \ $opts \ diff --git a/debian/modules/nginx-lua/util/gen-lexer-c b/debian/modules/nginx-lua/util/gen-lexer-c new file mode 100755 index 0000000..dfed3fc --- /dev/null +++ b/debian/modules/nginx-lua/util/gen-lexer-c @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +if [ -z "$1" ]; then + level=0 +else + level="$1" +fi + +#echo '{' '}' '\[=*\[' '--\[=*\[' '\]=*\]' '--[^\n]*' '"(?:\\[^\n]|[^"\n\\])*"' $'\'(?:\\\\[^\\n]|[^\'\\n\\\\])*\'' + +# we need the re.pl script here: +# https://github.com/openresty/sregex/blob/dfa-multi-re/re.pl +re.pl -W --no-main -c --cc="clang -O2" \ + --func-name ngx_http_lua_lex \ + --header ngx_http_lua_lex.h -o src/ngx_http_lua_lex.c \ + --debug=$level -n 8 \ + -- '{' '}' '\[=*\[' '--\[=*\[' '\]=*\]' '--[^\n]*' '"(?:\\[^\n]|[^"\n\\])*"' $'\'(?:\\\\[^\\n]|[^\'\\n\\\\])*\'' \ + || exit 1 diff --git a/debian/modules/nginx-lua/valgrind.suppress b/debian/modules/nginx-lua/valgrind.suppress index a69e606..fe161e8 100644 --- a/debian/modules/nginx-lua/valgrind.suppress +++ b/debian/modules/nginx-lua/valgrind.suppress @@ -103,6 +103,13 @@ fun:main fun:ngx_alloc fun:ngx_event_process_init } +{ + + Memcheck:Param + sendmsg(mmsg[0].msg_hdr) + fun:sendmmsg + fun:__libc_res_nsend +} { Memcheck:Param From b1928b468dcb842a0a989f108d89afa8d7b321d5 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 13 Nov 2015 16:08:16 +0200 Subject: [PATCH 063/651] Release 1.9.6-2 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 08dd22b..0a868c8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,10 +1,10 @@ -nginx (1.9.6-2) UNRELEASED; urgency=medium +nginx (1.9.6-2) unstable; urgency=medium [ Christos Trochalakis] * debian/modules/nginx-lua: + Update nginx-lua to v0.9.19 fixing HTTP/2 compatibility. - -- Christos Trochalakis Fri, 13 Nov 2015 16:04:32 +0200 + -- Christos Trochalakis Fri, 13 Nov 2015 16:08:01 +0200 nginx (1.9.6-1) unstable; urgency=medium From 255c62e0b5926e3d5517fe2331cd4f71400afff6 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Thu, 10 Dec 2015 04:09:20 -0600 Subject: [PATCH 064/651] Changing logrotate from 52 days to 14 because of a typo and similar bug. Bug #805322 --- debian/changelog | 7 +++++++ debian/nginx-common.nginx.logrotate | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 0a868c8..3000163 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.9.6-3) UNRELEASED; urgency=medium + + * debian/nginx-common.nginx.logrotate: + + Switching logrotate to 14 days. (Closes: #805322) + + -- Michael Lustfield Thu, 10 Dec 2015 04:07:29 -0600 + nginx (1.9.6-2) unstable; urgency=medium [ Christos Trochalakis] diff --git a/debian/nginx-common.nginx.logrotate b/debian/nginx-common.nginx.logrotate index 489c31b..1b25aad 100644 --- a/debian/nginx-common.nginx.logrotate +++ b/debian/nginx-common.nginx.logrotate @@ -1,7 +1,7 @@ /var/log/nginx/*.log { weekly missingok - rotate 52 + rotate 14 compress delaycompress notifempty From 23c5f9380615637d6d33f1583d07487e1f138637 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Tue, 15 Dec 2015 01:51:24 -0600 Subject: [PATCH 065/651] Adding some missing files --- .../nginx-lua/misc/recv-until-pm/Makefile | 3 + debian/modules/nginx-lua/util/reindex | 64 +++++++++++++++++++ debian/modules/nginx-lua/util/releng | 8 +++ 3 files changed, 75 insertions(+) create mode 100644 debian/modules/nginx-lua/misc/recv-until-pm/Makefile create mode 100755 debian/modules/nginx-lua/util/reindex create mode 100755 debian/modules/nginx-lua/util/releng diff --git a/debian/modules/nginx-lua/misc/recv-until-pm/Makefile b/debian/modules/nginx-lua/misc/recv-until-pm/Makefile new file mode 100644 index 0000000..eb4d937 --- /dev/null +++ b/debian/modules/nginx-lua/misc/recv-until-pm/Makefile @@ -0,0 +1,3 @@ +test: + prove -Ilib -r t + diff --git a/debian/modules/nginx-lua/util/reindex b/debian/modules/nginx-lua/util/reindex new file mode 100755 index 0000000..bd54c9d --- /dev/null +++ b/debian/modules/nginx-lua/util/reindex @@ -0,0 +1,64 @@ +#!/usr/bin/perl +#: reindex.pl +#: reindex .t files for Test::Base based test files +#: Copyright (c) 2006 Agent Zhang +#: 2006-04-27 2006-05-09 + +use strict; +use warnings; + +#use File::Copy; +use Getopt::Std; + +my %opts; +getopts('hb:', \%opts); +if ($opts{h} or ! @ARGV) { + die "Usage: reindex [-b 0] t/*.t\n"; +} + +my $init = $opts{b}; +$init = 1 if not defined $init; + +my @files = map glob, @ARGV; +for my $file (@files) { + next if -d $file or $file !~ /\.t_?$/; + reindex($file); +} + +sub reindex { + my $file = $_[0]; + open my $in, $file or + die "Can't open $file for reading: $!"; + my @lines; + my $counter = $init; + my $changed; + while (<$in>) { + s/\r$//; + my $num; + s/ ^ === \s+ TEST \s+ (\d+)/$num=$1; "=== TEST " . $counter++/xie; + next if !defined $num; + if ($num != $counter-1) { + $changed++; + } + } continue { + push @lines, $_; + } + close $in; + my $text = join '', @lines; + $text =~ s/(?x) \n+ === \s+ TEST/\n\n\n\n=== TEST/ixsg; + $text =~ s/__(DATA|END)__\n+=== TEST/__${1}__\n\n=== TEST/; + #$text =~ s/\n+$/\n\n/s; + if (! $changed and $text eq join '', @lines) { + warn "reindex: $file:\tskipped.\n"; + return; + } + #File::Copy::copy( $file, "$file.bak" ); + open my $out, "> $file" or + die "Can't open $file for writing: $!"; + binmode $out; + print $out $text; + close $out; + + warn "reindex: $file:\tdone.\n"; +} + diff --git a/debian/modules/nginx-lua/util/releng b/debian/modules/nginx-lua/util/releng new file mode 100755 index 0000000..adc2f4d --- /dev/null +++ b/debian/modules/nginx-lua/util/releng @@ -0,0 +1,8 @@ +#!/bin/bash + +./update-readme +ack '(?<=\#define)\s*DDEBUG\s*1' src +echo ==================================================== +ack '(?<=_version_string) "\d+\.\d+\.\d+"' src +ack '(?<=This document describes rds-json-nginx-module v)\d+\.\d+' README + From 6771862784569cc570591459a9248cee2873dd89 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 14 Jan 2016 10:06:28 +0200 Subject: [PATCH 066/651] Imported Upstream version 1.9.9 --- CHANGES | 41 ++ CHANGES.ru | 42 ++ auto/lib/openssl/conf | 1 + auto/lib/perl/conf | 2 +- auto/modules | 15 +- auto/options | 3 + auto/sources | 7 +- auto/unix | 16 + src/core/nginx.h | 4 +- src/core/ngx_conf_file.h | 2 +- src/core/ngx_parse.c | 2 +- src/core/ngx_string.c | 2 +- src/core/ngx_syslog.c | 8 + src/core/ngx_syslog.h | 3 +- .../modules/ngx_http_chunked_filter_module.c | 2 +- src/http/modules/ngx_http_fastcgi_module.c | 5 +- src/http/modules/ngx_http_proxy_module.c | 33 +- .../modules/ngx_http_range_filter_module.c | 28 +- src/http/modules/ngx_http_realip_module.c | 72 ++- src/http/modules/ngx_http_scgi_module.c | 5 +- .../modules/ngx_http_slice_filter_module.c | 526 ++++++++++++++++++ src/http/modules/ngx_http_static_module.c | 2 +- .../modules/ngx_http_stub_status_module.c | 2 +- src/http/modules/ngx_http_uwsgi_module.c | 5 +- src/http/ngx_http_core_module.c | 4 +- src/http/ngx_http_request.c | 32 +- src/http/ngx_http_request.h | 2 + src/http/ngx_http_special_response.c | 5 +- src/http/ngx_http_upstream.c | 21 +- src/http/ngx_http_upstream.h | 1 + src/http/v2/ngx_http_v2.c | 50 +- src/http/v2/ngx_http_v2.h | 3 +- src/http/v2/ngx_http_v2_filter_module.c | 52 +- src/os/unix/ngx_files.c | 151 +++-- src/os/unix/ngx_posix_init.c | 2 +- 35 files changed, 1005 insertions(+), 146 deletions(-) create mode 100644 src/http/modules/ngx_http_slice_filter_module.c diff --git a/CHANGES b/CHANGES index 2b9809c..267669b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,45 @@ +Changes with nginx 1.9.9 09 Dec 2015 + + *) Bugfix: proxying to unix domain sockets did not work when using + variables; the bug had appeared in 1.9.8. + + +Changes with nginx 1.9.8 08 Dec 2015 + + *) Feature: pwritev() support. + + *) Feature: the "include" directive inside the "upstream" block. + + *) Feature: the ngx_http_slice_module. + + *) Bugfix: a segmentation fault might occur in a worker process when + using LibreSSL; the bug had appeared in 1.9.6. + + *) Bugfix: nginx could not be built on OS X in some cases. + + +Changes with nginx 1.9.7 17 Nov 2015 + + *) Feature: the "nohostname" parameter of logging to syslog. + + *) Feature: the "proxy_cache_convert_head" directive. + + *) Feature: the $realip_remote_addr variable in the + ngx_http_realip_module. + + *) Bugfix: the "expires" directive might not work when using variables. + + *) Bugfix: a segmentation fault might occur in a worker process when + using HTTP/2; the bug had appeared in 1.9.6. + + *) Bugfix: if nginx was built with the ngx_http_v2_module it was + possible to use the HTTP/2 protocol even if the "http2" parameter of + the "listen" directive was not specified. + + *) Bugfix: in the ngx_http_v2_module. + + Changes with nginx 1.9.6 27 Oct 2015 *) Bugfix: a segmentation fault might occur in a worker process when diff --git a/CHANGES.ru b/CHANGES.ru index 3e8c364..315013b 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,46 @@ +Изменения в nginx 1.9.9 09.12.2015 + + *) Исправление: проксирование в unix domain сокеты не работало при + использовании переменных; ошибка появилась в 1.9.8. + + +Изменения в nginx 1.9.8 08.12.2015 + + *) Добавление: поддержка pwritev(). + + *) Добавление: директива include в блоке upstream. + + *) Добавление: модуль ngx_http_slice_module. + + *) Исправление: при использовании LibreSSL в рабочем процессе мог + произойти segmentation fault; ошибка появилась в 1.9.6. + + *) Исправление: nginx мог не собираться на OS X. + + +Изменения в nginx 1.9.7 17.11.2015 + + *) Добавление: параметр nohostname логгирования в syslog. + + *) Добавление: директива proxy_cache_convert_head. + + *) Добавление: переменная $realip_remote_addr в модуле + ngx_http_realip_module. + + *) Исправление: директива expires могла не срабатывать при использовании + переменных. + + *) Исправление: при использовании HTTP/2 в рабочем процессе мог + произойти segmentation fault; ошибка появилась в 1.9.6. + + *) Исправление: если nginx был собран с модулем ngx_http_v2_module, + протокол HTTP/2 мог быть использован клиентом, даже если не был + указан параметр http2 директивы listen. + + *) Исправление: в модуле ngx_http_v2_module. + + Изменения в nginx 1.9.6 27.10.2015 *) Исправление: при использовании HTTP/2 в рабочем процессе мог diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf index bca2050..28a99b2 100644 --- a/auto/lib/openssl/conf +++ b/auto/lib/openssl/conf @@ -105,6 +105,7 @@ else if [ $ngx_found = yes ]; then have=NGX_SSL . auto/have + CORE_INCS="$CORE_INCS $ngx_feature_path" CORE_LIBS="$CORE_LIBS $ngx_feature_libs $NGX_LIBDL" OPENSSL=YES fi diff --git a/auto/lib/perl/conf b/auto/lib/perl/conf index 2a1a3fe..4d1bcf1 100644 --- a/auto/lib/perl/conf +++ b/auto/lib/perl/conf @@ -57,7 +57,7 @@ if test -n "$NGX_PERL_VER"; then if [ "$NGX_SYSTEM" = "Darwin" ]; then # OS X system perl wants to link universal binaries ngx_perl_ldopts=`echo $ngx_perl_ldopts \ - | sed -e 's/-arch x86_64 -arch i386//'` + | sed -e 's/-arch i386//' -e 's/-arch x86_64//'` fi CORE_LINK="$CORE_LINK $ngx_perl_ldopts" diff --git a/auto/modules b/auto/modules index 5c734e1..b2d2ee4 100644 --- a/auto/modules +++ b/auto/modules @@ -73,6 +73,11 @@ if [ $HTTP_SSI = YES ]; then fi +if [ $HTTP_SLICE = YES ]; then + HTTP_POSTPONE=YES +fi + + if [ $HTTP_ADDITION = YES ]; then HTTP_POSTPONE=YES fi @@ -110,6 +115,7 @@ fi # ngx_http_copy_filter # ngx_http_range_body_filter # ngx_http_not_modified_filter +# ngx_http_slice_filter HTTP_FILTER_MODULES="$HTTP_WRITE_FILTER_MODULE \ $HTTP_HEADER_FILTER_MODULE \ @@ -179,6 +185,12 @@ if [ $HTTP_USERID = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_USERID_SRCS" fi +if [ $HTTP_SLICE = YES ]; then + HTTP_SRCS="$HTTP_SRCS $HTTP_SLICE_SRCS" +else + HTTP_SLICE_FILTER_MODULE="" +fi + if [ $HTTP_V2 = YES ]; then have=NGX_HTTP_V2 . auto/have @@ -461,7 +473,8 @@ if [ $HTTP = YES ]; then $HTTP_AUX_FILTER_MODULES \ $HTTP_COPY_FILTER_MODULE \ $HTTP_RANGE_BODY_FILTER_MODULE \ - $HTTP_NOT_MODIFIED_FILTER_MODULE" + $HTTP_NOT_MODIFIED_FILTER_MODULE \ + $HTTP_SLICE_FILTER_MODULE" NGX_ADDON_DEPS="$NGX_ADDON_DEPS \$(HTTP_DEPS)" fi diff --git a/auto/options b/auto/options index efc8943..931dabb 100644 --- a/auto/options +++ b/auto/options @@ -71,6 +71,7 @@ HTTP_ACCESS=YES HTTP_AUTH_BASIC=YES HTTP_AUTH_REQUEST=NO HTTP_USERID=YES +HTTP_SLICE=NO HTTP_AUTOINDEX=YES HTTP_RANDOM_INDEX=NO HTTP_STATUS=NO @@ -226,6 +227,7 @@ do --with-http_random_index_module) HTTP_RANDOM_INDEX=YES ;; --with-http_secure_link_module) HTTP_SECURE_LINK=YES ;; --with-http_degradation_module) HTTP_DEGRADATION=YES ;; + --with-http_slice_module) HTTP_SLICE=YES ;; --without-http_charset_module) HTTP_CHARSET=NO ;; --without-http_gzip_module) HTTP_GZIP=NO ;; @@ -394,6 +396,7 @@ cat << END --with-http_random_index_module enable ngx_http_random_index_module --with-http_secure_link_module enable ngx_http_secure_link_module --with-http_degradation_module enable ngx_http_degradation_module + --with-http_slice_module enable ngx_http_slice_module --with-http_stub_status_module enable ngx_http_stub_status_module --without-http_charset_module disable ngx_http_charset_module diff --git a/auto/sources b/auto/sources index 2abbc60..2e44ce1 100644 --- a/auto/sources +++ b/auto/sources @@ -254,9 +254,6 @@ NGX_WIN32_ICONS="src/os/win32/nginx.ico" NGX_WIN32_RC="src/os/win32/nginx.rc" -# the http modules that have their logging formats -# must be after ngx_http_log_module - HTTP_MODULES="ngx_http_module \ ngx_http_core_module \ ngx_http_log_module \ @@ -363,6 +360,10 @@ HTTP_USERID_FILTER_MODULE=ngx_http_userid_filter_module HTTP_USERID_SRCS=src/http/modules/ngx_http_userid_filter_module.c +HTTP_SLICE_FILTER_MODULE=ngx_http_slice_filter_module +HTTP_SLICE_SRCS=src/http/modules/ngx_http_slice_filter_module.c + + HTTP_REALIP_MODULE=ngx_http_realip_module HTTP_REALIP_SRCS=src/http/modules/ngx_http_realip_module.c diff --git a/auto/unix b/auto/unix index b7b7a25..7bfca8f 100755 --- a/auto/unix +++ b/auto/unix @@ -589,6 +589,22 @@ ngx_feature_test="char buf[1]; ssize_t n; n = pwrite(1, buf, 1, 0); . auto/feature +# pwritev() was introduced in FreeBSD 6 and Linux 2.6.30, glibc 2.10 + +ngx_feature="pwritev()" +ngx_feature_name="NGX_HAVE_PWRITEV" +ngx_feature_run=no +ngx_feature_incs='#include ' +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="char buf[1]; struct iovec vec[1]; ssize_t n; + vec[0].iov_base = buf; + vec[0].iov_len = 1; + n = pwritev(1, vec, 1, 0); + if (n == -1) return 1" +. auto/feature + + ngx_feature="sys_nerr" ngx_feature_name="NGX_SYS_NERR" ngx_feature_run=value diff --git a/src/core/nginx.h b/src/core/nginx.h index 56e9587..87a984a 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1009006 -#define NGINX_VERSION "1.9.6" +#define nginx_version 1009009 +#define NGINX_VERSION "1.9.9" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h index ee44306..2d03f43 100644 --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -50,7 +50,7 @@ #define NGX_DIRECT_CONF 0x00010000 #define NGX_MAIN_CONF 0x01000000 -#define NGX_ANY_CONF 0x0F000000 +#define NGX_ANY_CONF 0x1F000000 diff --git a/src/core/ngx_parse.c b/src/core/ngx_parse.c index d7350d4..7b60c5f 100644 --- a/src/core/ngx_parse.c +++ b/src/core/ngx_parse.c @@ -188,7 +188,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec) break; case 'm': - if (*p == 's') { + if (p < last && *p == 's') { if (is_sec || step >= st_msec) { return NGX_ERROR; } diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index d2a8d01..cf665a4 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -410,7 +410,7 @@ ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args) hex = 2; sign = 0; zero = '0'; - width = NGX_PTR_SIZE * 2; + width = 2 * sizeof(void *); break; case 'c': diff --git a/src/core/ngx_syslog.c b/src/core/ngx_syslog.c index d4e79f6..08f4c04 100644 --- a/src/core/ngx_syslog.c +++ b/src/core/ngx_syslog.c @@ -194,6 +194,9 @@ ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer) peer->tag.data = p + 4; peer->tag.len = len - 4; + } else if (len == 10 && ngx_strncmp(p, "nohostname", 10) == 0) { + peer->nohostname = 1; + } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unknown syslog parameter \"%s\"", p); @@ -220,6 +223,11 @@ ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf) pri = peer->facility * 8 + peer->severity; + if (peer->nohostname) { + return ngx_sprintf(buf, "<%ui>%V %V: ", pri, &ngx_cached_syslog_time, + &peer->tag); + } + return ngx_sprintf(buf, "<%ui>%V %V %V: ", pri, &ngx_cached_syslog_time, &ngx_cycle->hostname, &peer->tag); } diff --git a/src/core/ngx_syslog.h b/src/core/ngx_syslog.h index a915051..cc4c842 100644 --- a/src/core/ngx_syslog.h +++ b/src/core/ngx_syslog.h @@ -16,7 +16,8 @@ typedef struct { ngx_addr_t server; ngx_connection_t conn; - ngx_uint_t busy; /* unsigned busy:1; */ + unsigned busy:1; + unsigned nohostname:1; } ngx_syslog_peer_t; diff --git a/src/http/modules/ngx_http_chunked_filter_module.c b/src/http/modules/ngx_http_chunked_filter_module.c index a7dc5bf..0059a98 100644 --- a/src/http/modules/ngx_http_chunked_filter_module.c +++ b/src/http/modules/ngx_http_chunked_filter_module.c @@ -64,7 +64,7 @@ ngx_http_chunked_header_filter(ngx_http_request_t *r) || r->headers_out.status == NGX_HTTP_NO_CONTENT || r->headers_out.status < NGX_HTTP_OK || r != r->main - || (r->method & NGX_HTTP_HEAD)) + || r->method == NGX_HTTP_HEAD) { return ngx_http_next_header_filter(r); } diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 668719f..dbd7767 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -773,10 +773,11 @@ ngx_http_fastcgi_eval(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf) } else { u->resolved->host = url.host; - u->resolved->port = url.port; - u->resolved->no_port = url.no_port; } + u->resolved->port = url.port; + u->resolved->no_port = url.no_port; + return NGX_OK; } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 514c23b..a869e74 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -533,6 +533,13 @@ static ngx_command_t ngx_http_proxy_commands[] = { offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_revalidate), NULL }, + { ngx_string("proxy_cache_convert_head"), + 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_convert_head), + NULL }, + #endif { ngx_string("proxy_temp_path"), @@ -1008,10 +1015,11 @@ ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx, } else { u->resolved->host = url.host; - u->resolved->port = (in_port_t) (url.no_port ? port : url.port); - u->resolved->no_port = url.no_port; } + u->resolved->port = (in_port_t) (url.no_port ? port : url.port); + u->resolved->no_port = url.no_port; + return NGX_OK; } @@ -1149,25 +1157,24 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) if (u->method.len) { /* HEAD was changed to GET to cache response */ method = u->method; - method.len++; } else if (plcf->method.len) { method = plcf->method; } else { method = r->method_name; - 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) + if (method.len == 4 + && ngx_strncasecmp(method.data, (u_char *) "HEAD", 4) == 0) { ctx->head = 1; } - len = method.len + sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1; + len = method.len + 1 + sizeof(ngx_http_proxy_version) - 1 + + sizeof(CRLF) - 1; escape = 0; loc_len = 0; @@ -1286,6 +1293,7 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) /* the request line */ b->last = ngx_copy(b->last, method.data, method.len); + *b->last++ = ' '; u->uri.data = b->last; @@ -2845,6 +2853,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC; conf->upstream.cache_revalidate = NGX_CONF_UNSET; + conf->upstream.cache_convert_head = NGX_CONF_UNSET; #endif conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; @@ -3143,17 +3152,13 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->upstream.cache_revalidate, prev->upstream.cache_revalidate, 0); + ngx_conf_merge_value(conf->upstream.cache_convert_head, + prev->upstream.cache_convert_head, 1); + #endif ngx_conf_merge_str_value(conf->method, prev->method, ""); - if (conf->method.len - && conf->method.data[conf->method.len - 1] != ' ') - { - conf->method.data[conf->method.len] = ' '; - conf->method.len++; - } - ngx_conf_merge_value(conf->upstream.pass_request_headers, prev->upstream.pass_request_headers, 1); ngx_conf_merge_value(conf->upstream.pass_request_body, diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index 952da75..b07b2e2 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -154,7 +154,7 @@ ngx_http_range_header_filter(ngx_http_request_t *r) if (r->http_version < NGX_HTTP_VERSION_10 || r->headers_out.status != NGX_HTTP_OK - || r != r->main + || (r != r->main && !r->subrequest_ranges) || r->headers_out.content_length_n == -1 || !r->allow_ranges) { @@ -222,6 +222,8 @@ parse: return NGX_ERROR; } + ctx->offset = r->headers_out.content_offset; + if (ngx_array_init(&ctx->ranges, r->pool, 1, sizeof(ngx_http_range_t)) != NGX_OK) { @@ -273,10 +275,21 @@ static ngx_int_t ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, ngx_uint_t ranges) { - u_char *p; - off_t start, end, size, content_length, cutoff, cutlim; - ngx_uint_t suffix; - ngx_http_range_t *range; + u_char *p; + off_t start, end, size, content_length, cutoff, + cutlim; + ngx_uint_t suffix; + ngx_http_range_t *range; + ngx_http_range_filter_ctx_t *mctx; + + if (r != r->main) { + mctx = ngx_http_get_module_ctx(r->main, + ngx_http_range_body_filter_module); + if (mctx) { + ctx->ranges = mctx->ranges; + return NGX_OK; + } + } p = r->headers_in.range->value.data + 6; size = 0; @@ -395,6 +408,10 @@ ngx_http_range_singlepart_header(ngx_http_request_t *r, ngx_table_elt_t *content_range; ngx_http_range_t *range; + if (r != r->main) { + return ngx_http_next_header_filter(r); + } + content_range = ngx_list_push(&r->headers_out.headers); if (content_range == NULL) { return NGX_ERROR; @@ -422,6 +439,7 @@ ngx_http_range_singlepart_header(ngx_http_request_t *r, - content_range->value.data; r->headers_out.content_length_n = range->end - range->start; + r->headers_out.content_offset = range->start; if (r->headers_out.content_length) { r->headers_out.content_length->hash = 0; diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c index 7a62118..c3d7ebe 100644 --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -43,9 +43,14 @@ static char *ngx_http_realip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void *ngx_http_realip_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_realip_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); +static ngx_int_t ngx_http_realip_add_variables(ngx_conf_t *cf); static ngx_int_t ngx_http_realip_init(ngx_conf_t *cf); +static ngx_int_t ngx_http_realip_remote_addr_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + + static ngx_command_t ngx_http_realip_commands[] = { { ngx_string("set_real_ip_from"), @@ -75,7 +80,7 @@ static ngx_command_t ngx_http_realip_commands[] = { static ngx_http_module_t ngx_http_realip_module_ctx = { - NULL, /* preconfiguration */ + ngx_http_realip_add_variables, /* preconfiguration */ ngx_http_realip_init, /* postconfiguration */ NULL, /* create main configuration */ @@ -105,6 +110,15 @@ ngx_module_t ngx_http_realip_module = { }; +static ngx_http_variable_t ngx_http_realip_vars[] = { + + { ngx_string("realip_remote_addr"), NULL, + ngx_http_realip_remote_addr_variable, 0, 0, 0 }, + + { ngx_null_string, NULL, NULL, 0, 0, 0 } +}; + + static ngx_int_t ngx_http_realip_handler(ngx_http_request_t *r) { @@ -416,6 +430,25 @@ ngx_http_realip_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) } +static ngx_int_t +ngx_http_realip_add_variables(ngx_conf_t *cf) +{ + ngx_http_variable_t *var, *v; + + for (v = ngx_http_realip_vars; v->name.len; v++) { + var = ngx_http_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = v->get_handler; + var->data = v->data; + } + + return NGX_OK; +} + + static ngx_int_t ngx_http_realip_init(ngx_conf_t *cf) { @@ -440,3 +473,40 @@ ngx_http_realip_init(ngx_conf_t *cf) return NGX_OK; } + + +static ngx_int_t +ngx_http_realip_remote_addr_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_str_t *addr_text; + ngx_pool_cleanup_t *cln; + ngx_http_realip_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_realip_module); + + if (ctx == NULL && (r->internal || r->filter_finalize)) { + + /* + * if module context was reset, the original address + * can still be found in the cleanup handler + */ + + for (cln = r->pool->cleanup; cln; cln = cln->next) { + if (cln->handler == ngx_http_realip_cleanup) { + ctx = cln->data; + break; + } + } + } + + addr_text = ctx ? &ctx->addr_text : &r->connection->addr_text; + + v->len = addr_text->len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = addr_text->data; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index 6e5b077..76c7786 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -569,10 +569,11 @@ ngx_http_scgi_eval(ngx_http_request_t *r, ngx_http_scgi_loc_conf_t * scf) } else { u->resolved->host = url.host; - u->resolved->port = url.port; - u->resolved->no_port = url.no_port; } + u->resolved->port = url.port; + u->resolved->no_port = url.no_port; + return NGX_OK; } diff --git a/src/http/modules/ngx_http_slice_filter_module.c b/src/http/modules/ngx_http_slice_filter_module.c new file mode 100644 index 0000000..5e149b4 --- /dev/null +++ b/src/http/modules/ngx_http_slice_filter_module.c @@ -0,0 +1,526 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + size_t size; +} ngx_http_slice_loc_conf_t; + + +typedef struct { + off_t start; + off_t end; + ngx_str_t range; + ngx_str_t etag; + ngx_uint_t last; /* unsigned last:1; */ +} ngx_http_slice_ctx_t; + + +typedef struct { + off_t start; + off_t end; + off_t complete_length; +} ngx_http_slice_content_range_t; + + +static ngx_int_t ngx_http_slice_header_filter(ngx_http_request_t *r); +static ngx_int_t ngx_http_slice_body_filter(ngx_http_request_t *r, + ngx_chain_t *in); +static ngx_int_t ngx_http_slice_parse_content_range(ngx_http_request_t *r, + ngx_http_slice_content_range_t *cr); +static ngx_int_t ngx_http_slice_range_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static off_t ngx_http_slice_get_start(ngx_http_request_t *r); +static void *ngx_http_slice_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_slice_merge_loc_conf(ngx_conf_t *cf, void *parent, + void *child); +static ngx_int_t ngx_http_slice_add_variables(ngx_conf_t *cf); +static ngx_int_t ngx_http_slice_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_http_slice_filter_commands[] = { + + { ngx_string("slice"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_slice_loc_conf_t, size), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_slice_filter_module_ctx = { + ngx_http_slice_add_variables, /* preconfiguration */ + ngx_http_slice_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_slice_create_loc_conf, /* create location configuration */ + ngx_http_slice_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_slice_filter_module = { + NGX_MODULE_V1, + &ngx_http_slice_filter_module_ctx, /* module context */ + ngx_http_slice_filter_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_str_t ngx_http_slice_range_name = ngx_string("slice_range"); + +static ngx_http_output_header_filter_pt ngx_http_next_header_filter; +static ngx_http_output_body_filter_pt ngx_http_next_body_filter; + + +static ngx_int_t +ngx_http_slice_header_filter(ngx_http_request_t *r) +{ + off_t end; + ngx_int_t rc; + ngx_table_elt_t *h; + ngx_http_slice_ctx_t *ctx; + ngx_http_slice_loc_conf_t *slcf; + ngx_http_slice_content_range_t cr; + + ctx = ngx_http_get_module_ctx(r, ngx_http_slice_filter_module); + if (ctx == NULL) { + return ngx_http_next_header_filter(r); + } + + if (r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT) { + if (r == r->main) { + ngx_http_set_ctx(r, NULL, ngx_http_slice_filter_module); + return ngx_http_next_header_filter(r); + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "unexpected status code %ui in slice response", + r->headers_out.status); + return NGX_ERROR; + } + + h = r->headers_out.etag; + + if (ctx->etag.len) { + if (h == NULL + || h->value.len != ctx->etag.len + || ngx_strncmp(h->value.data, ctx->etag.data, ctx->etag.len) + != 0) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "etag mismatch in slice response"); + return NGX_ERROR; + } + } + + if (h) { + ctx->etag = h->value; + } + + if (ngx_http_slice_parse_content_range(r, &cr) != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid range in slice response"); + return NGX_ERROR; + } + + if (cr.complete_length == -1) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "no complete length in slice response"); + return NGX_ERROR; + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http slice response range: %O-%O/%O", + cr.start, cr.end, cr.complete_length); + + slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module); + + end = ngx_min(cr.start + (off_t) slcf->size, cr.complete_length); + + if (cr.start != ctx->start || cr.end != end) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "unexpected range in slice response: %O-%O", + cr.start, cr.end); + return NGX_ERROR; + } + + ctx->start = end; + + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.status_line.len = 0; + r->headers_out.content_length_n = cr.complete_length; + r->headers_out.content_offset = cr.start; + r->headers_out.content_range->hash = 0; + r->headers_out.content_range = NULL; + + r->allow_ranges = 1; + r->subrequest_ranges = 1; + r->single_range = 1; + + rc = ngx_http_next_header_filter(r); + + if (r != r->main) { + return rc; + } + + if (r->headers_out.status == NGX_HTTP_PARTIAL_CONTENT) { + if (ctx->start + (off_t) slcf->size <= r->headers_out.content_offset) { + ctx->start = slcf->size + * (r->headers_out.content_offset / slcf->size); + } + + ctx->end = r->headers_out.content_offset + + r->headers_out.content_length_n; + + } else { + ctx->end = cr.complete_length; + } + + return rc; +} + + +static ngx_int_t +ngx_http_slice_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_int_t rc; + ngx_chain_t *cl; + ngx_http_request_t *sr; + ngx_http_slice_ctx_t *ctx; + ngx_http_slice_loc_conf_t *slcf; + + ctx = ngx_http_get_module_ctx(r, ngx_http_slice_filter_module); + + if (ctx == NULL || r != r->main) { + return ngx_http_next_body_filter(r, in); + } + + for (cl = in; cl; cl = cl->next) { + if (cl->buf->last_buf) { + cl->buf->last_buf = 0; + cl->buf->last_in_chain = 1; + cl->buf->sync = 1; + ctx->last = 1; + } + } + + rc = ngx_http_next_body_filter(r, in); + + if (rc == NGX_ERROR || !ctx->last) { + return rc; + } + + if (ctx->start >= ctx->end) { + ngx_http_set_ctx(r, NULL, ngx_http_slice_filter_module); + ngx_http_send_special(r, NGX_HTTP_LAST); + return rc; + } + + if (r->buffered) { + return rc; + } + + if (ngx_http_subrequest(r, &r->uri, &r->args, &sr, NULL, 0) != NGX_OK) { + return NGX_ERROR; + } + + ngx_http_set_ctx(sr, ctx, ngx_http_slice_filter_module); + + slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module); + + ctx->range.len = ngx_sprintf(ctx->range.data, "bytes=%O-%O", ctx->start, + ctx->start + (off_t) slcf->size - 1) + - ctx->range.data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http slice subrequest: \"%V\"", &ctx->range); + + return rc; +} + + +static ngx_int_t +ngx_http_slice_parse_content_range(ngx_http_request_t *r, + ngx_http_slice_content_range_t *cr) +{ + off_t start, end, complete_length, cutoff, cutlim; + u_char *p; + ngx_table_elt_t *h; + + h = r->headers_out.content_range; + + if (h == NULL + || h->value.len < 7 + || ngx_strncmp(h->value.data, "bytes ", 6) != 0) + { + return NGX_ERROR; + } + + p = h->value.data + 6; + + cutoff = NGX_MAX_OFF_T_VALUE / 10; + cutlim = NGX_MAX_OFF_T_VALUE % 10; + + start = 0; + end = 0; + complete_length = 0; + + while (*p == ' ') { p++; } + + if (*p < '0' || *p > '9') { + return NGX_ERROR; + } + + while (*p >= '0' && *p <= '9') { + if (start >= cutoff && (start > cutoff || *p - '0' > cutlim)) { + return NGX_ERROR; + } + + start = start * 10 + *p++ - '0'; + } + + while (*p == ' ') { p++; } + + if (*p++ != '-') { + return NGX_ERROR; + } + + while (*p == ' ') { p++; } + + if (*p < '0' || *p > '9') { + return NGX_ERROR; + } + + while (*p >= '0' && *p <= '9') { + if (end >= cutoff && (end > cutoff || *p - '0' > cutlim)) { + return NGX_ERROR; + } + + end = end * 10 + *p++ - '0'; + } + + end++; + + while (*p == ' ') { p++; } + + if (*p++ != '/') { + return NGX_ERROR; + } + + while (*p == ' ') { p++; } + + if (*p != '*') { + if (*p < '0' || *p > '9') { + return NGX_ERROR; + } + + while (*p >= '0' && *p <= '9') { + if (complete_length >= cutoff + && (complete_length > cutoff || *p - '0' > cutlim)) + { + return NGX_ERROR; + } + + complete_length = complete_length * 10 + *p++ - '0'; + } + + } else { + complete_length = -1; + p++; + } + + while (*p == ' ') { p++; } + + if (*p != '\0') { + return NGX_ERROR; + } + + cr->start = start; + cr->end = end; + cr->complete_length = complete_length; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_slice_range_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *p; + ngx_http_slice_ctx_t *ctx; + ngx_http_slice_loc_conf_t *slcf; + + ctx = ngx_http_get_module_ctx(r, ngx_http_slice_filter_module); + + if (ctx == NULL) { + if (r != r->main || r->headers_out.status) { + v->not_found = 1; + return NGX_OK; + } + + slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module); + + if (slcf->size == 0) { + v->not_found = 1; + return NGX_OK; + } + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_slice_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_slice_filter_module); + + p = ngx_pnalloc(r->pool, sizeof("bytes=-") - 1 + 2 * NGX_OFF_T_LEN); + if (p == NULL) { + return NGX_ERROR; + } + + ctx->start = slcf->size * (ngx_http_slice_get_start(r) / slcf->size); + + ctx->range.data = p; + ctx->range.len = ngx_sprintf(p, "bytes=%O-%O", ctx->start, + ctx->start + (off_t) slcf->size - 1) + - p; + } + + v->data = ctx->range.data; + v->valid = 1; + v->not_found = 0; + v->no_cacheable = 1; + v->len = ctx->range.len; + + return NGX_OK; +} + + +static off_t +ngx_http_slice_get_start(ngx_http_request_t *r) +{ + off_t start, cutoff, cutlim; + u_char *p; + ngx_table_elt_t *h; + + if (r->headers_in.if_range) { + return 0; + } + + h = r->headers_in.range; + + if (h == NULL + || h->value.len < 7 + || ngx_strncasecmp(h->value.data, (u_char *) "bytes=", 6) != 0) + { + return 0; + } + + p = h->value.data + 6; + + if (ngx_strchr(p, ',')) { + return 0; + } + + while (*p == ' ') { p++; } + + if (*p == '-') { + return 0; + } + + cutoff = NGX_MAX_OFF_T_VALUE / 10; + cutlim = NGX_MAX_OFF_T_VALUE % 10; + + start = 0; + + while (*p >= '0' && *p <= '9') { + if (start >= cutoff && (start > cutoff || *p - '0' > cutlim)) { + return 0; + } + + start = start * 10 + *p++ - '0'; + } + + return start; +} + + +static void * +ngx_http_slice_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_slice_loc_conf_t *slcf; + + slcf = ngx_palloc(cf->pool, sizeof(ngx_http_slice_loc_conf_t)); + if (slcf == NULL) { + return NULL; + } + + slcf->size = NGX_CONF_UNSET_SIZE; + + return slcf; +} + + +static char * +ngx_http_slice_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_slice_loc_conf_t *prev = parent; + ngx_http_slice_loc_conf_t *conf = child; + + ngx_conf_merge_size_value(conf->size, prev->size, 0); + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_slice_add_variables(ngx_conf_t *cf) +{ + ngx_http_variable_t *var; + + var = ngx_http_add_variable(cf, &ngx_http_slice_range_name, 0); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = ngx_http_slice_range_variable; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_slice_init(ngx_conf_t *cf) +{ + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_slice_header_filter; + + ngx_http_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_slice_body_filter; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c index 631eb17..f79c4ae 100644 --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -204,7 +204,7 @@ ngx_http_static_handler(ngx_http_request_t *r) #endif - if (r->method & NGX_HTTP_POST) { + if (r->method == NGX_HTTP_POST) { return NGX_HTTP_NOT_ALLOWED; } diff --git a/src/http/modules/ngx_http_stub_status_module.c b/src/http/modules/ngx_http_stub_status_module.c index dd68358..61199f2 100644 --- a/src/http/modules/ngx_http_stub_status_module.c +++ b/src/http/modules/ngx_http_stub_status_module.c @@ -89,7 +89,7 @@ ngx_http_stub_status_handler(ngx_http_request_t *r) ngx_chain_t out; ngx_atomic_int_t ap, hn, ac, rq, rd, wr, wa; - if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { + if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; } diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index a50c553..0313dfa 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -771,10 +771,11 @@ ngx_http_uwsgi_eval(ngx_http_request_t *r, ngx_http_uwsgi_loc_conf_t * uwcf) } else { u->resolved->host = url.host; - u->resolved->port = url.port; - u->resolved->no_port = url.no_port; } + u->resolved->port = url.port; + u->resolved->no_port = url.no_port; + return NGX_OK; } diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 7a29608..4b8dd4c 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -776,7 +776,7 @@ ngx_module_t ngx_http_core_module = { }; -ngx_str_t ngx_http_core_get_method = { 3, (u_char *) "GET " }; +ngx_str_t ngx_http_core_get_method = { 3, (u_char *) "GET" }; void @@ -3503,7 +3503,7 @@ ngx_http_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) /* TODO: it does not merge, it inits only */ ngx_conf_merge_size_value(conf->connection_pool_size, - prev->connection_pool_size, 256); + prev->connection_pool_size, 64 * sizeof(void *)); ngx_conf_merge_size_value(conf->request_pool_size, prev->request_pool_size, 4096); ngx_conf_merge_msec_value(conf->client_header_timeout, diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 9da972e..99e9325 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -768,25 +768,31 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c) && (defined TLSEXT_TYPE_application_layer_protocol_negotiation \ || defined TLSEXT_TYPE_next_proto_neg)) { - unsigned int len; - const unsigned char *data; + unsigned int len; + const unsigned char *data; + ngx_http_connection_t *hc; + + hc = c->data; + + if (hc->addr_conf->http2) { #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation - SSL_get0_alpn_selected(c->ssl->connection, &data, &len); + SSL_get0_alpn_selected(c->ssl->connection, &data, &len); #ifdef TLSEXT_TYPE_next_proto_neg - if (len == 0) { - SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len); - } + if (len == 0) { + SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len); + } #endif #else /* TLSEXT_TYPE_next_proto_neg */ - SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len); + SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len); #endif - if (len == 2 && data[0] == 'h' && data[1] == '2') { - ngx_http_v2_init(c->read); - return; + if (len == 2 && data[0] == 'h' && data[1] == '2') { + ngx_http_v2_init(c->read); + return; + } } } #endif @@ -831,6 +837,10 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) c = ngx_ssl_get_connection(ssl_conn); + if (c->ssl->renegotiation) { + return SSL_TLSEXT_ERR_NOACK; + } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "SSL server name: \"%s\"", servername); @@ -1782,7 +1792,7 @@ ngx_http_process_request_header(ngx_http_request_t *r) } } - if (r->method & NGX_HTTP_TRACE) { + if (r->method == NGX_HTTP_TRACE) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client sent TRACE method"); ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 967032a..8b88139 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -271,6 +271,7 @@ typedef struct { ngx_array_t cache_control; off_t content_length_n; + off_t content_offset; time_t date_time; time_t last_modified_time; } ngx_http_headers_out_t; @@ -530,6 +531,7 @@ struct ngx_http_request_s { unsigned filter_need_in_memory:1; unsigned filter_need_temporary:1; unsigned allow_ranges:1; + unsigned subrequest_ranges:1; unsigned single_range:1; unsigned disable_not_modified:1; diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c index a97791e..2771e58 100644 --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -359,9 +359,6 @@ static ngx_str_t ngx_http_error_pages[] = { }; -static ngx_str_t ngx_http_get_name = { 3, (u_char *) "GET " }; - - ngx_int_t ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error) { @@ -564,7 +561,7 @@ ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page) if (r->method != NGX_HTTP_HEAD) { r->method = NGX_HTTP_GET; - r->method_name = ngx_http_get_name; + r->method_name = ngx_http_core_get_method; } return ngx_http_internal_redirect(r, &uri, &args); diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 1530596..6c6ee80 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -250,6 +250,11 @@ ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = { ngx_http_upstream_copy_allow_ranges, offsetof(ngx_http_headers_out_t, accept_ranges), 1 }, + { ngx_string("Content-Range"), + ngx_http_upstream_ignore_header_line, 0, + ngx_http_upstream_copy_header_line, + offsetof(ngx_http_headers_out_t, content_range), 0 }, + { ngx_string("Connection"), ngx_http_upstream_process_connection, 0, ngx_http_upstream_ignore_header_line, 0, 0 }, @@ -633,8 +638,20 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) u->ssl_name = u->resolved->host; #endif + host = &u->resolved->host; + if (u->resolved->sockaddr) { + if (u->resolved->port == 0 + && u->resolved->sockaddr->sa_family != AF_UNIX) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "no port in upstream \"%V\"", host); + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + if (ngx_http_upstream_create_round_robin_peer(r, u->resolved) != NGX_OK) { @@ -648,8 +665,6 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) return; } - host = &u->resolved->host; - umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); uscfp = umcf->upstreams.elts; @@ -764,7 +779,7 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u) return rc; } - if (r->method & NGX_HTTP_HEAD) { + if (r->method == NGX_HTTP_HEAD && u->conf->cache_convert_head) { u->method = ngx_http_core_get_method; } diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index 64157e6..8404265 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -193,6 +193,7 @@ typedef struct { ngx_msec_t cache_lock_age; ngx_flag_t cache_revalidate; + ngx_flag_t cache_convert_head; ngx_array_t *cache_valid; ngx_array_t *cache_bypass; diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 10cb727..869ce08 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -870,8 +870,6 @@ ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) return ngx_http_v2_state_skip_padded(h2c, pos, end); } - stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; - h2c->state.stream = stream; return ngx_http_v2_state_read_data(h2c, pos, end); @@ -899,6 +897,8 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, } if (stream->skip_data) { + stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, "skipping http2 DATA frame, reason: %d", stream->skip_data); @@ -988,7 +988,9 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, ngx_http_v2_state_read_data); } - if (stream->in_closed) { + if (h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG) { + stream->in_closed = 1; + if (r->headers_in.content_length_n < 0) { r->headers_in.content_length_n = rb->rest; @@ -1204,10 +1206,9 @@ static u_char * ngx_http_v2_state_header_block(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) { - u_char ch; - ngx_int_t value; - ngx_uint_t indexed, size_update, prefix; - ngx_http_v2_srv_conf_t *h2scf; + u_char ch; + ngx_int_t value; + ngx_uint_t indexed, size_update, prefix; if (end - pos < 1) { return ngx_http_v2_state_save(h2c, pos, end, @@ -1288,20 +1289,11 @@ ngx_http_v2_state_header_block(ngx_http_v2_connection_t *h2c, u_char *pos, return ngx_http_v2_state_header_complete(h2c, pos, end); } - h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, - ngx_http_v2_module); - - h2c->state.field_limit = h2scf->max_field_size; - if (value == 0) { h2c->state.parse_name = 1; - } else { - if (ngx_http_v2_get_indexed_header(h2c, value, 1) != NGX_OK) { - return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR); - } - - h2c->state.field_limit -= h2c->state.header.name.len; + } else if (ngx_http_v2_get_indexed_header(h2c, value, 1) != NGX_OK) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR); } h2c->state.parse_value = 1; @@ -1314,9 +1306,10 @@ static u_char * ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) { - size_t alloc; - ngx_int_t len; - ngx_uint_t huff; + size_t alloc; + ngx_int_t len; + ngx_uint_t huff; + ngx_http_v2_srv_conf_t *h2scf; if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) && h2c->state.length < NGX_HTTP_V2_INT_OCTETS) @@ -1363,14 +1356,16 @@ ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c, u_char *pos, "http2 hpack %s string length: %i", huff ? "encoded" : "raw", len); - if ((size_t) len > h2c->state.field_limit) { + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); + + if ((size_t) len > h2scf->max_field_size) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, "client exceeded http2_max_field_size limit"); return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM); } - h2c->state.field_limit -= len; h2c->state.field_rest = len; if (h2c->state.stream == NULL && !h2c->state.index) { @@ -1664,7 +1659,7 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, h->key.len = header->name.len; h->key.data = header->name.data; - /* TODO Optimization: precalculate hash and hadnler for indexed headers. */ + /* TODO Optimization: precalculate hash and handler for indexed headers. */ h->hash = ngx_hash_key(h->key.data, h->key.len); h->value.len = header->value.len; @@ -1818,7 +1813,7 @@ ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, u_char *pos, if (depend == h2c->state.sid) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, "client sent PRIORITY frame for stream %ui " - "with incorrect dependancy", h2c->state.sid); + "with incorrect dependency", h2c->state.sid); node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0); @@ -2954,6 +2949,8 @@ ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header) return NGX_ERROR; } + r->invalid_header = 0; + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); for (i = (header->name.data[0] == ':'); i != header->name.len; i++) { @@ -3297,9 +3294,6 @@ ngx_http_v2_construct_request_line(ngx_http_request_t *r) ngx_memcpy(p, ending, sizeof(ending)); - /* some modules expect the space character after method name */ - r->method_name.data = r->request_line.data; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http2 http request line: \"%V\"", &r->request_line); diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 462d254..4c63b21 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -80,7 +80,6 @@ typedef struct { unsigned index:1; ngx_http_v2_header_t header; size_t header_limit; - size_t field_limit; u_char field_state; u_char *field_start; u_char *field_end; @@ -179,7 +178,7 @@ struct ngx_http_v2_stream_s { size_t recv_window; ngx_http_v2_out_frame_t *free_frames; - ngx_chain_t *free_data_headers; + ngx_chain_t *free_frame_headers; ngx_chain_t *free_bufs; ngx_queue_t queue; diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index a866cde..ed30fe5 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -624,6 +624,8 @@ ngx_http_v2_create_headers_frame(ngx_http_request_t *r, u_char *pos, *b->last++ = flags; b->last = ngx_http_v2_write_sid(b->last, stream->node->id); + b->tag = (ngx_buf_tag_t) &ngx_http_v2_module; + cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NULL; @@ -929,7 +931,7 @@ ngx_http_v2_filter_get_data_frame(ngx_http_v2_stream_t *stream, stream->node->id, frame, len, (ngx_uint_t) flags); cl = ngx_chain_get_free_buf(stream->request->pool, - &stream->free_data_headers); + &stream->free_frame_headers); if (cl == NULL) { return NULL; } @@ -946,7 +948,7 @@ ngx_http_v2_filter_get_data_frame(ngx_http_v2_stream_t *stream, buf->end = buf->start + NGX_HTTP_V2_FRAME_HEADER_SIZE; buf->last = buf->end; - buf->tag = (ngx_buf_tag_t) &ngx_http_v2_filter_get_data_frame; + buf->tag = (ngx_buf_tag_t) &ngx_http_v2_module; buf->memory = 1; } @@ -1054,23 +1056,45 @@ static ngx_int_t ngx_http_v2_headers_frame_handler(ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame) { - ngx_buf_t *buf; + ngx_chain_t *cl, *ln; ngx_http_v2_stream_t *stream; - buf = frame->first->buf; - - if (buf->pos != buf->last) { - return NGX_AGAIN; - } - stream = frame->stream; + cl = frame->first; + + for ( ;; ) { + if (cl->buf->pos != cl->buf->last) { + frame->first = cl; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2:%ui HEADERS frame %p was sent partially", + stream->node->id, frame); + + return NGX_AGAIN; + } + + ln = cl->next; + + if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_module) { + cl->next = stream->free_frame_headers; + stream->free_frame_headers = cl; + + } else { + cl->next = stream->free_bufs; + stream->free_bufs = cl; + } + + if (cl == frame->last) { + break; + } + + cl = ln; + } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, "http2:%ui HEADERS frame %p was sent", stream->node->id, frame); - ngx_free_chain(stream->request->pool, frame->first); - ngx_http_v2_handle_frame(stream, frame); ngx_http_v2_handle_stream(h2c, stream); @@ -1091,7 +1115,7 @@ ngx_http_v2_data_frame_handler(ngx_http_v2_connection_t *h2c, cl = frame->first; - if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_filter_get_data_frame) { + if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_module) { if (cl->buf->pos != cl->buf->last) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, @@ -1103,8 +1127,8 @@ ngx_http_v2_data_frame_handler(ngx_http_v2_connection_t *h2c, ln = cl->next; - cl->next = stream->free_data_headers; - stream->free_data_headers = cl; + cl->next = stream->free_frame_headers; + stream->free_frame_headers = cl; if (cl == frame->last) { goto done; diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c index 417b598..00a6a49 100644 --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -14,6 +14,9 @@ static void ngx_thread_read_handler(void *data, ngx_log_t *log); #endif +static ssize_t ngx_writev_file(ngx_file_t *file, ngx_array_t *vec, size_t size, + off_t offset); + #if (NGX_HAVE_FILE_AIO) @@ -176,7 +179,8 @@ ngx_thread_read_handler(void *data, ngx_log_t *log) ssize_t ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) { - ssize_t n, written; + ssize_t n, written; + ngx_err_t err; ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, "write: %d, %p, %uz, %O", file->fd, buf, size, offset); @@ -189,7 +193,15 @@ ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) n = pwrite(file->fd, buf + written, size, offset); if (n == -1) { - ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, + err = ngx_errno; + + if (err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, file->log, err, + "pwrite() was interrupted"); + continue; + } + + ngx_log_error(NGX_LOG_CRIT, file->log, err, "pwrite() \"%s\" failed", file->name.data); return NGX_ERROR; } @@ -221,11 +233,20 @@ ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) n = write(file->fd, buf + written, size); if (n == -1) { - ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, + err = ngx_errno; + + if (err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, file->log, err, + "write() was interrupted"); + continue; + } + + ngx_log_error(NGX_LOG_CRIT, file->log, err, "write() \"%s\" failed", file->name.data); return NGX_ERROR; } + file->sys_offset += n; file->offset += n; written += n; @@ -264,7 +285,6 @@ ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, u_char *prev; size_t size; ssize_t total, n; - ngx_err_t err; ngx_array_t vec; struct iovec *iov, iovs[NGX_IOVS]; @@ -326,46 +346,12 @@ ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, return total + n; } - if (file->sys_offset != offset) { - if (lseek(file->fd, offset, SEEK_SET) == -1) { - ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, - "lseek() \"%s\" failed", file->name.data); - return NGX_ERROR; - } + n = ngx_writev_file(file, &vec, size, offset); - file->sys_offset = offset; + if (n == NGX_ERROR) { + return n; } -eintr: - - n = writev(file->fd, vec.elts, vec.nelts); - - if (n == -1) { - err = ngx_errno; - - if (err == NGX_EINTR) { - ngx_log_debug0(NGX_LOG_DEBUG_CORE, file->log, err, - "writev() was interrupted"); - goto eintr; - } - - ngx_log_error(NGX_LOG_CRIT, file->log, err, - "writev() \"%s\" failed", file->name.data); - return NGX_ERROR; - } - - if ((size_t) n != size) { - ngx_log_error(NGX_LOG_CRIT, file->log, 0, - "writev() \"%s\" has written only %z of %uz", - file->name.data, n, size); - return NGX_ERROR; - } - - ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0, - "writev: %d, %z", file->fd, n); - - file->sys_offset += n; - file->offset += n; offset += n; total += n; @@ -375,6 +361,89 @@ eintr: } +static ssize_t +ngx_writev_file(ngx_file_t *file, ngx_array_t *vec, size_t size, off_t offset) +{ + ssize_t n; + ngx_err_t err; + + ngx_log_debug3(NGX_LOG_DEBUG_CORE, file->log, 0, + "writev: %d, %uz, %O", file->fd, size, offset); + +#if (NGX_HAVE_PWRITEV) + +eintr: + + n = pwritev(file->fd, vec->elts, vec->nelts, offset); + + if (n == -1) { + err = ngx_errno; + + if (err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, file->log, err, + "pwritev() was interrupted"); + goto eintr; + } + + ngx_log_error(NGX_LOG_CRIT, file->log, err, + "pwritev() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + if ((size_t) n != size) { + ngx_log_error(NGX_LOG_CRIT, file->log, 0, + "pwritev() \"%s\" has written only %z of %uz", + file->name.data, n, size); + return NGX_ERROR; + } + +#else + + if (file->sys_offset != offset) { + if (lseek(file->fd, offset, SEEK_SET) == -1) { + ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, + "lseek() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + file->sys_offset = offset; + } + +eintr: + + n = writev(file->fd, vec->elts, vec->nelts); + + if (n == -1) { + err = ngx_errno; + + if (err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, file->log, err, + "writev() was interrupted"); + goto eintr; + } + + ngx_log_error(NGX_LOG_CRIT, file->log, err, + "writev() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + if ((size_t) n != size) { + ngx_log_error(NGX_LOG_CRIT, file->log, 0, + "writev() \"%s\" has written only %z of %uz", + file->name.data, n, size); + return NGX_ERROR; + } + + file->sys_offset += n; + +#endif + + file->offset += n; + + return n; +} + + ngx_int_t ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s) { diff --git a/src/os/unix/ngx_posix_init.c b/src/os/unix/ngx_posix_init.c index bf3a310..61cc8ca 100644 --- a/src/os/unix/ngx_posix_init.c +++ b/src/os/unix/ngx_posix_init.c @@ -63,7 +63,7 @@ ngx_os_init(ngx_log_t *log) if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, log, errno, - "getrlimit(RLIMIT_NOFILE) failed)"); + "getrlimit(RLIMIT_NOFILE) failed"); return NGX_ERROR; } From 2de69eb4943511047b082b2b60699f5e8292a7f7 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 14 Jan 2016 10:12:18 +0200 Subject: [PATCH 067/651] New upstream release (1.9.9) --- debian/changelog | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 3000163..897af34 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,9 +1,13 @@ -nginx (1.9.6-3) UNRELEASED; urgency=medium +nginx (1.9.9-1) UNRELEASED; urgency=medium + [ Michael Lustfield ] * debian/nginx-common.nginx.logrotate: + Switching logrotate to 14 days. (Closes: #805322) - -- Michael Lustfield Thu, 10 Dec 2015 04:07:29 -0600 + [ Christos Trochalakis ] + * New upstream release (1.9.9). + + -- Christos Trochalakis Thu, 14 Jan 2016 10:11:34 +0200 nginx (1.9.6-2) unstable; urgency=medium From 3ed34604605ae854620ec6b50acf942d7485190d Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 14 Jan 2016 10:11:18 +0200 Subject: [PATCH 068/651] Update nginx-lua to v0.10.0 --- debian/changelog | 2 + debian/modules/README.Modules-versions | 2 +- debian/modules/nginx-lua/README.markdown | 719 +++++++-- debian/modules/nginx-lua/config | 7 + .../modules/nginx-lua/doc/HttpLuaModule.wiki | 477 +++++- .../nginx-lua/src/api/ngx_http_lua_api.h | 2 +- .../nginx-lua/src/ngx_http_lua_accessby.c | 6 +- .../modules/nginx-lua/src/ngx_http_lua_args.c | 12 +- .../nginx-lua/src/ngx_http_lua_balancer.c | 607 ++++++++ .../nginx-lua/src/ngx_http_lua_balancer.h | 27 + .../nginx-lua/src/ngx_http_lua_bodyfilterby.c | 5 +- .../nginx-lua/src/ngx_http_lua_cache.c | 16 +- .../nginx-lua/src/ngx_http_lua_cache.h | 4 +- .../nginx-lua/src/ngx_http_lua_clfactory.c | 4 +- .../nginx-lua/src/ngx_http_lua_common.h | 70 +- .../nginx-lua/src/ngx_http_lua_consts.c | 51 + .../nginx-lua/src/ngx_http_lua_contentby.c | 7 +- .../nginx-lua/src/ngx_http_lua_contentby.h | 2 +- .../nginx-lua/src/ngx_http_lua_control.c | 71 +- .../nginx-lua/src/ngx_http_lua_coroutine.c | 14 +- .../nginx-lua/src/ngx_http_lua_directive.c | 77 +- .../nginx-lua/src/ngx_http_lua_directive.h | 3 + .../src/ngx_http_lua_headerfilterby.c | 4 +- .../nginx-lua/src/ngx_http_lua_headers.c | 10 +- .../nginx-lua/src/ngx_http_lua_headers_in.c | 42 +- .../nginx-lua/src/ngx_http_lua_headers_out.c | 2 +- .../nginx-lua/src/ngx_http_lua_logby.c | 6 +- .../modules/nginx-lua/src/ngx_http_lua_misc.c | 32 +- .../modules/nginx-lua/src/ngx_http_lua_misc.h | 2 + .../nginx-lua/src/ngx_http_lua_module.c | 169 +- .../nginx-lua/src/ngx_http_lua_output.c | 4 +- .../nginx-lua/src/ngx_http_lua_phase.c | 8 + .../nginx-lua/src/ngx_http_lua_regex.c | 20 +- .../nginx-lua/src/ngx_http_lua_req_body.c | 4 +- .../nginx-lua/src/ngx_http_lua_req_method.c | 6 +- .../nginx-lua/src/ngx_http_lua_rewriteby.c | 8 +- .../nginx-lua/src/ngx_http_lua_script.c | 2 +- .../nginx-lua/src/ngx_http_lua_semaphore.c | 546 +++++++ .../nginx-lua/src/ngx_http_lua_semaphore.h | 51 + .../nginx-lua/src/ngx_http_lua_shdict.c | 15 +- .../nginx-lua/src/ngx_http_lua_shdict.h | 1 + .../nginx-lua/src/ngx_http_lua_sleep.c | 5 +- .../nginx-lua/src/ngx_http_lua_socket_tcp.c | 184 +-- .../nginx-lua/src/ngx_http_lua_socket_tcp.h | 6 +- .../nginx-lua/src/ngx_http_lua_socket_udp.c | 10 +- .../nginx-lua/src/ngx_http_lua_socket_udp.h | 4 +- .../nginx-lua/src/ngx_http_lua_ssl_certby.c | 938 +++++++++++ .../nginx-lua/src/ngx_http_lua_ssl_certby.h | 47 + .../nginx-lua/src/ngx_http_lua_ssl_ocsp.c | 497 ++++++ .../nginx-lua/src/ngx_http_lua_string.c | 2 +- .../nginx-lua/src/ngx_http_lua_subrequest.c | 53 +- .../nginx-lua/src/ngx_http_lua_timer.c | 50 +- .../nginx-lua/src/ngx_http_lua_uthread.c | 6 +- .../modules/nginx-lua/src/ngx_http_lua_util.c | 166 +- .../modules/nginx-lua/src/ngx_http_lua_util.h | 22 +- .../nginx-lua/src/ngx_http_lua_variable.c | 8 +- .../nginx-lua/src/ngx_http_lua_worker.c | 58 +- debian/modules/nginx-lua/t/020-subrequest.t | 6 +- debian/modules/nginx-lua/t/022-redirect.t | 54 +- debian/modules/nginx-lua/t/028-req-header.t | 52 +- debian/modules/nginx-lua/t/056-flush.t | 2 +- debian/modules/nginx-lua/t/058-tcp-socket.t | 297 +++- debian/modules/nginx-lua/t/062-count.t | 18 +- debian/modules/nginx-lua/t/076-no-postpone.t | 64 +- debian/modules/nginx-lua/t/082-body-filter.t | 15 +- debian/modules/nginx-lua/t/129-ssl-socket.t | 18 +- debian/modules/nginx-lua/t/132-lua-blocks.t | 85 + debian/modules/nginx-lua/t/133-worker-count.t | 32 + .../modules/nginx-lua/t/134-worker-count-5.t | 32 + debian/modules/nginx-lua/t/135-worker-id.t | 33 + debian/modules/nginx-lua/t/136-timer-counts.t | 111 ++ debian/modules/nginx-lua/t/137-req-misc.t | 62 + debian/modules/nginx-lua/t/138-balancer.t | 304 ++++ debian/modules/nginx-lua/t/139-ssl-cert-by.t | 1382 +++++++++++++++++ debian/modules/nginx-lua/util/build2.sh | 8 +- 75 files changed, 7242 insertions(+), 506 deletions(-) create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_balancer.c create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_balancer.h create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_semaphore.h create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.h create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c create mode 100644 debian/modules/nginx-lua/t/133-worker-count.t create mode 100644 debian/modules/nginx-lua/t/134-worker-count-5.t create mode 100644 debian/modules/nginx-lua/t/135-worker-id.t create mode 100644 debian/modules/nginx-lua/t/136-timer-counts.t create mode 100644 debian/modules/nginx-lua/t/137-req-misc.t create mode 100644 debian/modules/nginx-lua/t/138-balancer.t create mode 100644 debian/modules/nginx-lua/t/139-ssl-cert-by.t diff --git a/debian/changelog b/debian/changelog index 897af34..bf298f1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -6,6 +6,8 @@ nginx (1.9.9-1) UNRELEASED; urgency=medium [ Christos Trochalakis ] * New upstream release (1.9.9). + * debian/modules/nginx-lua: + + Update nginx-lua to v0.10.0. -- Christos Trochalakis Thu, 14 Jan 2016 10:11:34 +0200 diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index 3690858..eb35054 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -22,7 +22,7 @@ README for Modules versions nginx-lua Homepage: https://github.com/openresty/lua-nginx-module - Version: v0.9.19 + Version: v0.10.0 nginx-upstream-fair Homepage: https://github.com/gnosek/nginx-upstream-fair diff --git a/debian/modules/nginx-lua/README.markdown b/debian/modules/nginx-lua/README.markdown index da06da6..64adc0e 100644 --- a/debian/modules/nginx-lua/README.markdown +++ b/debian/modules/nginx-lua/README.markdown @@ -61,7 +61,7 @@ Production ready. Version ======= -This document describes ngx_lua [v0.9.19](https://github.com/openresty/lua-nginx-module/tags) released on 11 November 2015. +This document describes ngx_lua [v0.10.0](https://github.com/openresty/lua-nginx-module/tags) released on 11 January 2015. Synopsis ======== @@ -241,19 +241,15 @@ The Lua state (Lua VM instance) is shared across all the requests handled by a s Nginx Compatibility =================== -The latest module is compatible with the following versions of Nginx: -* 1.9.x (last tested: 1.9.3) +The latest version of this module is compatible with the following versions of Nginx: + +* 1.9.x (last tested: 1.9.7) +* 1.8.x * 1.7.x (last tested: 1.7.10) * 1.6.x -* 1.5.x (last tested: 1.5.12) -* 1.4.x (last tested: 1.4.4) -* 1.3.x (last tested: 1.3.11) -* 1.2.x (last tested: 1.2.9) -* 1.1.x (last tested: 1.1.5) -* 1.0.x (last tested: 1.0.15) -* 0.9.x (last tested: 0.9.4) -* 0.8.x >= 0.8.54 (last tested: 0.8.54) + +Nginx cores older than 1.6.0 (exclusive) are *not* supported. [Back to TOC](#table-of-contents) @@ -273,9 +269,9 @@ Build the source with this module: ```bash - wget 'http://nginx.org/download/nginx-1.9.3.tar.gz' - tar -xzvf nginx-1.9.3.tar.gz - cd nginx-1.9.3/ + wget 'http://nginx.org/download/nginx-1.9.7.tar.gz' + tar -xzvf nginx-1.9.7.tar.gz + cd nginx-1.9.7/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib @@ -859,7 +855,6 @@ TODO } } ``` -* ssl: implement directives `ssl_certificate_by_lua` and `ssl_certificate_by_lua_file` to allow using Lua to dynamically serve SSL certificates and keys for downstream SSL handshake. (already done in CloudFlare's private branch and powering CloudFlare's SSL gateway of its global network. expected to be opensourced in March 2015.) * shm: implement a "shared queue API" to complement the existing [shared dict](#lua_shared_dict) API. * cosocket: add support in the context of [init_by_lua*](#init_by_lua). * cosocket: implement the `bind()` method for stream-typed cosockets. @@ -1028,7 +1023,11 @@ Directives * [log_by_lua](#log_by_lua) * [log_by_lua_block](#log_by_lua_block) * [log_by_lua_file](#log_by_lua_file) +* [balancer_by_lua_block](#balancer_by_lua_block) +* [balancer_by_lua_file](#balancer_by_lua_file) * [lua_need_request_body](#lua_need_request_body) +* [ssl_certificate_by_lua_block](#ssl_certificate_by_lua_block) +* [ssl_certificate_by_lua_file](#ssl_certificate_by_lua_file) * [lua_shared_dict](#lua_shared_dict) * [lua_socket_connect_timeout](#lua_socket_connect_timeout) * [lua_socket_send_timeout](#lua_socket_send_timeout) @@ -1045,6 +1044,7 @@ Directives * [lua_ssl_verify_depth](#lua_ssl_verify_depth) * [lua_http10_buffering](#lua_http10_buffering) * [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone) +* [access_by_lua_no_postpone](#access_by_lua_no_postpone) * [lua_transform_underscores_in_response_headers](#lua_transform_underscores_in_response_headers) * [lua_check_client_abort](#lua_check_client_abort) * [lua_max_pending_timers](#lua_max_pending_timers) @@ -1832,6 +1832,10 @@ As with other access phase handlers, [access_by_lua](#access_by_lua) will *not* Note that when calling `ngx.exit(ngx.OK)` within a [access_by_lua](#access_by_lua) handler, the nginx request processing control flow will still continue to the content handler. To terminate the current request from within a [access_by_lua](#access_by_lua) handler, calling [ngx.exit](#ngxexit) with status >= 200 (`ngx.HTTP_OK`) and status < 300 (`ngx.HTTP_SPECIAL_RESPONSE`) for successful quits and `ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)` (or its friends) for failures. +Starting from the `v0.9.20` release, you can use the [access_by_lua_no_postpone](#access_by_lua_no_postpone) +directive to control when to run this handler inside the "access" request-processing phase +of NGINX. + [Back to TOC](#directives) access_by_lua_block @@ -2212,6 +2216,83 @@ This directive was first introduced in the `v0.5.0rc31` release. [Back to TOC](#directives) +balancer_by_lua_block +--------------------- + +**syntax:** *balancer_by_lua_block { lua-script }* + +**context:** *upstream* + +**phase:** *content* + +This directive runs Lua code as an upstream balancer for any upstream entities defined +by the `upstream {}` configuration block. + +For instance, + +```nginx + + upstream foo { + server 127.0.0.1; + balancer_by_lua_block { + -- use Lua to do something interesting here + -- as a dynamic balancer + } + } + + server { + location / { + proxy_pass http://foo; + } + } +``` + +The resulting Lua load balancer can work with any existing nginx upstream modules +like [ngx_proxy](http://nginx.org/en/docs/http/ngx_http_proxy_module.html) and +[ngx_fastcgi](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html). + +Also, the Lua load balancer can work with the standard upstream connection pool mechanism, +i.e., the standard [keepalive](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive) directive. +Just ensure that the [keepalive](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive) directive +is used *after* this `balancer_by_lua_block` directive in a single `upstream {}` configuration block. + +The Lua load balancer can totally ignore the list of servers defined in the `upstream {}` block +and select peer from a completely dynamic server list (even changing per request) via the +[ngx.balancer](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md) module +from the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. + +The Lua code handler registered by this directive might get called more than once in a single +downstream request when the nginx upstream mechanism retries the request on conditions +specified by directives like the [proxy_next_upstream](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream) +directive. + +This Lua code execution context does not support yielding, so Lua APIs that may yield +(like cosockets and "light threads") are disabled in this context. One can usually work +around this limitation by doing such operations in an earlier phase handler (like +[access_by_lua*](#access_by_lua)) and passing along the result into this context +via the [ngx.ctx](#ngxctx) table. + +This directive was first introduced in the `v0.10.0` release. + +[Back to TOC](#directives) + +balancer_by_lua_file +-------------------- + +**syntax:** *balancer_by_lua_file <path-to-lua-script-file>* + +**context:** *upstream* + +**phase:** *content* + +Equivalent to [balancer_by_lua_block](#balancer_by_lua_block), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. + +When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. + +This directive was first introduced in the `v0.10.0` release. + +[Back to TOC](#directives) + lua_need_request_body --------------------- @@ -2240,6 +2321,112 @@ This also applies to [access_by_lua](#access_by_lua) and [access_by_lua_file](#a [Back to TOC](#directives) +ssl_certificate_by_lua_block +---------------------------- + +**syntax:** *ssl_certificate_by_lua_block { lua-script }* + +**context:** *server* + +**phase:** *right-before-SSL-handshake* + +This directive runs user Lua code when NGINX is about to start the SSL handshake for the downstream +SSL (https) connections. + +It is particularly useful for setting the SSL certificate chain and the corresponding private key on a per-request +basis. It is also useful to load such handshake configurations nonblockingly from the remote (for example, +with the [cosocket](#ngxsockettcp) API). And one can also do per-request OCSP stapling handling in pure +Lua here as well. + +Another typical use case is to do SSL handshake traffic control nonblockingly in this context, +with the help of the [lua-resty-limit-traffic#readme](https://github.com/openresty/lua-resty-limit-traffic) +library, for example. + +One can also do interesting things with the SSL handshake requests from the client side, like +rejecting old SSL clients using the SSLv3 protocol or even below selectively. + +The [ngx.ssl](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md) +and [ngx.ocsp](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md) Lua modules +provided by the [lua-resty-core](https://github.com/openresty/lua-resty-core/#readme) +library are particularly useful in this context. You can use the Lua API offered by these two Lua modules +to manipulate the SSL certificate chain and private key for the current SSL connection +being initiated. + +This Lua handler does not run at all, however, when NGINX/OpenSSL successfully resumes +the SSL session via SSL session IDs or TLS session tickets for the current SSL connection. In +other words, this Lua handler only runs when NGINX has to initiate a full SSL handshake. + +Below is a trivial example using the +[ngx.ssl](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md) module +at the same time: + +```nginx + + server { + listen 443 ssl; + server_name test.com; + + ssl_certificate_by_lua_block { + print("About to initiate a new SSL handshake!") + } + + location / { + root html; + } + } +``` + +See more complicated examples in the [ngx.ssl](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md) +and [ngx.ocsp](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md) +Lua modules' official documentation. + +Uncaught Lua exceptions in the user Lua code immediately abort the current SSL session, so does the +[ngx.exit](#ngxexit) call with an error code like `ngx.ERROR`. + +This Lua code execution context *does* support yielding, so Lua APIs that may yield +(like cosockets, sleeping, and "light threads") +are enabled in this context. + +Note, however, you still need to configure the [ssl_certificate](http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate) and +[ssl_certificate_key](http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate_key) +directives even though you will not use this static certificate and private key at all. This is +because the NGINX core requires their appearance otherwise you are seeing the following error +while starting NGINX: + + + nginx: [emerg] no ssl configured for the server + + +This directive currently requires the following NGINX core patch to work correctly: + + + +The bundled version of the NGINX core in OpenResty 1.9.7.2 (or above) already has this +patch applied. + +Furthermore, one needs at least OpenSSL 1.0.2e for this directive to work. + +This directive was first introduced in the `v0.10.0` release. + +[Back to TOC](#directives) + +ssl_certificate_by_lua_file +--------------------------- + +**syntax:** *ssl_certificate_by_lua_file <path-to-lua-script-file>* + +**context:** *server* + +**phase:** *right-before-SSL-handshake* + +Equivalent to [ssl_certificate_by_lua_block](#ssl_certificate_by_lua_block), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. + +When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. + +This directive was first introduced in the `v0.10.0` release. + +[Back to TOC](#directives) + lua_shared_dict --------------- @@ -2265,6 +2452,9 @@ The `` argument accepts size units such as `k` and `m`: } ``` +The hard-coded minimum size is 8KB while the practical minimum size depends +on actual user data set (some people start with 12KB). + See [ngx.shared.DICT](#ngxshareddict) for details. This directive was first introduced in the `v0.3.1rc22` release. @@ -2518,12 +2708,27 @@ rewrite_by_lua_no_postpone **context:** *http* -Controls whether or not to disable postponing [rewrite_by_lua](#rewrite_by_lua) and [rewrite_by_lua_file](#rewrite_by_lua_file) directives to run at the end of the `rewrite` request-processing phase. By default, this directive is turned off and the Lua code is postponed to run at the end of the `rewrite` phase. +Controls whether or not to disable postponing [rewrite_by_lua](#rewrite_by_lua)* directives to run at the end of the `rewrite` request-processing phase. By default, this directive is turned off and the Lua code is postponed to run at the end of the `rewrite` phase. This directive was first introduced in the `v0.5.0rc29` release. [Back to TOC](#directives) +access_by_lua_no_postpone +------------------------- + +**syntax:** *access_by_lua_no_postpone on|off* + +**default:** *access_by_lua_no_postpone off* + +**context:** *http* + +Controls whether or not to disable postponing [access_by_lua](#access_by_lua)* directives to run at the end of the `access` request-processing phase. By default, this directive is turned off and the Lua code is postponed to run at the end of the `access` phase. + +This directive was first introduced in the `v0.9.20` release. + +[Back to TOC](#directives) + lua_transform_underscores_in_response_headers --------------------------------------------- @@ -2629,6 +2834,7 @@ Nginx API for Lua * [ngx.status](#ngxstatus) * [ngx.header.HEADER](#ngxheaderheader) * [ngx.resp.get_headers](#ngxrespget_headers) +* [ngx.req.is_internal](#ngxreqis_internal) * [ngx.req.start_time](#ngxreqstart_time) * [ngx.req.http_version](#ngxreqhttp_version) * [ngx.req.raw_header](#ngxreqraw_header) @@ -2727,6 +2933,8 @@ Nginx API for Lua * [ngx.thread.kill](#ngxthreadkill) * [ngx.on_abort](#ngxon_abort) * [ngx.timer.at](#ngxtimerat) +* [ngx.timer.running_count](#ngxtimerrunning_count) +* [ngx.timer.pending_count](#ngxtimerpending_count) * [ngx.config.debug](#ngxconfigdebug) * [ngx.config.prefix](#ngxconfigprefix) * [ngx.config.nginx_version](#ngxconfignginx_version) @@ -2734,6 +2942,12 @@ Nginx API for Lua * [ngx.config.ngx_lua_version](#ngxconfigngx_lua_version) * [ngx.worker.exiting](#ngxworkerexiting) * [ngx.worker.pid](#ngxworkerpid) +* [ngx.worker.count](#ngxworkercount) +* [ngx.worker.id](#ngxworkerid) +* [ngx.semaphore](#ngxsemaphore) +* [ngx.balancer](#ngxbalancer) +* [ngx.ssl](#ngxssl) +* [ngx.ocsp](#ngxocsp) * [ndk.set_var.DIRECTIVE](#ndkset_vardirective) * [coroutine.create](#coroutinecreate) * [coroutine.resume](#coroutineresume) @@ -2786,7 +3000,7 @@ ngx.arg ------- **syntax:** *val = ngx.arg\[index\]* -**context:** *set_by_lua*, body_filter_by_lua** +**context:** *set_by_lua*, body_filter_by_lua** When this is used in the context of the [set_by_lua](#set_by_lua) or [set_by_lua_file](#set_by_lua_file) directives, this table is read-only and holds the input arguments to the config directives: @@ -2823,7 +3037,7 @@ ngx.var.VARIABLE ---------------- **syntax:** *ngx.var.VAR_NAME* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** Read and write Nginx variable values. @@ -2880,7 +3094,7 @@ This API requires a relatively expensive metamethod call and it is recommended t Core constants -------------- -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, *log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, *log_by_lua*, ngx.timer.** ```lua @@ -2906,7 +3120,7 @@ The `ngx.DECLINED` constant was first introduced in the `v0.5.0rc19` release. HTTP method constants --------------------- -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** ngx.HTTP_GET @@ -2932,34 +3146,51 @@ These constants are usually used in [ngx.location.capture](#ngxlocationcapture) HTTP status constants --------------------- -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** ```nginx + value = ngx.HTTP_CONTINUE (100) (first added in the v0.9.20 release) + value = ngx.HTTP_SWITCHING_PROTOCOLS (101) (first added in the v0.9.20 release) value = ngx.HTTP_OK (200) value = ngx.HTTP_CREATED (201) + value = ngx.HTTP_ACCEPTED (202) (first added in the v0.9.20 release) + value = ngx.HTTP_NO_CONTENT (204) (first added in the v0.9.20 release) + value = ngx.HTTP_PARTIAL_CONTENT (206) (first added in the v0.9.20 release) value = ngx.HTTP_SPECIAL_RESPONSE (300) value = ngx.HTTP_MOVED_PERMANENTLY (301) value = ngx.HTTP_MOVED_TEMPORARILY (302) value = ngx.HTTP_SEE_OTHER (303) value = ngx.HTTP_NOT_MODIFIED (304) + value = ngx.HTTP_TEMPORARY_REDIRECT (307) (first added in the v0.9.20 release) value = ngx.HTTP_BAD_REQUEST (400) value = ngx.HTTP_UNAUTHORIZED (401) + value = ngx.HTTP_PAYMENT_REQUIRED (402) (first added in the v0.9.20 release) value = ngx.HTTP_FORBIDDEN (403) value = ngx.HTTP_NOT_FOUND (404) value = ngx.HTTP_NOT_ALLOWED (405) + value = ngx.HTTP_NOT_ACCEPTABLE (406) (first added in the v0.9.20 release) + value = ngx.HTTP_REQUEST_TIMEOUT (408) (first added in the v0.9.20 release) + value = ngx.HTTP_CONFLICT (409) (first added in the v0.9.20 release) value = ngx.HTTP_GONE (410) + value = ngx.HTTP_UPGRADE_REQUIRED (426) (first added in the v0.9.20 release) + value = ngx.HTTP_TOO_MANY_REQUESTS (429) (first added in the v0.9.20 release) + value = ngx.HTTP_CLOSE (444) (first added in the v0.9.20 release) + value = ngx.HTTP_ILLEGAL (451) (first added in the v0.9.20 release) value = ngx.HTTP_INTERNAL_SERVER_ERROR (500) value = ngx.HTTP_METHOD_NOT_IMPLEMENTED (501) + value = ngx.HTTP_BAD_GATEWAY (502) (first added in the v0.9.20 release) value = ngx.HTTP_SERVICE_UNAVAILABLE (503) value = ngx.HTTP_GATEWAY_TIMEOUT (504) (first added in the v0.3.1rc38 release) + value = ngx.HTTP_VERSION_NOT_SUPPORTED (505) (first added in the v0.9.20 release) + value = ngx.HTTP_INSUFFICIENT_STORAGE (507) (first added in the v0.9.20 release) ``` [Back to TOC](#nginx-api-for-lua) Nginx log level constants ------------------------- -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** ```lua @@ -2982,7 +3213,7 @@ print ----- **syntax:** *print(...)* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, certificate_by_lua** Writes argument values into the nginx `error.log` file with the `ngx.NOTICE` log level. @@ -3001,7 +3232,7 @@ There is a hard coded `2048` byte limitation on error message lengths in the Ngi ngx.ctx ------- -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua** This table can be used to store per-request Lua context data and has a life time identical to the current request (as with the Nginx variables). @@ -3104,7 +3335,42 @@ Overriding `ngx.ctx` with a new Lua table is also supported, for example, When being used in the context of [init_worker_by_lua*](#init_worker_by_lua), this table just has the same lifetime of the current Lua handler. -The `ngx.ctx` lookup requires relatively expensive metamethod calls and it is much slower than explicitly passing per-request data along by your own function arguments. So do not abuse this API for saving your own function arguments because it usually has quite some performance impact. And because of the metamethod magic, never "local" the `ngx.ctx` table outside your function scope. +The `ngx.ctx` lookup requires relatively expensive metamethod calls and it is much slower than explicitly passing per-request data along by your own function arguments. So do not abuse this API for saving your own function arguments because it usually has quite some performance impact. + +Because of the metamethod magic, never "local" the `ngx.ctx` table outside your Lua function scope on the Lua module level level due to [worker-level data sharing](#data-sharing-within-an-nginx-worker). For example, the following is bad: + +```lua + + -- mymodule.lua + local _M = {} + + -- the following line is bad since ngx.ctx is a per-request + -- data while this `ctx` variable is on the Lua module level + -- and thus is per-nginx-worker. + local ctx = ngx.ctx + + function _M.main() + ctx.foo = "bar" + end + + return _M +``` + +Use the following instead: + +```lua + + -- mymodule.lua + local _M = {} + + function _M.main(ctx) + ctx.foo = "bar" + end + + return _M +``` + +That is, let the caller pass the `ctx` table explicitly via a function argument. [Back to TOC](#nginx-api-for-lua) @@ -3112,9 +3378,9 @@ ngx.location.capture -------------------- **syntax:** *res = ngx.location.capture(uri, options?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** -Issue a synchronous but still non-blocking *Nginx Subrequest* using `uri`. +Issues a synchronous but still non-blocking *Nginx Subrequest* using `uri`. Nginx's subrequests provide a powerful way to make non-blocking internal requests to other locations configured with disk file directory or *any* other nginx C modules like `ngx_proxy`, `ngx_fastcgi`, `ngx_memc`, `ngx_postgres`, `ngx_drizzle`, and even ngx_lua itself and etc etc etc. @@ -3125,6 +3391,9 @@ Subrequests are completely different from HTTP 301/302 redirection (via [ngx.red You should always read the request body (by either calling [ngx.req.read_body](#ngxreqread_body) or configuring [lua_need_request_body](#lua_need_request_body) on) before initiating a subrequest. +This API function (as well as [ngx.location.capture_multi](#ngxlocationcapture_multi)) always buffers the whole response body of the subrequest in memory. Thus, you should use [cosockets](#ngxsockettcp) +and streaming processing instead if you have to handle large subrequest responses. + Here is a basic example: ```lua @@ -3401,7 +3670,7 @@ ngx.location.capture_multi -------------------------- **syntax:** *res1, res2, ... = ngx.location.capture_multi({ {uri, options?}, {uri, options?}, ... })* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Just like [ngx.location.capture](#ngxlocationcapture), but supports multiple subrequests running in parallel. @@ -3464,7 +3733,7 @@ Please also refer to restrictions on capturing locations configured by [subreque ngx.status ---------- -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** Read and write the current request's response status. This should be called before sending out the response headers. @@ -3489,7 +3758,7 @@ ngx.header.HEADER **syntax:** *value = ngx.header.HEADER* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** Set, add to, or clear the current request's `HEADER` response header that is to be sent. @@ -3601,7 +3870,7 @@ ngx.resp.get_headers -------------------- **syntax:** *headers = ngx.resp.get_headers(max_headers?, raw?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, balancer_by_lua** Returns a Lua table holding all the current response headers for the current request. @@ -3619,11 +3888,26 @@ This API was first introduced in the `v0.9.5` release. [Back to TOC](#nginx-api-for-lua) +ngx.req.is_internal +------------------- +**syntax:** *is_internal = ngx.req.is_internal()* + +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + +Returns a boolean indicating whether the current request is an "internal request", i.e., +a request initiated from inside the current nginx server instead of from the client side. + +Subrequests are all internal requests and so are requests after internal redirects. + +This API was first introduced in the `v0.9.20` release. + +[Back to TOC](#nginx-api-for-lua) + ngx.req.start_time ------------------ **syntax:** *secs = ngx.req.start_time()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** Returns a floating-point number representing the timestamp (including milliseconds as the decimal part) when the current request was created. @@ -3644,7 +3928,7 @@ ngx.req.http_version -------------------- **syntax:** *num = ngx.req.http_version()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua** Returns the HTTP version number for the current request as a Lua number. @@ -3658,7 +3942,7 @@ ngx.req.raw_header ------------------ **syntax:** *str = ngx.req.raw_header(no_request_line?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua** Returns the original raw HTTP protocol header received by the Nginx server. @@ -3704,7 +3988,7 @@ ngx.req.get_method ------------------ **syntax:** *method_name = ngx.req.get_method()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, balancer_by_lua** Retrieves the current request's request method name. Strings like `"GET"` and `"POST"` are returned instead of numerical [method constants](#http-method-constants). @@ -3720,7 +4004,7 @@ ngx.req.set_method ------------------ **syntax:** *ngx.req.set_method(method_id)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua** Overrides the current request's request method with the `method_id` argument. Currently only numerical [method constants](#http-method-constants) are supported, like `ngx.HTTP_POST` and `ngx.HTTP_GET`. @@ -3736,7 +4020,7 @@ ngx.req.set_uri --------------- **syntax:** *ngx.req.set_uri(uri, jump?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua** Rewrite the current request's (parsed) URI by the `uri` argument. The `uri` argument must be a Lua string and cannot be of zero length, or a Lua exception will be thrown. @@ -3835,7 +4119,7 @@ ngx.req.set_uri_args -------------------- **syntax:** *ngx.req.set_uri_args(args)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua** Rewrite the current request's URI query arguments by the `args` argument. The `args` argument can be either a Lua string, as in @@ -3872,7 +4156,7 @@ ngx.req.get_uri_args -------------------- **syntax:** *args = ngx.req.get_uri_args(max_args?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, balancer_by_lua** Returns a Lua table holding all the current request URL query arguments. @@ -3968,7 +4252,7 @@ ngx.req.get_post_args --------------------- **syntax:** *args, err = ngx.req.get_post_args(max_args?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** Returns a Lua table holding all the current request POST query arguments (of the MIME type `application/x-www-form-urlencoded`). Call [ngx.req.read_body](#ngxreqread_body) to read the request body first or turn on the [lua_need_request_body](#lua_need_request_body) directive to avoid errors. @@ -4070,7 +4354,7 @@ ngx.req.get_headers ------------------- **syntax:** *headers = ngx.req.get_headers(max_headers?, raw?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** Returns a Lua table holding all the current request headers. @@ -4144,7 +4428,7 @@ ngx.req.set_header ------------------ **syntax:** *ngx.req.set_header(header_name, header_value)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua* +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua* Set the current request's request header named `header_name` to value `header_value`, overriding any existing ones. @@ -4195,7 +4479,7 @@ ngx.req.clear_header -------------------- **syntax:** *ngx.req.clear_header(header_name)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua** Clears the current request's request header named `header_name`. None of the current request's existing subrequests will be affected but subsequently initiated subrequests will inherit the change by default. @@ -4205,7 +4489,7 @@ ngx.req.read_body ----------------- **syntax:** *ngx.req.read_body()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Reads the client request body synchronously without blocking the Nginx event loop. @@ -4236,7 +4520,7 @@ ngx.req.discard_body -------------------- **syntax:** *ngx.req.discard_body()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Explicitly discard the request body, i.e., read the data on the connection and throw it away immediately. Please note that ignoring request body is not the right way to discard it, and that this function must be called to avoid breaking things under HTTP 1.1 keepalive or HTTP 1.1 pipelining. @@ -4254,7 +4538,7 @@ ngx.req.get_body_data --------------------- **syntax:** *data = ngx.req.get_body_data()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Retrieves in-memory request body data. It returns a Lua string rather than a Lua table holding all the parsed query arguments. Use the [ngx.req.get_post_args](#ngxreqget_post_args) function instead if a Lua table is required. @@ -4282,7 +4566,7 @@ ngx.req.get_body_file --------------------- **syntax:** *file_name = ngx.req.get_body_file()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Retrieves the file name for the in-file request body data. Returns `nil` if the request body has not been read or has been read into memory. @@ -4304,7 +4588,7 @@ ngx.req.set_body_data --------------------- **syntax:** *ngx.req.set_body_data(data)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Set the current request's request body using the in-memory data specified by the `data` argument. @@ -4320,7 +4604,7 @@ ngx.req.set_body_file --------------------- **syntax:** *ngx.req.set_body_file(file_name, auto_clean?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Set the current request's request body using the in-file data specified by the `file_name` argument. @@ -4340,7 +4624,7 @@ ngx.req.init_body ----------------- **syntax:** *ngx.req.init_body(buffer_size?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua** Creates a new blank request body for the current request and inializes the buffer for later request body data writing via the [ngx.req.append_body](#ngxreqappend_body) and [ngx.req.finish_body](#ngxreqfinish_body) APIs. @@ -4371,7 +4655,7 @@ ngx.req.append_body ------------------- **syntax:** *ngx.req.append_body(data_chunk)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua** Append new data chunk specified by the `data_chunk` argument onto the existing request body created by the [ngx.req.init_body](#ngxreqinit_body) call. @@ -4391,7 +4675,7 @@ ngx.req.finish_body ------------------- **syntax:** *ngx.req.finish_body()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua** Completes the construction process of the new request body created by the [ngx.req.init_body](#ngxreqinit_body) and [ngx.req.append_body](#ngxreqappend_body) calls. @@ -4409,7 +4693,7 @@ ngx.req.socket **syntax:** *tcpsock, err = ngx.req.socket(raw)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Returns a read-only cosocket object that wraps the downstream connection. Only [receive](#tcpsockreceive) and [receiveuntil](#tcpsockreceiveuntil) methods are supported on this object. @@ -4434,7 +4718,7 @@ ngx.exec -------- **syntax:** *ngx.exec(uri, args?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Does an internal redirect to `uri` with `args` and is similar to the [echo_exec](http://github.com/openresty/echo-nginx-module#echo_exec) directive of the [echo-nginx-module](http://github.com/openresty/echo-nginx-module). @@ -4501,7 +4785,7 @@ ngx.redirect ------------ **syntax:** *ngx.redirect(uri, status?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Issue an `HTTP 301` or `302` redirection to `uri`. @@ -4583,7 +4867,7 @@ ngx.send_headers ---------------- **syntax:** *ok, err = ngx.send_headers()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Explicitly send out the response headers. @@ -4598,7 +4882,7 @@ ngx.headers_sent ---------------- **syntax:** *value = ngx.headers_sent* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua** Returns `true` if the response headers have been sent (by ngx_lua), and `false` otherwise. @@ -4610,7 +4894,7 @@ ngx.print --------- **syntax:** *ok, err = ngx.print(...)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Emits arguments concatenated to the HTTP client (as response body). If response headers have not been sent, this function will send headers out first and then output body data. @@ -4651,7 +4935,7 @@ ngx.say ------- **syntax:** *ok, err = ngx.say(...)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Just as [ngx.print](#ngxprint) but also emit a trailing newline. @@ -4661,7 +4945,7 @@ ngx.log ------- **syntax:** *ngx.log(log_level, ...)* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Log arguments concatenated to error.log with the given logging level. @@ -4677,7 +4961,7 @@ ngx.flush --------- **syntax:** *ok, err = ngx.flush(wait?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Flushes response output to the client. @@ -4697,7 +4981,7 @@ ngx.exit -------- **syntax:** *ngx.exit(status)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** When `status >= 200` (i.e., `ngx.HTTP_OK` and above), it will interrupt the execution of the current request and return status code to nginx. @@ -4750,7 +5034,7 @@ ngx.eof ------- **syntax:** *ok, err = ngx.eof()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Explicitly specify the end of the response output stream. In the case of HTTP 1.1 chunked encoded output, it will just trigger the Nginx core to send out the "last chunk". @@ -4785,7 +5069,7 @@ ngx.sleep --------- **syntax:** *ngx.sleep(seconds)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** Sleeps for the specified seconds without blocking. One can specify time resolution up to 0.001 seconds (i.e., one milliseconds). @@ -4801,7 +5085,7 @@ ngx.escape_uri -------------- **syntax:** *newstr = ngx.escape_uri(str)* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Escape `str` as a URI component. @@ -4811,7 +5095,7 @@ ngx.unescape_uri ---------------- **syntax:** *newstr = ngx.unescape_uri(str)* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Unescape `str` as an escaped URI component. @@ -4834,7 +5118,7 @@ ngx.encode_args --------------- **syntax:** *str = ngx.encode_args(table)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Encode the Lua table to a query args string according to the URI encoded rules. @@ -4891,7 +5175,7 @@ ngx.decode_args --------------- **syntax:** *table = ngx.decode_args(str, max_args?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Decodes a URI encoded query-string into a Lua table. This is the inverse function of [ngx.encode_args](#ngxencode_args). @@ -4914,7 +5198,7 @@ ngx.encode_base64 ----------------- **syntax:** *newstr = ngx.encode_base64(str, no_padding?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Encodes `str` to a base64 digest. @@ -4926,7 +5210,7 @@ ngx.decode_base64 ----------------- **syntax:** *newstr = ngx.decode_base64(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Decodes the `str` argument as a base64 digest to the raw form. Returns `nil` if `str` is not well formed. @@ -4936,7 +5220,7 @@ ngx.crc32_short --------------- **syntax:** *intval = ngx.crc32_short(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Calculates the CRC-32 (Cyclic Redundancy Code) digest for the `str` argument. @@ -4952,7 +5236,7 @@ ngx.crc32_long -------------- **syntax:** *intval = ngx.crc32_long(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Calculates the CRC-32 (Cyclic Redundancy Code) digest for the `str` argument. @@ -4968,7 +5252,7 @@ ngx.hmac_sha1 ------------- **syntax:** *digest = ngx.hmac_sha1(secret_key, str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Computes the [HMAC-SHA1](http://en.wikipedia.org/wiki/HMAC) digest of the argument `str` and turns the result using the secret key ``. @@ -5000,7 +5284,7 @@ ngx.md5 ------- **syntax:** *digest = ngx.md5(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the hexadecimal representation of the MD5 digest of the `str` argument. @@ -5027,7 +5311,7 @@ ngx.md5_bin ----------- **syntax:** *digest = ngx.md5_bin(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the binary form of the MD5 digest of the `str` argument. @@ -5039,7 +5323,7 @@ ngx.sha1_bin ------------ **syntax:** *digest = ngx.sha1_bin(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the binary form of the SHA-1 digest of the `str` argument. @@ -5053,7 +5337,7 @@ ngx.quote_sql_str ----------------- **syntax:** *quoted_value = ngx.quote_sql_str(raw_value)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns a quoted SQL string literal according to the MySQL quoting rules. @@ -5063,7 +5347,7 @@ ngx.today --------- **syntax:** *str = ngx.today()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns current date (in the format `yyyy-mm-dd`) from the nginx cached time (no syscall involved unlike Lua's date library). @@ -5075,7 +5359,7 @@ ngx.time -------- **syntax:** *secs = ngx.time()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the elapsed seconds from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -5087,7 +5371,7 @@ ngx.now ------- **syntax:** *secs = ngx.now()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns a floating-point number for the elapsed time in seconds (including milliseconds as the decimal part) from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -5101,7 +5385,7 @@ ngx.update_time --------------- **syntax:** *ngx.update_time()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Forcibly updates the Nginx current time cache. This call involves a syscall and thus has some overhead, so do not abuse it. @@ -5113,7 +5397,7 @@ ngx.localtime ------------- **syntax:** *str = ngx.localtime()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the current time stamp (in the format `yyyy-mm-dd hh:mm:ss`) of the nginx cached time (no syscall involved unlike Lua's [os.date](http://www.lua.org/manual/5.1/manual.html#pdf-os.date) function). @@ -5125,7 +5409,7 @@ ngx.utctime ----------- **syntax:** *str = ngx.utctime()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the current time stamp (in the format `yyyy-mm-dd hh:mm:ss`) of the nginx cached time (no syscall involved unlike Lua's [os.date](http://www.lua.org/manual/5.1/manual.html#pdf-os.date) function). @@ -5137,7 +5421,7 @@ ngx.cookie_time --------------- **syntax:** *str = ngx.cookie_time(sec)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns a formatted string can be used as the cookie expiration time. The parameter `sec` is the time stamp in seconds (like those returned from [ngx.time](#ngxtime)). @@ -5153,7 +5437,7 @@ ngx.http_time ------------- **syntax:** *str = ngx.http_time(sec)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns a formated string can be used as the http header time (for example, being used in `Last-Modified` header). The parameter `sec` is the time stamp in seconds (like those returned from [ngx.time](#ngxtime)). @@ -5169,7 +5453,7 @@ ngx.parse_http_time ------------------- **syntax:** *sec = ngx.parse_http_time(str)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Parse the http time string (as returned by [ngx.http_time](#ngxhttp_time)) into seconds. Returns the seconds or `nil` if the input string is in bad forms. @@ -5187,7 +5471,7 @@ ngx.is_subrequest ----------------- **syntax:** *value = ngx.is_subrequest* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** Returns `true` if the current request is an nginx subrequest, or `false` otherwise. @@ -5197,7 +5481,7 @@ ngx.re.match ------------ **syntax:** *captures, err = ngx.re.match(subject, regex, options?, ctx?, res_table?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Matches the `subject` string using the Perl compatible regular expression `regex` with the optional `options`. @@ -5355,7 +5639,7 @@ ngx.re.find ----------- **syntax:** *from, to, err = ngx.re.find(subject, regex, options?, ctx?, nth?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Similar to [ngx.re.match](#ngxrematch) but only returns the begining index (`from`) and end index (`to`) of the matched substring. The returned indexes are 1-based and can be fed directly into the [string.sub](http://www.lua.org/manual/5.1/manual.html#pdf-string.sub) API function to obtain the matched substring. @@ -5409,7 +5693,7 @@ ngx.re.gmatch ------------- **syntax:** *iterator, err = ngx.re.gmatch(subject, regex, options?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Similar to [ngx.re.match](#ngxrematch), but returns a Lua iterator instead, so as to let the user programmer iterate all the matches over the `` string argument with the PCRE `regex`. @@ -5487,7 +5771,7 @@ ngx.re.sub ---------- **syntax:** *newstr, n, err = ngx.re.sub(subject, regex, replace, options?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Substitutes the first match of the Perl compatible regular expression `regex` on the `subject` argument string with the string or function argument `replace`. The optional `options` argument has exactly the same meaning as in [ngx.re.match](#ngxrematch). @@ -5553,7 +5837,7 @@ ngx.re.gsub ----------- **syntax:** *newstr, n, err = ngx.re.gsub(subject, regex, replace, options?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Just like [ngx.re.sub](#ngxresub), but does global substitution. @@ -5593,7 +5877,7 @@ ngx.shared.DICT **syntax:** *dict = ngx.shared\[name_var\]* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Fetching the shm-based Lua dictionary object for the shared memory zone named `DICT` defined by the [lua_shared_dict](#lua_shared_dict) directive. @@ -5666,7 +5950,7 @@ ngx.shared.DICT.get ------------------- **syntax:** *value, flags = ngx.shared.DICT:get(key)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Retrieving the value in the dictionary [ngx.shared.DICT](#ngxshareddict) for the key `key`. If the key does not exist or has been expired, then `nil` will be returned. @@ -5704,7 +5988,7 @@ ngx.shared.DICT.get_stale ------------------------- **syntax:** *value, flags, stale = ngx.shared.DICT:get_stale(key)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Similar to the [get](#ngxshareddictget) method but returns the value even if the key has already expired. @@ -5722,7 +6006,7 @@ ngx.shared.DICT.set ------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:set(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Unconditionally sets a key-value pair into the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). Returns three values: @@ -5732,7 +6016,7 @@ Unconditionally sets a key-value pair into the shm-based dictionary [ngx.shared. The `value` argument inserted can be Lua booleans, numbers, strings, or `nil`. Their value type will also be stored into the dictionary and the same data type can be retrieved later via the [get](#ngxshareddictget) method. -The optional `exptime` argument specifies expiration time (in seconds) for the inserted key-value pair. The time resolution is `0.001` seconds. If the `exptime` takes the value `0` (which is the default), then the item will never be expired. +The optional `exptime` argument specifies expiration time (in seconds) for the inserted key-value pair. The time resolution is `0.001` seconds. If the `exptime` takes the value `0` (which is the default), then the item will never expire. The optional `flags` argument specifies a user flags value associated with the entry to be stored. It can also be retrieved later with the value. The user flags is stored as an unsigned 32-bit integer internally. Defaults to `0`. The user flags argument was first introduced in the `v0.5.0rc2` release. @@ -5770,7 +6054,7 @@ ngx.shared.DICT.safe_set ------------------------ **syntax:** *ok, err = ngx.shared.DICT:safe_set(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Similar to the [set](#ngxshareddictset) method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return `nil` and the string "no memory". @@ -5784,7 +6068,7 @@ ngx.shared.DICT.add ------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:add(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Just like the [set](#ngxshareddictset) method, but only stores the key-value pair into the dictionary [ngx.shared.DICT](#ngxshareddict) if the key does *not* exist. @@ -5800,7 +6084,7 @@ ngx.shared.DICT.safe_add ------------------------ **syntax:** *ok, err = ngx.shared.DICT:safe_add(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Similar to the [add](#ngxshareddictadd) method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return `nil` and the string "no memory". @@ -5814,7 +6098,7 @@ ngx.shared.DICT.replace ----------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:replace(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Just like the [set](#ngxshareddictset) method, but only stores the key-value pair into the dictionary [ngx.shared.DICT](#ngxshareddict) if the key *does* exist. @@ -5830,7 +6114,7 @@ ngx.shared.DICT.delete ---------------------- **syntax:** *ngx.shared.DICT:delete(key)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Unconditionally removes the key-value pair from the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). @@ -5846,7 +6130,7 @@ ngx.shared.DICT.incr -------------------- **syntax:** *newval, err = ngx.shared.DICT:incr(key, value)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Increments the (numerical) value for `key` in the shm-based dictionary [ngx.shared.DICT](#ngxshareddict) by the step value `value`. Returns the new resulting number if the operation is successfully completed or `nil` and an error message otherwise. @@ -5866,7 +6150,7 @@ ngx.shared.DICT.flush_all ------------------------- **syntax:** *ngx.shared.DICT:flush_all()* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Flushes out all the items in the dictionary. This method does not actuall free up all the memory blocks in the dictionary but just marks all the existing items as expired. @@ -5880,7 +6164,7 @@ ngx.shared.DICT.flush_expired ----------------------------- **syntax:** *flushed = ngx.shared.DICT:flush_expired(max_count?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Flushes out the expired items in the dictionary, up to the maximal number specified by the optional `max_count` argument. When the `max_count` argument is given `0` or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. @@ -5896,7 +6180,7 @@ ngx.shared.DICT.get_keys ------------------------ **syntax:** *keys = ngx.shared.DICT:get_keys(max_count?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Fetch a list of the keys from the dictionary, up to ``. @@ -5912,7 +6196,7 @@ ngx.socket.udp -------------- **syntax:** *udpsock = ngx.socket.udp()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** Creates and returns a UDP or datagram-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: @@ -5936,7 +6220,7 @@ udpsock:setpeername **syntax:** *ok, err = udpsock:setpeername("unix:/path/to/unix-domain.socket")* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** Attempts to connect a UDP socket object to a remote server or to a datagram unix domain socket file. Because the datagram protocol is actually connection-less, this method does not really establish a "connection", but only just set the name of the remote peer for subsequent read/write operations. @@ -5995,7 +6279,7 @@ udpsock:send ------------ **syntax:** *ok, err = udpsock:send(data)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** Sends data on the current UDP or datagram unix domain socket object. @@ -6011,7 +6295,7 @@ udpsock:receive --------------- **syntax:** *data, err = udpsock:receive(size?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** Receives data from the UDP or datagram unix domain socket object with an optional receive buffer size argument, `size`. @@ -6046,7 +6330,7 @@ udpsock:close ------------- **syntax:** *ok, err = udpsock:close()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** Closes the current UDP or datagram unix domain socket. It returns the `1` in case of success and returns `nil` with a string describing the error otherwise. @@ -6060,7 +6344,7 @@ udpsock:settimeout ------------------ **syntax:** *udpsock:settimeout(time)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** Set the timeout value in milliseconds for subsequent socket operations (like [receive](#udpsockreceive)). @@ -6074,7 +6358,7 @@ ngx.socket.tcp -------------- **syntax:** *tcpsock = ngx.socket.tcp()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: @@ -6120,7 +6404,7 @@ tcpsock:connect **syntax:** *ok, err = tcpsock:connect("unix:/path/to/unix-domain.socket", options_table?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** Attempts to connect a TCP socket object to a remote server or to a stream unix domain socket file without blocking. @@ -6197,9 +6481,9 @@ This method was first introduced in the `v0.5.0rc1` release. tcpsock:sslhandshake -------------------- -**syntax:** *session, err = tcpsock:sslhandshake(reused_session?, server_name?, ssl_verify?)* +**syntax:** *session, err = tcpsock:sslhandshake(reused_session?, server_name?, ssl_verify?, send_status_req?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** Does SSL/TLS handshake on the currently established connection. @@ -6230,6 +6514,9 @@ Also, when the `ssl_verify` argument is true and the `server_name` argument is also specified, the latter will be used to validate the server name in the server certificate. +The optional `send_status_req` argument takes a boolean that controls whether to send +the OCSP status request in the SSL handshake request (which is for requesting OCSP stapling). + For connections that have already done SSL/TLS handshake, this method returns immediately. @@ -6241,7 +6528,7 @@ tcpsock:send ------------ **syntax:** *bytes, err = tcpsock:send(data)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** Sends data without blocking on the current TCP or Unix Domain Socket connection. @@ -6273,7 +6560,7 @@ tcpsock:receive **syntax:** *data, err, partial = tcpsock:receive(pattern?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** Receives data from the connected socket according to the reading pattern or size. @@ -6315,7 +6602,7 @@ tcpsock:receiveuntil -------------------- **syntax:** *iterator = tcpsock:receiveuntil(pattern, options?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** This method returns an iterator Lua function that can be called to read the data stream until it sees the specified pattern or an error occurs. @@ -6414,7 +6701,7 @@ tcpsock:close ------------- **syntax:** *ok, err = tcpsock:close()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** Closes the current TCP or stream unix domain socket. It returns the `1` in case of success and returns `nil` with a string describing the error otherwise. @@ -6430,7 +6717,7 @@ tcpsock:settimeout ------------------ **syntax:** *tcpsock:settimeout(time)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** Set the timeout value in milliseconds for subsequent socket operations ([connect](#tcpsockconnect), [receive](#tcpsockreceive), and iterators returned from [receiveuntil](#tcpsockreceiveuntil)). @@ -6446,7 +6733,7 @@ tcpsock:setoption ----------------- **syntax:** *tcpsock:setoption(option, value?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** This function is added for [LuaSocket](http://w3.impa.br/~diego/software/luasocket/tcp.html) API compatibility and does nothing for now. Its functionality will be implemented in future. @@ -6458,7 +6745,7 @@ tcpsock:setkeepalive -------------------- **syntax:** *ok, err = tcpsock:setkeepalive(timeout?, size?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** Puts the current socket's connection immediately into the cosocket built-in connection pool and keep it alive until other [connect](#tcpsockconnect) method calls request it or the associated maximal idle timeout is expired. @@ -6486,7 +6773,7 @@ tcpsock:getreusedtimes ---------------------- **syntax:** *count, err = tcpsock:getreusedtimes()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** This method returns the (successfully) reused times for the current connection. In case of error, it returns `nil` and a string describing the error. @@ -6502,7 +6789,7 @@ ngx.socket.connect **syntax:** *tcpsock, err = ngx.socket.connect("unix:/path/to/unix-domain.socket")* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** This function is a shortcut for combining [ngx.socket.tcp()](#ngxsockettcp) and the [connect()](#tcpsockconnect) method call in a single operation. It is actually implemented like this: @@ -6526,7 +6813,7 @@ ngx.get_phase ------------- **syntax:** *str = ngx.get_phase()* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Retrieves the current running phase name. Possible return values are @@ -6559,7 +6846,7 @@ ngx.thread.spawn ---------------- **syntax:** *co = ngx.thread.spawn(func, arg1, arg2, ...)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** Spawns a new user "light thread" with the Lua function `func` as well as those optional arguments `arg1`, `arg2`, and etc. Returns a Lua thread (or Lua coroutine) object represents this "light thread". @@ -6697,7 +6984,7 @@ ngx.thread.wait --------------- **syntax:** *ok, res1, res2, ... = ngx.thread.wait(thread1, thread2, ...)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** Waits on one or more child "light threads" and returns the results of the first "light thread" that terminates (either successfully or with an error). @@ -6800,7 +7087,7 @@ ngx.thread.kill --------------- **syntax:** *ok, err = ngx.thread.kill(thread)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Kills a running "light thread" created by [ngx.thread.spawn](#ngxthreadspawn). Returns a true value when successful or `nil` and a string describing the error otherwise. @@ -6814,7 +7101,7 @@ ngx.on_abort ------------ **syntax:** *ok, err = ngx.on_abort(callback)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Registers a user Lua function as the callback which gets called automatically when the client closes the (downstream) connection prematurely. @@ -6854,7 +7141,7 @@ ngx.timer.at ------------ **syntax:** *ok, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Creates an Nginx timer with a user callback function as well as optional user arguments. @@ -6976,11 +7263,35 @@ This API was first introduced in the `v0.8.0` release. [Back to TOC](#nginx-api-for-lua) +ngx.timer.running_count +----------------------- +**syntax:** *count = ngx.timer.running_count()* + +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** + +Returns the number of timers currently running. + +This directive was first introduced in the `v0.9.20` release. + +[Back to TOC](#nginx-api-for-lua) + +ngx.timer.pending_count +----------------------- +**syntax:** *count = ngx.timer.pending_count()* + +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** + +Returns the number of pending timers. + +This directive was first introduced in the `v0.9.20` release. + +[Back to TOC](#nginx-api-for-lua) + ngx.config.debug ---------------- **syntax:** *debug = ngx.config.debug* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua** This boolean field indicates whether the current Nginx is a debug build, i.e., being built by the `./configure` option `--with-debug`. @@ -6993,7 +7304,7 @@ ngx.config.prefix **syntax:** *prefix = ngx.config.prefix()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua** Returns the Nginx server "prefix" path, as determined by the `-p` command-line option when running the nginx executable, or the path specified by the `--prefix` command-line option when building Nginx with the `./configure` script. @@ -7006,7 +7317,7 @@ ngx.config.nginx_version **syntax:** *ver = ngx.config.nginx_version* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua** This field take an integral value indicating the version number of the current Nginx core being used. For example, the version number `1.4.3` results in the Lua number 1004003. @@ -7019,7 +7330,7 @@ ngx.config.nginx_configure **syntax:** *str = ngx.config.nginx_configure()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua** This function returns a string for the NGINX `./configure` command's arguments string. @@ -7032,7 +7343,7 @@ ngx.config.ngx_lua_version **syntax:** *ver = ngx.config.ngx_lua_version* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua** This field take an integral value indicating the version number of the current `ngx_lua` module being used. For example, the version number `0.9.3` results in the Lua number 9003. @@ -7045,7 +7356,7 @@ ngx.worker.exiting **syntax:** *exiting = ngx.worker.exiting()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua** This function returns a boolean value indicating whether the current Nginx worker process already starts exiting. Nginx worker process exiting happens on Nginx server quit or configuration reload (aka HUP reload). @@ -7058,7 +7369,7 @@ ngx.worker.pid **syntax:** *pid = ngx.worker.pid()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua** This function returns a Lua number for the process ID (PID) of the current Nginx worker process. This API is more efficient than `ngx.var.pid` and can be used in contexts where the [ngx.var.VARIABLE](#ngxvarvariable) API cannot be used (like [init_worker_by_lua](#init_worker_by_lua)). @@ -7066,11 +7377,127 @@ This API was first introduced in the `0.9.5` release. [Back to TOC](#nginx-api-for-lua) +ngx.worker.count +---------------- + +**syntax:** *count = ngx.worker.count()* + +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua** + +Returns the total number of the Nginx worker processes (i.e., the value configured +by the [worker_processes](http://nginx.org/en/docs/ngx_core_module.html#worker_processes) +directive in `nginx.conf`). + +This API was first introduced in the `0.9.20` release. + +[Back to TOC](#nginx-api-for-lua) + +ngx.worker.id +------------- + +**syntax:** *count = ngx.worker.id()* + +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_worker_by_lua** + +Returns the ordinal number of the current Nginx worker processes (starting from number 0). + +So if the total number of workers is `N`, then this method may return a number between 0 +and `N - 1` (inclusive). + +This function returns meaningful values only for NGINX 1.9.1+. With earlier versions of NGINX, it +always returns `nil`. + +See also [ngx.worker.count](#ngxworkercount). + +This API was first introduced in the `0.9.20` release. + +[Back to TOC](#nginx-api-for-lua) + +ngx.semaphore +------------- +**syntax:** *local semaphore = require "ngx.semaphore"* + +This is a Lua module that implements a classic-style semaphore API for efficient synchronizations among +different "light threads". Sharing the same semaphore among different "light threads" created in different (request) +contexts are also supported as long as the "light threads" reside in the same NGINX worker process +and the [lua_code_cache](#lua_code_cache) directive is turned on (which is the default). + +This Lua module does not ship with this ngx_lua module itself rather it is shipped with +the +[lua-resty-core](https://github.com/openresty/lua-resty-core) library. + +Please refer to the [documentation](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/semaphore.md) +for this `ngx.semaphore` Lua module in [lua-resty-core](https://github.com/openresty/lua-resty-core) +for more details. + +This feature requires at least ngx_lua `v0.10.0`. + +[Back to TOC](#nginx-api-for-lua) + +ngx.balancer +------------ +**syntax:** *local balancer = require "ngx.balancer"* + +This is a Lua module that provides a Lua API to allow defining completely dynamic load balancers +in pure Lua. + +This Lua module does not ship with this ngx_lua module itself rather it is shipped with +the +[lua-resty-core](https://github.com/openresty/lua-resty-core) library. + +Please refer to the [documentation](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md) +for this `ngx.balancer` Lua module in [lua-resty-core](https://github.com/openresty/lua-resty-core) +for more details. + +This feature requires at least ngx_lua `v0.10.0`. + +[Back to TOC](#nginx-api-for-lua) + +ngx.ssl +------- +**syntax:** *local ssl = require "ngx.ssl"* + +This Lua module provides API functions to control the SSL handshake process in contexts like +[ssl_certificate_by_lua*](#ssl_certificate_by_lua_block). + +This Lua module does not ship with this ngx_lua module itself rather it is shipped with +the +[lua-resty-core](https://github.com/openresty/lua-resty-core) library. + +Please refer to the [documentation](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md) +for this `ngx.ssl` Lua module for more details. + +This feature requires at least ngx_lua `v0.10.0`. + +[Back to TOC](#nginx-api-for-lua) + +ngx.ocsp +-------- +**syntax:** *local ocsp = require "ngx.ocsp"* + +This Lua module provides API to perform OCSP queries, OCSP response validations, and +OCSP stapling planting. + +Usually, this module is used together with the [ngx.ssl](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md) +module in the +context of [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block). + +This Lua module does not ship with this ngx_lua module itself rather it is shipped with +the +[lua-resty-core](https://github.com/openresty/lua-resty-core) library. + +Please refer to the [documentation](https://github.com/openresty/lua-resty-core/blob/ocsp-cert-by-lua-2/lib/ngx/ocsp.md) +for this `ngx.ocsp` Lua module for more details. + +This feature requires at least ngx_lua `v0.10.0`. + +[Back to TOC](#nginx-api-for-lua) + ndk.set_var.DIRECTIVE --------------------- **syntax:** *res = ndk.set_var.DIRECTIVE_NAME* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** This mechanism allows calling other nginx C modules' directives that are implemented by [Nginx Devel Kit](https://github.com/simpl/ngx_devel_kit) (NDK)'s set_var submodule's `ndk_set_var_value`. @@ -7111,7 +7538,7 @@ coroutine.create ---------------- **syntax:** *co = coroutine.create(f)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** Creates a user Lua coroutines with a Lua function, and returns a coroutine object. @@ -7127,7 +7554,7 @@ coroutine.resume ---------------- **syntax:** *ok, ... = coroutine.resume(co, ...)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** Resumes the executation of a user Lua coroutine object previously yielded or just created. @@ -7143,9 +7570,9 @@ coroutine.yield --------------- **syntax:** *... = coroutine.yield(...)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** -Yields the executation of the current user Lua coroutine. +Yields the execution of the current user Lua coroutine. Similar to the standard Lua [coroutine.yield](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.yield) API, but works in the context of the Lua coroutines created by ngx_lua. @@ -7159,7 +7586,7 @@ coroutine.wrap -------------- **syntax:** *co = coroutine.wrap(f)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** Similar to the standard Lua [coroutine.wrap](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.wrap) API, but works in the context of the Lua coroutines created by ngx_lua. @@ -7173,7 +7600,7 @@ coroutine.running ----------------- **syntax:** *co = coroutine.running()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** Identical to the standard Lua [coroutine.running](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.running) API. @@ -7187,7 +7614,7 @@ coroutine.status ---------------- **syntax:** *status = coroutine.status(co)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** Identical to the standard Lua [coroutine.status](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.status) API. diff --git a/debian/modules/nginx-lua/config b/debian/modules/nginx-lua/config index 4b770d7..030788c 100644 --- a/debian/modules/nginx-lua/config +++ b/debian/modules/nginx-lua/config @@ -339,6 +339,7 @@ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ $ngx_addon_dir/src/ngx_http_lua_api.c \ $ngx_addon_dir/src/ngx_http_lua_logby.c \ $ngx_addon_dir/src/ngx_http_lua_sleep.c \ + $ngx_addon_dir/src/ngx_http_lua_semaphore.c\ $ngx_addon_dir/src/ngx_http_lua_coroutine.c \ $ngx_addon_dir/src/ngx_http_lua_bodyfilterby.c \ $ngx_addon_dir/src/ngx_http_lua_initby.c \ @@ -350,7 +351,10 @@ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ $ngx_addon_dir/src/ngx_http_lua_timer.c \ $ngx_addon_dir/src/ngx_http_lua_config.c \ $ngx_addon_dir/src/ngx_http_lua_worker.c \ + $ngx_addon_dir/src/ngx_http_lua_ssl_certby.c \ + $ngx_addon_dir/src/ngx_http_lua_ssl_ocsp.c \ $ngx_addon_dir/src/ngx_http_lua_lex.c \ + $ngx_addon_dir/src/ngx_http_lua_balancer.c \ " NGX_ADDON_DEPS="$NGX_ADDON_DEPS \ @@ -392,6 +396,7 @@ NGX_ADDON_DEPS="$NGX_ADDON_DEPS \ $ngx_addon_dir/src/api/ngx_http_lua_api.h \ $ngx_addon_dir/src/ngx_http_lua_logby.h \ $ngx_addon_dir/src/ngx_http_lua_sleep.h \ + $ngx_addon_dir/src/ngx_http_lua_semaphore.h\ $ngx_addon_dir/src/ngx_http_lua_coroutine.h \ $ngx_addon_dir/src/ngx_http_lua_bodyfilterby.h \ $ngx_addon_dir/src/ngx_http_lua_initby.h \ @@ -404,7 +409,9 @@ NGX_ADDON_DEPS="$NGX_ADDON_DEPS \ $ngx_addon_dir/src/ngx_http_lua_timer.h \ $ngx_addon_dir/src/ngx_http_lua_config.h \ $ngx_addon_dir/src/ngx_http_lua_worker.h \ + $ngx_addon_dir/src/ngx_http_lua_ssl_certby.h \ $ngx_addon_dir/src/ngx_http_lua_lex.h \ + $ngx_addon_dir/src/ngx_http_lua_balancer.h \ " CFLAGS="$CFLAGS -DNDK_SET_VAR" diff --git a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki index 3726509..f3bf06e 100644 --- a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.9.19] released on 11 November 2015. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.0] released on 11 January 2015. = Synopsis = @@ -179,19 +179,15 @@ Other scripting language implementations typically struggle to match this perfor The Lua state (Lua VM instance) is shared across all the requests handled by a single nginx worker process to minimize memory use. = Nginx Compatibility = -The latest module is compatible with the following versions of Nginx: -* 1.9.x (last tested: 1.9.3) +The latest version of this module is compatible with the following versions of Nginx: + +* 1.9.x (last tested: 1.9.7) +* 1.8.x * 1.7.x (last tested: 1.7.10) * 1.6.x -* 1.5.x (last tested: 1.5.12) -* 1.4.x (last tested: 1.4.4) -* 1.3.x (last tested: 1.3.11) -* 1.2.x (last tested: 1.2.9) -* 1.1.x (last tested: 1.1.5) -* 1.0.x (last tested: 1.0.15) -* 0.9.x (last tested: 0.9.4) -* 0.8.x >= 0.8.54 (last tested: 0.8.54) + +Nginx cores older than 1.6.0 (exclusive) are *not* supported. = Installation = @@ -207,9 +203,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.9.3.tar.gz' - tar -xzvf nginx-1.9.3.tar.gz - cd nginx-1.9.3/ + wget 'http://nginx.org/download/nginx-1.9.7.tar.gz' + tar -xzvf nginx-1.9.7.tar.gz + cd nginx-1.9.7/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib @@ -696,7 +692,6 @@ phases. } } -* ssl: implement directives ssl_certificate_by_lua and ssl_certificate_by_lua_file to allow using Lua to dynamically serve SSL certificates and keys for downstream SSL handshake. (already done in CloudFlare's private branch and powering CloudFlare's SSL gateway of its global network. expected to be opensourced in March 2015.) * shm: implement a "shared queue API" to complement the existing [[#lua_shared_dict|shared dict]] API. * cosocket: add support in the context of [[#init_by_lua|init_by_lua*]]. * cosocket: implement the bind() method for stream-typed cosockets. @@ -1514,6 +1509,10 @@ As with other access phase handlers, [[#access_by_lua|access_by_lua]] will ''not Note that when calling ngx.exit(ngx.OK) within a [[#access_by_lua|access_by_lua]] handler, the nginx request processing control flow will still continue to the content handler. To terminate the current request from within a [[#access_by_lua|access_by_lua]] handler, calling [[#ngx.exit|ngx.exit]] with status >= 200 (ngx.HTTP_OK) and status < 300 (ngx.HTTP_SPECIAL_RESPONSE) for successful quits and ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) (or its friends) for failures. +Starting from the v0.9.20 release, you can use the [[#access_by_lua_no_postpone|access_by_lua_no_postpone]] +directive to control when to run this handler inside the "access" request-processing phase +of NGINX. + == access_by_lua_block == '''syntax:''' ''access_by_lua_block { lua-script }'' @@ -1849,6 +1848,76 @@ When a relative path like foo/bar.lua is given, they will be turned This directive was first introduced in the v0.5.0rc31 release. +== balancer_by_lua_block == + +'''syntax:''' ''balancer_by_lua_block { lua-script }'' + +'''context:''' ''upstream'' + +'''phase:''' ''content'' + +This directive runs Lua code as an upstream balancer for any upstream entities defined +by the upstream {} configuration block. + +For instance, + + + upstream foo { + server 127.0.0.1; + balancer_by_lua_block { + -- use Lua to do something interesting here + -- as a dynamic balancer + } + } + + server { + location / { + proxy_pass http://foo; + } + } + + +The resulting Lua load balancer can work with any existing nginx upstream modules +like [http://nginx.org/en/docs/http/ngx_http_proxy_module.html ngx_proxy] and +[http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html ngx_fastcgi]. + +Also, the Lua load balancer can work with the standard upstream connection pool mechanism, +i.e., the standard [http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive keepalive] directive. +Just ensure that the [http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive keepalive] directive +is used *after* this balancer_by_lua_block directive in a single upstream {} configuration block. + +The Lua load balancer can totally ignore the list of servers defined in the upstream {} block +and select peer from a completely dynamic server list (even changing per request) via the +[https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md ngx.balancer] module +from the [https://github.com/openresty/lua-resty-core lua-resty-core] library. + +The Lua code handler registered by this directive might get called more than once in a single +downstream request when the nginx upstream mechanism retries the request on conditions +specified by directives like the [http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream proxy_next_upstream] +directive. + +This Lua code execution context does not support yielding, so Lua APIs that may yield +(like cosockets and "light threads") are disabled in this context. One can usually work +around this limitation by doing such operations in an earlier phase handler (like +[[#access_by_lua|access_by_lua*]]) and passing along the result into this context +via the [[#ngx.ctx|ngx.ctx]] table. + +This directive was first introduced in the v0.10.0 release. + +== balancer_by_lua_file == + +'''syntax:''' ''balancer_by_lua_file '' + +'''context:''' ''upstream'' + +'''phase:''' ''content'' + +Equivalent to [[#balancer_by_lua_block|balancer_by_lua_block]], except that the file specified by contains the Lua code, or, as from the v0.5.0rc32 release, the [[#Lua/LuaJIT bytecode support|Lua/LuaJIT bytecode]] to be executed. + +When a relative path like foo/bar.lua is given, they will be turned into the absolute path relative to the server prefix path determined by the -p PATH command-line option while starting the Nginx server. + +This directive was first introduced in the v0.10.0 release. + == lua_need_request_body == '''syntax:''' ''lua_need_request_body '' @@ -1874,6 +1943,105 @@ It is recommended however, to use the [[#ngx.req.read_body|ngx.req.read_body]] a This also applies to [[#access_by_lua|access_by_lua]] and [[#access_by_lua_file|access_by_lua_file]]. +== ssl_certificate_by_lua_block == + +'''syntax:''' ''ssl_certificate_by_lua_block { lua-script }'' + +'''context:''' ''server'' + +'''phase:''' ''right-before-SSL-handshake'' + +This directive runs user Lua code when NGINX is about to start the SSL handshake for the downstream +SSL (https) connections. + +It is particularly useful for setting the SSL certificate chain and the corresponding private key on a per-request +basis. It is also useful to load such handshake configurations nonblockingly from the remote (for example, +with the [[#ngx.socket.tcp|cosocket]] API). And one can also do per-request OCSP stapling handling in pure +Lua here as well. + +Another typical use case is to do SSL handshake traffic control nonblockingly in this context, +with the help of the [https://github.com/openresty/lua-resty-limit-traffic lua-resty-limit-traffic#readme] +library, for example. + +One can also do interesting things with the SSL handshake requests from the client side, like +rejecting old SSL clients using the SSLv3 protocol or even below selectively. + +The [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md ngx.ssl] +and [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md ngx.ocsp] Lua modules +provided by the [https://github.com/openresty/lua-resty-core/#readme lua-resty-core] +library are particularly useful in this context. You can use the Lua API offered by these two Lua modules +to manipulate the SSL certificate chain and private key for the current SSL connection +being initiated. + +This Lua handler does not run at all, however, when NGINX/OpenSSL successfully resumes +the SSL session via SSL session IDs or TLS session tickets for the current SSL connection. In +other words, this Lua handler only runs when NGINX has to initiate a full SSL handshake. + +Below is a trivial example using the +[https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md ngx.ssl] module +at the same time: + + + server { + listen 443 ssl; + server_name test.com; + + ssl_certificate_by_lua_block { + print("About to initiate a new SSL handshake!") + } + + location / { + root html; + } + } + + +See more complicated examples in the [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md ngx.ssl] +and [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md ngx.ocsp] +Lua modules' official documentation. + +Uncaught Lua exceptions in the user Lua code immediately abort the current SSL session, so does the +[[#ngx.exit|ngx.exit]] call with an error code like ngx.ERROR. + +This Lua code execution context *does* support yielding, so Lua APIs that may yield +(like cosockets, sleeping, and "light threads") +are enabled in this context. + +Note, however, you still need to configure the [http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate ssl_certificate] and +[http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate_key ssl_certificate_key] +directives even though you will not use this static certificate and private key at all. This is +because the NGINX core requires their appearance otherwise you are seeing the following error +while starting NGINX: + + + nginx: [emerg] no ssl configured for the server + + +This directive currently requires the following NGINX core patch to work correctly: + +http://mailman.nginx.org/pipermail/nginx-devel/2016-January/007748.html + +The bundled version of the NGINX core in OpenResty 1.9.7.2 (or above) already has this +patch applied. + +Furthermore, one needs at least OpenSSL 1.0.2e for this directive to work. + +This directive was first introduced in the v0.10.0 release. + +== ssl_certificate_by_lua_file == + +'''syntax:''' ''ssl_certificate_by_lua_file '' + +'''context:''' ''server'' + +'''phase:''' ''right-before-SSL-handshake'' + +Equivalent to [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua_block]], except that the file specified by contains the Lua code, or, as from the v0.5.0rc32 release, the [[#Lua/LuaJIT bytecode support|Lua/LuaJIT bytecode]] to be executed. + +When a relative path like foo/bar.lua is given, they will be turned into the absolute path relative to the server prefix path determined by the -p PATH command-line option while starting the Nginx server. + +This directive was first introduced in the v0.10.0 release. + == lua_shared_dict == '''syntax:''' ''lua_shared_dict '' @@ -1897,6 +2065,9 @@ The argument accepts size units such as k and < } +The hard-coded minimum size is 8KB while the practical minimum size depends +on actual user data set (some people start with 12KB). + See [[#ngx.shared.DICT|ngx.shared.DICT]] for details. This directive was first introduced in the v0.3.1rc22 release. @@ -2105,10 +2276,22 @@ This directive was first introduced in the v0.5.0rc19 release. '''context:''' ''http'' -Controls whether or not to disable postponing [[#rewrite_by_lua|rewrite_by_lua]] and [[#rewrite_by_lua_file|rewrite_by_lua_file]] directives to run at the end of the rewrite request-processing phase. By default, this directive is turned off and the Lua code is postponed to run at the end of the rewrite phase. +Controls whether or not to disable postponing [[#rewrite_by_lua|rewrite_by_lua]]* directives to run at the end of the rewrite request-processing phase. By default, this directive is turned off and the Lua code is postponed to run at the end of the rewrite phase. This directive was first introduced in the v0.5.0rc29 release. +== access_by_lua_no_postpone == + +'''syntax:''' ''access_by_lua_no_postpone on|off'' + +'''default:''' ''access_by_lua_no_postpone off'' + +'''context:''' ''http'' + +Controls whether or not to disable postponing [[#access_by_lua|access_by_lua]]* directives to run at the end of the access request-processing phase. By default, this directive is turned off and the Lua code is postponed to run at the end of the access phase. + +This directive was first introduced in the v0.9.20 release. + == lua_transform_underscores_in_response_headers == '''syntax:''' ''lua_transform_underscores_in_response_headers on|off'' @@ -2352,23 +2535,40 @@ These constants are usually used in [[#ngx.location.capture|ngx.location.capture '''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*'' + value = ngx.HTTP_CONTINUE (100) (first added in the v0.9.20 release) + value = ngx.HTTP_SWITCHING_PROTOCOLS (101) (first added in the v0.9.20 release) value = ngx.HTTP_OK (200) value = ngx.HTTP_CREATED (201) + value = ngx.HTTP_ACCEPTED (202) (first added in the v0.9.20 release) + value = ngx.HTTP_NO_CONTENT (204) (first added in the v0.9.20 release) + value = ngx.HTTP_PARTIAL_CONTENT (206) (first added in the v0.9.20 release) value = ngx.HTTP_SPECIAL_RESPONSE (300) value = ngx.HTTP_MOVED_PERMANENTLY (301) value = ngx.HTTP_MOVED_TEMPORARILY (302) value = ngx.HTTP_SEE_OTHER (303) value = ngx.HTTP_NOT_MODIFIED (304) + value = ngx.HTTP_TEMPORARY_REDIRECT (307) (first added in the v0.9.20 release) value = ngx.HTTP_BAD_REQUEST (400) value = ngx.HTTP_UNAUTHORIZED (401) + value = ngx.HTTP_PAYMENT_REQUIRED (402) (first added in the v0.9.20 release) value = ngx.HTTP_FORBIDDEN (403) value = ngx.HTTP_NOT_FOUND (404) value = ngx.HTTP_NOT_ALLOWED (405) + value = ngx.HTTP_NOT_ACCEPTABLE (406) (first added in the v0.9.20 release) + value = ngx.HTTP_REQUEST_TIMEOUT (408) (first added in the v0.9.20 release) + value = ngx.HTTP_CONFLICT (409) (first added in the v0.9.20 release) value = ngx.HTTP_GONE (410) + value = ngx.HTTP_UPGRADE_REQUIRED (426) (first added in the v0.9.20 release) + value = ngx.HTTP_TOO_MANY_REQUESTS (429) (first added in the v0.9.20 release) + value = ngx.HTTP_CLOSE (444) (first added in the v0.9.20 release) + value = ngx.HTTP_ILLEGAL (451) (first added in the v0.9.20 release) value = ngx.HTTP_INTERNAL_SERVER_ERROR (500) value = ngx.HTTP_METHOD_NOT_IMPLEMENTED (501) + value = ngx.HTTP_BAD_GATEWAY (502) (first added in the v0.9.20 release) value = ngx.HTTP_SERVICE_UNAVAILABLE (503) value = ngx.HTTP_GATEWAY_TIMEOUT (504) (first added in the v0.3.1rc38 release) + value = ngx.HTTP_VERSION_NOT_SUPPORTED (505) (first added in the v0.9.20 release) + value = ngx.HTTP_INSUFFICIENT_STORAGE (507) (first added in the v0.9.20 release) == Nginx log level constants == @@ -2391,7 +2591,7 @@ These constants are usually used by the [[#ngx.log|ngx.log]] method. == print == '''syntax:''' ''print(...)'' -'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, certificate_by_lua*'' Writes argument values into the nginx error.log file with the ngx.NOTICE log level. @@ -2406,7 +2606,7 @@ Lua nil arguments are accepted and result in literal "nil"2048 byte limitation on error message lengths in the Nginx core. This limit includes trailing newlines and leading time stamps. If the message size exceeds this limit, Nginx will truncate the message text accordingly. This limit can be manually modified by editing the NGX_MAX_ERROR_STR macro definition in the src/core/ngx_log.h file in the Nginx source tree. == ngx.ctx == -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*'' This table can be used to store per-request Lua context data and has a life time identical to the current request (as with the Nginx variables). @@ -2502,14 +2702,47 @@ Overriding ngx.ctx with a new Lua table is also supported, for exam When being used in the context of [[#init_worker_by_lua|init_worker_by_lua*]], this table just has the same lifetime of the current Lua handler. -The ngx.ctx lookup requires relatively expensive metamethod calls and it is much slower than explicitly passing per-request data along by your own function arguments. So do not abuse this API for saving your own function arguments because it usually has quite some performance impact. And because of the metamethod magic, never "local" the ngx.ctx table outside your function scope. +The ngx.ctx lookup requires relatively expensive metamethod calls and it is much slower than explicitly passing per-request data along by your own function arguments. So do not abuse this API for saving your own function arguments because it usually has quite some performance impact. + +Because of the metamethod magic, never "local" the ngx.ctx table outside your Lua function scope on the Lua module level level due to [[#Data_Sharing_within_an_Nginx_Worker|worker-level data sharing]]. For example, the following is bad: + + +-- mymodule.lua +local _M = {} + +-- the following line is bad since ngx.ctx is a per-request +-- data while this `ctx` variable is on the Lua module level +-- and thus is per-nginx-worker. +local ctx = ngx.ctx + +function _M.main() + ctx.foo = "bar" +end + +return _M + + +Use the following instead: + + +-- mymodule.lua +local _M = {} + +function _M.main(ctx) + ctx.foo = "bar" +end + +return _M + + +That is, let the caller pass the `ctx` table explicitly via a function argument. == ngx.location.capture == '''syntax:''' ''res = ngx.location.capture(uri, options?)'' '''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' -Issue a synchronous but still non-blocking ''Nginx Subrequest'' using uri. +Issues a synchronous but still non-blocking ''Nginx Subrequest'' using uri. Nginx's subrequests provide a powerful way to make non-blocking internal requests to other locations configured with disk file directory or ''any'' other nginx C modules like ngx_proxy, ngx_fastcgi, ngx_memc, ngx_postgres, ngx_drizzle, and even ngx_lua itself and etc etc etc. @@ -2520,6 +2753,9 @@ Subrequests are completely different from HTTP 301/302 redirection (via [[#ngx.r You should always read the request body (by either calling [[#ngx.req.read_body|ngx.req.read_body]] or configuring [[#lua_need_request_body|lua_need_request_body]] on) before initiating a subrequest. +This API function (as well as [[#ngx.location.capture_multi|ngx.location.capture_multi]]) always buffers the whole response body of the subrequest in memory. Thus, you should use [[#ngx.socket.tcp|cosockets]] +and streaming processing instead if you have to handle large subrequest responses. + Here is a basic example: @@ -2959,7 +3195,7 @@ For reading ''request'' headers, use the [[#ngx.req.get_headers|ngx.req.get_head == ngx.resp.get_headers == '''syntax:''' ''headers = ngx.resp.get_headers(max_headers?, raw?)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, balancer_by_lua*'' Returns a Lua table holding all the current response headers for the current request. @@ -2974,6 +3210,18 @@ This function has the same signature as [[#ngx.req.get_headers|ngx.req.get_heade This API was first introduced in the v0.9.5 release. +== ngx.req.is_internal == +'''syntax:''' ''is_internal = ngx.req.is_internal()'' + +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' + +Returns a boolean indicating whether the current request is an "internal request", i.e., +a request initiated from inside the current nginx server instead of from the client side. + +Subrequests are all internal requests and so are requests after internal redirects. + +This API was first introduced in the v0.9.20 release. + == ngx.req.start_time == '''syntax:''' ''secs = ngx.req.start_time()'' @@ -3046,7 +3294,7 @@ This method was first introduced in the v0.7.17 release. == ngx.req.get_method == '''syntax:''' ''method_name = ngx.req.get_method()'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, balancer_by_lua*'' Retrieves the current request's request method name. Strings like "GET" and "POST" are returned instead of numerical [[#HTTP method constants|method constants]]. @@ -3189,7 +3437,7 @@ See also [[#ngx.req.set_uri|ngx.req.set_uri]]. == ngx.req.get_uri_args == '''syntax:''' ''args = ngx.req.get_uri_args(max_args?)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, balancer_by_lua*'' Returns a Lua table holding all the current request URL query arguments. @@ -3868,7 +4116,7 @@ Just as [[#ngx.print|ngx.print]] but also emit a trailing newline. == ngx.log == '''syntax:''' ''ngx.log(log_level, ...)'' -'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Log arguments concatenated to error.log with the given logging level. @@ -3898,7 +4146,7 @@ Since v0.8.3 this function returns 1 on success, or re == ngx.exit == '''syntax:''' ''ngx.exit(status)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' When status >= 200 (i.e., ngx.HTTP_OK and above), it will interrupt the execution of the current request and return status code to nginx. @@ -3975,7 +4223,7 @@ Since v0.8.3 this function returns 1 on success, or re == ngx.sleep == '''syntax:''' ''ngx.sleep(seconds)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' Sleeps for the specified seconds without blocking. One can specify time resolution up to 0.001 seconds (i.e., one milliseconds). @@ -4794,7 +5042,7 @@ Unconditionally sets a key-value pair into the shm-based dictionary [[#ngx.share The value argument inserted can be Lua booleans, numbers, strings, or nil. Their value type will also be stored into the dictionary and the same data type can be retrieved later via the [[#ngx.shared.DICT.get|get]] method. -The optional exptime argument specifies expiration time (in seconds) for the inserted key-value pair. The time resolution is 0.001 seconds. If the exptime takes the value 0 (which is the default), then the item will never be expired. +The optional exptime argument specifies expiration time (in seconds) for the inserted key-value pair. The time resolution is 0.001 seconds. If the exptime takes the value 0 (which is the default), then the item will never expire. The optional flags argument specifies a user flags value associated with the entry to be stored. It can also be retrieved later with the value. The user flags is stored as an unsigned 32-bit integer internally. Defaults to 0. The user flags argument was first introduced in the v0.5.0rc2 release. @@ -4942,7 +5190,7 @@ This feature was first introduced in the v0.7.3 release. == ngx.socket.udp == '''syntax:''' ''udpsock = ngx.socket.udp()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' Creates and returns a UDP or datagram-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: @@ -4963,7 +5211,7 @@ See also [[#ngx.socket.tcp|ngx.socket.tcp]]. '''syntax:''' ''ok, err = udpsock:setpeername("unix:/path/to/unix-domain.socket")'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' Attempts to connect a UDP socket object to a remote server or to a datagram unix domain socket file. Because the datagram protocol is actually connection-less, this method does not really establish a "connection", but only just set the name of the remote peer for subsequent read/write operations. @@ -5016,7 +5264,7 @@ This method was first introduced in the v0.5.7 release. == udpsock:send == '''syntax:''' ''ok, err = udpsock:send(data)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' Sends data on the current UDP or datagram unix domain socket object. @@ -5029,7 +5277,7 @@ This feature was first introduced in the v0.5.7 release. == udpsock:receive == '''syntax:''' ''data, err = udpsock:receive(size?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' Receives data from the UDP or datagram unix domain socket object with an optional receive buffer size argument, size. @@ -5060,7 +5308,7 @@ This feature was first introduced in the v0.5.7 release. == udpsock:close == '''syntax:''' ''ok, err = udpsock:close()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' Closes the current UDP or datagram unix domain socket. It returns the 1 in case of success and returns nil with a string describing the error otherwise. @@ -5071,7 +5319,7 @@ This feature was first introduced in the v0.5.7 release. == udpsock:settimeout == '''syntax:''' ''udpsock:settimeout(time)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' Set the timeout value in milliseconds for subsequent socket operations (like [[#udpsock:receive|receive]]). @@ -5082,7 +5330,7 @@ This feature was first introduced in the v0.5.7 release. == ngx.socket.tcp == '''syntax:''' ''tcpsock = ngx.socket.tcp()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: @@ -5125,7 +5373,7 @@ See also [[#ngx.socket.udp|ngx.socket.udp]]. '''syntax:''' ''ok, err = tcpsock:connect("unix:/path/to/unix-domain.socket", options_table?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' Attempts to connect a TCP socket object to a remote server or to a stream unix domain socket file without blocking. @@ -5195,9 +5443,9 @@ The support for the options table argument was first introduced in the v0. This method was first introduced in the v0.5.0rc1 release. == tcpsock:sslhandshake == -'''syntax:''' ''session, err = tcpsock:sslhandshake(reused_session?, server_name?, ssl_verify?)'' +'''syntax:''' ''session, err = tcpsock:sslhandshake(reused_session?, server_name?, ssl_verify?, send_status_req?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' Does SSL/TLS handshake on the currently established connection. @@ -5228,6 +5476,9 @@ Also, when the ssl_verify argument is true and the server_name argument is also specified, the latter will be used to validate the server name in the server certificate. +The optional send_status_req argument takes a boolean that controls whether to send +the OCSP status request in the SSL handshake request (which is for requesting OCSP stapling). + For connections that have already done SSL/TLS handshake, this method returns immediately. @@ -5236,7 +5487,7 @@ This method was first introduced in the v0.9.11 release. == tcpsock:send == '''syntax:''' ''bytes, err = tcpsock:send(data)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' Sends data without blocking on the current TCP or Unix Domain Socket connection. @@ -5264,7 +5515,7 @@ This feature was first introduced in the v0.5.0rc1 release. '''syntax:''' ''data, err, partial = tcpsock:receive(pattern?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' Receives data from the connected socket according to the reading pattern or size. @@ -5302,7 +5553,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:receiveuntil == '''syntax:''' ''iterator = tcpsock:receiveuntil(pattern, options?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' This method returns an iterator Lua function that can be called to read the data stream until it sees the specified pattern or an error occurs. @@ -5394,7 +5645,7 @@ This method was first introduced in the v0.5.0rc1 release. == tcpsock:close == '''syntax:''' ''ok, err = tcpsock:close()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' Closes the current TCP or stream unix domain socket. It returns the 1 in case of success and returns nil with a string describing the error otherwise. @@ -5407,7 +5658,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:settimeout == '''syntax:''' ''tcpsock:settimeout(time)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' Set the timeout value in milliseconds for subsequent socket operations ([[#tcpsock:connect|connect]], [[#tcpsock:receive|receive]], and iterators returned from [[#tcpsock:receiveuntil|receiveuntil]]). @@ -5420,7 +5671,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:setoption == '''syntax:''' ''tcpsock:setoption(option, value?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' This function is added for [http://w3.impa.br/~diego/software/luasocket/tcp.html LuaSocket] API compatibility and does nothing for now. Its functionality will be implemented in future. @@ -5429,7 +5680,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:setkeepalive == '''syntax:''' ''ok, err = tcpsock:setkeepalive(timeout?, size?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' Puts the current socket's connection immediately into the cosocket built-in connection pool and keep it alive until other [[#tcpsock:connect|connect]] method calls request it or the associated maximal idle timeout is expired. @@ -5454,7 +5705,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:getreusedtimes == '''syntax:''' ''count, err = tcpsock:getreusedtimes()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' This method returns the (successfully) reused times for the current connection. In case of error, it returns nil and a string describing the error. @@ -5487,7 +5738,7 @@ This feature was first introduced in the v0.5.0rc1 release. == ngx.get_phase == '''syntax:''' ''str = ngx.get_phase()'' -'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Retrieves the current running phase name. Possible return values are @@ -5517,7 +5768,7 @@ This API was first introduced in the v0.5.10 release. == ngx.thread.spawn == '''syntax:''' ''co = ngx.thread.spawn(func, arg1, arg2, ...)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' Spawns a new user "light thread" with the Lua function func as well as those optional arguments arg1, arg2, and etc. Returns a Lua thread (or Lua coroutine) object represents this "light thread". @@ -5650,7 +5901,7 @@ This API was first enabled in the v0.7.0 release. == ngx.thread.wait == '''syntax:''' ''ok, res1, res2, ... = ngx.thread.wait(thread1, thread2, ...)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' Waits on one or more child "light threads" and returns the results of the first "light thread" that terminates (either successfully or with an error). @@ -5913,6 +6164,24 @@ You can pass most of the standard Lua values (nils, booleans, numbers, strings, This API was first introduced in the v0.8.0 release. +== ngx.timer.running_count == +'''syntax:''' ''count = ngx.timer.running_count()'' + +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' + +Returns the number of timers currently running. + +This directive was first introduced in the v0.9.20 release. + +== ngx.timer.pending_count == +'''syntax:''' ''count = ngx.timer.pending_count()'' + +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' + +Returns the number of pending timers. + +This directive was first introduced in the v0.9.20 release. + == ngx.config.debug == '''syntax:''' ''debug = ngx.config.debug'' @@ -5982,6 +6251,104 @@ This function returns a Lua number for the process ID (PID) of the current Nginx This API was first introduced in the 0.9.5 release. +== ngx.worker.count == + +'''syntax:''' ''count = ngx.worker.count()'' + +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*'' + +Returns the total number of the Nginx worker processes (i.e., the value configured +by the [http://nginx.org/en/docs/ngx_core_module.html#worker_processes worker_processes] +directive in `nginx.conf`). + +This API was first introduced in the 0.9.20 release. + +== ngx.worker.id == + +'''syntax:''' ''count = ngx.worker.id()'' + +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_worker_by_lua*'' + +Returns the ordinal number of the current Nginx worker processes (starting from number 0). + +So if the total number of workers is `N`, then this method may return a number between 0 +and `N - 1` (inclusive). + +This function returns meaningful values only for NGINX 1.9.1+. With earlier versions of NGINX, it +always returns `nil`. + +See also [[#ngx.worker.count|ngx.worker.count]]. + +This API was first introduced in the 0.9.20 release. + +== ngx.semaphore == +'''syntax:''' ''local semaphore = require "ngx.semaphore"'' + +This is a Lua module that implements a classic-style semaphore API for efficient synchronizations among +different "light threads". Sharing the same semaphore among different "light threads" created in different (request) +contexts are also supported as long as the "light threads" reside in the same NGINX worker process +and the [[#lua_code_cache|lua_code_cache]] directive is turned on (which is the default). + +This Lua module does not ship with this ngx_lua module itself rather it is shipped with +the +[https://github.com/openresty/lua-resty-core lua-resty-core] library. + +Please refer to the [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/semaphore.md documentation] +for this ngx.semaphore Lua module in [https://github.com/openresty/lua-resty-core lua-resty-core] +for more details. + +This feature requires at least ngx_lua v0.10.0. + +== ngx.balancer == +'''syntax:''' ''local balancer = require "ngx.balancer"'' + +This is a Lua module that provides a Lua API to allow defining completely dynamic load balancers +in pure Lua. + +This Lua module does not ship with this ngx_lua module itself rather it is shipped with +the +[https://github.com/openresty/lua-resty-core lua-resty-core] library. + +Please refer to the [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md documentation] +for this ngx.balancer Lua module in [https://github.com/openresty/lua-resty-core lua-resty-core] +for more details. + +This feature requires at least ngx_lua v0.10.0. + +== ngx.ssl == +'''syntax:''' ''local ssl = require "ngx.ssl"'' + +This Lua module provides API functions to control the SSL handshake process in contexts like +[ssl_certificate_by_lua*](#ssl_certificate_by_lua_block). + +This Lua module does not ship with this ngx_lua module itself rather it is shipped with +the +[https://github.com/openresty/lua-resty-core lua-resty-core] library. + +Please refer to the [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md documentation] +for this ngx.ssl Lua module for more details. + +This feature requires at least ngx_lua v0.10.0. + +== ngx.ocsp == +'''syntax:''' ''local ocsp = require "ngx.ocsp"'' + +This Lua module provides API to perform OCSP queries, OCSP response validations, and +OCSP stapling planting. + +Usually, this module is used together with the [ngx.ssl](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md) +module in the +context of [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block). + +This Lua module does not ship with this ngx_lua module itself rather it is shipped with +the +[https://github.com/openresty/lua-resty-core lua-resty-core] library. + +Please refer to the [https://github.com/openresty/lua-resty-core/blob/ocsp-cert-by-lua-2/lib/ngx/ocsp.md documentation] +for this ngx.ocsp Lua module for more details. + +This feature requires at least ngx_lua v0.10.0. + == ndk.set_var.DIRECTIVE == '''syntax:''' ''res = ndk.set_var.DIRECTIVE_NAME'' @@ -6022,7 +6389,7 @@ This feature requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_kit] == coroutine.create == '''syntax:''' ''co = coroutine.create(f)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' Creates a user Lua coroutines with a Lua function, and returns a coroutine object. @@ -6035,7 +6402,7 @@ This API was first introduced in the v0.6.0 release. == coroutine.resume == '''syntax:''' ''ok, ... = coroutine.resume(co, ...)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' Resumes the executation of a user Lua coroutine object previously yielded or just created. @@ -6048,9 +6415,9 @@ This API was first introduced in the v0.6.0 release. == coroutine.yield == '''syntax:''' ''... = coroutine.yield(...)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' -Yields the executation of the current user Lua coroutine. +Yields the execution of the current user Lua coroutine. Similar to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.yield coroutine.yield] API, but works in the context of the Lua coroutines created by ngx_lua. @@ -6061,7 +6428,7 @@ This API was first introduced in the v0.6.0 release. == coroutine.wrap == '''syntax:''' ''co = coroutine.wrap(f)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' Similar to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.wrap coroutine.wrap] API, but works in the context of the Lua coroutines created by ngx_lua. @@ -6072,7 +6439,7 @@ This API was first introduced in the v0.6.0 release. == coroutine.running == '''syntax:''' ''co = coroutine.running()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' Identical to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.running coroutine.running] API. @@ -6083,7 +6450,7 @@ This API was first enabled in the v0.6.0 release. == coroutine.status == '''syntax:''' ''status = coroutine.status(co)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' Identical to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.status coroutine.status] API. diff --git a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h index 962c651..84a0579 100644 --- a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 9019 +#define ngx_http_lua_version 10000 typedef struct { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c b/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c index 8a82e07..14cc342 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c @@ -176,7 +176,8 @@ ngx_http_lua_access_handler_inline(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua inline script (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadbuffer(r, L, llcf->access_src.value.data, + rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, + llcf->access_src.value.data, llcf->access_src.value.len, llcf->access_src_key, (const char *) llcf->access_chunkname); @@ -215,7 +216,8 @@ ngx_http_lua_access_handler_file(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua script file (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadfile(r, L, script_path, llcf->access_src_key); + rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path, + llcf->access_src_key); if (rc != NGX_OK) { if (rc < NGX_HTTP_SPECIAL_RESPONSE) { return NGX_HTTP_INTERNAL_SERVER_ERROR; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_args.c b/debian/modules/nginx-lua/src/ngx_http_lua_args.c index d1376bd..dbc2ac6 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_args.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_args.c @@ -113,6 +113,11 @@ ngx_http_lua_ngx_req_get_uri_args(lua_State *L) lua_createtable(L, 0, 4); + if (r->args.len == 0) { + lua_createtable(L, 0, 0); + return 1; + } + /* we copy r->args over to buf to simplify * unescaping query arg keys and values */ @@ -197,6 +202,11 @@ ngx_http_lua_ngx_req_get_post_args(lua_State *L) dd("post body length: %d", (int) len); + if (len == 0) { + lua_createtable(L, 0, 0); + return 1; + } + buf = ngx_palloc(r->pool, len); if (buf == NULL) { return luaL_error(L, "no memory"); @@ -379,7 +389,7 @@ ngx_http_lua_ffi_req_get_uri_args_count(ngx_http_request_t *r, int max) int count; u_char *p, *last; - if (r->connection->fd == -1) { + if (r->connection->fd == (ngx_socket_t) -1) { return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c b/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c new file mode 100644 index 0000000..4fa91fc --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c @@ -0,0 +1,607 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_lua_cache.h" +#include "ngx_http_lua_balancer.h" +#include "ngx_http_lua_util.h" +#include "ngx_http_lua_directive.h" + + +struct ngx_http_lua_balancer_peer_data_s { + /* the round robin data must be first */ + ngx_http_upstream_rr_peer_data_t rrp; + + ngx_http_lua_srv_conf_t *conf; + ngx_http_request_t *request; + + ngx_event_get_peer_pt get_rr_peer; + + ngx_uint_t more_tries; + ngx_uint_t total_tries; + + struct sockaddr *sockaddr; + socklen_t socklen; + + ngx_str_t host; + in_port_t port; + + int last_peer_state; +}; + + +static ngx_int_t ngx_http_lua_balancer_init(ngx_conf_t *cf, + ngx_http_upstream_srv_conf_t *us); +static ngx_int_t ngx_http_lua_balancer_init_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us); +static ngx_int_t ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, + void *data); +static ngx_int_t ngx_http_lua_balancer_by_chunk(lua_State *L, + ngx_http_request_t *r); +void ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data, + ngx_uint_t state); + + +ngx_int_t +ngx_http_lua_balancer_handler_file(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L) +{ + ngx_int_t rc; + + rc = ngx_http_lua_cache_loadfile(r->connection->log, L, + lscf->balancer.src.data, + lscf->balancer.src_key); + if (rc != NGX_OK) { + return rc; + } + + /* make sure we have a valid code chunk */ + ngx_http_lua_assert(lua_isfunction(L, -1)); + + return ngx_http_lua_balancer_by_chunk(L, r); +} + + +ngx_int_t +ngx_http_lua_balancer_handler_inline(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L) +{ + ngx_int_t rc; + + rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, + lscf->balancer.src.data, + lscf->balancer.src.len, + lscf->balancer.src_key, + "=balancer_by_lua"); + if (rc != NGX_OK) { + return rc; + } + + /* make sure we have a valid code chunk */ + ngx_http_lua_assert(lua_isfunction(L, -1)); + + return ngx_http_lua_balancer_by_chunk(L, r); +} + + +char * +ngx_http_lua_balancer_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_balancer_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + +char * +ngx_http_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + u_char *p; + u_char *name; + ngx_str_t *value; + ngx_http_lua_srv_conf_t *lscf = conf; + + ngx_http_upstream_srv_conf_t *uscf; + + dd("enter"); + + /* must specifiy a content handler */ + if (cmd->post == NULL) { + return NGX_CONF_ERROR; + } + + if (lscf->balancer.handler) { + return "is duplicate"; + } + + value = cf->args->elts; + + lscf->balancer.handler = (ngx_http_lua_srv_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_http_lua_balancer_handler_file) { + /* Lua code in an external file */ + + name = ngx_http_lua_rebase_path(cf->pool, value[1].data, + value[1].len); + if (name == NULL) { + return NGX_CONF_ERROR; + } + + lscf->balancer.src.data = name; + lscf->balancer.src.len = ngx_strlen(name); + + p = ngx_palloc(cf->pool, NGX_HTTP_LUA_FILE_KEY_LEN + 1); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + lscf->balancer.src_key = p; + + p = ngx_copy(p, NGX_HTTP_LUA_FILE_TAG, NGX_HTTP_LUA_FILE_TAG_LEN); + p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); + *p = '\0'; + + } else { + /* inlined Lua code */ + + lscf->balancer.src = value[1]; + + p = ngx_palloc(cf->pool, NGX_HTTP_LUA_INLINE_KEY_LEN + 1); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + lscf->balancer.src_key = p; + + p = ngx_copy(p, NGX_HTTP_LUA_INLINE_TAG, NGX_HTTP_LUA_INLINE_TAG_LEN); + p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); + *p = '\0'; + } + + uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); + + if (uscf->peer.init_upstream) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "load balancing method redefined"); + } + + uscf->peer.init_upstream = ngx_http_lua_balancer_init; + + uscf->flags = NGX_HTTP_UPSTREAM_CREATE + |NGX_HTTP_UPSTREAM_WEIGHT + |NGX_HTTP_UPSTREAM_MAX_FAILS + |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT + |NGX_HTTP_UPSTREAM_DOWN; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_lua_balancer_init(ngx_conf_t *cf, + ngx_http_upstream_srv_conf_t *us) +{ + if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) { + return NGX_ERROR; + } + + /* this callback is called upon individual requests */ + us->peer.init = ngx_http_lua_balancer_init_peer; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_balancer_init_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us) +{ + ngx_http_lua_srv_conf_t *bcf; + ngx_http_lua_balancer_peer_data_t *bp; + + bp = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_balancer_peer_data_t)); + if (bp == NULL) { + return NGX_ERROR; + } + + r->upstream->peer.data = &bp->rrp; + + if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) { + return NGX_ERROR; + } + + r->upstream->peer.get = ngx_http_lua_balancer_get_peer; + r->upstream->peer.free = ngx_http_lua_balancer_free_peer; + + bcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_lua_module); + + bp->conf = bcf; + bp->get_rr_peer = ngx_http_upstream_get_round_robin_peer; + bp->request = r; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) +{ + lua_State *L; + ngx_int_t rc; + ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_srv_conf_t *lscf; + ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_balancer_peer_data_t *bp = data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "lua balancer peer, try: %ui", pc->tries); + + lscf = bp->conf; + + r = bp->request; + + ngx_http_lua_assert(lscf->balancer.handler && r); + + L = ngx_http_lua_get_lua_vm(r, NULL); + + bp->sockaddr = NULL; + bp->socklen = 0; + bp->more_tries = 0; + bp->total_tries++; + + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + + /* balancer_by_lua does not support yielding and + * there cannot be any conflicts among concurrent requests, + * thus it is safe to store the peer data in the main conf. + */ + lmcf->balancer_peer_data = bp; + + rc = lscf->balancer.handler(r, lscf, L); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + if (ctx->exited && ctx->exit_code != NGX_OK) { + rc = ctx->exit_code; + if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) { + return rc; + } + + if (rc > NGX_OK) { + return NGX_ERROR; + } + } + + if (bp->sockaddr && bp->socklen) { + pc->sockaddr = bp->sockaddr; + pc->socklen = bp->socklen; + pc->name = &bp->host; + bp->rrp.peers->single = 0; + + if (bp->more_tries) { + r->upstream->peer.tries += bp->more_tries; + } + + dd("tries: %d", (int) r->upstream->peer.tries); + + return NGX_OK; + } + + return bp->get_rr_peer(pc, &bp->rrp); +} + + +static ngx_int_t +ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r) +{ + u_char *err_msg; + size_t len; + ngx_int_t rc; + ngx_http_lua_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + if (ctx == NULL) { + ctx = ngx_http_lua_create_ctx(r); + if (ctx == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + } else { + dd("reset ctx"); + ngx_http_lua_reset_ctx(r, L, ctx); + } + + ctx->context = NGX_HTTP_LUA_CONTEXT_BALANCER; + + /* init nginx context in Lua VM */ + ngx_http_lua_set_req(L, r); + ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); + + /* {{{ make new env inheriting main thread's globals table */ + lua_createtable(L, 0, 1 /* nrec */); /* the metatable for the new env */ + ngx_http_lua_get_globals_table(L); + lua_setfield(L, -2, "__index"); + lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */ + /* }}} */ + + lua_setfenv(L, -2); /* set new running env for the code closure */ + + lua_pushcfunction(L, ngx_http_lua_traceback); + lua_insert(L, 1); /* put it under chunk and args */ + + /* protected call user code */ + rc = lua_pcall(L, 0, 1, 1); + + lua_remove(L, 1); /* remove traceback function */ + + dd("rc == %d", (int) rc); + + if (rc != 0) { + /* error occured when running loaded code */ + err_msg = (u_char *) lua_tolstring(L, -1, &len); + + if (err_msg == NULL) { + err_msg = (u_char *) "unknown reason"; + len = sizeof("unknown reason") - 1; + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "failed to run balancer_by_lua*: %*s", len, err_msg); + + lua_settop(L, 0); /* clear remaining elems on stack */ + + return NGX_ERROR; + } + + lua_settop(L, 0); /* clear remaining elems on stack */ + return rc; +} + + +void +ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data, + ngx_uint_t state) +{ + ngx_http_lua_balancer_peer_data_t *bp = data; + + if (bp->sockaddr && bp->socklen) { + bp->last_peer_state = (int) state; + + if (pc->tries) { + pc->tries--; + } + + return; + } + + /* fallback */ + + ngx_http_upstream_free_round_robin_peer(pc, data, state); +} + + +#ifndef NGX_LUA_NO_FFI_API + +int +ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r, + const u_char *addr, size_t addr_len, int port, char **err) +{ + ngx_url_t url; + ngx_http_lua_ctx_t *ctx; + ngx_http_upstream_t *u; + + ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_balancer_peer_data_t *bp; + + if (r == NULL) { + *err = "no request found"; + return NGX_ERROR; + } + + u = r->upstream; + + if (u == NULL) { + *err = "no upstream found"; + return NGX_ERROR; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + *err = "no ctx found"; + return NGX_ERROR; + } + + if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) { + *err = "API disabled in the current context"; + return NGX_ERROR; + } + + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + + /* we cannot read r->upstream->peer.data here directly because + * it could be overridden by other modules like + * ngx_http_upstream_keepalive_module. + */ + bp = lmcf->balancer_peer_data; + if (bp == NULL) { + *err = "no upstream peer data found"; + return NGX_ERROR; + } + + ngx_memzero(&url, sizeof(ngx_url_t)); + + url.url.data = ngx_palloc(r->pool, addr_len); + if (url.url.data == NULL) { + *err = "no memory"; + return NGX_ERROR; + } + + ngx_memcpy(url.url.data, addr, addr_len); + + url.url.len = addr_len; + url.default_port = (in_port_t) port; + url.uri_part = 0; + url.no_resolve = 1; + + if (ngx_parse_url(r->pool, &url) != NGX_OK) { + if (url.err) { + *err = url.err; + } + + return NGX_ERROR; + } + + if (url.addrs && url.addrs[0].sockaddr) { + bp->sockaddr = url.addrs[0].sockaddr; + bp->socklen = url.addrs[0].socklen; + bp->host = url.addrs[0].name; + + } else { + *err = "no host allowed"; + return NGX_ERROR; + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r, + int count, char **err) +{ + ngx_uint_t max_tries; + ngx_http_lua_ctx_t *ctx; + ngx_http_upstream_t *u; + + ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_balancer_peer_data_t *bp; + + if (r == NULL) { + *err = "no request found"; + return NGX_ERROR; + } + + u = r->upstream; + + if (u == NULL) { + *err = "no upstream found"; + return NGX_ERROR; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + *err = "no ctx found"; + return NGX_ERROR; + } + + if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) { + *err = "API disabled in the current context"; + return NGX_ERROR; + } + + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + + bp = lmcf->balancer_peer_data; + if (bp == NULL) { + *err = "no upstream peer data found"; + return NGX_ERROR; + } + +#if (nginx_version >= 1007005) + max_tries = r->upstream->conf->next_upstream_tries; + + if (bp->total_tries + count > max_tries) { + count = max_tries - bp->total_tries; + *err = "reduced tries due to limit"; + + } else { + *err = NULL; + } +#else + *err = NULL; +#endif + + bp->more_tries = count; + return NGX_OK; +} + + +int +ngx_http_lua_ffi_balancer_get_last_failure(ngx_http_request_t *r, + int *status, char **err) +{ + ngx_http_lua_ctx_t *ctx; + ngx_http_upstream_t *u; + ngx_http_upstream_state_t *state; + + ngx_http_lua_balancer_peer_data_t *bp; + ngx_http_lua_main_conf_t *lmcf; + + if (r == NULL) { + *err = "no request found"; + return NGX_ERROR; + } + + u = r->upstream; + + if (u == NULL) { + *err = "no upstream found"; + return NGX_ERROR; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + *err = "no ctx found"; + return NGX_ERROR; + } + + if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) { + *err = "API disabled in the current context"; + return NGX_ERROR; + } + + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + + bp = lmcf->balancer_peer_data; + if (bp == NULL) { + *err = "no upstream peer data found"; + return NGX_ERROR; + } + + if (r->upstream_states && r->upstream_states->nelts > 1) { + state = r->upstream_states->elts; + *status = (int) state[r->upstream_states->nelts - 2].status; + + } else { + *status = 0; + } + + return bp->last_peer_state; +} + +#endif /* NGX_LUA_NO_FFI_API */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.h b/debian/modules/nginx-lua/src/ngx_http_lua_balancer.h new file mode 100644 index 0000000..bb49dc0 --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_balancer.h @@ -0,0 +1,27 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_BALANCER_H_INCLUDED_ +#define _NGX_HTTP_LUA_BALANCER_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +ngx_int_t ngx_http_lua_balancer_handler_inline(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L); + +ngx_int_t ngx_http_lua_balancer_handler_file(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L); + +char *ngx_http_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + +char *ngx_http_lua_balancer_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +#endif /* _NGX_HTTP_LUA_BALANCER_H_INCLUDED_ */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_bodyfilterby.c b/debian/modules/nginx-lua/src/ngx_http_lua_bodyfilterby.c index a07a0d9..86e347e 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_bodyfilterby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_bodyfilterby.c @@ -160,7 +160,8 @@ ngx_http_lua_body_filter_inline(ngx_http_request_t *r, ngx_chain_t *in) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua inline script (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadbuffer(r, L, llcf->body_filter_src.value.data, + rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, + llcf->body_filter_src.value.data, llcf->body_filter_src.value.len, llcf->body_filter_src_key, "=body_filter_by_lua"); @@ -208,7 +209,7 @@ ngx_http_lua_body_filter_file(ngx_http_request_t *r, ngx_chain_t *in) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua script file (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadfile(r, L, script_path, + rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path, llcf->body_filter_src_key); if (rc != NGX_OK) { return NGX_ERROR; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_cache.c b/debian/modules/nginx-lua/src/ngx_http_lua_cache.c index 6a1655f..e8a132e 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_cache.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_cache.c @@ -32,7 +32,7 @@ * * */ static ngx_int_t -ngx_http_lua_cache_load_code(ngx_http_request_t *r, lua_State *L, +ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, const char *key) { int rc; @@ -68,7 +68,7 @@ ngx_http_lua_cache_load_code(ngx_http_request_t *r, lua_State *L, err = (u_char *) "unknown error"; } - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + ngx_log_error(NGX_LOG_ERR, log, 0, "lua: failed to run factory at key \"%s\": %s", key, err); lua_pop(L, 2); @@ -133,7 +133,7 @@ ngx_http_lua_cache_store_code(lua_State *L, const char *key) ngx_int_t -ngx_http_lua_cache_loadbuffer(ngx_http_request_t *r, lua_State *L, +ngx_http_lua_cache_loadbuffer(ngx_log_t *log, lua_State *L, const u_char *src, size_t src_len, const u_char *cache_key, const char *name) { @@ -145,7 +145,7 @@ ngx_http_lua_cache_loadbuffer(ngx_http_request_t *r, lua_State *L, dd("XXX cache key: [%s]", cache_key); - rc = ngx_http_lua_cache_load_code(r, L, (char *) cache_key); + rc = ngx_http_lua_cache_load_code(log, L, (char *) cache_key); if (rc == NGX_OK) { /* code chunk loaded from cache, sp++ */ dd("Code cache hit! cache key='%s', stack top=%d, script='%.*s'", @@ -194,7 +194,7 @@ ngx_http_lua_cache_loadbuffer(ngx_http_request_t *r, lua_State *L, error: - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + ngx_log_error(NGX_LOG_ERR, log, 0, "failed to load inlined Lua code: %s", err); lua_settop(L, n); return NGX_ERROR; @@ -202,7 +202,7 @@ error: ngx_int_t -ngx_http_lua_cache_loadfile(ngx_http_request_t *r, lua_State *L, +ngx_http_lua_cache_loadfile(ngx_log_t *log, lua_State *L, const u_char *script, const u_char *cache_key) { int n; @@ -229,7 +229,7 @@ ngx_http_lua_cache_loadfile(ngx_http_request_t *r, lua_State *L, dd("XXX cache key for file: [%s]", cache_key); - rc = ngx_http_lua_cache_load_code(r, L, (char *) cache_key); + rc = ngx_http_lua_cache_load_code(log, L, (char *) cache_key); if (rc == NGX_OK) { /* code chunk loaded from cache, sp++ */ dd("Code cache hit! cache key='%s', stack top=%d, file path='%s'", @@ -286,7 +286,7 @@ ngx_http_lua_cache_loadfile(ngx_http_request_t *r, lua_State *L, error: - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + ngx_log_error(NGX_LOG_ERR, log, 0, "failed to load external Lua file \"%s\": %s", script, err); lua_settop(L, n); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_cache.h b/debian/modules/nginx-lua/src/ngx_http_lua_cache.h index 64c4aa2..52e6d2c 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_cache.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_cache.h @@ -12,10 +12,10 @@ #include "ngx_http_lua_common.h" -ngx_int_t ngx_http_lua_cache_loadbuffer(ngx_http_request_t *r, lua_State *L, +ngx_int_t ngx_http_lua_cache_loadbuffer(ngx_log_t *log, lua_State *L, const u_char *src, size_t src_len, const u_char *cache_key, const char *name); -ngx_int_t ngx_http_lua_cache_loadfile(ngx_http_request_t *r, lua_State *L, +ngx_int_t ngx_http_lua_cache_loadfile(ngx_log_t *log, lua_State *L, const u_char *script, const u_char *cache_key); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_clfactory.c b/debian/modules/nginx-lua/src/ngx_http_lua_clfactory.c index 221f952..86885bb 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_clfactory.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_clfactory.c @@ -368,7 +368,7 @@ ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, dd("==LJ_BT_HEADER=="); size_t i; for (i = 0; i < LJ_HEADERSIZE; i++) { - dd("%ld: 0x%02X", i, (unsigned)(u_char)lf->begin_code.str[i]); + dd("%ld: 0x%02X", i, (unsigned)(u_char) lf->begin_code.str[i]); } dd("==LJ_BT_HEADER_END=="); } @@ -471,7 +471,7 @@ ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, dd("==LUA_BT_HEADER=="); size_t i; for (i = 0; i < LUAC_HEADERSIZE; i++) { - dd("%ld, 0x%02X", i, (unsigned)(u_char)lf->begin_code.str[i]); + dd("%ld, 0x%02X", i, (unsigned)(u_char) lf->begin_code.str[i]); } dd("==LUA_BT_HEADER_END=="); } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_common.h b/debian/modules/nginx-lua/src/ngx_http_lua_common.h index 582815c..e7b9969 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_common.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_common.h @@ -21,6 +21,12 @@ #include #include + +#if !defined(nginx_version) || (nginx_version < 1006000) +#error at least nginx 1.6.0 is required but found an older version +#endif + + #if defined(NDK) && NDK #include #endif @@ -31,6 +37,11 @@ #endif +#if (!defined OPENSSL_NO_OCSP && defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) +# define NGX_HTTP_LUA_USE_OCSP 1 +#endif + + #ifndef MD5_DIGEST_LENGTH #define MD5_DIGEST_LENGTH 16 #endif @@ -94,6 +105,8 @@ typedef struct { #define NGX_HTTP_LUA_CONTEXT_BODY_FILTER 0x040 #define NGX_HTTP_LUA_CONTEXT_TIMER 0x080 #define NGX_HTTP_LUA_CONTEXT_INIT_WORKER 0x100 +#define NGX_HTTP_LUA_CONTEXT_BALANCER 0x200 +#define NGX_HTTP_LUA_CONTEXT_SSL_CERT 0x400 #ifndef NGX_LUA_NO_FFI_API @@ -102,11 +115,21 @@ typedef struct { #endif -typedef struct ngx_http_lua_main_conf_s ngx_http_lua_main_conf_t; +typedef struct ngx_http_lua_main_conf_s ngx_http_lua_main_conf_t; +typedef union ngx_http_lua_srv_conf_u ngx_http_lua_srv_conf_t; -typedef ngx_int_t (*ngx_http_lua_conf_handler_pt)(ngx_log_t *log, - ngx_http_lua_main_conf_t *lmcf, lua_State *L); +typedef struct ngx_http_lua_balancer_peer_data_s + ngx_http_lua_balancer_peer_data_t; + + +typedef struct ngx_http_lua_semaphore_mm_s ngx_http_lua_semaphore_mm_t; + + +typedef ngx_int_t (*ngx_http_lua_main_conf_handler_pt)(ngx_log_t *log, + ngx_http_lua_main_conf_t *lmcf, lua_State *L); +typedef ngx_int_t (*ngx_http_lua_srv_conf_handler_pt)(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lmcf, lua_State *L); typedef struct { @@ -145,14 +168,22 @@ struct ngx_http_lua_main_conf_s { ngx_flag_t postponed_to_rewrite_phase_end; ngx_flag_t postponed_to_access_phase_end; - ngx_http_lua_conf_handler_pt init_handler; - ngx_str_t init_src; + ngx_http_lua_main_conf_handler_pt init_handler; + ngx_str_t init_src; - ngx_http_lua_conf_handler_pt init_worker_handler; - ngx_str_t init_worker_src; + ngx_http_lua_main_conf_handler_pt init_worker_handler; + ngx_str_t init_worker_src; + + ngx_http_lua_balancer_peer_data_t *balancer_peer_data; + /* balancer_by_lua does not support yielding and + * there cannot be any conflicts among concurrent requests, + * thus it is safe to store the peer data in the main conf. + */ ngx_uint_t shm_zones_inited; + ngx_http_lua_semaphore_mm_t *semaphore_mm; + unsigned requires_header_filter:1; unsigned requires_body_filter:1; unsigned requires_capture_filter:1; @@ -163,6 +194,24 @@ struct ngx_http_lua_main_conf_s { }; +union ngx_http_lua_srv_conf_u { +#if (NGX_HTTP_SSL) + struct { + ngx_http_lua_srv_conf_handler_pt cert_handler; + ngx_str_t cert_src; + u_char *cert_src_key; + } ssl; +#endif + + struct { + ngx_str_t src; + u_char *src_key; + + ngx_http_lua_srv_conf_handler_pt handler; + } balancer; +}; + + typedef struct { #if (NGX_HTTP_SSL) ngx_ssl_t *ssl; /* shared by SSL cosockets */ @@ -303,6 +352,8 @@ struct ngx_http_lua_co_ctx_s { ngx_event_t sleep; /* used for ngx.sleep */ + ngx_queue_t sem_wait_queue; + #ifdef NGX_LUA_USE_ASSERT int co_top; /* stack top after yielding/creation, only for sanity checks */ @@ -330,6 +381,7 @@ struct ngx_http_lua_co_ctx_s { unsigned thread_spawn_yielded:1; /* yielded from the ngx.thread.spawn() call */ + unsigned sem_resume_status:1; }; @@ -372,6 +424,8 @@ typedef struct ngx_http_lua_ctx_s { ngx_http_cleanup_pt *cleanup; + ngx_http_cleanup_t *free_cleanup; /* free list of cleanup records */ + ngx_chain_t *body; /* buffered subrequest response body chains */ @@ -451,7 +505,7 @@ typedef struct ngx_http_lua_ctx_s { } ngx_http_lua_ctx_t; -typedef struct ngx_http_lua_header_val_s ngx_http_lua_header_val_t; +typedef struct ngx_http_lua_header_val_s ngx_http_lua_header_val_t; typedef ngx_int_t (*ngx_http_lua_set_header_pt)(ngx_http_request_t *r, diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_consts.c b/debian/modules/nginx-lua/src/ngx_http_lua_consts.c index ebf8724..30a86f1 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_consts.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_consts.c @@ -89,12 +89,27 @@ ngx_http_lua_inject_http_consts(lua_State *L) lua_setfield(L, -2, "HTTP_TRACE"); /* }}} */ + lua_pushinteger(L, NGX_HTTP_CONTINUE); + lua_setfield(L, -2, "HTTP_CONTINUE"); + + lua_pushinteger(L, NGX_HTTP_SWITCHING_PROTOCOLS); + lua_setfield(L, -2, "HTTP_SWITCHING_PROTOCOLS"); + lua_pushinteger(L, NGX_HTTP_OK); lua_setfield(L, -2, "HTTP_OK"); lua_pushinteger(L, NGX_HTTP_CREATED); lua_setfield(L, -2, "HTTP_CREATED"); + lua_pushinteger(L, NGX_HTTP_ACCEPTED); + lua_setfield(L, -2, "HTTP_ACCEPTED"); + + lua_pushinteger(L, NGX_HTTP_NO_CONTENT); + lua_setfield(L, -2, "HTTP_NO_CONTENT"); + + lua_pushinteger(L, NGX_HTTP_PARTIAL_CONTENT); + lua_setfield(L, -2, "HTTP_PARTIAL_CONTENT"); + lua_pushinteger(L, NGX_HTTP_SPECIAL_RESPONSE); lua_setfield(L, -2, "HTTP_SPECIAL_RESPONSE"); @@ -112,12 +127,17 @@ ngx_http_lua_inject_http_consts(lua_State *L) lua_pushinteger(L, NGX_HTTP_NOT_MODIFIED); lua_setfield(L, -2, "HTTP_NOT_MODIFIED"); + lua_pushinteger(L, NGX_HTTP_TEMPORARY_REDIRECT); + lua_setfield(L, -2, "HTTP_TEMPORARY_REDIRECT"); + lua_pushinteger(L, NGX_HTTP_BAD_REQUEST); lua_setfield(L, -2, "HTTP_BAD_REQUEST"); lua_pushinteger(L, NGX_HTTP_UNAUTHORIZED); lua_setfield(L, -2, "HTTP_UNAUTHORIZED"); + lua_pushinteger(L, 402); + lua_setfield(L, -2, "HTTP_PAYMENT_REQUIRED"); lua_pushinteger(L, NGX_HTTP_FORBIDDEN); lua_setfield(L, -2, "HTTP_FORBIDDEN"); @@ -128,20 +148,51 @@ ngx_http_lua_inject_http_consts(lua_State *L) lua_pushinteger(L, NGX_HTTP_NOT_ALLOWED); lua_setfield(L, -2, "HTTP_NOT_ALLOWED"); + lua_pushinteger(L, 406); + lua_setfield(L, -2, "HTTP_NOT_ACCEPTABLE"); + + lua_pushinteger(L, NGX_HTTP_REQUEST_TIME_OUT); + lua_setfield(L, -2, "HTTP_REQUEST_TIMEOUT"); + + lua_pushinteger(L, NGX_HTTP_CONFLICT); + lua_setfield(L, -2, "HTTP_CONFLICT"); + lua_pushinteger(L, 410); lua_setfield(L, -2, "HTTP_GONE"); + lua_pushinteger(L, 426); + lua_setfield(L, -2, "HTTP_UPGRADE_REQUIRED"); + + lua_pushinteger(L, 429); + lua_setfield(L, -2, "HTTP_TOO_MANY_REQUESTS"); + + lua_pushinteger(L, 451); + lua_setfield(L, -2, "HTTP_ILLEGAL"); + + lua_pushinteger(L, NGX_HTTP_CLOSE); + lua_setfield(L, -2, "HTTP_CLOSE"); + lua_pushinteger(L, NGX_HTTP_INTERNAL_SERVER_ERROR); lua_setfield(L, -2, "HTTP_INTERNAL_SERVER_ERROR"); lua_pushinteger(L, NGX_HTTP_NOT_IMPLEMENTED); lua_setfield(L, -2, "HTTP_METHOD_NOT_IMPLEMENTED"); + lua_pushinteger(L, NGX_HTTP_BAD_GATEWAY); + lua_setfield(L, -2, "HTTP_BAD_GATEWAY"); + lua_pushinteger(L, NGX_HTTP_SERVICE_UNAVAILABLE); lua_setfield(L, -2, "HTTP_SERVICE_UNAVAILABLE"); lua_pushinteger(L, NGX_HTTP_GATEWAY_TIME_OUT); lua_setfield(L, -2, "HTTP_GATEWAY_TIMEOUT"); + + lua_pushinteger(L, 505); + lua_setfield(L, -2, "HTTP_VERSION_NOT_SUPPORTED"); + + lua_pushinteger(L, NGX_HTTP_INSUFFICIENT_STORAGE); + lua_setfield(L, -2, "HTTP_INSUFFICIENT_STORAGE"); + /* }}} */ } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c b/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c index 9234dd9..666b549 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c @@ -54,7 +54,7 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) if (co == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "lua: failed to create new coroutine to handle request"); + "lua: failed to create new coroutine to handle request"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -251,7 +251,7 @@ ngx_http_lua_content_handler_file(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua script file (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadfile(r, L, script_path, + rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path, llcf->content_src_key); if (rc != NGX_OK) { if (rc < NGX_HTTP_SPECIAL_RESPONSE) { @@ -280,7 +280,8 @@ ngx_http_lua_content_handler_inline(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua inline script (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadbuffer(r, L, llcf->content_src.value.data, + rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, + llcf->content_src.value.data, llcf->content_src.value.len, llcf->content_src_key, (const char *) diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_contentby.h b/debian/modules/nginx-lua/src/ngx_http_lua_contentby.h index 766baa6..58ba8e1 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_contentby.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_contentby.h @@ -12,7 +12,7 @@ #include "ngx_http_lua_common.h" -ngx_int_t ngx_http_lua_content_by_chunk(lua_State *l, ngx_http_request_t *r); +ngx_int_t ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r); void ngx_http_lua_content_wev_handler(ngx_http_request_t *r); ngx_int_t ngx_http_lua_content_handler_file(ngx_http_request_t *r); ngx_int_t ngx_http_lua_content_handler_inline(ngx_http_request_t *r); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_control.c b/debian/modules/nginx-lua/src/ngx_http_lua_control.c index 6105edd..0e1dd47 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_control.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_control.c @@ -10,6 +10,7 @@ #endif #include "ddebug.h" + #include "ngx_http_lua_control.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_coroutine.h" @@ -209,12 +210,15 @@ ngx_http_lua_ngx_redirect(lua_State *L) if (n == 2) { rc = (ngx_int_t) luaL_checknumber(L, 2); - if (rc != NGX_HTTP_MOVED_TEMPORARILY && - rc != NGX_HTTP_MOVED_PERMANENTLY) + if (rc != NGX_HTTP_MOVED_TEMPORARILY + && rc != NGX_HTTP_MOVED_PERMANENTLY + && rc != NGX_HTTP_TEMPORARY_REDIRECT) { - return luaL_error(L, "only ngx.HTTP_MOVED_TEMPORARILY and " - "ngx.HTTP_MOVED_PERMANENTLY are allowed"); + return luaL_error(L, "only ngx.HTTP_MOVED_TEMPORARILY, " + "ngx.HTTP_MOVED_PERMANENTLY, and " + "ngx.HTTP_TEMPORARY_REDIRECT are allowed"); } + } else { rc = NGX_HTTP_MOVED_TEMPORARILY; } @@ -256,9 +260,9 @@ ngx_http_lua_ngx_redirect(lua_State *L) #if 0 dd("location hash: %lu == %lu", - (unsigned long) h->hash, - (unsigned long) ngx_hash_key_lc((u_char *) "Location", - sizeof("Location") - 1)); + (unsigned long) h->hash, + (unsigned long) ngx_hash_key_lc((u_char *) "Location", + sizeof("Location") - 1)); #endif h->value.len = len; @@ -290,9 +294,9 @@ ngx_http_lua_ngx_redirect(lua_State *L) static int ngx_http_lua_ngx_exit(lua_State *L) { + ngx_int_t rc; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; - ngx_int_t rc; if (lua_gettop(L) != 1) { return luaL_error(L, "expecting one argument"); @@ -312,10 +316,31 @@ ngx_http_lua_ngx_exit(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_HEADER_FILTER); + | NGX_HTTP_LUA_CONTEXT_HEADER_FILTER + | NGX_HTTP_LUA_CONTEXT_BALANCER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT); rc = (ngx_int_t) luaL_checkinteger(L, 1); + if (ctx->context == NGX_HTTP_LUA_CONTEXT_SSL_CERT) { + +#if (NGX_HTTP_SSL) + + ctx->exit_code = rc; + ctx->exited = 1; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua exit with code %i", rc); + + return lua_yield(L, 0); + +#else + + return luaL_error(L, "no SSL support"); + +#endif + } + if (ctx->no_abort && rc != NGX_ERROR && rc != NGX_HTTP_CLOSE @@ -348,7 +373,9 @@ ngx_http_lua_ngx_exit(lua_State *L) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua exit with code %i", ctx->exit_code); - if (ctx->context & NGX_HTTP_LUA_CONTEXT_HEADER_FILTER) { + if (ctx->context & (NGX_HTTP_LUA_CONTEXT_HEADER_FILTER + | NGX_HTTP_LUA_CONTEXT_BALANCER)) + { return 0; } @@ -431,13 +458,33 @@ ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, u_char *err, | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_HEADER_FILTER, + | NGX_HTTP_LUA_CONTEXT_HEADER_FILTER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT, err, errlen) != NGX_OK) { return NGX_ERROR; } + if (ctx->context == NGX_HTTP_LUA_CONTEXT_SSL_CERT) { + +#if (NGX_HTTP_SSL) + + ctx->exit_code = status; + ctx->exited = 1; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua exit with code %d", status); + + return NGX_OK; + +#else + + return NGX_ERROR; + +#endif + } + if (ctx->no_abort && status != NGX_ERROR && status != NGX_HTTP_CLOSE @@ -458,7 +505,7 @@ ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, u_char *err, { if (status != (ngx_int_t) r->headers_out.status) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to " - "set status %i via ngx.exit after sending out the " + "set status %d via ngx.exit after sending out the " "response status %ui", status, r->headers_out.status); } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_coroutine.c b/debian/modules/nginx-lua/src/ngx_http_lua_coroutine.c index 2bd9cb7..cb819c6 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_coroutine.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_coroutine.c @@ -71,12 +71,13 @@ ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r, ngx_http_lua_co_ctx_t *coctx; /* co ctx for the new coroutine */ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, - "Lua function expected"); + "Lua function expected"); ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT - | NGX_HTTP_LUA_CONTEXT_TIMER); + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT); vm = ngx_http_lua_get_lua_vm(r, ctx); @@ -151,7 +152,8 @@ ngx_http_lua_coroutine_resume(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT - | NGX_HTTP_LUA_CONTEXT_TIMER); + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT); p_coctx = ctx->cur_co_ctx; if (p_coctx == NULL) { @@ -210,7 +212,8 @@ ngx_http_lua_coroutine_yield(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT - | NGX_HTTP_LUA_CONTEXT_TIMER); + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT); coctx = ctx->cur_co_ctx; @@ -358,7 +361,8 @@ ngx_http_lua_coroutine_status(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT - | NGX_HTTP_LUA_CONTEXT_TIMER); + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT); coctx = ngx_http_lua_get_co_ctx(co, ctx); if (coctx == NULL) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c b/debian/modules/nginx-lua/src/ngx_http_lua_directive.c index ae8b09f..7ac8c28 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_directive.c @@ -24,6 +24,7 @@ #include "ngx_http_lua_initby.h" #include "ngx_http_lua_initworkerby.h" #include "ngx_http_lua_shdict.h" +#include "ngx_http_lua_ssl_certby.h" #include "ngx_http_lua_lex.h" @@ -40,8 +41,6 @@ static ngx_int_t ngx_http_lua_set_by_lua_init(ngx_http_request_t *r); static u_char *ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len); -static char *ngx_http_lua_conf_lua_block_parse(ngx_conf_t *cf, - ngx_command_t *cmd); static ngx_int_t ngx_http_lua_conf_read_lua_token(ngx_conf_t *cf, ngx_http_lua_block_parser_ctx_t *ctx); static u_char *ngx_http_lua_strlstrn(u_char *s1, u_char *last, u_char *s2, @@ -121,6 +120,7 @@ ngx_http_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ctx->name = name; ctx->main_conf = lmcf; ctx->log = &cf->cycle->new_log; + ctx->cycle = cf->cycle; zone = ngx_shared_memory_add(cf, &name, (size_t) size, &ngx_http_lua_module); @@ -354,7 +354,8 @@ ngx_http_lua_filter_set_by_lua_inline(ngx_http_request_t *r, ngx_str_t *val, L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua inline script (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadbuffer(r, L, filter_data->script.data, + rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, + filter_data->script.data, filter_data->script.len, filter_data->key, "=set_by_lua"); if (rc != NGX_OK) { @@ -407,7 +408,8 @@ ngx_http_lua_filter_set_by_lua_file(ngx_http_request_t *r, ngx_str_t *val, L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua script file (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadfile(r, L, script_path, filter_data->key); + rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path, + filter_data->key); if (rc != NGX_OK) { return NGX_ERROR; } @@ -1126,7 +1128,7 @@ ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, return NGX_CONF_ERROR; } - lmcf->init_handler = (ngx_http_lua_conf_handler_pt) cmd->post; + lmcf->init_handler = (ngx_http_lua_main_conf_handler_pt) cmd->post; if (cmd->post == ngx_http_lua_init_by_file) { name = ngx_http_lua_rebase_path(cf->pool, value[1].data, @@ -1186,7 +1188,7 @@ ngx_http_lua_init_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, value = cf->args->elts; - lmcf->init_worker_handler = (ngx_http_lua_conf_handler_pt) cmd->post; + lmcf->init_worker_handler = (ngx_http_lua_main_conf_handler_pt) cmd->post; if (cmd->post == ngx_http_lua_init_worker_by_file) { name = ngx_http_lua_rebase_path(cf->pool, value[1].data, @@ -1284,7 +1286,7 @@ found: /* a specialized version of the standard ngx_conf_parse() function */ -static char * +char * ngx_http_lua_conf_lua_block_parse(ngx_conf_t *cf, ngx_command_t *cmd) { ngx_http_lua_block_parser_ctx_t ctx; @@ -1555,12 +1557,63 @@ ngx_http_lua_conf_read_lua_token(ngx_conf_t *cf, rc = ngx_http_lua_lex(b->pos, b->last - b->pos, ovec); if (rc < 0) { /* no match */ - cf->conf_file->line = start_line; - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "Lua code block missing the \"}\" " - "character"); + /* alas. the lexer does not yet support streaming processing. need + * more work below */ - return NGX_ERROR; + if (cf->conf_file->file.offset >= file_size) { + + cf->conf_file->line = ctx->start_line; + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unexpected end of file, expecting " + "terminating characters for lua code " + "block"); + return NGX_ERROR; + } + + len = b->last - b->pos; + + if (len == buf_size) { + + cf->conf_file->line = start_line; + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "too long lua code block, probably " + "missing terminating characters"); + + return NGX_ERROR; + } + + if (len) { + ngx_memcpy(b->start, b->pos, len); + } + + size = (ssize_t) (file_size - cf->conf_file->file.offset); + + if (size > b->end - (b->start + len)) { + size = b->end - (b->start + len); + } + + n = ngx_read_file(&cf->conf_file->file, b->start + len, size, + cf->conf_file->file.offset); + + if (n == NGX_ERROR) { + return NGX_ERROR; + } + + if (n != size) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + ngx_read_file_n " returned " + "only %z bytes instead of %z", + n, size); + return NGX_ERROR; + } + + b->pos = b->start + len; + b->last = b->pos + n; + start = b->start; + + continue; } if (rc == FOUND_LEFT_LBRACKET_STR || rc == FOUND_LEFT_LBRACKET_CMT) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_directive.h b/debian/modules/nginx-lua/src/ngx_http_lua_directive.h index 5a8d93b..be591f3 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_directive.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_directive.h @@ -68,6 +68,9 @@ ngx_int_t ngx_http_lua_filter_set_by_lua_file(ngx_http_request_t *r, char *ngx_http_lua_rewrite_no_postpone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_lua_conf_lua_block_parse(ngx_conf_t *cf, + ngx_command_t *cmd); + #endif /* _NGX_HTTP_LUA_DIRECTIVE_H_INCLUDED_ */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c b/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c index 79bac65..75ce324 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c @@ -168,7 +168,7 @@ ngx_http_lua_header_filter_inline(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua inline script (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadbuffer(r, L, + rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, llcf->header_filter_src.value.data, llcf->header_filter_src.value.len, llcf->header_filter_src_key, @@ -211,7 +211,7 @@ ngx_http_lua_header_filter_file(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua script file (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadfile(r, L, script_path, + rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path, llcf->header_filter_src_key); if (rc != NGX_OK) { return NGX_ERROR; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers.c b/debian/modules/nginx-lua/src/ngx_http_lua_headers.c index 5f8e59a..a9e45d3 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headers.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headers.c @@ -608,7 +608,7 @@ ngx_http_lua_ngx_header_get(lua_State *L) if (llcf->transform_underscores_in_resp_headers && memchr(p, '_', len) != NULL) { - key.data = (u_char*) lua_newuserdata(L, len); + key.data = (u_char *) lua_newuserdata(L, len); if (key.data == NULL) { return luaL_error(L, "no memory"); } @@ -989,7 +989,7 @@ ngx_http_lua_ffi_req_get_headers_count(ngx_http_request_t *r, int max) int count; ngx_list_part_t *part; - if (r->connection->fd == -1) { + if (r->connection->fd == (ngx_socket_t) -1) { return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } @@ -1082,7 +1082,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, return NGX_HTTP_LUA_FFI_NO_REQ_CTX; } - if (r->connection->fd == -1) { + if (r->connection->fd == (ngx_socket_t) -1) { return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } @@ -1198,7 +1198,7 @@ ngx_http_lua_ffi_req_header_set_single_value(ngx_http_request_t *r, ngx_str_t k; ngx_str_t v; - if (r->connection->fd == -1) { /* fake request */ + if (r->connection->fd == (ngx_socket_t) -1) { /* fake request */ return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } @@ -1253,7 +1253,7 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, ngx_http_lua_loc_conf_t *llcf; - if (r->connection->fd == -1) { + if (r->connection->fd == (ngx_socket_t) -1) { return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers_in.c b/debian/modules/nginx-lua/src/ngx_http_lua_headers_in.c index abce458..82b4331 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headers_in.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headers_in.c @@ -29,7 +29,7 @@ static ngx_int_t ngx_http_set_connection_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_set_content_length_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); -static ngx_int_t ngx_http_set_cookie_header(ngx_http_request_t *r, +static ngx_int_t ngx_http_set_builtin_multi_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_clear_builtin_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); @@ -128,6 +128,13 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { offsetof(ngx_http_headers_in_t, keep_alive), ngx_http_set_builtin_header }, +#if (NGX_HTTP_X_FORWARDED_FOR) + { ngx_string("X-Forwarded-For"), + offsetof(ngx_http_headers_in_t, x_forwarded_for), + ngx_http_set_builtin_multi_header }, + +#endif + #if (NGX_HTTP_REALIP) { ngx_string("X-Real-IP"), offsetof(ngx_http_headers_in_t, x_real_ip), @@ -152,8 +159,8 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { #endif { ngx_string("Cookie"), - 0, - ngx_http_set_cookie_header }, + offsetof(ngx_http_headers_in_t, cookies), + ngx_http_set_builtin_multi_header }, { ngx_null_string, 0, ngx_http_set_header } }; @@ -558,7 +565,7 @@ ngx_http_set_content_length_header(ngx_http_request_t *r, return NGX_ERROR; } - dd("reset headers_in.content_length_n to %d", (int)len); + dd("reset headers_in.content_length_n to %d", (int) len); r->headers_in.content_length_n = len; @@ -567,27 +574,30 @@ ngx_http_set_content_length_header(ngx_http_request_t *r, static ngx_int_t -ngx_http_set_cookie_header(ngx_http_request_t *r, +ngx_http_set_builtin_multi_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value) { - ngx_table_elt_t **cookie, *h; + ngx_array_t *headers; + ngx_table_elt_t **v, *h; - if (!hv->no_override && r->headers_in.cookies.nelts > 0) { - ngx_array_destroy(&r->headers_in.cookies); + headers = (ngx_array_t *) ((char *) &r->headers_in + hv->offset); - if (ngx_array_init(&r->headers_in.cookies, r->pool, 2, + if (!hv->no_override && headers->nelts > 0) { + ngx_array_destroy(headers); + + if (ngx_array_init(headers, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK) { return NGX_ERROR; } - dd("clear headers in cookies: %d", (int) r->headers_in.cookies.nelts); + dd("clear multi-value headers: %d", (int) headers->nelts); } #if 1 - if (r->headers_in.cookies.nalloc == 0) { - if (ngx_array_init(&r->headers_in.cookies, r->pool, 2, + if (headers->nalloc == 0) { + if (ngx_array_init(headers, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK) { @@ -604,14 +614,14 @@ ngx_http_set_cookie_header(ngx_http_request_t *r, return NGX_OK; } - dd("new cookie header: %p", h); + dd("new multi-value header: %p", h); - cookie = ngx_array_push(&r->headers_in.cookies); - if (cookie == NULL) { + v = ngx_array_push(headers); + if (v == NULL) { return NGX_ERROR; } - *cookie = h; + *v = h; return NGX_OK; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c b/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c index 5fd077f..b908eae 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c @@ -179,7 +179,7 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, } else { dd("setting header to value %.*s", (int) value->len, - value->data); + value->data); h[i].value = *value; h[i].hash = hv->hash; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_logby.c b/debian/modules/nginx-lua/src/ngx_http_lua_logby.c index 9d06323..0a79acd 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_logby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_logby.c @@ -113,7 +113,8 @@ ngx_http_lua_log_handler_inline(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua inline script (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadbuffer(r, L, llcf->log_src.value.data, + rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, + llcf->log_src.value.data, llcf->log_src.value.len, llcf->log_src_key, (const char *) llcf->log_chunkname); @@ -150,7 +151,8 @@ ngx_http_lua_log_handler_file(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua script file (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadfile(r, L, script_path, llcf->log_src_key); + rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path, + llcf->log_src_key); if (rc != NGX_OK) { return NGX_ERROR; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_misc.c b/debian/modules/nginx-lua/src/ngx_http_lua_misc.c index 4990e26..e3c7ec7 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_misc.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_misc.c @@ -18,6 +18,7 @@ static int ngx_http_lua_ngx_get(lua_State *L); static int ngx_http_lua_ngx_set(lua_State *L); +static int ngx_http_lua_ngx_req_is_internal(lua_State *L); void @@ -33,6 +34,29 @@ ngx_http_lua_inject_misc_api(lua_State *L) } +void +ngx_http_lua_inject_req_misc_api(lua_State *L) +{ + lua_pushcfunction(L, ngx_http_lua_ngx_req_is_internal); + lua_setfield(L, -2, "is_internal"); +} + + +static int +ngx_http_lua_ngx_req_is_internal(lua_State *L) +{ + ngx_http_request_t *r; + + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request object found"); + } + + lua_pushboolean(L, r->internal == 1); + return 1; +} + + static int ngx_http_lua_ngx_get(lua_State *L) { @@ -176,7 +200,7 @@ ngx_http_lua_ngx_set(lua_State *L) int ngx_http_lua_ffi_get_resp_status(ngx_http_request_t *r) { - if (r->connection->fd == -1) { + if (r->connection->fd == (ngx_socket_t) -1) { return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } @@ -198,7 +222,7 @@ ngx_http_lua_ffi_get_resp_status(ngx_http_request_t *r) int ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int status) { - if (r->connection->fd == -1) { + if (r->connection->fd == (ngx_socket_t) -1) { return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } @@ -230,7 +254,7 @@ ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int status) int ngx_http_lua_ffi_is_subrequest(ngx_http_request_t *r) { - if (r->connection->fd == -1) { + if (r->connection->fd == (ngx_socket_t) -1) { return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } @@ -248,7 +272,7 @@ ngx_http_lua_ffi_headers_sent(ngx_http_request_t *r) return NGX_HTTP_LUA_FFI_NO_REQ_CTX; } - if (r->connection->fd == -1) { + if (r->connection->fd == (ngx_socket_t) -1) { return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_misc.h b/debian/modules/nginx-lua/src/ngx_http_lua_misc.h index 8a79b92..c26d869 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_misc.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_misc.h @@ -14,6 +14,8 @@ void ngx_http_lua_inject_misc_api(lua_State *L); +void ngx_http_lua_inject_req_misc_api(lua_State *L); + #endif /* _NGX_HTTP_LUA_MISC_H_INCLUDED_ */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_module.c b/debian/modules/nginx-lua/src/ngx_http_lua_module.c index 3bf50c2..c72a705 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_module.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_module.c @@ -23,16 +23,18 @@ #include "ngx_http_lua_initby.h" #include "ngx_http_lua_initworkerby.h" #include "ngx_http_lua_probe.h" - - -#if !defined(nginx_version) || nginx_version < 8054 -#error "at least nginx 0.8.54 is required" -#endif +#include "ngx_http_lua_semaphore.h" +#include "ngx_http_lua_balancer.h" +#include "ngx_http_lua_ssl_certby.h" static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf); static char *ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf); +static void *ngx_http_lua_create_srv_conf(ngx_conf_t *cf); +static char *ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, + void *child); static void *ngx_http_lua_create_loc_conf(ngx_conf_t *cf); + static char *ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); static ngx_int_t ngx_http_lua_init(ngx_conf_t *cf); @@ -313,6 +315,13 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, (void *) ngx_http_lua_access_handler_file }, + { ngx_string("access_by_lua_no_postpone"), + NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_lua_main_conf_t, postponed_to_access_phase_end), + NULL }, + /* content_by_lua_file rel/or/abs/path/to/script */ { ngx_string("content_by_lua_file"), NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, @@ -380,6 +389,20 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, (void *) ngx_http_lua_body_filter_file }, + { ngx_string("balancer_by_lua_block"), + NGX_HTTP_UPS_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_http_lua_balancer_by_lua_block, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + (void *) ngx_http_lua_balancer_handler_inline }, + + { ngx_string("balancer_by_lua_file"), + NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, + ngx_http_lua_balancer_by_lua, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + (void *) ngx_http_lua_balancer_handler_file }, + { ngx_string("lua_socket_keepalive_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF |NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, @@ -480,6 +503,24 @@ static ngx_command_t ngx_http_lua_cmds[] = { offsetof(ngx_http_lua_loc_conf_t, ssl_ciphers), NULL }, +#if (NGX_HTTP_SSL) + + { ngx_string("ssl_certificate_by_lua_block"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_http_lua_ssl_cert_by_lua_block, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + (void *) ngx_http_lua_ssl_cert_handler_inline }, + + { ngx_string("ssl_certificate_by_lua_file"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_lua_ssl_cert_by_lua, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + (void *) ngx_http_lua_ssl_cert_handler_file }, + +#endif /* NGX_HTTP_SSL */ + { ngx_string("lua_ssl_verify_depth"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, @@ -514,8 +555,8 @@ ngx_http_module_t ngx_http_lua_module_ctx = { ngx_http_lua_create_main_conf, /* create main configuration */ ngx_http_lua_init_main_conf, /* init main configuration */ - NULL, /* create server configuration */ - NULL, /* merge server configuration */ + ngx_http_lua_create_srv_conf, /* create server configuration */ + ngx_http_lua_merge_srv_conf, /* merge server configuration */ ngx_http_lua_create_loc_conf, /* create location configuration */ ngx_http_lua_merge_loc_conf /* merge location configuration */ @@ -545,8 +586,12 @@ ngx_http_lua_init(ngx_conf_t *cf) ngx_int_t rc; ngx_array_t *arr; ngx_http_handler_pt *h; + volatile ngx_cycle_t *saved_cycle; ngx_http_core_main_conf_t *cmcf; ngx_http_lua_main_conf_t *lmcf; +#ifndef NGX_LUA_NO_FFI_API + ngx_pool_cleanup_t *cln; +#endif lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); @@ -569,6 +614,10 @@ ngx_http_lua_init(ngx_conf_t *cf) lmcf->postponed_to_rewrite_phase_end = 0; } + if (lmcf->postponed_to_access_phase_end == NGX_CONF_UNSET) { + lmcf->postponed_to_access_phase_end = 0; + } + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); if (lmcf->requires_rewrite) { @@ -621,6 +670,19 @@ ngx_http_lua_init(ngx_conf_t *cf) } } +#ifndef NGX_LUA_NO_FFI_API + + /* add the cleanup of semaphores after the lua_close */ + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->data = lmcf; + cln->handler = ngx_http_lua_cleanup_semaphore_mm; + +#endif + if (lmcf->lua == NULL) { dd("initializing lua vm"); @@ -637,7 +699,14 @@ ngx_http_lua_init(ngx_conf_t *cf) } if (!lmcf->requires_shm && lmcf->init_handler) { - if (lmcf->init_handler(cf->log, lmcf, lmcf->lua) != NGX_OK) { + saved_cycle = ngx_cycle; + ngx_cycle = cf->cycle; + + rc = lmcf->init_handler(cf->log, lmcf, lmcf->lua); + + ngx_cycle = saved_cycle; + + if (rc != NGX_OK) { /* an error happened */ return NGX_ERROR; } @@ -683,6 +752,7 @@ static void * ngx_http_lua_create_main_conf(ngx_conf_t *cf) { ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_semaphore_mm_t *mm; lmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_main_conf_t)); if (lmcf == NULL) { @@ -719,6 +789,25 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) lmcf->regex_match_limit = NGX_CONF_UNSET; #endif lmcf->postponed_to_rewrite_phase_end = NGX_CONF_UNSET; + lmcf->postponed_to_access_phase_end = NGX_CONF_UNSET; + + mm = ngx_palloc(cf->pool, sizeof(ngx_http_lua_semaphore_mm_t)); + if (mm == NULL) { + return NULL; + } + + lmcf->semaphore_mm = mm; + mm->lmcf = lmcf; + + ngx_queue_init(&mm->free_queue); + mm->cur_epoch = 0; + mm->total = 0; + mm->used = 0; + + /* it's better to be 4096, but it needs some space for + * ngx_http_lua_semaphore_mm_block_t, one is enough, so it is 4095 + */ + mm->num_per_block = 4095; dd("nginx Lua module main config structure initialized!"); @@ -755,6 +844,70 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf) } +static void * +ngx_http_lua_create_srv_conf(ngx_conf_t *cf) +{ + ngx_http_lua_srv_conf_t *lscf; + + lscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_srv_conf_t)); + if (lscf == NULL) { + return NULL; + } + + /* set by ngx_pcalloc: + * lscf->ssl.cert_handler = NULL; + * lscf->ssl.cert_src = { 0, NULL }; + * lscf->ssl.cert_src_key = NULL; + * lscf->balancer.handler = NULL; + * lscf->balancer.src = { 0, NULL }; + * lscf->balancer.src_key = NULL; + */ + + return lscf; +} + + +static char * +ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ +#if (NGX_HTTP_SSL) + + ngx_http_lua_srv_conf_t *prev = parent; + ngx_http_lua_srv_conf_t *conf = child; + ngx_http_ssl_srv_conf_t *sscf; + + dd("merge srv conf"); + + if (conf->ssl.cert_src.len == 0) { + conf->ssl.cert_src = prev->ssl.cert_src; + conf->ssl.cert_handler = prev->ssl.cert_handler; + } + + if (conf->ssl.cert_src.len) { + sscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_ssl_module); + if (sscf == NULL || sscf->ssl.ctx == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no ssl configured for the server"); + + return NGX_CONF_ERROR; + } + +#if OPENSSL_VERSION_NUMBER >= 0x1000205fL + + SSL_CTX_set_cert_cb(sscf->ssl.ctx, ngx_http_lua_ssl_cert_handler, NULL); + +#else + + return NGX_CONF_ERROR; + +#endif + } + +#endif /* NGX_HTTP_SSL */ + return NGX_CONF_OK; +} + + static void * ngx_http_lua_create_loc_conf(ngx_conf_t *cf) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_output.c b/debian/modules/nginx-lua/src/ngx_http_lua_output.c index 2062e5a..dca5fb9 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_output.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_output.c @@ -345,7 +345,7 @@ ngx_http_lua_calc_strlen_in_table(lua_State *L, int index, int arg_i, bad_type: msg = lua_pushfstring(L, "bad data type %s found", - lua_typename(L, type)); + lua_typename(L, type)); return luaL_argerror(L, arg_i, msg); } @@ -458,7 +458,7 @@ ngx_http_lua_ngx_flush(lua_State *L) n = lua_gettop(L); if (n > 1) { return luaL_error(L, "attempt to pass %d arguments, but accepted 0 " - "or 1", n); + "or 1", n); } r = ngx_http_lua_get_req(L); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_phase.c b/debian/modules/nginx-lua/src/ngx_http_lua_phase.c index 6053a39..b8e936a 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_phase.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_phase.c @@ -76,6 +76,14 @@ ngx_http_lua_ngx_get_phase(lua_State *L) lua_pushliteral(L, "timer"); break; + case NGX_HTTP_LUA_CONTEXT_BALANCER: + lua_pushliteral(L, "balancer"); + break; + + case NGX_HTTP_LUA_CONTEXT_SSL_CERT: + lua_pushliteral(L, "ssl_cert"); + break; + default: return luaL_error(L, "unknown phase: %d", (int) ctx->context); } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c b/debian/modules/nginx-lua/src/ngx_http_lua_regex.c index 1ecfd70..8b4a668 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_regex.c @@ -449,7 +449,7 @@ ngx_http_lua_ngx_re_match_helper(lua_State *L, int wantcaps) } dd("saving regex %p, ncaptures %d, captures %p", re_comp.regex, - re_comp.captures, cap); + re_comp.captures, cap); re->regex = re_comp.regex; re->regex_sd = sd; @@ -681,7 +681,7 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) if (nargs != 2 && nargs != 3) { return luaL_error(L, "expecting two or three arguments, but got %d", - nargs); + nargs); } r = ngx_http_lua_get_req(L); @@ -1321,7 +1321,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) if (nargs != 3 && nargs != 4) { return luaL_error(L, "expecting three or four arguments, but got %d", - nargs); + nargs); } r = ngx_http_lua_get_req(L); @@ -1820,7 +1820,7 @@ exec: } rc = ngx_http_lua_complex_value(r, &subj, cp_offset, rc, cap, ctpl, - &luabuf); + &luabuf); if (rc != NGX_OK) { msg = lua_pushfstring(L, "failed to eval the template for " @@ -1972,16 +1972,16 @@ ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc) if (re == NULL) { if ((size_t) erroff == rc->pattern.len) { - rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, - "pcre_compile() failed: %s in \"%V\"", + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "pcre_compile() failed: %s in \"%V\"", errstr, &rc->pattern) - rc->err.data; } else { - rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, - "pcre_compile() failed: %s in \"%V\" " - "at \"%s\"", errstr, &rc->pattern, - rc->pattern.data + erroff) + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "pcre_compile() failed: %s in \"%V\" " + "at \"%s\"", errstr, &rc->pattern, + rc->pattern.data + erroff) - rc->err.data; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c b/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c index af90245..a916396 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c @@ -110,7 +110,7 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua start to read buffered request body"); + "lua start to read buffered request body"); rc = ngx_http_read_client_request_body(r, ngx_http_lua_req_body_post_read); @@ -332,7 +332,7 @@ ngx_http_lua_ngx_req_get_body_file(lua_State *L) r->request_body->bufs->buf->memory, r->request_body->bufs->buf->temporary, (int) (r->request_body->bufs->buf->end - - r->request_body->bufs->buf->pos), + r->request_body->bufs->buf->pos), (int) ngx_buf_size(r->request_body->bufs->buf)); lua_pushlstring(L, (char *) r->request_body->temp_file->file.name.data, diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_req_method.c b/debian/modules/nginx-lua/src/ngx_http_lua_req_method.c index 41736c3..0a2a154 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_req_method.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_req_method.c @@ -149,7 +149,7 @@ ngx_http_lua_ngx_req_set_method(lua_State *L) int ngx_http_lua_ffi_req_get_method(ngx_http_request_t *r) { - if (r->connection->fd == -1) { + if (r->connection->fd == (ngx_socket_t) -1) { return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } @@ -161,7 +161,7 @@ int ngx_http_lua_ffi_req_get_method_name(ngx_http_request_t *r, char *buf, size_t *len) { - if (r->connection->fd == -1) { + if (r->connection->fd == (ngx_socket_t) -1) { return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } @@ -174,7 +174,7 @@ ngx_http_lua_ffi_req_get_method_name(ngx_http_request_t *r, char *buf, int ngx_http_lua_ffi_req_set_method(ngx_http_request_t *r, int method) { - if (r->connection->fd == -1) { + if (r->connection->fd == (ngx_socket_t) -1) { return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c b/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c index af3b499..da30b8b 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c @@ -67,7 +67,7 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) tmp = *cur_ph; memmove(cur_ph, cur_ph + 1, - (last_ph - cur_ph) * sizeof (ngx_http_phase_handler_t)); + (last_ph - cur_ph) * sizeof (ngx_http_phase_handler_t)); *last_ph = tmp; @@ -176,7 +176,8 @@ ngx_http_lua_rewrite_handler_inline(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua inline script (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadbuffer(r, L, llcf->rewrite_src.value.data, + rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, + llcf->rewrite_src.value.data, llcf->rewrite_src.value.len, llcf->rewrite_src_key, (const char *) @@ -214,7 +215,8 @@ ngx_http_lua_rewrite_handler_file(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua script file (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadfile(r, L, script_path, llcf->rewrite_src_key); + rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path, + llcf->rewrite_src_key); if (rc != NGX_OK) { if (rc < NGX_HTTP_SPECIAL_RESPONSE) { return NGX_HTTP_INTERNAL_SERVER_ERROR; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_script.c b/debian/modules/nginx-lua/src/ngx_http_lua_script.c index 24be601..95ebadf 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_script.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_script.c @@ -59,7 +59,7 @@ ngx_http_lua_compile_complex_value(ngx_http_lua_compile_complex_value_t *ccv) } n = nv * (2 * sizeof(ngx_http_lua_script_copy_code_t) - + sizeof(ngx_http_lua_script_capture_code_t)) + + sizeof(ngx_http_lua_script_capture_code_t)) + sizeof(uintptr_t); if (ngx_array_init(&lengths, ccv->pool, n, 1) != NGX_OK) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c b/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c new file mode 100644 index 0000000..b022604 --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c @@ -0,0 +1,546 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + * Copyright (C) cuiweixie + * I hereby assign copyright in this code to the lua-nginx-module project, + * to be licensed under the same terms as the rest of the code. + */ + + +#ifndef NGX_LUA_NO_FFI_API + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_lua_util.h" +#include "ngx_http_lua_semaphore.h" +#include "ngx_http_lua_contentby.h" + + +ngx_int_t ngx_http_lua_semaphore_init_mm(ngx_http_lua_semaphore_mm_t *mm); +static ngx_http_lua_semaphore_t *ngx_http_lua_alloc_semaphore(void); +void ngx_http_lua_cleanup_semaphore_mm(void *data); +static void ngx_http_lua_free_semaphore(ngx_http_lua_semaphore_t *sem); +static ngx_int_t ngx_http_lua_semaphore_resume(ngx_http_request_t *r); +int ngx_http_lua_ffi_semaphore_new(ngx_http_lua_semaphore_t **psem, + int n, char **errmsg); +int ngx_http_lua_ffi_semaphore_post(ngx_http_lua_semaphore_t *sem, + int n); +int ngx_http_lua_ffi_semaphore_wait(ngx_http_request_t *r, + ngx_http_lua_semaphore_t *sem, int wait_ms, u_char *err, size_t *errlen); +static void ngx_http_lua_semaphore_cleanup(void *data); +static void ngx_http_lua_semaphore_handler(ngx_event_t *ev); +static void ngx_http_lua_semaphore_timeout_handler(ngx_event_t *ev); +void ngx_http_lua_ffi_semaphore_gc(ngx_http_lua_semaphore_t *sem); + + +enum { + SEMAPHORE_WAIT_SUCC = 0, + SEMAPHORE_WAIT_TIMEOUT = 1 +}; + + +static ngx_http_lua_semaphore_t * +ngx_http_lua_alloc_semaphore(void) +{ + ngx_http_lua_semaphore_t *sem, *iter; + ngx_http_lua_main_conf_t *lmcf; + ngx_queue_t *q; + ngx_uint_t i, n; + ngx_http_lua_semaphore_mm_block_t *block; + ngx_http_lua_semaphore_mm_t *mm; + + ngx_http_lua_assert(ngx_cycle && ngx_cycle->conf_ctx); + + lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle, + ngx_http_lua_module); + + mm = lmcf->semaphore_mm; + + if (!ngx_queue_empty(&mm->free_queue)) { + q = ngx_queue_head(&mm->free_queue); + ngx_queue_remove(q); + + sem = ngx_queue_data(q, ngx_http_lua_semaphore_t, chain); + + sem->block->used++; + + ngx_memzero(&sem->sem_event, sizeof(ngx_event_t)); + + sem->sem_event.handler = ngx_http_lua_semaphore_handler; + sem->sem_event.data = sem; + sem->sem_event.log = ngx_cycle->log; + + mm->used++; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "from head of free queue, alloc semaphore: %p", sem); + + return sem; + } + + /* free_queue is empty */ + + n = sizeof(ngx_http_lua_semaphore_mm_block_t) + + mm->num_per_block * sizeof(ngx_http_lua_semaphore_t); + + dd("block size: %d, item size: %d", + (int) sizeof(ngx_http_lua_semaphore_mm_block_t), + (int) sizeof(ngx_http_lua_semaphore_t)); + + block = ngx_alloc(n, ngx_cycle->log); + if (block == NULL) { + return NULL; + } + + mm->cur_epoch++; + mm->total += mm->num_per_block; + mm->used++; + + block->mm = mm; + block->epoch = mm->cur_epoch; + + sem = (ngx_http_lua_semaphore_t *) (block + 1); + sem->block = block; + sem->block->used = 1; + + ngx_memzero(&sem->sem_event, sizeof(ngx_event_t)); + + sem->sem_event.handler = ngx_http_lua_semaphore_handler; + sem->sem_event.data = sem; + sem->sem_event.log = ngx_cycle->log; + + for (iter = sem + 1, i = 1; i < mm->num_per_block; i++, iter++) { + iter->block = block; + ngx_queue_insert_tail(&mm->free_queue, &iter->chain); + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "new block, alloc semaphore: %p block: %p", sem, block); + + return sem; +} + + +void +ngx_http_lua_cleanup_semaphore_mm(void *data) +{ + ngx_http_lua_semaphore_t *sem, *iter; + ngx_uint_t i; + ngx_http_lua_main_conf_t *lmcf; + ngx_queue_t *q; + ngx_http_lua_semaphore_mm_block_t *block; + ngx_http_lua_semaphore_mm_t *mm; + + lmcf = (ngx_http_lua_main_conf_t *) data; + mm = lmcf->semaphore_mm; + + while (!ngx_queue_empty(&mm->free_queue)) { + q = ngx_queue_head(&mm->free_queue); + + sem = ngx_queue_data(q, ngx_http_lua_semaphore_t, chain); + block = sem->block; + + if (block->used == 0) { + iter = (ngx_http_lua_semaphore_t *) (block + 1); + + for (i = 0; i < block->mm->num_per_block; i++, iter++) { + ngx_queue_remove(&iter->chain); + } + + dd("free semaphore block: %p at final", block); + + ngx_free(block); + + } else { + /* just return directly when some thing goes wrong */ + + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "ngx_http_lua_cleanup_semaphore_mm when cleanup" + " block %p is still used by someone", block); + + return; + } + } + + dd("ngx_http_lua_cleanup_semaphore_mm"); +} + + +static void +ngx_http_lua_free_semaphore(ngx_http_lua_semaphore_t *sem) +{ + ngx_http_lua_semaphore_t *iter; + ngx_uint_t i, mid_epoch; + ngx_http_lua_semaphore_mm_block_t *block; + ngx_http_lua_semaphore_mm_t *mm; + + block = sem->block; + block->used--; + + mm = block->mm; + mm->used--; + + mid_epoch = mm->cur_epoch - ((mm->total / mm->num_per_block) >> 1); + + if (block->epoch < mid_epoch) { + ngx_queue_insert_tail(&mm->free_queue, &sem->chain); + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "add to free queue tail semaphore: %p epoch: %d" + "mid_epoch: %d cur_epoch: %d", sem, (int) block->epoch, + (int) mid_epoch, (int) mm->cur_epoch); + + } else { + ngx_queue_insert_head(&mm->free_queue, &sem->chain); + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "add to free queue head semaphore: %p epoch: %d" + "mid_epoch: %d cur_epoch: %d", sem, (int) block->epoch, + (int) mid_epoch, (int) mm->cur_epoch); + } + + dd("used: %d", (int) block->used); + + if (block->used == 0 + && mm->used <= (mm->total >> 1) + && block->epoch < mid_epoch) + { + /* load <= 50% and it's on the older side */ + iter = (ngx_http_lua_semaphore_t *) (block + 1); + + for (i = 0; i < mm->num_per_block; i++, iter++) { + ngx_queue_remove(&iter->chain); + } + + mm->total -= mm->num_per_block; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "free semaphore block: %p", block); + + ngx_free(block); + } +} + + +static ngx_int_t +ngx_http_lua_semaphore_resume(ngx_http_request_t *r) +{ + lua_State *vm; + ngx_connection_t *c; + ngx_int_t rc; + ngx_http_lua_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return NGX_ERROR; + } + + ctx->resume_handler = ngx_http_lua_wev_handler; + + c = r->connection; + vm = ngx_http_lua_get_lua_vm(r, ctx); + + if (ctx->cur_co_ctx->sem_resume_status == SEMAPHORE_WAIT_SUCC) { + lua_pushboolean(ctx->cur_co_ctx->co, 1); + lua_pushnil(ctx->cur_co_ctx->co); + + } else { + lua_pushboolean(ctx->cur_co_ctx->co, 0); + lua_pushstring(ctx->cur_co_ctx->co, "timeout"); + } + + rc = ngx_http_lua_run_thread(vm, r, ctx, 2); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + } + + if (rc == NGX_DONE) { + ngx_http_lua_finalize_request(r, NGX_DONE); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + } + + /* rc == NGX_ERROR || rc >= NGX_OK */ + + if (ctx->entered_content_phase) { + ngx_http_lua_finalize_request(r, rc); + return NGX_DONE; + } + + return rc; +} + + +int +ngx_http_lua_ffi_semaphore_new(ngx_http_lua_semaphore_t **psem, + int n, char **errmsg) +{ + ngx_http_lua_semaphore_t *sem; + + sem = ngx_http_lua_alloc_semaphore(); + if (sem == NULL) { + *errmsg = "no memory"; + return NGX_ERROR; + } + + ngx_queue_init(&sem->wait_queue); + + sem->resource_count = n; + sem->wait_count = 0; + *psem = sem; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http lua semaphore new: %p, resources: %d", + sem, sem->resource_count); + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_semaphore_post(ngx_http_lua_semaphore_t *sem, int n) +{ + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http lua semaphore post: %p, n: %d, resources: %d", + sem, n, sem->resource_count); + + sem->resource_count += n; + + if (!ngx_queue_empty(&sem->wait_queue)) { + /* we need the extra paranthese around the first argument of + * ngx_post_event() just to work around macro issues in nginx + * cores older than nginx 1.7.12 (exclusive). + */ + ngx_post_event((&sem->sem_event), &ngx_posted_events); + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_semaphore_wait(ngx_http_request_t *r, + ngx_http_lua_semaphore_t *sem, int wait_ms, u_char *err, size_t *errlen) +{ + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_int_t rc; + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http lua semaphore wait: %p, timeout: %d, " + "resources: %d, event posted: %d", + sem, wait_ms, sem->resource_count, +#if (nginx_version >= 1007005) + (int) sem->sem_event.posted +#else + sem->sem_event.prev ? 1 : 0 +#endif + ); + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + *errlen = ngx_snprintf(err, *errlen, "no request ctx found") - err; + return NGX_ERROR; + } + + rc = ngx_http_lua_ffi_check_context(ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_ACCESS + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT, + err, errlen); + + if (rc != NGX_OK) { + return NGX_ERROR; + } + + /* we keep the order, will resume the older waited firtly + * in ngx_http_lua_semaphore_handler + */ + + if (ngx_queue_empty(&sem->wait_queue) && sem->resource_count > 0) { + sem->resource_count--; + return NGX_OK; + } + + if (wait_ms == 0) { + return NGX_DECLINED; + } + + sem->wait_count++; + wait_co_ctx = ctx->cur_co_ctx; + + wait_co_ctx->sleep.handler = ngx_http_lua_semaphore_timeout_handler; + wait_co_ctx->sleep.data = ctx->cur_co_ctx; + wait_co_ctx->sleep.log = r->connection->log; + + ngx_add_timer(&wait_co_ctx->sleep, (ngx_msec_t) wait_ms); + + dd("ngx_http_lua_ffi_semaphore_wait add timer coctx:%p wait: %d(ms)", + wait_co_ctx, wait_ms); + + ngx_queue_insert_tail(&sem->wait_queue, &wait_co_ctx->sem_wait_queue); + + wait_co_ctx->data = sem; + wait_co_ctx->cleanup = ngx_http_lua_semaphore_cleanup; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http lua semaphore wait yielding"); + + return NGX_AGAIN; +} + + +int +ngx_http_lua_ffi_semaphore_count(ngx_http_lua_semaphore_t *sem) +{ + return sem->resource_count - sem->wait_count; +} + + +static void +ngx_http_lua_semaphore_cleanup(void *data) +{ + ngx_http_lua_co_ctx_t *coctx = data; + ngx_queue_t *q; + ngx_http_lua_semaphore_t *sem; + + sem = coctx->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http lua semaphore cleanup"); + + if (coctx->sleep.timer_set) { + ngx_del_timer(&coctx->sleep); + } + + q = &coctx->sem_wait_queue; + + ngx_queue_remove(q); + sem->wait_count--; + coctx->cleanup = NULL; +} + + +static void +ngx_http_lua_semaphore_handler(ngx_event_t *ev) +{ + ngx_http_lua_semaphore_t *sem; + ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_connection_t *c; + ngx_queue_t *q; + + sem = ev->data; + + while (!ngx_queue_empty(&sem->wait_queue) && sem->resource_count > 0) { + + q = ngx_queue_head(&sem->wait_queue); + ngx_queue_remove(q); + + sem->wait_count--; + + wait_co_ctx = ngx_queue_data(q, ngx_http_lua_co_ctx_t, sem_wait_queue); + wait_co_ctx->cleanup = NULL; + + if (wait_co_ctx->sleep.timer_set) { + ngx_del_timer(&wait_co_ctx->sleep); + } + + r = ngx_http_lua_get_req(wait_co_ctx->co); + c = r->connection; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + ngx_http_lua_assert(ctx != NULL); + + sem->resource_count--; + + ctx->cur_co_ctx = wait_co_ctx; + + wait_co_ctx->sem_resume_status = SEMAPHORE_WAIT_SUCC; + + if (ctx->entered_content_phase) { + (void) ngx_http_lua_semaphore_resume(r); + + } else { + ctx->resume_handler = ngx_http_lua_semaphore_resume; + ngx_http_core_run_phases(r); + } + + ngx_http_run_posted_requests(c); + } +} + + +static void +ngx_http_lua_semaphore_timeout_handler(ngx_event_t *ev) +{ + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; + ngx_connection_t *c; + ngx_http_lua_semaphore_t *sem; + + wait_co_ctx = ev->data; + wait_co_ctx->cleanup = NULL; + + dd("ngx_http_lua_semaphore_timeout_handler timeout coctx:%p", wait_co_ctx); + + sem = wait_co_ctx->data; + + ngx_queue_remove(&wait_co_ctx->sem_wait_queue); + sem->wait_count--; + + r = ngx_http_lua_get_req(wait_co_ctx->co); + c = r->connection; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + ngx_http_lua_assert(ctx != NULL); + + ctx->cur_co_ctx = wait_co_ctx; + + wait_co_ctx->sem_resume_status = SEMAPHORE_WAIT_TIMEOUT; + + if (ctx->entered_content_phase) { + (void) ngx_http_lua_semaphore_resume(r); + + } else { + ctx->resume_handler = ngx_http_lua_semaphore_resume; + ngx_http_core_run_phases(r); + } + + ngx_http_run_posted_requests(c); +} + + +void +ngx_http_lua_ffi_semaphore_gc(ngx_http_lua_semaphore_t *sem) +{ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "in lua gc, semaphore %p", sem); + + if (sem == NULL) { + return; + } + + if (!ngx_queue_empty(&sem->wait_queue)) { + ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0, + "in lua semaphore gc wait queue is" + " not empty while the semaphore %p is being " + "destroyed", sem); + } + + ngx_http_lua_free_semaphore(sem); +} + + +#endif /* NGX_LUA_NO_FFI_API */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.h b/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.h new file mode 100644 index 0000000..a71cc23 --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.h @@ -0,0 +1,51 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + * Copyright (C) cuiweixie + * I hereby assign copyright in this code to the lua-nginx-module project, + * to be licensed under the same terms as the rest of the code. + */ + + +#ifndef _NGX_HTTP_LUA_SEMAPHORE_H_INCLUDED_ +#define _NGX_HTTP_LUA_SEMAPHORE_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +typedef struct ngx_http_lua_semaphore_mm_block_s { + ngx_uint_t used; + ngx_http_lua_semaphore_mm_t *mm; + ngx_uint_t epoch; +} ngx_http_lua_semaphore_mm_block_t; + + +struct ngx_http_lua_semaphore_mm_s { + ngx_queue_t free_queue; + ngx_uint_t total; + ngx_uint_t used; + ngx_uint_t num_per_block; + ngx_uint_t cur_epoch; + ngx_http_lua_main_conf_t *lmcf; +}; + + +typedef struct ngx_http_lua_semaphore_s { + ngx_queue_t wait_queue; + ngx_queue_t chain; + ngx_event_t sem_event; + ngx_http_lua_semaphore_mm_block_t *block; + int resource_count; + unsigned wait_count; +} ngx_http_lua_semaphore_t; + + +#ifndef NGX_LUA_NO_FFI_API +void ngx_http_lua_cleanup_semaphore_mm(void *data); +#endif + + +#endif /* _NGX_HTTP_LUA_SEMAPHORE_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c b/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c index a72f9da..d853382 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c @@ -56,6 +56,8 @@ ngx_http_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data) ngx_http_lua_shdict_ctx_t *octx = data; size_t len; + ngx_int_t rc; + volatile ngx_cycle_t *saved_cycle; ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_main_conf_t *lmcf; @@ -117,7 +119,14 @@ done: if (lmcf->shm_zones_inited == lmcf->shm_zones->nelts && lmcf->init_handler) { - if (lmcf->init_handler(ctx->log, lmcf, lmcf->lua) != NGX_OK) { + saved_cycle = ngx_cycle; + ngx_cycle = ctx->cycle; + + rc = lmcf->init_handler(ctx->log, lmcf, lmcf->lua); + + ngx_cycle = saved_cycle; + + if (rc != NGX_OK) { /* an error happened */ return NGX_ERROR; } @@ -378,14 +387,14 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) static int ngx_http_lua_shdict_get(lua_State *L) { - return ngx_http_lua_shdict_get_helper(L, 0 /* stale */); + return ngx_http_lua_shdict_get_helper(L, 0 /* stale */); } static int ngx_http_lua_shdict_get_stale(lua_State *L) { - return ngx_http_lua_shdict_get_helper(L, 1 /* stale */); + return ngx_http_lua_shdict_get_helper(L, 1 /* stale */); } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.h b/debian/modules/nginx-lua/src/ngx_http_lua_shdict.h index 29ea28f..aa1bb58 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_shdict.h @@ -37,6 +37,7 @@ typedef struct { ngx_str_t name; ngx_http_lua_main_conf_t *main_conf; ngx_log_t *log; + ngx_cycle_t *cycle; } ngx_http_lua_shdict_ctx_t; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c b/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c index b59b9e7..a887c3a 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c @@ -55,7 +55,8 @@ ngx_http_lua_ngx_sleep(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT - | NGX_HTTP_LUA_CONTEXT_TIMER); + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT); coctx = ctx->cur_co_ctx; if (coctx == NULL) { @@ -102,7 +103,7 @@ ngx_http_lua_sleep_handler(ngx_event_t *ev) return; } - if (c->fd != -1) { /* not a fake connection */ + if (c->fd != (ngx_socket_t) -1) { /* not a fake connection */ log_ctx = c->log->data; log_ctx->current_request = r; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c index 4640f87..98801f5 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c @@ -383,7 +383,8 @@ ngx_http_lua_socket_tcp(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT - | NGX_HTTP_LUA_CONTEXT_TIMER); + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT); lua_createtable(L, 3 /* narr */, 1 /* nrec */); lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key); @@ -440,22 +441,13 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT - | NGX_HTTP_LUA_CONTEXT_TIMER); + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT); luaL_checktype(L, 1, LUA_TTABLE); p = (u_char *) luaL_checklstring(L, 2, &len); - host.data = ngx_palloc(r->pool, len + 1); - if (host.data == NULL) { - return luaL_error(L, "no memory"); - } - - host.len = len; - - ngx_memcpy(host.data, p, len); - host.data[len] = '\0'; - key_index = 2; custom_pool = 0; @@ -610,6 +602,18 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) /* rc == NGX_DECLINED */ + /* TODO: we should avoid this in-pool allocation */ + + host.data = ngx_palloc(r->pool, len + 1); + if (host.data == NULL) { + return luaL_error(L, "no memory"); + } + + host.len = len; + + ngx_memcpy(host.data, p, len); + host.data[len] = '\0'; + ngx_memzero(&url, sizeof(ngx_url_t)); url.url.len = host.len; @@ -804,7 +808,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) u->write_prepare_retvals = ngx_http_lua_socket_conn_error_retval_handler; ngx_http_lua_socket_handle_conn_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_RESOLVER); + NGX_HTTP_LUA_SOCKET_FT_RESOLVER); if (waiting) { ngx_http_run_posted_requests(c); @@ -1001,7 +1005,7 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, } if (u->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_http_lua_cleanup_add(r, 0); if (cln == NULL) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR; lua_pushnil(L); @@ -1089,7 +1093,7 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, if (ngx_handle_write_event(c->write, 0) != NGX_OK) { ngx_http_lua_socket_handle_conn_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_ERROR); + NGX_HTTP_LUA_SOCKET_FT_ERROR); lua_pushnil(L); lua_pushliteral(L, "failed to handle write event"); return 2; @@ -1097,7 +1101,7 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, if (ngx_handle_read_event(c->read, 0) != NGX_OK) { ngx_http_lua_socket_handle_conn_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_ERROR); + NGX_HTTP_LUA_SOCKET_FT_ERROR); lua_pushnil(L); lua_pushliteral(L, "failed to handle read event"); return 2; @@ -1310,6 +1314,17 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) if (n >= 4) { u->ssl_verify = lua_toboolean(L, 4); + + if (n >= 5) { + if (lua_toboolean(L, 5)) { +#ifdef NGX_HTTP_LUA_USE_OCSP + SSL_set_tlsext_status_type(c->ssl->connection, + TLSEXT_STATUSTYPE_ocsp); +#else + return luaL_error(L, "no OCSP support"); +#endif + } + } } } } @@ -1353,6 +1368,12 @@ new_ssl_name: u->write_co_ctx = coctx; +#if 0 +#ifdef NGX_HTTP_LUA_USE_OCSP + SSL_set_tlsext_status_type(c->ssl->connection, TLSEXT_STATUSTYPE_ocsp); +#endif +#endif + rc = ngx_ssl_handshake(c); dd("ngx_ssl_handshake returned %d", (int) rc); @@ -1513,7 +1534,7 @@ ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, return 1; } - ud = lua_newuserdata(L, sizeof(ngx_ssl_session_t*)); + ud = lua_newuserdata(L, sizeof(ngx_ssl_session_t *)); c = u->peer.connection; @@ -1525,8 +1546,8 @@ ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, *ud = ssl_session; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua ssl save session: %p:%d", ssl_session, - ssl_session->references); + "lua ssl save session: %p:%d", ssl_session, + ssl_session->references); /* set up the __gc metamethod */ lua_pushlightuserdata(L, &ngx_http_lua_ssl_session_metatable_key); @@ -1945,8 +1966,8 @@ ngx_http_lua_socket_read_line(void *data, ssize_t bytes) #endif dd("already read: %p: %.*s", u->buf_in, - (int) (u->buf_in->buf->last - u->buf_in->buf->pos), - u->buf_in->buf->pos); + (int) (u->buf_in->buf->last - u->buf_in->buf->pos), + u->buf_in->buf->pos); dd("data read: %.*s", (int) bytes, b->pos); @@ -1965,8 +1986,8 @@ ngx_http_lua_socket_read_line(void *data, ssize_t bytes) u->buf_in->buf->last = dst; dd("read a line: %p: %.*s", u->buf_in, - (int) (u->buf_in->buf->last - u->buf_in->buf->pos), - u->buf_in->buf->pos); + (int) (u->buf_in->buf->last - u->buf_in->buf->pos), + u->buf_in->buf->pos); return NGX_OK; @@ -2242,7 +2263,7 @@ success: if (n == NGX_ERROR) { u->socket_errno = ngx_socket_errno; ngx_http_lua_socket_handle_read_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_ERROR); + NGX_HTTP_LUA_SOCKET_FT_ERROR); return NGX_ERROR; } @@ -2687,7 +2708,7 @@ ngx_http_lua_socket_tcp_handler(ngx_event_t *ev) r = u->request; c = r->connection; - if (c->fd != -1) { /* not a fake connection */ + if (c->fd != (ngx_socket_t) -1) { /* not a fake connection */ ctx = c->log->data; ctx->current_request = r; } @@ -2775,7 +2796,7 @@ ngx_http_lua_socket_send_handler(ngx_http_request_t *r, } ngx_http_lua_socket_handle_write_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_TIMEOUT); + NGX_HTTP_LUA_SOCKET_FT_TIMEOUT); return; } @@ -2802,7 +2823,7 @@ ngx_http_lua_socket_send(ngx_http_request_t *r, ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { ngx_http_lua_socket_handle_write_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_ERROR); + NGX_HTTP_LUA_SOCKET_FT_ERROR); return NGX_ERROR; } @@ -3332,6 +3353,7 @@ ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, if (u->cleanup) { *u->cleanup = NULL; + ngx_http_lua_cleanup_free(r, u->cleanup); u->cleanup = NULL; } @@ -3423,7 +3445,7 @@ ngx_http_lua_socket_test_connect(ngx_http_request_t *r, ngx_connection_t *c) if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { dd("pending eof: (%p)%d (%p)%d", c->write, c->write->pending_eof, - c->read, c->read->pending_eof); + c->read, c->read->pending_eof); if (c->write->pending_eof) { ev = c->write; @@ -4251,7 +4273,7 @@ ngx_http_lua_req_socket(lua_State *L) u->connect_timeout = u->conf->connect_timeout; u->send_timeout = u->conf->send_timeout; - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_http_lua_cleanup_add(r, 0); if (cln == NULL) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR; lua_pushnil(L); @@ -4347,7 +4369,7 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) ngx_http_lua_socket_tcp_upstream_t *u; ngx_connection_t *c; ngx_http_lua_socket_pool_t *spool; - size_t size; + size_t size, key_len; ngx_str_t key; ngx_uint_t i; ngx_queue_t *q; @@ -4477,7 +4499,9 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket connection pool size: %ui", pool_size); - size = sizeof(ngx_http_lua_socket_pool_t) + key.len + key_len = ngx_align(key.len + 1, sizeof(void *)); + + size = sizeof(ngx_http_lua_socket_pool_t) + key_len - 1 + sizeof(ngx_http_lua_socket_pool_item_t) * pool_size; @@ -4505,7 +4529,12 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) p = ngx_copy(spool->key, key.data, key.len); *p++ = '\0'; - items = (ngx_http_lua_socket_pool_item_t *) p; + items = (ngx_http_lua_socket_pool_item_t *) (spool->key + key_len); + + dd("items: %p", items); + + ngx_http_lua_assert((void *) items == ngx_align_ptr(items, + sizeof(void *))); for (i = 0; i < pool_size; i++) { ngx_queue_insert_head(&spool->free, &items[i].queue); @@ -4688,7 +4717,7 @@ ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, lua_State *L, #endif if (u->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_http_lua_cleanup_add(r, 0); if (cln == NULL) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR; lua_settop(L, top); @@ -4893,83 +4922,52 @@ ngx_http_lua_socket_push_input_data(ngx_http_request_t *r, { ngx_chain_t *cl; ngx_chain_t **ll; - size_t size; +#if (DDEBUG) || (NGX_DTRACE) + size_t size = 0; +#endif + size_t chunk_size; ngx_buf_t *b; size_t nbufs; - u_char *p; - u_char *last; - - if (!u->bufs_in) { - lua_pushliteral(L, ""); - ngx_http_lua_probe_socket_tcp_receive_done(r, u, (u_char *) "", 0); - return NGX_OK; - } + luaL_Buffer luabuf; dd("bufs_in: %p, buf_in: %p", u->bufs_in, u->buf_in); - size = 0; nbufs = 0; ll = NULL; + luaL_buffinit(L, &luabuf); + for (cl = u->bufs_in; cl; cl = cl->next) { b = cl->buf; - size += b->last - b->pos; + chunk_size = b->last - b->pos; + + dd("copying input data chunk from %p: \"%.*s\"", cl, + (int) chunk_size, b->pos); + + luaL_addlstring(&luabuf, (char *) b->pos, chunk_size); if (cl->next) { ll = &cl->next; } +#if (DDEBUG) || (NGX_DTRACE) + size += chunk_size; +#endif + nbufs++; } + luaL_pushresult(&luabuf); + +#if (DDEBUG) dd("size: %d, nbufs: %d", (int) size, (int) nbufs); +#endif - if (size == 0) { - lua_pushliteral(L, ""); - - ngx_http_lua_probe_socket_tcp_receive_done(r, u, (u_char *) "", 0); - - goto done; - } - - if (nbufs == 1) { - b = u->buf_in->buf; - - lua_pushlstring(L, (char *) b->pos, size); - - dd("copying input data chunk from %p: \"%.*s\"", u->buf_in, (int) size, - b->pos); - - ngx_http_lua_probe_socket_tcp_receive_done(r, u, b->pos, size); - - goto done; - } - - /* nbufs > 1 */ - - dd("WARN: allocate a big memory: %d", (int) size); - - p = ngx_palloc(r->pool, size); - if (p == NULL) { - return NGX_ERROR; - } - - last = p; - for (cl = u->bufs_in; cl; cl = cl->next) { - b = cl->buf; - last = ngx_copy(last, b->pos, b->last - b->pos); - - dd("copying input data chunk from %p: \"%.*s\"", cl, - (int) (b->last - b->pos), b->pos); - } - - lua_pushlstring(L, (char *) p, size); - - ngx_http_lua_probe_socket_tcp_receive_done(r, u, p, size); - - ngx_pfree(r->pool, p); - -done: +#if (NGX_DTRACE) + ngx_http_lua_probe_socket_tcp_receive_done(r, u, + (u_char *) lua_tostring(L, -1), + size); +#endif if (nbufs > 1 && ll) { dd("recycle buffers: %d", (int) (nbufs - 1)); @@ -4985,8 +4983,10 @@ done: u->buffer.last = u->buffer.start; } - u->buf_in->buf->last = u->buffer.pos; - u->buf_in->buf->pos = u->buffer.pos; + if (u->bufs_in) { + u->buf_in->buf->last = u->buffer.pos; + u->buf_in->buf->pos = u->buffer.pos; + } return NGX_OK; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.h b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.h index 915d4f4..dbdee41 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.h @@ -31,8 +31,8 @@ typedef ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); -typedef void (*ngx_http_lua_socket_tcp_upstream_handler_pt)( - ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); +typedef void (*ngx_http_lua_socket_tcp_upstream_handler_pt) + (ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); typedef struct { @@ -111,7 +111,7 @@ struct ngx_http_lua_socket_tcp_upstream_s { }; -typedef struct ngx_http_lua_dfa_edge_s ngx_http_lua_dfa_edge_t; +typedef struct ngx_http_lua_dfa_edge_s ngx_http_lua_dfa_edge_t; struct ngx_http_lua_dfa_edge_s { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c b/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c index 23cc69a..bfb122f 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c @@ -140,7 +140,8 @@ ngx_http_lua_socket_udp(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT - | NGX_HTTP_LUA_CONTEXT_TIMER); + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT); lua_createtable(L, 3 /* narr */, 1 /* nrec */); lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key); @@ -200,7 +201,8 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT - | NGX_HTTP_LUA_CONTEXT_TIMER); + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT); luaL_checktype(L, 1, LUA_TTABLE); @@ -1299,7 +1301,7 @@ ngx_http_lua_socket_udp_handler(ngx_event_t *ev) r = u->request; c = r->connection; - if (c->fd != -1) { /* not a fake connection */ + if (c->fd != (ngx_socket_t) -1) { /* not a fake connection */ ctx = c->log->data; ctx->current_request = r; } @@ -1358,7 +1360,7 @@ ngx_http_lua_udp_connect(ngx_udp_connection_t *uc) ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "UDP socket %d", s); - if (s == -1) { + if (s == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, ngx_socket_n " failed"); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.h b/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.h index 819e36b..dd75b2d 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.h @@ -20,8 +20,8 @@ typedef ngx_http_lua_socket_udp_upstream_t *u, lua_State *L); -typedef void (*ngx_http_lua_socket_udp_upstream_handler_pt)( - ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u); +typedef void (*ngx_http_lua_socket_udp_upstream_handler_pt) + (ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u); struct ngx_http_lua_socket_udp_upstream_s { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c new file mode 100644 index 0000000..f8648a7 --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c @@ -0,0 +1,938 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#if (NGX_HTTP_SSL) + + +#include "ngx_http_lua_cache.h" +#include "ngx_http_lua_initworkerby.h" +#include "ngx_http_lua_util.h" +#include "ngx_http_ssl_module.h" +#include "ngx_http_lua_contentby.h" +#include "ngx_http_lua_ssl_certby.h" +#include "ngx_http_lua_directive.h" + + +enum { + NGX_HTTP_LUA_ADDR_TYPE_UNIX = 0, + NGX_HTTP_LUA_ADDR_TYPE_INET = 1, + NGX_HTTP_LUA_ADDR_TYPE_INET6 = 2 +}; + + +static void ngx_http_lua_ssl_cert_done(void *data); +static void ngx_http_lua_ssl_cert_aborted(void *data); +static u_char *ngx_http_lua_log_ssl_cert_error(ngx_log_t *log, u_char *buf, + size_t len); +static ngx_int_t ngx_http_lua_ssl_cert_by_chunk(lua_State *L, + ngx_http_request_t *r); + + +int ngx_http_lua_ssl_ctx_index = -1; + + +ngx_int_t +ngx_http_lua_ssl_cert_handler_file(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L) +{ + ngx_int_t rc; + + rc = ngx_http_lua_cache_loadfile(r->connection->log, L, + lscf->ssl.cert_src.data, + lscf->ssl.cert_src_key); + if (rc != NGX_OK) { + return rc; + } + + /* make sure we have a valid code chunk */ + ngx_http_lua_assert(lua_isfunction(L, -1)); + + return ngx_http_lua_ssl_cert_by_chunk(L, r); +} + + +ngx_int_t +ngx_http_lua_ssl_cert_handler_inline(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L) +{ + ngx_int_t rc; + + rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, + lscf->ssl.cert_src.data, + lscf->ssl.cert_src.len, + lscf->ssl.cert_src_key, + "=ssl_certificate_by_lua"); + if (rc != NGX_OK) { + return rc; + } + + /* make sure we have a valid code chunk */ + ngx_http_lua_assert(lua_isfunction(L, -1)); + + return ngx_http_lua_ssl_cert_by_chunk(L, r); +} + + +char * +ngx_http_lua_ssl_cert_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_ssl_cert_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + +char * +ngx_http_lua_ssl_cert_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ +#if OPENSSL_VERSION_NUMBER < 0x1000205fL + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "at least OpenSSL 1.0.2e required but found " + OPENSSL_VERSION_TEXT); + + return NGX_CONF_ERROR; + +#else + + u_char *p; + u_char *name; + ngx_str_t *value; + ngx_http_lua_srv_conf_t *lscf = conf; + + /* must specifiy a concrete handler */ + if (cmd->post == NULL) { + return NGX_CONF_ERROR; + } + + if (lscf->ssl.cert_handler) { + return "is duplicate"; + } + + if (ngx_http_lua_ssl_ctx_index == -1) { + ngx_http_lua_ssl_ctx_index = SSL_get_ex_new_index(0, NULL, NULL, + NULL, NULL); + + if (ngx_ssl_connection_index == -1) { + ngx_ssl_error(NGX_LOG_ALERT, cf->log, 0, + "lua: SSL_get_ex_new_index() failed"); + return NGX_CONF_ERROR; + } + } + + value = cf->args->elts; + + lscf->ssl.cert_handler = (ngx_http_lua_srv_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_http_lua_ssl_cert_handler_file) { + /* Lua code in an external file */ + + name = ngx_http_lua_rebase_path(cf->pool, value[1].data, + value[1].len); + if (name == NULL) { + return NGX_CONF_ERROR; + } + + lscf->ssl.cert_src.data = name; + lscf->ssl.cert_src.len = ngx_strlen(name); + + p = ngx_palloc(cf->pool, NGX_HTTP_LUA_FILE_KEY_LEN + 1); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + lscf->ssl.cert_src_key = p; + + p = ngx_copy(p, NGX_HTTP_LUA_FILE_TAG, NGX_HTTP_LUA_FILE_TAG_LEN); + p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); + *p = '\0'; + + } else { + /* inlined Lua code */ + + lscf->ssl.cert_src = value[1]; + + p = ngx_palloc(cf->pool, NGX_HTTP_LUA_INLINE_KEY_LEN + 1); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + lscf->ssl.cert_src_key = p; + + p = ngx_copy(p, NGX_HTTP_LUA_INLINE_TAG, NGX_HTTP_LUA_INLINE_TAG_LEN); + p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); + *p = '\0'; + } + + return NGX_CONF_OK; + +#endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */ +} + + +int +ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) +{ + lua_State *L; + ngx_int_t rc; + ngx_connection_t *c, *fc; + ngx_http_request_t *r = NULL; + ngx_pool_cleanup_t *cln; + ngx_http_connection_t *hc; + ngx_http_lua_srv_conf_t *lscf; + ngx_http_lua_ssl_cert_ctx_t *cctx; + + c = ngx_ssl_get_connection(ssl_conn); + + dd("c = %p", c); + + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + + dd("ssl cert handler, cert-ctx=%p", cctx); + + if (cctx) { + /* not the first time */ + + if (cctx->done) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "lua_certificate_by_lua: cert cb exit code: %d", + cctx->exit_code); + + dd("lua ssl cert done, finally"); + return cctx->exit_code; + } + + return -1; + } + + /* cctx == NULL */ + + dd("first time"); + + hc = c->data; + + fc = ngx_http_lua_create_fake_connection(NULL); + if (fc == NULL) { + goto failed; + } + + fc->log->handler = ngx_http_lua_log_ssl_cert_error; + fc->log->data = fc; + + fc->addr_text = c->addr_text; + fc->listening = c->listening; + + r = ngx_http_lua_create_fake_request(fc); + if (r == NULL) { + goto failed; + } + + r->main_conf = hc->conf_ctx->main_conf; + r->srv_conf = hc->conf_ctx->srv_conf; + r->loc_conf = hc->conf_ctx->loc_conf; + + fc->log->file = c->log->file; + fc->log->log_level = c->log->log_level; + fc->ssl = c->ssl; + + cctx = ngx_pcalloc(c->pool, sizeof(ngx_http_lua_ssl_cert_ctx_t)); + if (cctx == NULL) { + goto failed; /* error */ + } + + cctx->exit_code = 1; /* successful by default */ + cctx->connection = c; + cctx->request = r; + + dd("setting cctx"); + + if (SSL_set_ex_data(c->ssl->connection, ngx_http_lua_ssl_ctx_index, cctx) + == 0) + { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed"); + goto failed; + } + + lscf = ngx_http_get_module_srv_conf(r, ngx_http_lua_module); + + /* TODO honor lua_code_cache off */ + L = ngx_http_lua_get_lua_vm(r, NULL); + + c->log->action = "loading SSL certificate by lua"; + + rc = lscf->ssl.cert_handler(r, lscf, L); + + if (rc >= NGX_OK || rc == NGX_ERROR) { + cctx->done = 1; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "lua_certificate_by_lua: handler return value: %i, " + "cert cb exit code: %d", rc, cctx->exit_code); + + c->log->action = "SSL handshaking"; + return cctx->exit_code; + } + + /* rc == NGX_DONE */ + + cln = ngx_pool_cleanup_add(fc->pool, 0); + if (cln == NULL) { + goto failed; + } + + cln->handler = ngx_http_lua_ssl_cert_done; + cln->data = cctx; + + cln = ngx_pool_cleanup_add(c->pool, 0); + if (cln == NULL) { + goto failed; + } + + cln->handler = ngx_http_lua_ssl_cert_aborted; + cln->data = cctx; + + return -1; + +#if 1 +failed: + + if (r && r->pool) { + ngx_http_lua_free_fake_request(r); + } + + if (fc) { + ngx_http_lua_close_fake_connection(fc); + } + + return 0; +#endif +} + + +static void +ngx_http_lua_ssl_cert_done(void *data) +{ + ngx_connection_t *c; + ngx_http_lua_ssl_cert_ctx_t *cctx = data; + + dd("lua ssl cert done"); + + if (cctx->aborted) { + return; + } + + ngx_http_lua_assert(cctx->done == 0); + + cctx->done = 1; + + c = cctx->connection; + + c->log->action = "SSL handshaking"; + + ngx_post_event(c->write, &ngx_posted_events); +} + + +static void +ngx_http_lua_ssl_cert_aborted(void *data) +{ + ngx_http_lua_ssl_cert_ctx_t *cctx = data; + + dd("lua ssl cert done"); + + if (cctx->done) { + /* completed successfully already */ + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cctx->connection->log, 0, + "lua_certificate_by_lua: cert cb aborted"); + + cctx->aborted = 1; + cctx->request->connection->ssl = NULL; + + ngx_http_lua_finalize_fake_request(cctx->request, NGX_ERROR); +} + + +static u_char * +ngx_http_lua_log_ssl_cert_error(ngx_log_t *log, u_char *buf, size_t len) +{ + u_char *p; + ngx_connection_t *c; + + if (log->action) { + p = ngx_snprintf(buf, len, " while %s", log->action); + len -= p - buf; + buf = p; + } + + p = ngx_snprintf(buf, len, ", context: ssl_certificate_by_lua*"); + len -= p - buf; + buf = p; + + c = log->data; + + if (c->addr_text.len) { + p = ngx_snprintf(buf, len, ", client: %V", &c->addr_text); + len -= p - buf; + buf = p; + } + + if (c && c->listening && c->listening->addr_text.len) { + p = ngx_snprintf(buf, len, ", server: %V", &c->listening->addr_text); + /* len -= p - buf; */ + buf = p; + } + + return buf; +} + + +static ngx_int_t +ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) +{ + int co_ref; + ngx_int_t rc; + lua_State *co; + ngx_http_lua_ctx_t *ctx; + ngx_http_cleanup_t *cln; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + if (ctx == NULL) { + ctx = ngx_http_lua_create_ctx(r); + if (ctx == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + } else { + dd("reset ctx"); + ngx_http_lua_reset_ctx(r, L, ctx); + } + + ctx->entered_content_phase = 1; + + /* {{{ new coroutine to handle request */ + co = ngx_http_lua_new_thread(r, L, &co_ref); + + if (co == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "lua: failed to create new coroutine to handle request"); + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + /* move code closure to new coroutine */ + lua_xmove(L, co, 1); + + /* set closure's env table to new coroutine's globals table */ + ngx_http_lua_get_globals_table(co); + lua_setfenv(co, -2); + + /* save nginx request in coroutine globals table */ + ngx_http_lua_set_req(co, r); + + ctx->cur_co_ctx = &ctx->entry_co_ctx; + ctx->cur_co_ctx->co = co; + ctx->cur_co_ctx->co_ref = co_ref; +#ifdef NGX_LUA_USE_ASSERT + ctx->cur_co_ctx->co_top = 1; +#endif + + /* register request cleanup hooks */ + if (ctx->cleanup == NULL) { + cln = ngx_http_cleanup_add(r, 0); + if (cln == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + cln->handler = ngx_http_lua_request_cleanup_handler; + cln->data = ctx; + ctx->cleanup = &cln->handler; + } + + ctx->context = NGX_HTTP_LUA_CONTEXT_SSL_CERT; + + rc = ngx_http_lua_run_thread(L, r, ctx, 0); + + if (rc == NGX_ERROR || rc >= NGX_OK) { + /* do nothing */ + + } else if (rc == NGX_AGAIN) { + rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 0); + + } else if (rc == NGX_DONE) { + rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 1); + + } else { + rc = NGX_OK; + } + + ngx_http_lua_finalize_request(r, rc); + return rc; +} + + +#ifndef NGX_LUA_NO_FFI_API + +int +ngx_http_lua_ffi_ssl_get_tls1_version(ngx_http_request_t *r, char **err) +{ +#ifndef TLS1_get_version + + *err = "no TLS1 support"; + return NGX_ERROR; + +#else + + ngx_ssl_conn_t *ssl_conn; + + if (r->connection == NULL || r->connection->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = r->connection->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + dd("tls1 ver: %d", (int) TLS1_get_version(ssl_conn)); + + return (int) TLS1_get_version(ssl_conn); + +#endif +} + + +int +ngx_http_lua_ffi_ssl_clear_certs(ngx_http_request_t *r, char **err) +{ +#if OPENSSL_VERSION_NUMBER < 0x1000205fL + + *err = "at least OpenSSL 1.0.2e required but found " OPENSSL_VERSION_TEXT; + return NGX_ERROR; + +#else + + ngx_ssl_conn_t *ssl_conn; + + if (r->connection == NULL || r->connection->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = r->connection->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + SSL_certs_clear(ssl_conn); + return NGX_OK; + +#endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */ +} + + +int +ngx_http_lua_ffi_ssl_set_der_certificate(ngx_http_request_t *r, + const char *data, size_t len, char **err) +{ +#if OPENSSL_VERSION_NUMBER < 0x1000205fL + + *err = "at least OpenSSL 1.0.2e required but found " OPENSSL_VERSION_TEXT; + return NGX_ERROR; + +#else + + BIO *bio = NULL; + X509 *x509 = NULL; + ngx_ssl_conn_t *ssl_conn; + + if (r->connection == NULL || r->connection->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = r->connection->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + bio = BIO_new_mem_buf((char *) data, len); + if (bio == NULL) { + *err = " BIO_new_mem_buf() failed"; + goto failed; + } + + x509 = d2i_X509_bio(bio, NULL); + if (x509 == NULL) { + *err = " d2i_X509_bio() failed"; + goto failed; + } + + if (SSL_use_certificate(ssl_conn, x509) == 0) { + *err = " SSL_use_certificate() failed"; + goto failed; + } + +#if 0 + if (SSL_set_ex_data(ssl_conn, ngx_ssl_certificate_index, x509) == 0) { + *err = " SSL_set_ex_data() failed"; + goto failed; + } +#endif + + X509_free(x509); + x509 = NULL; + + /* read rest of the chain */ + + while (!BIO_eof(bio)) { + + x509 = d2i_X509_bio(bio, NULL); + if (x509 == NULL) { + *err = "d2i_X509_bio() failed"; + goto failed; + } + + if (SSL_add0_chain_cert(ssl_conn, x509) == 0) { + *err = "SSL_add0_chain_cert() failed"; + goto failed; + } + } + + BIO_free(bio); + + *err = NULL; + return NGX_OK; + +failed: + + if (bio) { + BIO_free(bio); + } + + if (x509) { + X509_free(x509); + } + + return NGX_ERROR; + +#endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */ +} + + +int +ngx_http_lua_ffi_ssl_set_der_private_key(ngx_http_request_t *r, + const char *data, size_t len, char **err) +{ + BIO *bio = NULL; + EVP_PKEY *pkey = NULL; + ngx_ssl_conn_t *ssl_conn; + + if (r->connection == NULL || r->connection->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = r->connection->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + bio = BIO_new_mem_buf((char *) data, len); + if (bio == NULL) { + *err = "BIO_new_mem_buf() failed"; + goto failed; + } + + pkey = d2i_PrivateKey_bio(bio, NULL); + if (pkey == NULL) { + *err = "d2i_PrivateKey_bio() failed"; + goto failed; + } + + if (SSL_use_PrivateKey(ssl_conn, pkey) == 0) { + *err = "SSL_CTX_use_PrivateKey() failed"; + goto failed; + } + + EVP_PKEY_free(pkey); + BIO_free(bio); + + return NGX_OK; + +failed: + + if (pkey) { + EVP_PKEY_free(pkey); + } + + if (bio) { + BIO_free(bio); + } + + return NGX_ERROR; +} + + +int +ngx_http_lua_ffi_ssl_raw_server_addr(ngx_http_request_t *r, char **addr, + size_t *addrlen, int *addrtype, char **err) +{ +#if (NGX_HAVE_UNIX_DOMAIN) + struct sockaddr_un *saun; +#endif + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + if (r->connection == NULL || r->connection->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = r->connection->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + c = ngx_ssl_get_connection(ssl_conn); + + if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { + return 0; + } + + switch (c->local_sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) c->local_sockaddr; + *addrlen = 16; + *addr = (char *) &sin6->sin6_addr.s6_addr; + *addrtype = NGX_HTTP_LUA_ADDR_TYPE_INET6; + + break; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + saun = (struct sockaddr_un *) c->local_sockaddr; + + /* on Linux sockaddr might not include sun_path at all */ + if (c->local_socklen <= (socklen_t) + offsetof(struct sockaddr_un, sun_path)) + { + *addr = ""; + *addrlen = 0; + + } else { + *addr = saun->sun_path; + *addrlen = ngx_strlen(saun->sun_path); + } + + *addrtype = NGX_HTTP_LUA_ADDR_TYPE_UNIX; + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) c->local_sockaddr; + *addr = (char *) &sin->sin_addr.s_addr; + *addrlen = 4; + *addrtype = NGX_HTTP_LUA_ADDR_TYPE_INET; + break; + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_ssl_server_name(ngx_http_request_t *r, char **name, + size_t *namelen, char **err) +{ + ngx_ssl_conn_t *ssl_conn; + + if (r->connection == NULL || r->connection->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = r->connection->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + + *name = (char *) SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name); + + if (*name) { + *namelen = ngx_strlen(*name); + return NGX_OK; + } + + return NGX_DECLINED; + +#else + + *err = "no TLS extension support"; + return NGX_ERROR; + +#endif +} + + +int +ngx_http_lua_ffi_cert_pem_to_der(const u_char *pem, size_t pem_len, u_char *der, + char **err) +{ + int total, len; + BIO *bio; + X509 *x509; + u_long n; + + bio = BIO_new_mem_buf((char *) pem, (int) pem_len); + if (bio == NULL) { + *err = "BIO_new_mem_buf() failed"; + return NGX_ERROR; + } + + x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); + if (x509 == NULL) { + *err = "PEM_read_bio_X509_AUX() failed"; + return NGX_ERROR; + } + + total = i2d_X509(x509, &der); + if (total < 0) { + X509_free(x509); + BIO_free(bio); + return NGX_ERROR; + } + + X509_free(x509); + + /* read rest of the chain */ + + for ( ;; ) { + + x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); + if (x509 == NULL) { + n = ERR_peek_last_error(); + + if (ERR_GET_LIB(n) == ERR_LIB_PEM + && ERR_GET_REASON(n) == PEM_R_NO_START_LINE) + { + /* end of file */ + ERR_clear_error(); + break; + } + + /* some real error */ + + *err = "PEM_read_bio_X509() failed"; + BIO_free(bio); + return NGX_ERROR; + } + + len = i2d_X509(x509, &der); + if (len < 0) { + *err = "i2d_X509() failed"; + X509_free(x509); + BIO_free(bio); + return NGX_ERROR; + } + + total += len; + + X509_free(x509); + } + + BIO_free(bio); + + return total; +} + + +int +ngx_http_lua_ffi_priv_key_pem_to_der(const u_char *pem, size_t pem_len, + u_char *der, char **err) +{ + int len; + BIO *in; + RSA *rsa; + EVP_PKEY *pkey; + + in = BIO_new_mem_buf((char *) pem, (int) pem_len); + if (in == NULL) { + *err = "BIO_new_mem_buf() failed"; + return NGX_ERROR; + } + + pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); + if (pkey == NULL) { + BIO_free(in); + *err = "PEM_read_bio_PrivateKey failed"; + return NGX_ERROR; + } + + BIO_free(in); + + rsa = EVP_PKEY_get1_RSA(pkey); + if (rsa == NULL) { + EVP_PKEY_free(pkey); + *err = "EVP_PKEY_get1_RSA failed"; + return NGX_ERROR; + } + + EVP_PKEY_free(pkey); + + len = i2d_RSAPrivateKey(rsa, &der); + if (len < 0) { + RSA_free(rsa); + *err = "i2d_RSAPrivateKey failed"; + return NGX_ERROR; + } + + RSA_free(rsa); + + return len; +} + + +#endif /* NGX_LUA_NO_FFI_API */ + + +#endif /* NGX_HTTP_SSL */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.h b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.h new file mode 100644 index 0000000..11cb963 --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.h @@ -0,0 +1,47 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_SSL_CERTBY_H_INCLUDED_ +#define _NGX_HTTP_LUA_SSL_CERTBY_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +#if (NGX_HTTP_SSL) + + +typedef struct { + ngx_connection_t *connection; /* original true connection */ + ngx_http_request_t *request; /* fake request */ + int exit_code; /* exit code for openssl's + set_cert_cb callback */ + unsigned done; /* :1 */ + unsigned aborted; /* :1 */ +} ngx_http_lua_ssl_cert_ctx_t; + + +ngx_int_t ngx_http_lua_ssl_cert_handler_inline(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L); + +ngx_int_t ngx_http_lua_ssl_cert_handler_file(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L); + +char *ngx_http_lua_ssl_cert_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + +char *ngx_http_lua_ssl_cert_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + +int ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data); + + +#endif /* NGX_HTTP_SSL */ + + +#endif /* _NGX_HTTP_LUA_SSL_CERTBY_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c new file mode 100644 index 0000000..9f9e276 --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c @@ -0,0 +1,497 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#if (NGX_HTTP_SSL) + + +#include "ngx_http_lua_common.h" + + +#ifndef NGX_LUA_NO_FFI_API + +#ifdef NGX_HTTP_LUA_USE_OCSP +static int ngx_http_lua_ssl_empty_status_callback(ngx_ssl_conn_t *ssl_conn, + void *data); +#endif + + +int +ngx_http_lua_ffi_ssl_get_ocsp_responder_from_der_chain( + const char *chain_data, size_t chain_len, unsigned char *out, + size_t *out_size, char **err) +{ +#ifndef NGX_HTTP_LUA_USE_OCSP + + *err = "no OCSP support"; + return NGX_ERROR; + +#else + + int rc = NGX_OK; + BIO *bio = NULL; + char *s; + X509 *cert = NULL, *issuer = NULL; + size_t len; + STACK_OF(OPENSSL_STRING) *aia = NULL; + + /* certificate */ + + bio = BIO_new_mem_buf((char *) chain_data, chain_len); + if (bio == NULL) { + *err = "BIO_new_mem_buf() failed"; + rc = NGX_ERROR; + goto done; + } + + cert = d2i_X509_bio(bio, NULL); + if (cert == NULL) { + *err = "d2i_X509_bio() failed"; + rc = NGX_ERROR; + goto done; + } + + /* responder */ + + aia = X509_get1_ocsp(cert); + if (aia == NULL) { + rc = NGX_DECLINED; + goto done; + } + +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + s = sk_OPENSSL_STRING_value(aia, 0); +#else + s = sk_value(aia, 0); +#endif + if (s == NULL) { + rc = NGX_DECLINED; + goto done; + } + + len = ngx_strlen(s); + if (len > *out_size) { + len = *out_size; + rc = NGX_BUSY; + + } else { + rc = NGX_OK; + *out_size = len; + } + + ngx_memcpy(out, s, len); + + X509_email_free(aia); + aia = NULL; + + /* issuer */ + + if (BIO_eof(bio)) { + *err = "no issuer certificate in chain"; + rc = NGX_ERROR; + goto done; + } + + issuer = d2i_X509_bio(bio, NULL); + if (issuer == NULL) { + *err = "d2i_X509_bio() failed"; + rc = NGX_ERROR; + goto done; + } + + if (X509_check_issued(issuer, cert) != X509_V_OK) { + *err = "issuer certificate not next to leaf"; + rc = NGX_ERROR; + goto done; + } + + X509_free(issuer); + X509_free(cert); + BIO_free(bio); + + return rc; + +done: + + if (aia) { + X509_email_free(aia); + } + + if (issuer) { + X509_free(issuer); + } + + if (cert) { + X509_free(cert); + } + + if (bio) { + BIO_free(bio); + } + + return rc; + +#endif /* NGX_HTTP_LUA_USE_OCSP */ +} + + +int +ngx_http_lua_ffi_ssl_create_ocsp_request(const char *chain_data, + size_t chain_len, unsigned char *out, size_t *out_size, char **err) +{ +#ifndef NGX_HTTP_LUA_USE_OCSP + + *err = "no OCSP support"; + return NGX_ERROR; + +#else + + int rc = NGX_ERROR; + BIO *bio = NULL; + X509 *cert = NULL, *issuer = NULL; + size_t len; + OCSP_CERTID *id; + OCSP_REQUEST *ocsp = NULL; + + /* certificate */ + + bio = BIO_new_mem_buf((char *) chain_data, chain_len); + if (bio == NULL) { + *err = "BIO_new_mem_buf() failed"; + goto failed; + } + + cert = d2i_X509_bio(bio, NULL); + if (cert == NULL) { + *err = "d2i_X509_bio() failed"; + goto failed; + } + + if (BIO_eof(bio)) { + *err = "no issuer certificate in chain"; + goto failed; + } + + issuer = d2i_X509_bio(bio, NULL); + if (issuer == NULL) { + *err = "d2i_X509_bio() failed"; + goto failed; + } + + ocsp = OCSP_REQUEST_new(); + if (ocsp == NULL) { + *err = "OCSP_REQUEST_new() failed"; + goto failed; + } + + id = OCSP_cert_to_id(NULL, cert, issuer); + if (id == NULL) { + *err = "OCSP_cert_to_id() failed"; + goto failed; + } + + if (OCSP_request_add0_id(ocsp, id) == NULL) { + *err = "OCSP_request_add0_id() failed"; + goto failed; + } + + len = i2d_OCSP_REQUEST(ocsp, NULL); + if (len <= 0) { + *err = "i2d_OCSP_REQUEST() failed"; + goto failed; + } + + if (len > *out_size) { + *err = "output buffer too small"; + *out_size = len; + rc = NGX_BUSY; + goto failed; + } + + len = i2d_OCSP_REQUEST(ocsp, &out); + if (len <= 0) { + *err = "i2d_OCSP_REQUEST() failed"; + goto failed; + } + + *out_size = len; + + OCSP_REQUEST_free(ocsp); + X509_free(issuer); + X509_free(cert); + BIO_free(bio); + + return NGX_OK; + +failed: + + if (ocsp) { + OCSP_REQUEST_free(ocsp); + } + + if (issuer) { + X509_free(issuer); + } + + if (cert) { + X509_free(cert); + } + + if (bio) { + BIO_free(bio); + } + + return rc; + +#endif /* NGX_HTTP_LUA_USE_OCSP */ +} + + +int +ngx_http_lua_ffi_ssl_validate_ocsp_response(const u_char *resp, + size_t resp_len, const char *chain_data, size_t chain_len, + u_char *errbuf, size_t *errbuf_size) +{ +#ifndef NGX_HTTP_LUA_USE_OCSP + + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "no OCSP support") - errbuf; + return NGX_ERROR; + +#else + + int n; + BIO *bio = NULL; + X509 *cert = NULL, *issuer = NULL; + OCSP_CERTID *id = NULL; + OCSP_RESPONSE *ocsp = NULL; + OCSP_BASICRESP *basic = NULL; + STACK_OF(X509) *chain = NULL; + ASN1_GENERALIZEDTIME *thisupdate, *nextupdate; + + ocsp = d2i_OCSP_RESPONSE(NULL, &resp, resp_len); + if (ocsp == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "d2i_OCSP_RESPONSE() failed") - errbuf; + goto error; + } + + n = OCSP_response_status(ocsp); + + if (n != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "OCSP response not successful (%d: %s)", + n, OCSP_response_status_str(n)) - errbuf; + goto error; + } + + basic = OCSP_response_get1_basic(ocsp); + if (basic == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "OCSP_response_get1_basic() failed") + - errbuf; + goto error; + } + + /* get issuer certificate from chain */ + + bio = BIO_new_mem_buf((char *) chain_data, chain_len); + if (bio == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "BIO_new_mem_buf() failed") + - errbuf; + goto error; + } + + cert = d2i_X509_bio(bio, NULL); + if (cert == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "d2i_X509_bio() failed") + - errbuf; + goto error; + } + + if (BIO_eof(bio)) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "no issuer certificate in chain") + - errbuf; + goto error; + } + + issuer = d2i_X509_bio(bio, NULL); + if (issuer == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "d2i_X509_bio() failed") - errbuf; + goto error; + } + + chain = sk_X509_new_null(); + if (chain == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "sk_X509_new_null() failed") - errbuf; + goto error; + } + + (void) sk_X509_push(chain, issuer); + + if (OCSP_basic_verify(basic, chain, NULL, OCSP_NOVERIFY) != 1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "OCSP_basic_verify() failed") - errbuf; + goto error; + } + + id = OCSP_cert_to_id(NULL, cert, issuer); + if (id == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "OCSP_cert_to_id() failed") - errbuf; + goto error; + } + + if (OCSP_resp_find_status(basic, id, &n, NULL, NULL, + &thisupdate, &nextupdate) + != 1) + { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "certificate status not found in the " + "OCSP response") - errbuf; + goto error; + } + + if (n != V_OCSP_CERTSTATUS_GOOD) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "certificate status \"%s\" in the OCSP " + "response", OCSP_cert_status_str(n)) + - errbuf; + goto error; + } + + if (OCSP_check_validity(thisupdate, nextupdate, 300, -1) != 1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "OCSP_check_validity() failed") - errbuf; + goto error; + } + + sk_X509_free(chain); + X509_free(cert); + X509_free(issuer); + BIO_free(bio); + OCSP_CERTID_free(id); + OCSP_BASICRESP_free(basic); + OCSP_RESPONSE_free(ocsp); + + return NGX_OK; + +error: + + if (chain) { + sk_X509_free(chain); + } + + if (id) { + OCSP_CERTID_free(id); + } + + if (basic) { + OCSP_BASICRESP_free(basic); + } + + if (ocsp) { + OCSP_RESPONSE_free(ocsp); + } + + if (cert) { + X509_free(cert); + } + + if (issuer) { + X509_free(issuer); + } + + if (bio) { + BIO_free(bio); + } + + ERR_clear_error(); + + return NGX_ERROR; + +#endif /* NGX_HTTP_LUA_USE_OCSP */ +} + + +#ifdef NGX_HTTP_LUA_USE_OCSP +static int +ngx_http_lua_ssl_empty_status_callback(ngx_ssl_conn_t *ssl_conn, void *data) +{ + return SSL_TLSEXT_ERR_OK; +} +#endif + + +int +ngx_http_lua_ffi_ssl_set_ocsp_status_resp(ngx_http_request_t *r, + const u_char *resp, size_t resp_len, char **err) +{ +#ifndef NGX_HTTP_LUA_USE_OCSP + + *err = "no OCSP support"; + return NGX_ERROR; + +#else + + u_char *p; + SSL_CTX *ctx; + ngx_ssl_conn_t *ssl_conn; + + if (r->connection == NULL || r->connection->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = r->connection->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + if (ssl_conn->tlsext_status_type == -1) { + dd("no ocsp status req from client"); + return NGX_DECLINED; + } + + /* we have to register an empty status callback here otherwise + * OpenSSL won't send the response staple. */ + + ctx = SSL_get_SSL_CTX(ssl_conn); + SSL_CTX_set_tlsext_status_cb(ctx, + ngx_http_lua_ssl_empty_status_callback); + + p = OPENSSL_malloc(resp_len); + if (p == NULL) { + *err = "OPENSSL_malloc() failed"; + return NGX_ERROR; + } + + ngx_memcpy(p, resp, resp_len); + + dd("set ocsp resp: resp_len=%d", (int) resp_len); + (void) SSL_set_tlsext_status_ocsp_resp(ssl_conn, p, resp_len); + ssl_conn->tlsext_status_expected = 1; + + return NGX_OK; + +#endif /* NGX_HTTP_LUA_USE_OCSP */ +} + +#endif /* NGX_LUA_NO_FFI_API */ + + +#endif /* NGX_HTTP_SSL */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_string.c b/debian/modules/nginx-lua/src/ngx_http_lua_string.c index 750d95e..241b969 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_string.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_string.c @@ -548,7 +548,7 @@ ngx_http_lua_ngx_crc32_short(lua_State *L) if (lua_gettop(L) != 1) { return luaL_error(L, "expecting one argument, but got %d", - lua_gettop(L)); + lua_gettop(L)); } p = (u_char *) luaL_checklstring(L, 1, &len); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_subrequest.c b/debian/modules/nginx-lua/src/ngx_http_lua_subrequest.c index 4ac801b..4f8a753 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_subrequest.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_subrequest.c @@ -143,6 +143,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) size_t sr_headers_len; size_t sr_bodies_len; size_t sr_flags_len; + size_t ofs1, ofs2; unsigned custom_ctx; ngx_http_lua_co_ctx_t *coctx; @@ -527,23 +528,31 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) args.len = len; } - p = ngx_pnalloc(r->pool, sizeof(ngx_http_post_subrequest_t) - + sizeof(ngx_http_lua_ctx_t) - + sizeof(ngx_http_lua_post_subrequest_data_t)); + ofs1 = ngx_align(sizeof(ngx_http_post_subrequest_t), sizeof(void *)); + ofs2 = ngx_align(sizeof(ngx_http_lua_ctx_t), sizeof(void *)); + + p = ngx_palloc(r->pool, ofs1 + ofs2 + + sizeof(ngx_http_lua_post_subrequest_data_t)); if (p == NULL) { return luaL_error(L, "no memory"); } psr = (ngx_http_post_subrequest_t *) p; - p += sizeof(ngx_http_post_subrequest_t); + p += ofs1; sr_ctx = (ngx_http_lua_ctx_t *) p; - p += sizeof(ngx_http_lua_ctx_t); + ngx_http_lua_assert((void *) sr_ctx == ngx_align_ptr(sr_ctx, + sizeof(void *))); + + p += ofs2; psr_data = (ngx_http_lua_post_subrequest_data_t *) p; + ngx_http_lua_assert((void *) psr_data == ngx_align_ptr(psr_data, + sizeof(void *))); + ngx_memzero(sr_ctx, sizeof(ngx_http_lua_ctx_t)); /* set by ngx_memzero: @@ -766,7 +775,7 @@ ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method, static ngx_int_t ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t *sr, - ngx_array_t *extra_vars) + ngx_array_t *extra_vars) { ngx_http_core_main_conf_t *cmcf; ngx_http_variable_t *v; @@ -1155,11 +1164,11 @@ ngx_http_lua_set_content_length_header(ngx_http_request_t *r, off_t len) #if 0 dd("content length hash: %lu == %lu", (unsigned long) h->hash, ngx_hash_key_lc((u_char *) "Content-Length", - sizeof("Content-Length") - 1)); + sizeof("Content-Length") - 1)); #endif dd("r content length: %.*s", - (int)r->headers_in.content_length->value.len, + (int) r->headers_in.content_length->value.len, r->headers_in.content_length->value.data); pr = r->parent; @@ -1293,7 +1302,7 @@ ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, } dd("checking sr header %.*s", (int) header[i].key.len, - header[i].key.data); + header[i].key.data); #if 1 if (header[i].hash == 0) { @@ -1304,7 +1313,7 @@ ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, header[i].hash = 0; dd("pushing sr header %.*s", (int) header[i].key.len, - header[i].key.data); + header[i].key.data); lua_pushlstring(co, (char *) header[i].key.data, header[i].key.len); /* header key */ @@ -1434,6 +1443,20 @@ ngx_http_lua_subrequest(ngx_http_request_t *r, ngx_http_request_t *sr; ngx_http_core_srv_conf_t *cscf; +#if nginx_version >= 1009005 + + if (r->subrequests == 0) { +#if defined(NGX_DTRACE) && NGX_DTRACE + ngx_http_probe_subrequest_cycle(r, uri, args); +#endif + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "lua subrequests cycle while processing \"%V\"", uri); + return NGX_ERROR; + } + +#else /* nginx_version <= 1009004 */ + r->main->subrequests--; if (r->main->subrequests == 0) { @@ -1442,11 +1465,13 @@ ngx_http_lua_subrequest(ngx_http_request_t *r, #endif ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "subrequests cycle while processing \"%V\"", uri); + "lua subrequests cycle while processing \"%V\"", uri); r->main->subrequests = 1; return NGX_ERROR; } +#endif + sr = ngx_pcalloc(r->pool, sizeof(ngx_http_request_t)); if (sr == NULL) { return NGX_ERROR; @@ -1508,7 +1533,7 @@ ngx_http_lua_subrequest(ngx_http_request_t *r, } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http subrequest \"%V?%V\"", uri, &sr->args); + "lua http subrequest \"%V?%V\"", uri, &sr->args); sr->subrequest_in_memory = (flags & NGX_HTTP_SUBREQUEST_IN_MEMORY) != 0; sr->waited = (flags & NGX_HTTP_SUBREQUEST_WAITED) != 0; @@ -1537,6 +1562,10 @@ ngx_http_lua_subrequest(ngx_http_request_t *r, sr->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1; +#if nginx_version >= 1009005 + sr->subrequests = r->subrequests - 1; +#endif + tp = ngx_timeofday(); sr->start_sec = tp->sec; sr->start_msec = tp->msec; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c index 49230f4..393eac7 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c @@ -40,6 +40,8 @@ typedef struct { static int ngx_http_lua_ngx_timer_at(lua_State *L); +static int ngx_http_lua_ngx_timer_running_count(lua_State *L); +static int ngx_http_lua_ngx_timer_pending_count(lua_State *L); static void ngx_http_lua_timer_handler(ngx_event_t *ev); static u_char *ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, size_t len); @@ -49,15 +51,59 @@ static void ngx_http_lua_abort_pending_timers(ngx_event_t *ev); void ngx_http_lua_inject_timer_api(lua_State *L) { - lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* ngx.timer. */ + lua_createtable(L, 0 /* narr */, 3 /* nrec */); /* ngx.timer. */ lua_pushcfunction(L, ngx_http_lua_ngx_timer_at); lua_setfield(L, -2, "at"); + lua_pushcfunction(L, ngx_http_lua_ngx_timer_running_count); + lua_setfield(L, -2, "running_count"); + + lua_pushcfunction(L, ngx_http_lua_ngx_timer_pending_count); + lua_setfield(L, -2, "pending_count"); + lua_setfield(L, -2, "timer"); } +static int +ngx_http_lua_ngx_timer_running_count(lua_State *L) +{ + ngx_http_request_t *r; + ngx_http_lua_main_conf_t *lmcf; + + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request"); + } + + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + + lua_pushnumber(L, lmcf->running_timers); + + return 1; +} + + +static int +ngx_http_lua_ngx_timer_pending_count(lua_State *L) +{ + ngx_http_request_t *r; + ngx_http_lua_main_conf_t *lmcf; + + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request"); + } + + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + + lua_pushnumber(L, lmcf->pending_timers); + + return 1; +} + + static int ngx_http_lua_ngx_timer_at(lua_State *L) { @@ -89,7 +135,7 @@ ngx_http_lua_ngx_timer_at(lua_State *L) delay = (ngx_msec_t) (luaL_checknumber(L, 1) * 1000); luaL_argcheck(L, lua_isfunction(L, 2) && !lua_iscfunction(L, 2), 2, - "Lua function expected"); + "Lua function expected"); r = ngx_http_lua_get_req(L); if (r == NULL) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_uthread.c b/debian/modules/nginx-lua/src/ngx_http_lua_uthread.c index de7a72c..8195ec0 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_uthread.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_uthread.c @@ -126,7 +126,8 @@ ngx_http_lua_uthread_wait(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT - | NGX_HTTP_LUA_CONTEXT_TIMER); + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT); coctx = ctx->cur_co_ctx; @@ -223,7 +224,8 @@ ngx_http_lua_uthread_kill(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT - | NGX_HTTP_LUA_CONTEXT_TIMER); + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT); coctx = ctx->cur_co_ctx; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.c b/debian/modules/nginx-lua/src/ngx_http_lua_util.c index 65916be..afb7655 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_util.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_util.c @@ -49,6 +49,7 @@ #include "ngx_http_lua_config.h" #include "ngx_http_lua_worker.h" #include "ngx_http_lua_socket_tcp.h" +#include "ngx_http_lua_ssl_certby.h" #if 1 @@ -111,7 +112,6 @@ static void ngx_http_lua_cleanup_zombie_child_uthreads(ngx_http_request_t *r, lua_State *L, ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx); static ngx_int_t ngx_http_lua_on_abort_resume(ngx_http_request_t *r); static void ngx_http_lua_close_fake_request(ngx_http_request_t *r); -static void ngx_http_lua_free_fake_request(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_flush_pending_output(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); static ngx_int_t @@ -139,7 +139,7 @@ ngx_http_lua_set_path(ngx_cycle_t *cycle, lua_State *L, int tab_idx, /* XXX here we use some hack to simplify string manipulation */ tmp_path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP, - LUA_PATH_SEP AUX_MARK LUA_PATH_SEP); + LUA_PATH_SEP AUX_MARK LUA_PATH_SEP); lua_pushlstring(L, (char *) cycle->prefix.data, cycle->prefix.len); prefix = lua_tostring(L, -1); @@ -719,7 +719,7 @@ static void ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log) { - lua_createtable(L, 0 /* narr */, 99 /* nrec */); /* ngx.* */ + lua_createtable(L, 0 /* narr */, 116 /* nrec */); /* ngx.* */ lua_pushcfunction(L, ngx_http_lua_get_raw_phase_context); lua_setfield(L, -2, "_phase_ctx"); @@ -926,7 +926,7 @@ ngx_http_lua_request_cleanup(ngx_http_lua_ctx_t *ctx, int forcible) lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); #if 1 - if (r->connection->fd == -1) { + if (r->connection->fd == (ngx_socket_t) -1) { /* being a fake request */ lmcf->running_timers--; } @@ -1480,7 +1480,9 @@ no_parent: done: - if (ctx->entered_content_phase && r->connection->fd != -1) { + if (ctx->entered_content_phase + && r->connection->fd != (ngx_socket_t) -1) + { rc = ngx_http_lua_send_chain_link(r, ctx, NULL /* last_buf */); @@ -2090,7 +2092,7 @@ ngx_http_lua_inject_req_api(ngx_log_t *log, lua_State *L) { /* ngx.req table */ - lua_createtable(L, 0 /* narr */, 23 /* nrec */); /* .req */ + lua_createtable(L, 0 /* narr */, 24 /* nrec */); /* .req */ ngx_http_lua_inject_req_header_api(L); ngx_http_lua_inject_req_uri_api(log, L); @@ -2099,6 +2101,7 @@ ngx_http_lua_inject_req_api(ngx_log_t *log, lua_State *L) ngx_http_lua_inject_req_socket_api(L); ngx_http_lua_inject_req_method_api(L); ngx_http_lua_inject_req_time_api(L); + ngx_http_lua_inject_req_misc_api(L); lua_setfield(L, -2, "req"); } @@ -2169,7 +2172,7 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, } dd("internal redirect to %.*s", (int) ctx->exec_uri.len, - ctx->exec_uri.data); + ctx->exec_uri.data); r->write_event_handler = ngx_http_request_empty_handler; @@ -2182,7 +2185,7 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, rc = ngx_http_internal_redirect(r, &ctx->exec_uri, &ctx->exec_args); dd("internal redirect returned %d when in content phase? " - "%d", (int) rc, ctx->entered_content_phase); + "%d", (int) rc, ctx->entered_content_phase); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; @@ -2212,16 +2215,6 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, "lua thread aborting request with status %d", ctx->exit_code); -#if 1 - if (!r->header_sent - && !ctx->header_sent - && r->headers_out.status == 0 - && ctx->exit_code >= NGX_HTTP_OK) - { - r->headers_out.status = ctx->exit_code; - } -#endif - ngx_http_lua_cleanup_pending_operation(ctx->cur_co_ctx); ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 1); @@ -2234,6 +2227,20 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, ngx_http_lua_request_cleanup(ctx, 0); + if (r->connection->fd == (ngx_socket_t) -1) { /* fake request */ + return ctx->exit_code; + } + +#if 1 + if (!r->header_sent + && !ctx->header_sent + && r->headers_out.status == 0 + && ctx->exit_code >= NGX_HTTP_OK) + { + r->headers_out.status = ctx->exit_code; + } +#endif + if (ctx->buffering && r->headers_out.status && ctx->exit_code != NGX_ERROR @@ -2326,7 +2333,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, value = (u_char *) lua_tolstring(L, -1, &value_len); total_escape += 2 * ngx_http_lua_escape_uri(NULL, value, value_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI); len += key_len + value_len + (sizeof("=") - 1); n++; @@ -2548,7 +2555,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (p - args->data != (ssize_t) len) { luaL_error(L, "buffer error: %d != %d", - (int) (p - args->data), (int) len); + (int) (p - args->data), (int) len); return; } } @@ -3523,7 +3530,7 @@ ngx_http_lua_finalize_request(ngx_http_request_t *r, ngx_int_t rc) ngx_http_lua_cleanup_pending_operation(ctx->cur_co_ctx); } - if (r->connection->fd != -1) { + if (r->connection->fd != (ngx_socket_t) -1) { ngx_http_finalize_request(r, rc); return; } @@ -3536,6 +3543,11 @@ void ngx_http_lua_finalize_fake_request(ngx_http_request_t *r, ngx_int_t rc) { ngx_connection_t *c; +#if (NGX_HTTP_SSL) + ngx_ssl_conn_t *ssl_conn; + + ngx_http_lua_ssl_cert_ctx_t *cctx; +#endif c = r->connection; @@ -3549,6 +3561,25 @@ ngx_http_lua_finalize_fake_request(ngx_http_request_t *r, ngx_int_t rc) } if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { + +#if (NGX_HTTP_SSL) + + if (r->connection->ssl) { + ssl_conn = r->connection->ssl->connection; + if (ssl_conn) { + c = ngx_ssl_get_connection(ssl_conn); + + if (c && c->ssl) { + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + if (cctx != NULL) { + cctx->exit_code = 0; + } + } + } + } + +#endif + ngx_http_lua_close_fake_request(r); return; } @@ -3593,7 +3624,7 @@ ngx_http_lua_close_fake_request(ngx_http_request_t *r) } -static void +void ngx_http_lua_free_fake_request(ngx_http_request_t *r) { ngx_log_t *log; @@ -3610,10 +3641,15 @@ ngx_http_lua_free_fake_request(ngx_http_request_t *r) return; } - for (cln = r->cleanup; cln; cln = cln->next) { + cln = r->cleanup; + r->cleanup = NULL; + + while (cln) { if (cln->handler) { cln->handler(cln->data); } + + cln = cln->next; } r->request_line.len = 0; @@ -3628,8 +3664,8 @@ ngx_http_lua_close_fake_connection(ngx_connection_t *c) ngx_pool_t *pool; ngx_connection_t *saved_c = NULL; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http lua close fake http connection"); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http lua close fake http connection %p", c); c->destroyed = 1; @@ -3819,6 +3855,8 @@ ngx_http_lua_create_fake_connection(ngx_pool_t *pool) c->error = 1; + dd("created fake connection: %p", c); + return c; failed: @@ -3878,7 +3916,7 @@ ngx_http_lua_create_fake_request(ngx_connection_t *c) cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts - * sizeof(ngx_http_variable_value_t)); + * sizeof(ngx_http_variable_value_t)); if (r->variables == NULL) { goto failed; } @@ -3905,6 +3943,8 @@ ngx_http_lua_create_fake_request(ngx_connection_t *c) r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE; r->discard_body = 1; + dd("created fake request %p", r); + return r; } @@ -3980,4 +4020,78 @@ ngx_http_lua_get_raw_phase_context(lua_State *L) return 1; } + +ngx_http_cleanup_t * +ngx_http_lua_cleanup_add(ngx_http_request_t *r, size_t size) +{ + ngx_http_cleanup_t *cln; + ngx_http_lua_ctx_t *ctx; + + if (size == 0) { + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + r = r->main; + + if (ctx != NULL && ctx->free_cleanup) { + cln = ctx->free_cleanup; + ctx->free_cleanup = cln->next; + + dd("reuse cleanup: %p", cln); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua http cleanup reuse: %p", cln); + + cln->handler = NULL; + cln->next = r->cleanup; + + r->cleanup = cln; + + return cln; + } + } + + return ngx_http_cleanup_add(r, size); +} + + +void +ngx_http_lua_cleanup_free(ngx_http_request_t *r, ngx_http_cleanup_pt *cleanup) +{ + ngx_http_cleanup_t **last; + ngx_http_cleanup_t *cln; + ngx_http_lua_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return; + } + + r = r->main; + + cln = (ngx_http_cleanup_t *) + ((u_char *) cleanup - offsetof(ngx_http_cleanup_t, handler)); + + dd("cln: %p, cln->handler: %p, &cln->handler: %p", + cln, cln->handler, &cln->handler); + + last = &r->cleanup; + + while (*last) { + if (*last == cln) { + *last = cln->next; + + cln->next = ctx->free_cleanup; + ctx->free_cleanup = cln; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua http cleanup free: %p", cln); + + return; + } + + last = &(*last)->next; + } +} + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.h b/debian/modules/nginx-lua/src/ngx_http_lua_util.h index 42ba07e..f0e8923 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_util.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_util.h @@ -82,8 +82,11 @@ extern char ngx_http_lua_headers_metatable_key; : (c) == NGX_HTTP_LUA_CONTEXT_CONTENT ? "content_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_LOG ? "log_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_HEADER_FILTER ? "header_filter_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_BODY_FILTER ? "body_filter_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_TIMER ? "ngx.timer" \ : (c) == NGX_HTTP_LUA_CONTEXT_INIT_WORKER ? "init_worker_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_BALANCER ? "balancer_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_SSL_CERT ? "ssl_certificate_by_lua*" \ : "(unknown)") @@ -114,18 +117,22 @@ ngx_http_lua_ffi_check_context(ngx_http_lua_ctx_t *ctx, unsigned flags, #define ngx_http_lua_check_fake_request(L, r) \ - if ((r)->connection->fd == -1) { \ + if ((r)->connection->fd == (ngx_socket_t) -1) { \ return luaL_error(L, "API disabled in the current context"); \ } #define ngx_http_lua_check_fake_request2(L, r, ctx) \ - if ((r)->connection->fd == -1) { \ + if ((r)->connection->fd == (ngx_socket_t) -1) { \ return luaL_error(L, "API disabled in the context of %s", \ ngx_http_lua_context_name((ctx)->context)); \ } +#define ngx_http_lua_ssl_get_ctx(ssl_conn) \ + SSL_get_ex_data(ssl_conn, ngx_http_lua_ssl_ctx_index) + + lua_State *ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, ngx_pool_t *pool, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log, ngx_pool_cleanup_t **pcln); @@ -216,6 +223,8 @@ void ngx_http_lua_finalize_fake_request(ngx_http_request_t *r, void ngx_http_lua_close_fake_connection(ngx_connection_t *c); +void ngx_http_lua_free_fake_request(ngx_http_request_t *r); + void ngx_http_lua_release_ngx_ctx_table(ngx_log_t *log, lua_State *L, ngx_http_lua_ctx_t *ctx); @@ -230,6 +239,12 @@ ngx_int_t ngx_http_lua_report(ngx_log_t *log, lua_State *L, int status, int ngx_http_lua_do_call(ngx_log_t *log, lua_State *L); +ngx_http_cleanup_t *ngx_http_lua_cleanup_add(ngx_http_request_t *r, + size_t size); + +void ngx_http_lua_cleanup_free(ngx_http_request_t *r, + ngx_http_cleanup_pt *cleanup); + #define ngx_http_lua_check_if_abortable(L, ctx) \ if ((ctx)->no_abort) { \ @@ -266,7 +281,7 @@ ngx_http_lua_create_ctx(ngx_http_request_t *r) ngx_http_set_ctx(r, ctx, ngx_http_lua_module); llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - if (!llcf->enable_code_cache && r->connection->fd != -1) { + if (!llcf->enable_code_cache && r->connection->fd != (ngx_socket_t) -1) { lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); dd("lmcf: %p", lmcf); @@ -418,6 +433,7 @@ ngx_http_lua_get_flush_chain(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) extern ngx_uint_t ngx_http_lua_location_hash; extern ngx_uint_t ngx_http_lua_content_length_hash; +extern int ngx_http_lua_ssl_ctx_index; #endif /* _NGX_HTTP_LUA_UTIL_H_INCLUDED_ */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_variable.c b/debian/modules/nginx-lua/src/ngx_http_lua_variable.c index 67ba86d..0de9312 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_variable.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_variable.c @@ -307,7 +307,7 @@ ngx_http_lua_ffi_var_get(ngx_http_request_t *r, u_char *name_data, return NGX_ERROR; } - if ((r)->connection->fd == -1) { + if ((r)->connection->fd == (ngx_socket_t) -1) { *err = "API disabled in the current context"; return NGX_ERROR; } @@ -377,7 +377,7 @@ ngx_http_lua_ffi_var_set(ngx_http_request_t *r, u_char *name_data, return NGX_ERROR; } - if ((r)->connection->fd == -1) { + if ((r)->connection->fd == (ngx_socket_t) -1) { ngx_snprintf(errbuf, errlen, "API disabled in the current context"); return NGX_ERROR; } @@ -405,8 +405,8 @@ ngx_http_lua_ffi_var_set(ngx_http_request_t *r, u_char *name_data, dd("set variables with set_handler"); if (value != NULL && value_len) { - vv = ngx_pnalloc(r->pool, sizeof(ngx_http_variable_value_t) - + value_len); + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t) + + value_len); if (vv == NULL) { goto nomem; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_worker.c b/debian/modules/nginx-lua/src/ngx_http_lua_worker.c index f9c4a44..44faf48 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_worker.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_worker.c @@ -15,12 +15,14 @@ static int ngx_http_lua_ngx_worker_exiting(lua_State *L); static int ngx_http_lua_ngx_worker_pid(lua_State *L); +static int ngx_http_lua_ngx_worker_id(lua_State *L); +static int ngx_http_lua_ngx_worker_count(lua_State *L); void ngx_http_lua_inject_worker_api(lua_State *L) { - lua_createtable(L, 0 /* narr */, 2 /* nrec */); /* ngx.worker. */ + lua_createtable(L, 0 /* narr */, 4 /* nrec */); /* ngx.worker. */ lua_pushcfunction(L, ngx_http_lua_ngx_worker_exiting); lua_setfield(L, -2, "exiting"); @@ -28,6 +30,12 @@ ngx_http_lua_inject_worker_api(lua_State *L) lua_pushcfunction(L, ngx_http_lua_ngx_worker_pid); lua_setfield(L, -2, "pid"); + lua_pushcfunction(L, ngx_http_lua_ngx_worker_id); + lua_setfield(L, -2, "id"); + + lua_pushcfunction(L, ngx_http_lua_ngx_worker_count); + lua_setfield(L, -2, "count"); + lua_setfield(L, -2, "worker"); } @@ -48,6 +56,31 @@ ngx_http_lua_ngx_worker_pid(lua_State *L) } +static int +ngx_http_lua_ngx_worker_id(lua_State *L) +{ +#if (nginx_version >= 1009001) + lua_pushinteger(L, (lua_Integer) ngx_worker); +#else + lua_pushnil(L); +#endif + return 1; +} + + +static int +ngx_http_lua_ngx_worker_count(lua_State *L) +{ + ngx_core_conf_t *ccf; + + ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_core_module); + + lua_pushinteger(L, (lua_Integer) ccf->worker_processes); + return 1; +} + + #ifndef NGX_LUA_NO_FFI_API int ngx_http_lua_ffi_worker_pid(void) @@ -56,9 +89,32 @@ ngx_http_lua_ffi_worker_pid(void) } +int +ngx_http_lua_ffi_worker_id(void) +{ +#if (nginx_version >= 1009001) + return (int) ngx_worker; +#else + return -1; +#endif +} + + int ngx_http_lua_ffi_worker_exiting(void) { return (int) ngx_exiting; } + + +int +ngx_http_lua_ffi_worker_count(void) +{ + ngx_core_conf_t *ccf; + + ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_core_module); + + return (int) ccf->worker_processes; +} #endif diff --git a/debian/modules/nginx-lua/t/020-subrequest.t b/debian/modules/nginx-lua/t/020-subrequest.t index 21e728d..88ac1b4 100644 --- a/debian/modules/nginx-lua/t/020-subrequest.t +++ b/debian/modules/nginx-lua/t/020-subrequest.t @@ -11,7 +11,7 @@ use Test::Nginx::Socket::Lua; no_root_location; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 22); +plan tests => repeat_each() * (blocks() * 3 + 23); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; @@ -42,6 +42,8 @@ __DATA__ GET /lua --- response_body DELETE +--- error_log +lua http subrequest "/other?" --- no_error_log [error] @@ -1059,7 +1061,7 @@ hello, world GET /t --- ignore_response --- error_log -subrequests cycle while processing "/t" +lua subrequests cycle while processing "/t" diff --git a/debian/modules/nginx-lua/t/022-redirect.t b/debian/modules/nginx-lua/t/022-redirect.t index 0e2a107..57c7add 100644 --- a/debian/modules/nginx-lua/t/022-redirect.t +++ b/debian/modules/nginx-lua/t/022-redirect.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 3 + 1); +plan tests => repeat_each() * (blocks() * 3 + 2); #no_diff(); #no_long_string(); @@ -83,6 +83,8 @@ GET /read !Location --- response_body_like: 500 Internal Server Error --- error_code: 500 +--- error_log +only ngx.HTTP_MOVED_TEMPORARILY, ngx.HTTP_MOVED_PERMANENTLY, and ngx.HTTP_TEMPORARY_REDIRECT are allowed @@ -166,3 +168,53 @@ Location: http://agentzh.org/foo?bar=3 --- response_body eval [qr/302 Found/, qr/302 Found/] + + +=== TEST 9: explicit 307 +--- config + location /read { + content_by_lua ' + ngx.redirect("http://agentzh.org/foo", ngx.HTTP_TEMPORARY_REDIRECT); + ngx.say("hi") + '; + } +--- request +GET /read +--- response_headers +Location: http://agentzh.org/foo +--- response_body_like: 307 Temporary Redirect +--- error_code: 307 + + + +=== TEST 10: explicit 307 with args +--- config + location /read { + content_by_lua ' + ngx.redirect("http://agentzh.org/foo?a=b&c=d", ngx.HTTP_TEMPORARY_REDIRECT); + ngx.say("hi") + '; + } +--- request +GET /read +--- response_headers +Location: http://agentzh.org/foo?a=b&c=d +--- response_body_like: 307 Temporary Redirect +--- error_code: 307 + + + +=== TEST 11: explicit 307 +--- config + location /read { + content_by_lua ' + ngx.redirect("http://agentzh.org/foo?a=b&c=d", 307); + ngx.say("hi") + '; + } +--- request +GET /read +--- response_headers +Location: http://agentzh.org/foo?a=b&c=d +--- response_body_like: 307 Temporary Redirect +--- error_code: 307 diff --git a/debian/modules/nginx-lua/t/028-req-header.t b/debian/modules/nginx-lua/t/028-req-header.t index 77c0b06..fd13cba 100644 --- a/debian/modules/nginx-lua/t/028-req-header.t +++ b/debian/modules/nginx-lua/t/028-req-header.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (2 * blocks() + 26); +plan tests => repeat_each() * (2 * blocks() + 28); #no_diff(); #no_long_string(); @@ -1532,3 +1532,53 @@ MOVE /a.txt client sent no "Destination" header [error] --- error_code: 204 + + + +=== TEST 50: X-Forwarded-For +--- config + location = /t { + access_by_lua_block { + ngx.req.set_header("X-Forwarded-For", "8.8.8.8") + } + proxy_pass http://127.0.0.1:$server_port/back; + proxy_set_header Foo $proxy_add_x_forwarded_for; + } + + location = /back { + echo "Foo: $http_foo"; + } + +--- request +GET /t + +--- response_body +Foo: 8.8.8.8, 127.0.0.1 +--- no_error_log +[error] + + + +=== TEST 51: X-Forwarded-For +--- config + location = /t { + access_by_lua_block { + ngx.req.clear_header("X-Forwarded-For") + } + proxy_pass http://127.0.0.1:$server_port/back; + proxy_set_header Foo $proxy_add_x_forwarded_for; + } + + location = /back { + echo "Foo: $http_foo"; + } + +--- request +GET /t + +--- more_headers +X-Forwarded-For: 8.8.8.8 +--- response_body +Foo: 127.0.0.1 +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/056-flush.t b/debian/modules/nginx-lua/t/056-flush.t index 260e39a..d189cd5 100644 --- a/debian/modules/nginx-lua/t/056-flush.t +++ b/debian/modules/nginx-lua/t/056-flush.t @@ -42,7 +42,7 @@ hiya --- no_error_log [error] --- error_log -lua reuse free buf memory 13 >= 5 +lua reuse free buf chain, but reallocate memory because 5 >= 0 diff --git a/debian/modules/nginx-lua/t/058-tcp-socket.t b/debian/modules/nginx-lua/t/058-tcp-socket.t index 145a07b..3368589 100644 --- a/debian/modules/nginx-lua/t/058-tcp-socket.t +++ b/debian/modules/nginx-lua/t/058-tcp-socket.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 175; +plan tests => repeat_each() * 187; our $HtmlDir = html_dir; @@ -3343,3 +3343,298 @@ failed to setkeepalive: closed lua tcp socket connect timeout: 100 --- timeout: 10 + + +=== TEST 56: reuse cleanup +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + local sock = ngx.socket.tcp() + local port = ngx.var.port + + for i = 1, 2 do + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local req = "GET /foo HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + ngx.say("request sent: ", bytes) + + while true do + local line, err, part = sock:receive() + if not line then + ngx.say("failed to receive a line: ", err, " [", part, "]") + break + end + end + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end + } + } + + location /foo { + content_by_lua 'ngx.say("foo")'; + more_clear_headers Date; + } + +--- request +GET /t +--- response_body +connected: 1 +request sent: 57 +failed to receive a line: closed [] +close: 1 nil +connected: 1 +request sent: 57 +failed to receive a line: closed [] +close: 1 nil +--- error_log +lua http cleanup reuse + + + +=== TEST 57: reuse cleanup in ngx.timer (fake_request) +--- config + server_tokens off; + location /t { + #set $port 5000; + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + local total_send_bytes = 0 + local port = ngx.var.port + + local function network() + local sock = ngx.socket.tcp() + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.log(ngx.ERR, "failed to connect: ", err) + return + end + + local req = "GET /foo HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.log(ngx.ERR, "failed to send request: ", err) + return + end + + total_send_bytes = total_send_bytes + bytes + + while true do + local line, err, part = sock:receive() + if not line then + break + end + end + + ok, err = sock:close() + end + + local done = false + + local function double_network() + network() + network() + done = true + end + + local ok, err = ngx.timer.at(0, double_network) + if not ok then + ngx.say("failed to create timer: ", err) + end + + i = 1 + while not done do + local time = 0.005 * i + if time > 0.1 then + time = 0.1 + end + ngx.sleep(time) + i = i + 1 + end + + collectgarbage("collect") + + ngx.say("total_send_bytes: ", total_send_bytes) + } + } + + location /foo { + content_by_lua 'ngx.say("foo")'; + more_clear_headers Date; + } + +--- request +GET /t +--- response_body +total_send_bytes: 114 +--- error_log +lua http cleanup reuse + + + +=== TEST 58: free cleanup in ngx.timer (without sock:close) +--- config + server_tokens off; + location /t { + #set $port 5000; + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + local total_send_bytes = 0 + local port = ngx.var.port + + local function network() + local sock = ngx.socket.tcp() + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.log(ngx.ERR, "failed to connect: ", err) + return + end + + local req = "GET /foo HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.log(ngx.ERR, "failed to send request: ", err) + return + end + + total_send_bytes = total_send_bytes + bytes + + while true do + local line, err, part = sock:receive() + if not line then + break + end + end + end + + local done = false + + local function double_network() + network() + network() + done = true + end + + local ok, err = ngx.timer.at(0, double_network) + if not ok then + ngx.say("failed to create timer: ", err) + end + + i = 1 + while not done do + local time = 0.005 * i + if time > 0.1 then + time = 0.1 + end + ngx.sleep(time) + i = i + 1 + end + + collectgarbage("collect") + + ngx.say("total_send_bytes: ", total_send_bytes) + } + } + + location /foo { + content_by_lua 'ngx.say("foo")'; + more_clear_headers Date; + } + +--- request +GET /t +--- response_body +total_send_bytes: 114 +--- no_error_log +[error] + + + +=== TEST 59: reuse cleanup in subrequest +--- config + server_tokens off; + location /t { + echo_location /tt; + } + + location /tt { + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua ' + local sock = ngx.socket.tcp() + local port = ngx.var.port + + for i = 1, 2 do + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local req = "GET /foo HTTP/1.0\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + ngx.say("request sent: ", bytes) + + while true do + local line, err, part = sock:receive() + if not line then + ngx.say("failed to receive a line: ", err, " [", part, "]") + break + end + end + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end + '; + } + + location /foo { + content_by_lua 'ngx.say("foo")'; + more_clear_headers Date; + } + +--- request +GET /t +--- response_body +connected: 1 +request sent: 57 +failed to receive a line: closed [] +close: 1 nil +connected: 1 +request sent: 57 +failed to receive a line: closed [] +close: 1 nil +--- error_log +lua http cleanup reuse diff --git a/debian/modules/nginx-lua/t/062-count.t b/debian/modules/nginx-lua/t/062-count.t index 120d131..c94491c 100644 --- a/debian/modules/nginx-lua/t/062-count.t +++ b/debian/modules/nginx-lua/t/062-count.t @@ -34,7 +34,7 @@ __DATA__ --- request GET /test --- response_body -ngx: 99 +ngx: 116 --- no_error_log [error] @@ -55,7 +55,7 @@ ngx: 99 --- request GET /test --- response_body -99 +116 --- no_error_log [error] @@ -83,7 +83,7 @@ GET /test --- request GET /test --- response_body -n = 99 +n = 116 --- no_error_log [error] @@ -123,7 +123,7 @@ n = 1 --- request GET /test --- response_body -n = 23 +n = 24 --- no_error_log [error] @@ -145,7 +145,7 @@ n = 23 --- request GET /test --- response_body -n = 23 +n = 24 --- no_error_log [error] @@ -172,7 +172,7 @@ n = 23 --- request GET /test --- response_body -n = 23 +n = 24 --- no_error_log [error] @@ -305,7 +305,7 @@ GET /t --- response_body_like: 404 Not Found --- error_code: 404 --- error_log -ngx. entry count: 99 +ngx. entry count: 116 @@ -323,7 +323,7 @@ ngx. entry count: 99 --- request GET /test --- response_body -n = 1 +n = 3 --- no_error_log [error] @@ -438,7 +438,7 @@ thread: 3 --- request GET /test --- response_body -worker: 2 +worker: 4 --- no_error_log [error] diff --git a/debian/modules/nginx-lua/t/076-no-postpone.t b/debian/modules/nginx-lua/t/076-no-postpone.t index d19bb77..94da63a 100644 --- a/debian/modules/nginx-lua/t/076-no-postpone.t +++ b/debian/modules/nginx-lua/t/076-no-postpone.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 3); +plan tests => repeat_each() * (blocks() * 3 + 1); #no_diff(); #no_long_string(); @@ -82,3 +82,65 @@ no foo: 1 --- no_error_log [error] + + +=== TEST 4: access no postpone on +--- http_config + access_by_lua_no_postpone on; +--- config + location /t { + access_by_lua ' + ngx.redirect("http://www.taobao.com/foo") + ngx.say("hi") + '; + content_by_lua 'return'; + deny all; + } +--- request +GET /t +--- response_headers +Location: http://www.taobao.com/foo +--- response_body_like: 302 Found +--- error_code: 302 +--- no_error_log +[error] + + + +=== TEST 5: access no postpone explicitly off +--- http_config + access_by_lua_no_postpone off; +--- config + location /t { + access_by_lua ' + ngx.redirect("http://www.taobao.com/foo") + ngx.say("hi") + '; + content_by_lua 'return'; + deny all; + } +--- request +GET /t +--- response_body_like: 403 Forbidden +--- error_code: 403 +--- error_log +access forbidden by rule + + + +=== TEST 6: access no postpone off by default +--- config + location /t { + access_by_lua ' + ngx.redirect("http://www.taobao.com/foo") + ngx.say("hi") + '; + content_by_lua 'return'; + deny all; + } +--- request +GET /t +--- response_body_like: 403 Forbidden +--- error_code: 403 +--- error_log +access forbidden by rule diff --git a/debian/modules/nginx-lua/t/082-body-filter.t b/debian/modules/nginx-lua/t/082-body-filter.t index c0a7c23..98efa84 100644 --- a/debian/modules/nginx-lua/t/082-body-filter.t +++ b/debian/modules/nginx-lua/t/082-body-filter.t @@ -10,7 +10,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 13); +plan tests => repeat_each() * (blocks() * 3 + 11); #no_diff(); no_long_string(); @@ -824,3 +824,16 @@ eof 2: true [error] [alert] + + +=== TEST 26: no ngx.print +--- config + location /lua { + echo ok; + body_filter_by_lua "ngx.print(32) return 1"; + } +--- request +GET /lua +--- ignore_response +--- error_log +API disabled in the context of body_filter_by_lua* diff --git a/debian/modules/nginx-lua/t/129-ssl-socket.t b/debian/modules/nginx-lua/t/129-ssl-socket.t index 45eaa82..446cfeb 100644 --- a/debian/modules/nginx-lua/t/129-ssl-socket.t +++ b/debian/modules/nginx-lua/t/129-ssl-socket.t @@ -371,11 +371,12 @@ lua ssl free session === TEST 5: certificate does not match host name (verify) +The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.org". --- config server_tokens off; resolver $TEST_NGINX_RESOLVER; lua_ssl_trusted_certificate ../html/trusted.crt; - lua_ssl_verify_depth 2; + lua_ssl_verify_depth 5; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -393,14 +394,14 @@ lua ssl free session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "agentzh.org", true) + local session, err = sock:sslhandshake(nil, "blah.agentzh.org", true) if not session then ngx.say("failed to do SSL handshake: ", err) else ngx.say("ssl handshake: ", type(session)) end - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: agentzh.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -439,8 +440,8 @@ failed to send http request: closed --- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ --- grep_error_log_out --- error_log -lua ssl server name: "agentzh.org" -lua ssl certificate does not match host "agentzh.org" +lua ssl server name: "blah.agentzh.org" +lua ssl certificate does not match host "blah.agentzh.org" --- no_error_log SSL reused session [alert] @@ -449,6 +450,7 @@ SSL reused session === TEST 6: certificate does not match host name (verify, no log socket errors) +The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.org". --- config server_tokens off; resolver $TEST_NGINX_RESOLVER; @@ -472,14 +474,14 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "agentzh.org", true) + local session, err = sock:sslhandshake(nil, "blah.agentzh.org", true) if not session then ngx.say("failed to do SSL handshake: ", err) else ngx.say("ssl handshake: ", type(session)) end - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: blah.agentzh.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -518,7 +520,7 @@ failed to send http request: closed --- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ --- grep_error_log_out --- error_log -lua ssl server name: "agentzh.org" +lua ssl server name: "blah.agentzh.org" --- no_error_log lua ssl certificate does not match host SSL reused session diff --git a/debian/modules/nginx-lua/t/132-lua-blocks.t b/debian/modules/nginx-lua/t/132-lua-blocks.t index 874d017..d157d27 100644 --- a/debian/modules/nginx-lua/t/132-lua-blocks.t +++ b/debian/modules/nginx-lua/t/132-lua-blocks.t @@ -488,3 +488,88 @@ GET /t Hey, it is '! --- no_error_log [error] + + + +=== TEST 21: lexer no match due to incomplete data chunks in a fixed size buffer +--- config + location /test1 { + content_by_lua_block { + ngx.say("1: this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error") + } + } + location /test2 { + content_by_lua_block { + ngx.say("2: this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error") + } + } + + location /test3 { + content_by_lua_block { + ngx.say("3: this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error", + "this is just some random filler to cause an error") + } + } +--- request +GET /test3 +--- response_body eval +"3: " . ("this is just some random filler to cause an error" x 20) . "\n" +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/133-worker-count.t b/debian/modules/nginx-lua/t/133-worker-count.t new file mode 100644 index 0000000..a7bae65 --- /dev/null +++ b/debian/modules/nginx-lua/t/133-worker-count.t @@ -0,0 +1,32 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +#no_diff(); +#no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: content_by_lua +--- config + location /lua { + content_by_lua_block { + ngx.say("workers: ", ngx.worker.count()) + } + } +--- request +GET /lua +--- response_body +workers: 1 +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/134-worker-count-5.t b/debian/modules/nginx-lua/t/134-worker-count-5.t new file mode 100644 index 0000000..d6f16c2 --- /dev/null +++ b/debian/modules/nginx-lua/t/134-worker-count-5.t @@ -0,0 +1,32 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_on(); +workers(5); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +#no_diff(); +#no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /lua { + content_by_lua_block { + ngx.say("worker count: ", ngx.worker.count()) + } + } +--- request +GET /lua +--- response_body +worker count: 5 +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/135-worker-id.t b/debian/modules/nginx-lua/t/135-worker-id.t new file mode 100644 index 0000000..752b406 --- /dev/null +++ b/debian/modules/nginx-lua/t/135-worker-id.t @@ -0,0 +1,33 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_on(); +workers(2); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +#no_diff(); +#no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /lua { + content_by_lua_block { + ngx.say("worker id: ", ngx.worker.id()) + } + } +--- request +GET /lua +--- response_body_like chop +^worker id: [0-1]$ +--- no_error_log +[error] +--- skip_nginx: 3: <=1.9.0 diff --git a/debian/modules/nginx-lua/t/136-timer-counts.t b/debian/modules/nginx-lua/t/136-timer-counts.t new file mode 100644 index 0000000..8f5329b --- /dev/null +++ b/debian/modules/nginx-lua/t/136-timer-counts.t @@ -0,0 +1,111 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +repeat_each(1); + +plan tests => blocks() * (repeat_each() * 3); + +run_tests(); + +__DATA__ + +=== TEST 1: running count with no running timers +--- config + location /timers { + content_by_lua_block { ngx.say(ngx.timer.running_count()) } + } +--- request +GET /timers +--- response_body +0 +--- no_error_log +[error] + + + +=== TEST 2: running count with no pending timers +--- config + location /timers { + content_by_lua_block { ngx.say(ngx.timer.pending_count()) } + } +--- request +GET /timers +--- response_body +0 +--- no_error_log +[error] + + + +=== TEST 3: pending count with one pending timer +--- config + location /timers { + content_by_lua_block { + ngx.timer.at(3, function() end) + ngx.say(ngx.timer.pending_count()) + } + } +--- request +GET /timers +--- response_body +1 +--- no_error_log +[error] + + + +=== TEST 4: pending count with 3 pending timers +--- config + location /timers { + content_by_lua_block { + ngx.timer.at(4, function() end) + ngx.timer.at(2, function() end) + ngx.timer.at(1, function() end) + ngx.say(ngx.timer.pending_count()) + } + } +--- request +GET /timers +--- response_body +3 +--- no_error_log +[error] + + + +=== TEST 5: one running timer +--- config + location /timers { + content_by_lua_block { + ngx.timer.at(0.1, function() ngx.sleep(0.3) end) + ngx.sleep(0.2) + ngx.say(ngx.timer.running_count()) + } + } +--- request +GET /timers +--- response_body +1 +--- no_error_log +[error] + + + +=== TEST 6: 3 running timers +--- config + location /timers { + content_by_lua_block { + ngx.timer.at(0.1, function() ngx.sleep(0.3) end) + ngx.timer.at(0.11, function() ngx.sleep(0.3) end) + ngx.timer.at(0.09, function() ngx.sleep(0.3) end) + ngx.sleep(0.2) + ngx.say(ngx.timer.running_count()) + } + } +--- request +GET /timers +--- response_body +3 +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/137-req-misc.t b/debian/modules/nginx-lua/t/137-req-misc.t new file mode 100644 index 0000000..20ada3c --- /dev/null +++ b/debian/modules/nginx-lua/t/137-req-misc.t @@ -0,0 +1,62 @@ +use Test::Nginx::Socket::Lua; + +#master_on(); +#workers(1); +#worker_connections(1014); +#log_level('warn'); +#master_process_enabled(1); + +repeat_each(2); + +plan tests => repeat_each() * blocks() * 2; + +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; + +#no_diff(); +no_long_string(); +#no_shuffle(); + +run_tests(); + +__DATA__ + +=== TEST 1: not internal request +--- config + location /test { + rewrite ^/test$ /lua last; + } + location /lua { + content_by_lua ' + if ngx.req.is_internal() then + ngx.say("internal") + else + ngx.say("not internal") + end + '; + } +--- request +GET /lua +--- response_body +not internal + + + +=== TEST 2: internal request +--- config + location /test { + rewrite ^/test$ /lua last; + } + location /lua { + content_by_lua ' + if ngx.req.is_internal() then + ngx.say("internal") + else + ngx.say("not internal") + end + '; + } +--- request +GET /test +--- response_body +internal + diff --git a/debian/modules/nginx-lua/t/138-balancer.t b/debian/modules/nginx-lua/t/138-balancer.t new file mode 100644 index 0000000..076465a --- /dev/null +++ b/debian/modules/nginx-lua/t/138-balancer.t @@ -0,0 +1,304 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4 + 8); + +#no_diff(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: simple logging +--- http_config + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + print("hello from balancer by lua!") + } + } +--- config + location = /t { + proxy_pass http://backend; + } +--- request + GET /t +--- response_body_like: 502 Bad Gateway +--- error_code: 502 +--- error_log eval +[ +'[lua] balancer_by_lua:2: hello from balancer by lua! while connecting to upstream,', +qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\.0\.1:80/t"}, +] +--- no_error_log +[warn] + + + +=== TEST 2: exit 403 +--- http_config + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + print("hello from balancer by lua!") + ngx.exit(403) + } + } +--- config + location = /t { + proxy_pass http://backend; + } +--- request + GET /t +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log +[lua] balancer_by_lua:2: hello from balancer by lua! while connecting to upstream, +--- no_error_log eval +[ +'[warn]', +qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\.0\.1:80/t"}, +] + + + +=== TEST 3: exit OK +--- http_config + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + print("hello from balancer by lua!") + ngx.exit(ngx.OK) + } + } +--- config + location = /t { + proxy_pass http://backend; + } +--- request + GET /t +--- response_body_like: 502 Bad Gateway +--- error_code: 502 +--- error_log eval +[ +'[lua] balancer_by_lua:2: hello from balancer by lua! while connecting to upstream,', +qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\.0\.1:80/t"}, +] +--- no_error_log +[warn] + + + +=== TEST 4: ngx.var works +--- http_config + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + print("1: variable foo = ", ngx.var.foo) + ngx.var.foo = tonumber(ngx.var.foo) + 1 + print("2: variable foo = ", ngx.var.foo) + } + } +--- config + location = /t { + set $foo 32; + proxy_pass http://backend; + } +--- request + GET /t +--- response_body_like: 502 Bad Gateway +--- error_code: 502 +--- error_log eval +[ +"1: variable foo = 32", +"2: variable foo = 33", +qr/\[crit\] .* connect\(\) .*? failed/, +] +--- no_error_log +[warn] + + + +=== TEST 5: ngx.req.get_headers works +--- http_config + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + print("header foo: ", ngx.req.get_headers()["foo"]) + } + } +--- config + location = /t { + proxy_pass http://backend; + } +--- request + GET /t +--- more_headers +Foo: bar +--- response_body_like: 502 Bad Gateway +--- error_code: 502 +--- error_log eval +[ +"header foo: bar", +qr/\[crit\] .* connect\(\) .*? failed/, +] +--- no_error_log +[warn] + + + +=== TEST 6: ngx.req.get_uri_args() works +--- http_config + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + print("arg foo: ", ngx.req.get_uri_args()["foo"]) + } + } +--- config + location = /t { + proxy_pass http://backend; + } +--- request + GET /t?baz=blah&foo=bar +--- more_headers +Foo: bar +--- response_body_like: 502 Bad Gateway +--- error_code: 502 +--- error_log eval +["arg foo: bar", +qr/\[crit\] .* connect\(\) .*? failed/, +] +--- no_error_log +[warn] + + + +=== TEST 7: ngx.req.get_method() works +--- http_config + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + print("method: ", ngx.req.get_method()) + } + } +--- config + location = /t { + proxy_pass http://backend; + } +--- request + GET /t +--- more_headers +Foo: bar +--- response_body_like: 502 Bad Gateway +--- error_code: 502 +--- error_log eval +[ +"method: GET", +qr/\[crit\] .* connect\(\) .*? failed/, +] +--- no_error_log +[warn] + + + +=== TEST 8: simple logging (by_lua_file) +--- http_config + upstream backend { + server 0.0.0.1; + balancer_by_lua_file html/a.lua; + } +--- config + location = /t { + proxy_pass http://backend; + } +--- user_files +>>> a.lua +print("hello from balancer by lua!") +--- request + GET /t +--- response_body_like: 502 Bad Gateway +--- error_code: 502 +--- error_log eval +[ +'[lua] a.lua:1: hello from balancer by lua! while connecting to upstream,', +qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\.0\.1:80/t"}, +] +--- no_error_log +[warn] + + + +=== TEST 9: cosockets are disabled +--- http_config + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + local sock, err = ngx.socket.tcp() + } + } +--- config + location = /t { + proxy_pass http://backend; + } +--- request + GET /t +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log eval +qr/\[error\] .*? failed to run balancer_by_lua\*: balancer_by_lua:2: API disabled in the context of balancer_by_lua\*/ + + + +=== TEST 10: ngx.sleep is disabled +--- http_config + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + ngx.sleep(0.1) + } + } +--- config + location = /t { + proxy_pass http://backend; + } +--- request + GET /t +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log eval +qr/\[error\] .*? failed to run balancer_by_lua\*: balancer_by_lua:2: API disabled in the context of balancer_by_lua\*/ + + + +=== TEST 11: get_phase +--- http_config + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + print("I am in phase ", ngx.get_phase()) + } + } +--- config + location = /t { + proxy_pass http://backend; + } +--- request + GET /t +--- response_body_like: 502 Bad Gateway +--- error_code: 502 +--- grep_error_log eval: qr/I am in phase \w+/ +--- grep_error_log_out +I am in phase balancer +--- error_log eval +qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\.0\.1:80/t"} +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/139-ssl-cert-by.t b/debian/modules/nginx-lua/t/139-ssl-cert-by.t new file mode 100644 index 0000000..e40fe85 --- /dev/null +++ b/debian/modules/nginx-lua/t/139-ssl-cert-by.t @@ -0,0 +1,1382 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +repeat_each(3); + +# All these tests need to have new openssl +my $NginxBinary = $ENV{'TEST_NGINX_BINARY'} || 'nginx'; +my $openssl_version = eval { `$NginxBinary -V 2>&1` }; + +if ($openssl_version =~ m/built with OpenSSL (0|1\.0\.(?:0|1[^\d]|2[a-d]).*)/) { + plan(skip_all => "too old OpenSSL, need 1.0.2e, was $1"); +} else { + plan tests => repeat_each() * (blocks() * 6 + 10); +} + +$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; + +#log_level 'warn'; +log_level 'debug'; + +no_long_string(); +#no_diff(); + +run_tests(); + +__DATA__ + +=== TEST 1: simple logging +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate_by_lua_block { print("ssl cert by lua is running!") } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to recieve response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +ssl_certificate_by_lua:1: ssl cert by lua is running! + +--- no_error_log +[error] +[alert] + + + +=== TEST 2: sleep +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate_by_lua_block { + local begin = ngx.now() + ngx.sleep(0.1) + print("elapsed in ssl cert by lua: ", ngx.now() - begin) + } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to recieve response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- error_log eval +[ +'lua ssl server name: "test.com"', +qr/elapsed in ssl cert by lua: 0.(?:09|1[01])\d+,/, +] + +--- no_error_log +[error] +[alert] + + + +=== TEST 3: timer +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate_by_lua_block { + local function f() + print("my timer run!") + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.log(ngx.ERR, "failed to create timer: ", err) + return + end + } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to recieve response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +my timer run! + +--- no_error_log +[error] +[alert] + + + +=== TEST 4: cosocket +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate_by_lua_block { + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if not ok then + ngx.log(ngx.ERR, "failed to connect to memc: ", err) + return + end + + local bytes, err = sock:send("flush_all\r\n") + if not bytes then + ngx.log(ngx.ERR, "failed to send flush_all command: ", err) + return + end + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "failed to receive memc reply: ", err) + return + end + + print("received memc reply: ", res) + } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to recieve response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +received memc reply: OK + +--- no_error_log +[error] +[alert] + + + +=== TEST 5: ngx.exit(0) - no yield +--- http_config + server { + listen 127.0.0.2:8080 ssl; + server_name test.com; + ssl_certificate_by_lua_block { + ngx.exit(0) + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("127.0.0.2", 8080) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(false, nil, true, false) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + end -- do + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: boolean + +--- error_log +lua exit with code 0 + +--- no_error_log +should never reached here +[error] +[alert] +[emerg] + + + +=== TEST 6: ngx.exit(ngx.ERROR) - no yield +--- http_config + server { + listen 127.0.0.2:8080 ssl; + server_name test.com; + ssl_certificate_by_lua_block { + ngx.exit(ngx.ERROR) + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("127.0.0.2", 8080) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(false, nil, true, false) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + end -- do + } + } + +--- request +GET /t +--- response_body +connected: 1 +failed to do SSL handshake: handshake failed + +--- error_log eval +[ +'lua_certificate_by_lua: handler return value: -1, cert cb exit code: 0', +qr/\[crit\] .*? SSL_do_handshake\(\) failed .*?cert cb error/, +'lua exit with code -1', +] + +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 7: ngx.exit(0) - yield +--- http_config + server { + listen 127.0.0.2:8080 ssl; + server_name test.com; + ssl_certificate_by_lua_block { + ngx.sleep(0.001) + ngx.exit(0) + + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("127.0.0.2", 8080) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(false, nil, true, false) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + end -- do + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: boolean + +--- error_log +lua exit with code 0 + +--- no_error_log +should never reached here +[error] +[alert] +[emerg] + + + +=== TEST 8: ngx.exit(ngx.ERROR) - yield +--- http_config + server { + listen 127.0.0.2:8080 ssl; + server_name test.com; + ssl_certificate_by_lua_block { + ngx.sleep(0.001) + ngx.exit(ngx.ERROR) + + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("127.0.0.2", 8080) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(false, nil, true, false) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + end -- do + } + } + +--- request +GET /t +--- response_body +connected: 1 +failed to do SSL handshake: handshake failed + +--- error_log eval +[ +'lua_certificate_by_lua: cert cb exit code: 0', +qr/\[crit\] .*? SSL_do_handshake\(\) failed .*?cert cb error/, +'lua exit with code -1', +] + +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 9: lua exception - no yield +--- http_config + server { + listen 127.0.0.2:8080 ssl; + server_name test.com; + ssl_certificate_by_lua_block { + error("bad bad bad") + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("127.0.0.2", 8080) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(false, nil, true, false) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + end -- do + } + } + +--- request +GET /t +--- response_body +connected: 1 +failed to do SSL handshake: handshake failed + +--- error_log eval +[ +'runtime error: ssl_certificate_by_lua:2: bad bad bad', +'lua_certificate_by_lua: handler return value: 500, cert cb exit code: 0', +qr/\[crit\] .*? SSL_do_handshake\(\) failed .*?cert cb error/, +qr/context: ssl_certificate_by_lua\*, client: \d+\.\d+\.\d+\.\d+, server: \d+\.\d+\.\d+\.\d+:\d+/, +] + +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 10: lua exception - yield +--- http_config + server { + listen 127.0.0.2:8080 ssl; + server_name test.com; + ssl_certificate_by_lua_block { + ngx.sleep(0.001) + error("bad bad bad") + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("127.0.0.2", 8080) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(false, nil, true, false) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + end -- do + } + } + +--- request +GET /t +--- response_body +connected: 1 +failed to do SSL handshake: handshake failed + +--- error_log eval +[ +'runtime error: ssl_certificate_by_lua:3: bad bad bad', +'lua_certificate_by_lua: cert cb exit code: 0', +qr/\[crit\] .*? SSL_do_handshake\(\) failed .*?cert cb error/, +] + +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 11: get phase +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate_by_lua_block {print("get_phase: ", ngx.get_phase())} + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + end + collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata + +--- error_log +lua ssl server name: "test.com" +get_phase: ssl_cert + +--- no_error_log +[error] +[alert] + + + +=== TEST 12: connection aborted prematurely +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate_by_lua_block { + ngx.sleep(0.3) + -- local ssl = require "ngx.ssl" + -- ssl.clear_certs() + print("ssl-cert-by-lua: after sleeping") + } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(150) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(false, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t + +--- response_body +connected: 1 +failed to do SSL handshake: timeout + +--- error_log +lua ssl server name: "test.com" +ssl-cert-by-lua: after sleeping + +--- no_error_log +[error] +[alert] +--- wait: 0.6 + + + +=== TEST 13: subrequests disabled +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate_by_lua_block {ngx.location.capture("/foo")} + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +failed to do SSL handshake: handshake failed + +--- error_log eval +[ +'lua ssl server name: "test.com"', +'ssl_certificate_by_lua:1: API disabled in the context of ssl_certificate_by_lua*', +qr/\[crit\] .*?cert cb error/, +] + +--- no_error_log +[alert] + + + +=== TEST 14: simple logging (by_lua_file) +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate_by_lua_file html/a.lua; + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} + more_clear_headers Date; + } + } + +--- user_files +>>> a.lua +print("ssl cert by lua is running!") + +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to recieve response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +a.lua:1: ssl cert by lua is running! + +--- no_error_log +[error] +[alert] + + + +=== TEST 15: coroutine API +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate_by_lua_block { + local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield + + local function f() + local cnt = 0 + for i = 1, 20 do + print("co yield: ", cnt) + cy() + cnt = cnt + 1 + end + end + + local c = cc(f) + for i = 1, 3 do + print("co resume, status: ", coroutine.status(c)) + cr(c) + end + } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to recieve response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- grep_error_log eval: qr/co (?:yield: \d+|resume, status: \w+)/ +--- grep_error_log_out +co resume, status: suspended +co yield: 0 +co resume, status: suspended +co yield: 1 +co resume, status: suspended +co yield: 2 + +--- error_log +lua ssl server name: "test.com" + +--- no_error_log +[error] +[alert] + + + +=== TEST 16: simple user thread wait with yielding +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate_by_lua_block { + function f() + ngx.sleep(0.01) + print("uthread: hello in thread") + return "done" + end + + local t, err = ngx.thread.spawn(f) + if not t then + ngx.log(ngx.ERR, "uthread: failed to spawn thread: ", err) + return ngx.exit(ngx.ERROR) + end + + print("uthread: thread created: ", coroutine.status(t)) + + local ok, res = ngx.thread.wait(t) + if not ok then + print("uthread: failed to wait thread: ", res) + return + end + + print("uthread: ", res) + } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to recieve response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- no_error_log +[error] +[alert] +--- grep_error_log eval: qr/uthread: [^.,]+/ +--- grep_error_log_out +uthread: thread created: running +uthread: hello in thread +uthread: done diff --git a/debian/modules/nginx-lua/util/build2.sh b/debian/modules/nginx-lua/util/build2.sh index 5a89c29..2aa79cc 100755 --- a/debian/modules/nginx-lua/util/build2.sh +++ b/debian/modules/nginx-lua/util/build2.sh @@ -21,16 +21,16 @@ force=$2 #--with-cc=clang \ #--without-http_referer_module \ #--with-http_v2_module \ + #--with-http_spdy_module \ time ngx-build $force $version \ --with-ipv6 \ - --with-cc-opt="-I$PCRE_INC" \ + --with-cc-opt="-I$PCRE_INC -I$OPENSSL_INC" \ --with-http_realip_module \ - --with-http_ssl_module \ + --with-http_ssl_module \ --add-module=$root/../ndk-nginx-module \ --add-module=$root/../set-misc-nginx-module \ - --with-ld-opt="-L$PCRE_LIB -Wl,-rpath,$PCRE_LIB:$LIBDRIZZLE_LIB:/usr/local/lib" \ - --with-http_spdy_module \ + --with-ld-opt="-L$PCRE_LIB -L$OPENSSL_LIB -Wl,-rpath,$PCRE_LIB:$LIBDRIZZLE_LIB:$OPENSSL_LIB" \ --without-mail_pop3_module \ --without-mail_imap_module \ --with-http_image_filter_module \ From 45aed60c9d102d2dd12030f05c318ed6e9ff0522 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 14 Jan 2016 10:31:38 +0200 Subject: [PATCH 069/651] Keep logs for 14 *days* Complements Mike's 255c62e0 (#805322) --- debian/nginx-common.nginx.logrotate | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/nginx-common.nginx.logrotate b/debian/nginx-common.nginx.logrotate index 1b25aad..423c6ad 100644 --- a/debian/nginx-common.nginx.logrotate +++ b/debian/nginx-common.nginx.logrotate @@ -1,5 +1,5 @@ /var/log/nginx/*.log { - weekly + daily missingok rotate 14 compress From 706a679a92e1bfa57e22f6f09eec02800b7d289a Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 14 Jan 2016 10:37:03 +0200 Subject: [PATCH 070/651] Add a NEWS entry for our logrotate policy change --- debian/nginx-common.NEWS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/nginx-common.NEWS b/debian/nginx-common.NEWS index 46a6f14..a72049d 100644 --- a/debian/nginx-common.NEWS +++ b/debian/nginx-common.NEWS @@ -1,3 +1,10 @@ +nginx-common (1.9.9-1) UNRELEASED; urgency=medium + + Starting with this release we are changing the default logrotate rule to keep + daily logs for 14 days, this aligns our policy with apache2 (Bug #805322). + + -- Christos Trochalakis Thu, 14 Jan 2016 10:17:33 +0200 + nginx-common (1.9.6-1) unstable; urgency=medium As of nginx 1.9.5 spdy has been replaced by the http2 module. Make sure to From 4f41a6929370dd71500208b147bd9af0fc950858 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 14 Jan 2016 10:41:13 +0200 Subject: [PATCH 071/651] Release 1.9.9-1 --- debian/changelog | 4 ++-- debian/nginx-common.NEWS | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index bf298f1..5e94be3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.9.9-1) UNRELEASED; urgency=medium +nginx (1.9.9-1) unstable; urgency=medium [ Michael Lustfield ] * debian/nginx-common.nginx.logrotate: @@ -9,7 +9,7 @@ nginx (1.9.9-1) UNRELEASED; urgency=medium * debian/modules/nginx-lua: + Update nginx-lua to v0.10.0. - -- Christos Trochalakis Thu, 14 Jan 2016 10:11:34 +0200 + -- Christos Trochalakis Thu, 14 Jan 2016 10:40:35 +0200 nginx (1.9.6-2) unstable; urgency=medium diff --git a/debian/nginx-common.NEWS b/debian/nginx-common.NEWS index a72049d..3d06e67 100644 --- a/debian/nginx-common.NEWS +++ b/debian/nginx-common.NEWS @@ -1,4 +1,4 @@ -nginx-common (1.9.9-1) UNRELEASED; urgency=medium +nginx-common (1.9.9-1) unstable; urgency=medium Starting with this release we are changing the default logrotate rule to keep daily logs for 14 days, this aligns our policy with apache2 (Bug #805322). From 647d381b13d22aee80f29ee9dd88ca453f49735a Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 26 Jan 2016 19:42:15 +0200 Subject: [PATCH 072/651] Imported Upstream version 1.9.10 --- CHANGES | 30 +++ CHANGES.ru | 36 ++- LICENSE | 4 +- src/core/nginx.c | 43 +++- src/core/nginx.h | 4 +- src/core/ngx_cycle.h | 1 + src/core/ngx_resolver.c | 234 ++++++++++-------- src/core/ngx_resolver.h | 15 +- .../ngx_http_upstream_keepalive_module.c | 4 + src/http/ngx_http.c | 1 + src/http/ngx_http_request_body.c | 6 - src/http/ngx_http_upstream.c | 4 + src/http/ngx_http_upstream.h | 1 + 13 files changed, 263 insertions(+), 120 deletions(-) diff --git a/CHANGES b/CHANGES index 267669b..3827f90 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,34 @@ +Changes with nginx 1.9.10 26 Jan 2016 + + *) Security: invalid pointer dereference might occur during DNS server + response processing if the "resolver" directive was used, allowing an + attacker who is able to forge UDP packets from the DNS server to + cause segmentation fault in a worker process (CVE-2016-0742). + + *) Security: use-after-free condition might occur during CNAME response + processing if the "resolver" directive was used, allowing an attacker + who is able to trigger name resolution to cause segmentation fault in + a worker process, or might have potential other impact + (CVE-2016-0746). + + *) Security: CNAME resolution was insufficiently limited if the + "resolver" directive was used, allowing an attacker who is able to + trigger arbitrary name resolution to cause excessive resource + consumption in worker processes (CVE-2016-0747). + + *) Feature: the "auto" parameter of the "worker_cpu_affinity" directive. + + *) Bugfix: the "proxy_protocol" parameter of the "listen" directive did + not work with IPv6 listen sockets. + + *) Bugfix: connections to upstream servers might be cached incorrectly + when using the "keepalive" directive. + + *) Bugfix: proxying used the HTTP method of the original request after + an "X-Accel-Redirect" redirection. + + Changes with nginx 1.9.9 09 Dec 2015 *) Bugfix: proxying to unix domain sockets did not work when using diff --git a/CHANGES.ru b/CHANGES.ru index 315013b..563163a 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,38 @@ +Изменения в nginx 1.9.10 26.01.2016 + + *) Безопасность: при использовании директивы resolver во время обработки + ответов DNS-сервера могло происходить разыменование некорректного + адреса, что позволяло атакующему, имеющему возможность подделывать + UDP-пакеты от DNS-сервера, вызвать segmentation fault в рабочем + процессе (CVE-2016-0742). + + *) Безопасность: при использовании директивы resolver во время обработки + CNAME-записей могло произойти обращение к ранее освобождённой памяти, + что позволяло атакующему, имеющему возможность инициировать + преобразование произвольных имён в адреса, вызвать segmentation fault + в рабочем процессе, а также потенциально могло иметь другие + последствия (CVE-2016-0746). + + *) Безопасность: при использовании директивы resolver во время обработки + CNAME-записей не во всех случаях проверялось ограничение на + максимальное количество записей в цепочке, что позволяло атакующему, + имеющему возможность инициировать преобразование произвольных имён в + адреса, вызвать чрезмерное потребление ресурсов рабочими процессами + (CVE-2016-0747). + + *) Добавление: параметр auto директивы worker_cpu_affinity. + + *) Исправление: параметр proxy_protocol директивы listen не работал с + IPv6 listen-сокетами. + + *) Исправление: при использовании директивы keepalive соединения к + бэкендам могли кэшироваться некорректно. + + *) Исправление: после перенаправления запроса с помощью X-Accel-Redirect + при проксировании использовался HTTP-метод оригинального запроса. + + Изменения в nginx 1.9.9 09.12.2015 *) Исправление: проксирование в unix domain сокеты не работало при @@ -138,7 +172,7 @@ *) Добавление: ограничение количества соединений в модуле stream. - *) Добавление: органичение скорости в модуле stream. + *) Добавление: ограничение скорости в модуле stream. *) Исправление: директива zone в блоке upstream не работала на Windows. diff --git a/LICENSE b/LICENSE index f752308..1d3d15c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ /* - * Copyright (C) 2002-2015 Igor Sysoev - * Copyright (C) 2011-2015 Nginx, Inc. + * Copyright (C) 2002-2016 Igor Sysoev + * Copyright (C) 2011-2016 Nginx, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/core/nginx.c b/src/core/nginx.c index 3335587..64db381 100644 --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -961,6 +961,7 @@ ngx_core_module_create_conf(ngx_cycle_t *cycle) * ccf->pid = NULL; * ccf->oldpid = NULL; * ccf->priority = 0; + * ccf->cpu_affinity_auto = 0; * ccf->cpu_affinity_n = 0; * ccf->cpu_affinity = NULL; */ @@ -1002,7 +1003,8 @@ ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf) #if (NGX_HAVE_CPU_AFFINITY) - if (ccf->cpu_affinity_n + if (!ccf->cpu_affinity_auto + && ccf->cpu_affinity_n && ccf->cpu_affinity_n != 1 && ccf->cpu_affinity_n != (ngx_uint_t) ccf->worker_processes) { @@ -1273,7 +1275,24 @@ ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) value = cf->args->elts; - for (n = 1; n < cf->args->nelts; n++) { + if (ngx_strcmp(value[1].data, "auto") == 0) { + + if (cf->args->nelts > 3) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid number of arguments in " + "\"worker_cpu_affinity\" directive"); + return NGX_CONF_ERROR; + } + + ccf->cpu_affinity_auto = 1; + mask[0] = (uint64_t) -1 >> (64 - ngx_min(64, ngx_ncpu)); + n = 2; + + } else { + n = 1; + } + + for ( /* void */ ; n < cf->args->nelts; n++) { if (value[n].len > 64) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -1323,6 +1342,8 @@ ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) uint64_t ngx_get_cpu_affinity(ngx_uint_t n) { + uint64_t mask; + ngx_uint_t i; ngx_core_conf_t *ccf; ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, @@ -1332,6 +1353,24 @@ ngx_get_cpu_affinity(ngx_uint_t n) return 0; } + if (ccf->cpu_affinity_auto) { + mask = ccf->cpu_affinity[ccf->cpu_affinity_n - 1]; + + if (mask == 0) { + return 0; + } + + for (i = 0; /* void */ ; i++) { + if ((mask & ((uint64_t) 1 << (i % 64))) && n-- == 0) { + break; + } + + /* void */ + } + + return (uint64_t) 1 << (i % 64); + } + if (ccf->cpu_affinity_n > n) { return ccf->cpu_affinity[n]; } diff --git a/src/core/nginx.h b/src/core/nginx.h index 87a984a..0960afb 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1009009 -#define NGINX_VERSION "1.9.9" +#define nginx_version 1009010 +#define NGINX_VERSION "1.9.10" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h index b77c109..a730efe 100644 --- a/src/core/ngx_cycle.h +++ b/src/core/ngx_cycle.h @@ -88,6 +88,7 @@ typedef struct { int priority; + ngx_uint_t cpu_affinity_auto; ngx_uint_t cpu_affinity_n; uint64_t *cpu_affinity; diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index 7013885..7b60abd 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -59,15 +59,15 @@ ngx_int_t ngx_udp_connect(ngx_udp_connection_t *uc); static void ngx_resolver_cleanup(void *data); static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree); static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r, - ngx_resolver_ctx_t *ctx); + ngx_resolver_ctx_t *ctx, ngx_str_t *name); static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue); static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn); -static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_node_t *rn, - ngx_resolver_ctx_t *ctx); -static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, - ngx_resolver_ctx_t *ctx); +static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r, + ngx_resolver_node_t *rn, ngx_str_t *name); +static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r, + ngx_resolver_node_t *rn, ngx_addr_t *addr); static void ngx_resolver_resend_handler(ngx_event_t *ev); static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue); @@ -376,7 +376,7 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx) /* lock name mutex */ - rc = ngx_resolve_name_locked(r, ctx); + rc = ngx_resolve_name_locked(r, ctx, &ctx->name); if (rc == NGX_OK) { return NGX_OK; @@ -403,7 +403,6 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx) void ngx_resolve_name_done(ngx_resolver_ctx_t *ctx) { - uint32_t hash; ngx_resolver_t *r; ngx_resolver_ctx_t *w, **p; ngx_resolver_node_t *rn; @@ -423,11 +422,9 @@ ngx_resolve_name_done(ngx_resolver_ctx_t *ctx) /* lock name mutex */ - if (ctx->state == NGX_AGAIN) { + if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) { - hash = ngx_crc32_short(ctx->name.data, ctx->name.len); - - rn = ngx_resolver_lookup_name(r, &ctx->name, hash); + rn = ctx->node; if (rn) { p = &rn->waiting; @@ -472,23 +469,28 @@ done: static ngx_int_t -ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) +ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, + ngx_str_t *name) { uint32_t hash; ngx_int_t rc; + ngx_str_t cname; ngx_uint_t naddrs; ngx_addr_t *addrs; - ngx_resolver_ctx_t *next; + ngx_resolver_ctx_t *next, *last; ngx_resolver_node_t *rn; - ngx_strlow(ctx->name.data, ctx->name.data, ctx->name.len); + ngx_strlow(name->data, name->data, name->len); - hash = ngx_crc32_short(ctx->name.data, ctx->name.len); + hash = ngx_crc32_short(name->data, name->len); - rn = ngx_resolver_lookup_name(r, &ctx->name, hash); + rn = ngx_resolver_lookup_name(r, name, hash); if (rn) { + /* ctx can be a list after NGX_RESOLVE_CNAME */ + for (last = ctx; last->next; last = last->next); + if (rn->valid >= ngx_time()) { ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached"); @@ -516,7 +518,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) } } - ctx->next = rn->waiting; + last->next = rn->waiting; rn->waiting = NULL; /* unlock name mutex */ @@ -556,13 +558,13 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) { - ctx->name.len = rn->cnlen; - ctx->name.data = rn->u.cname; + cname.len = rn->cnlen; + cname.data = rn->u.cname; - return ngx_resolve_name_locked(r, ctx); + return ngx_resolve_name_locked(r, ctx, &cname); } - ctx->next = rn->waiting; + last->next = rn->waiting; rn->waiting = NULL; /* unlock name mutex */ @@ -581,10 +583,29 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) if (rn->waiting) { - ctx->next = rn->waiting; + if (ctx->event == NULL) { + ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); + if (ctx->event == NULL) { + return NGX_ERROR; + } + + ctx->event->handler = ngx_resolver_timeout_handler; + ctx->event->data = ctx; + ctx->event->log = r->log; + ctx->ident = -1; + + ngx_add_timer(ctx->event, ctx->timeout); + } + + last->next = rn->waiting; rn->waiting = ctx; ctx->state = NGX_AGAIN; + do { + ctx->node = rn; + ctx = ctx->next; + } while (ctx); + return NGX_AGAIN; } @@ -623,14 +644,14 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) return NGX_ERROR; } - rn->name = ngx_resolver_dup(r, ctx->name.data, ctx->name.len); + rn->name = ngx_resolver_dup(r, name->data, name->len); if (rn->name == NULL) { ngx_resolver_free(r, rn); return NGX_ERROR; } rn->node.key = hash; - rn->nlen = (u_short) ctx->name.len; + rn->nlen = (u_short) name->len; rn->query = NULL; #if (NGX_HAVE_INET6) rn->query6 = NULL; @@ -639,7 +660,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) ngx_rbtree_insert(&r->name_rbtree, &rn->node); } - rc = ngx_resolver_create_name_query(rn, ctx); + rc = ngx_resolver_create_name_query(r, rn, name); if (rc == NGX_ERROR) { goto failed; @@ -652,8 +673,14 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) ngx_resolver_free(r, rn->name); ngx_resolver_free(r, rn); - ctx->state = NGX_RESOLVE_NXDOMAIN; - ctx->handler(ctx); + do { + ctx->state = NGX_RESOLVE_NXDOMAIN; + next = ctx->next; + + ctx->handler(ctx); + + ctx = next; + } while (ctx); return NGX_OK; } @@ -674,9 +701,9 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) } ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = rn; + ctx->event->data = ctx; ctx->event->log = r->log; - rn->ident = -1; + ctx->ident = -1; ngx_add_timer(ctx->event, ctx->timeout); } @@ -697,6 +724,11 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) ctx->state = NGX_AGAIN; + do { + ctx->node = rn; + ctx = ctx->next; + } while (ctx); + return NGX_AGAIN; failed: @@ -804,9 +836,22 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) if (rn->waiting) { + ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); + if (ctx->event == NULL) { + return NGX_ERROR; + } + + ctx->event->handler = ngx_resolver_timeout_handler; + ctx->event->data = ctx; + ctx->event->log = r->log; + ctx->ident = -1; + + ngx_add_timer(ctx->event, ctx->timeout); + ctx->next = rn->waiting; rn->waiting = ctx; ctx->state = NGX_AGAIN; + ctx->node = rn; /* unlock addr mutex */ @@ -848,7 +893,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) ngx_rbtree_insert(tree, &rn->node); } - if (ngx_resolver_create_addr_query(rn, ctx) != NGX_OK) { + if (ngx_resolver_create_addr_query(r, rn, &ctx->addr) != NGX_OK) { goto failed; } @@ -867,9 +912,9 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) } ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = rn; + ctx->event->data = ctx; ctx->event->log = r->log; - rn->ident = -1; + ctx->ident = -1; ngx_add_timer(ctx->event, ctx->timeout); @@ -892,6 +937,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) /* unlock addr mutex */ ctx->state = NGX_AGAIN; + ctx->node = rn; return NGX_OK; @@ -922,17 +968,11 @@ failed: void ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx) { - in_addr_t addr; ngx_queue_t *expire_queue; ngx_rbtree_t *tree; ngx_resolver_t *r; ngx_resolver_ctx_t *w, **p; - struct sockaddr_in *sin; ngx_resolver_node_t *rn; -#if (NGX_HAVE_INET6) - uint32_t hash; - struct sockaddr_in6 *sin6; -#endif r = ctx->resolver; @@ -959,23 +999,9 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx) /* lock addr mutex */ - if (ctx->state == NGX_AGAIN) { + if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) { - switch (ctx->addr.sockaddr->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr; - hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16); - rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash); - break; -#endif - - default: /* AF_INET */ - sin = (struct sockaddr_in *) ctx->addr.sockaddr; - addr = ntohl(sin->sin_addr.s_addr); - rn = ngx_resolver_lookup_addr(r, addr); - } + rn = ctx->node; if (rn) { p = &rn->waiting; @@ -1312,7 +1338,7 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n) times = 0; for (q = ngx_queue_head(&r->name_resend_queue); - q != ngx_queue_sentinel(&r->name_resend_queue) || times++ < 100; + q != ngx_queue_sentinel(&r->name_resend_queue) && times++ < 100; q = ngx_queue_next(q)) { rn = ngx_queue_data(q, ngx_resolver_node_t, queue); @@ -1975,21 +2001,40 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, ngx_queue_insert_head(&r->name_expire_queue, &rn->queue); - ctx = rn->waiting; - rn->waiting = NULL; - - if (ctx) { - ctx->name = name; - - (void) ngx_resolve_name_locked(r, ctx); - } - ngx_resolver_free(r, rn->query); rn->query = NULL; #if (NGX_HAVE_INET6) rn->query6 = NULL; #endif + ctx = rn->waiting; + rn->waiting = NULL; + + if (ctx) { + + if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) { + + /* unlock name mutex */ + + do { + ctx->state = NGX_RESOLVE_NXDOMAIN; + next = ctx->next; + + ctx->handler(ctx); + + ctx = next; + } while (ctx); + + return; + } + + for (next = ctx; next; next = next->next) { + next->node = NULL; + } + + (void) ngx_resolve_name_locked(r, ctx, &name); + } + /* unlock name mutex */ return; @@ -2496,27 +2541,23 @@ ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp, static ngx_int_t -ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) +ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, + ngx_str_t *name) { u_char *p, *s; size_t len, nlen; ngx_uint_t ident; -#if (NGX_HAVE_INET6) - ngx_resolver_t *r; -#endif ngx_resolver_qs_t *qs; ngx_resolver_hdr_t *query; - nlen = ctx->name.len ? (1 + ctx->name.len + 1) : 1; + nlen = name->len ? (1 + name->len + 1) : 1; len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t); #if (NGX_HAVE_INET6) - r = ctx->resolver; - - p = ngx_resolver_alloc(ctx->resolver, r->ipv6 ? len * 2 : len); + p = ngx_resolver_alloc(r, r->ipv6 ? len * 2 : len); #else - p = ngx_resolver_alloc(ctx->resolver, len); + p = ngx_resolver_alloc(r, len); #endif if (p == NULL) { return NGX_ERROR; @@ -2535,8 +2576,8 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) ident = ngx_random(); - ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0, - "resolve: \"%V\" A %i", &ctx->name, ident & 0xffff); + ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolve: \"%V\" A %i", name, ident & 0xffff); query->ident_hi = (u_char) ((ident >> 8) & 0xff); query->ident_lo = (u_char) (ident & 0xff); @@ -2566,11 +2607,11 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) p--; *p-- = '\0'; - if (ctx->name.len == 0) { + if (name->len == 0) { return NGX_DECLINED; } - for (s = ctx->name.data + ctx->name.len - 1; s >= ctx->name.data; s--) { + for (s = name->data + name->len - 1; s >= name->data; s--) { if (*s != '.') { *p = *s; len++; @@ -2606,8 +2647,8 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) ident = ngx_random(); - ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0, - "resolve: \"%V\" AAAA %i", &ctx->name, ident & 0xffff); + ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolve: \"%V\" AAAA %i", name, ident & 0xffff); query->ident_hi = (u_char) ((ident >> 8) & 0xff); query->ident_lo = (u_char) (ident & 0xff); @@ -2624,11 +2665,12 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) static ngx_int_t -ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) +ngx_resolver_create_addr_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, + ngx_addr_t *addr) { u_char *p, *d; size_t len; - in_addr_t addr; + in_addr_t inaddr; ngx_int_t n; ngx_uint_t ident; ngx_resolver_hdr_t *query; @@ -2637,7 +2679,7 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) struct sockaddr_in6 *sin6; #endif - switch (ctx->addr.sockaddr->sa_family) { + switch (addr->sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: @@ -2654,7 +2696,7 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) + sizeof(ngx_resolver_qs_t); } - p = ngx_resolver_alloc(ctx->resolver, len); + p = ngx_resolver_alloc(r, len); if (p == NULL) { return NGX_ERROR; } @@ -2678,11 +2720,11 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) p += sizeof(ngx_resolver_hdr_t); - switch (ctx->addr.sockaddr->sa_family) { + switch (addr->sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: - sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr; + sin6 = (struct sockaddr_in6 *) addr->sockaddr; for (n = 15; n >= 0; n--) { p = ngx_sprintf(p, "\1%xd\1%xd", @@ -2697,11 +2739,11 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) default: /* AF_INET */ - sin = (struct sockaddr_in *) ctx->addr.sockaddr; - addr = ntohl(sin->sin_addr.s_addr); + sin = (struct sockaddr_in *) addr->sockaddr; + inaddr = ntohl(sin->sin_addr.s_addr); for (n = 0; n < 32; n += 8) { - d = ngx_sprintf(&p[1], "%ud", (addr >> n) & 0xff); + d = ngx_sprintf(&p[1], "%ud", (inaddr >> n) & 0xff); *p = (u_char) (d - &p[1]); p = d; } @@ -2815,21 +2857,13 @@ done: static void ngx_resolver_timeout_handler(ngx_event_t *ev) { - ngx_resolver_ctx_t *ctx, *next; - ngx_resolver_node_t *rn; + ngx_resolver_ctx_t *ctx; - rn = ev->data; - ctx = rn->waiting; - rn->waiting = NULL; + ctx = ev->data; - do { - ctx->state = NGX_RESOLVE_TIMEDOUT; - next = ctx->next; + ctx->state = NGX_RESOLVE_TIMEDOUT; - ctx->handler(ctx); - - ctx = next; - } while (ctx); + ctx->handler(ctx); } diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h index d3519fb..07fa257 100644 --- a/src/core/ngx_resolver.h +++ b/src/core/ngx_resolver.h @@ -51,15 +51,11 @@ typedef void (*ngx_resolver_handler_pt)(ngx_resolver_ctx_t *ctx); typedef struct { - /* PTR: resolved name, A: name to resolve */ - u_char *name; - + ngx_rbtree_node_t node; ngx_queue_t queue; - /* event ident must be after 3 pointers as in ngx_connection_t */ - ngx_int_t ident; - - ngx_rbtree_node_t node; + /* PTR: resolved name, A: name to resolve */ + u_char *name; #if (NGX_HAVE_INET6) /* PTR: IPv6 address to resolve (IPv4 address is in rbtree node key) */ @@ -147,6 +143,9 @@ struct ngx_resolver_ctx_s { ngx_resolver_t *resolver; ngx_udp_connection_t *udp_connection; + /* event ident must be after 3 pointers as in ngx_connection_t */ + ngx_int_t ident; + ngx_int_t state; ngx_str_t name; @@ -162,6 +161,8 @@ struct ngx_resolver_ctx_s { ngx_uint_t quick; /* unsigned quick:1; */ ngx_uint_t recursion; ngx_event_t *event; + + ngx_resolver_node_t *node; }; diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c b/src/http/modules/ngx_http_upstream_keepalive_module.c index 51887b4..85bfcdb 100644 --- a/src/http/modules/ngx_http_upstream_keepalive_module.c +++ b/src/http/modules/ngx_http_upstream_keepalive_module.c @@ -302,6 +302,10 @@ ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data, goto invalid; } + if (!u->request_body_sent) { + goto invalid; + } + if (ngx_terminate || ngx_exiting) { goto invalid; } diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index d09e3f0..64af447 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1927,6 +1927,7 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport, #if (NGX_HTTP_V2) addrs6[i].conf.http2 = addr[i].opt.http2; #endif + addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; if (addr[i].hash.buckets == NULL && (addr[i].wc_head == NULL diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c index 77e92e3..e9562c0 100644 --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -172,9 +172,6 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, b->file = &rb->temp_file->file; rb->bufs = cl; - - } else { - rb->bufs = NULL; } } @@ -466,9 +463,6 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) b->file = &rb->temp_file->file; rb->bufs = cl; - - } else { - rb->bufs = NULL; } } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 6c6ee80..7f377b6 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -1441,6 +1441,7 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) } u->request_sent = 0; + u->request_body_sent = 0; if (rc == NGX_AGAIN) { ngx_add_timer(c->write, u->conf->connect_timeout); @@ -1825,6 +1826,8 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u, /* rc == NGX_OK */ + u->request_body_sent = 1; + if (c->write->timer_set) { ngx_del_timer(c->write); } @@ -2496,6 +2499,7 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) if (r->method != NGX_HTTP_HEAD) { r->method = NGX_HTTP_GET; + r->method_name = ngx_http_core_get_method; } ngx_http_internal_redirect(r, &uri, &args); diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index 8404265..4246c8a 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -370,6 +370,7 @@ struct ngx_http_upstream_s { unsigned upgrade:1; unsigned request_sent:1; + unsigned request_body_sent:1; unsigned header_sent:1; }; From e752ea86a642040d3628dbfc496003403d1429bf Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 26 Jan 2016 19:43:53 +0200 Subject: [PATCH 073/651] New upstream release (1.9.10) --- debian/changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index 5e94be3..14d5de7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.9.10-1) UNRELEASED; urgency=medium + + [ Christos Trochalakis ] + * New upstream release (1.9.10) (Closes: #812806) + + -- Christos Trochalakis Tue, 26 Jan 2016 19:43:29 +0200 + nginx (1.9.9-1) unstable; urgency=medium [ Michael Lustfield ] From 0bcc8e5f72587e2e3ce56376a9b1343894049753 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 26 Jan 2016 20:11:10 +0200 Subject: [PATCH 074/651] Remove python from nginx-common deps, closes ##808699 ngx-conf is going to be shipped as a separate package. --- debian/changelog | 2 ++ debian/control | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 14d5de7..9a30425 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,8 @@ nginx (1.9.10-1) UNRELEASED; urgency=medium [ Christos Trochalakis ] * New upstream release (1.9.10) (Closes: #812806) + * debian/control: + + Drop python dependency from nginx-common. (Closes: #808699) -- Christos Trochalakis Tue, 26 Jan 2016 19:43:29 +0200 diff --git a/debian/control b/debian/control index de705d4..7c60e5f 100644 --- a/debian/control +++ b/debian/control @@ -59,7 +59,7 @@ Description: small, powerful, scalable web/proxy server - documentation Package: nginx-common Architecture: all -Depends: lsb-base (>= 3.2-14), ${misc:Depends}, python +Depends: lsb-base (>= 3.2-14), ${misc:Depends} Replaces: nginx (<< 0.8.54-4), nginx-extras (<< 0.8.54-4), nginx-full (<< 0.8.54-4), From 19d658f41b1fa17c6ac343001606702a7690982f Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 26 Jan 2016 20:12:14 +0200 Subject: [PATCH 075/651] Release 1.9.10-1 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 9a30425..5b341ce 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,11 +1,11 @@ -nginx (1.9.10-1) UNRELEASED; urgency=medium +nginx (1.9.10-1) unstable; urgency=medium [ Christos Trochalakis ] * New upstream release (1.9.10) (Closes: #812806) * debian/control: + Drop python dependency from nginx-common. (Closes: #808699) - -- Christos Trochalakis Tue, 26 Jan 2016 19:43:29 +0200 + -- Christos Trochalakis Tue, 26 Jan 2016 20:12:06 +0200 nginx (1.9.9-1) unstable; urgency=medium From 04dd4497718279c1a64d70bdfcc048cb222cc367 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 27 Jan 2016 12:17:44 +0200 Subject: [PATCH 076/651] Fix multiple resolver CVEs (Closes #812806) Backported all relevant commits from the 1.8.1 series. --- debian/changelog | 9 + ...ossible-segmentation-fault-on-DNS-fo.patch | 21 ++ ...ver-fixed-crashes-in-timeout-handler.patch | 128 +++++++++ ...NAME-processing-for-several-requests.patch | 78 ++++++ ...-the-ngx_resolver_create_-_query-arg.patch | 179 +++++++++++++ ...se-after-free-memory-accesses-with-C.patch | 248 ++++++++++++++++++ ...008-Resolver-limited-CNAME-recursion.patch | 60 +++++ debian/patches/series | 6 + 8 files changed, 729 insertions(+) create mode 100644 debian/patches/0003-Resolver-fixed-possible-segmentation-fault-on-DNS-fo.patch create mode 100644 debian/patches/0004-Resolver-fixed-crashes-in-timeout-handler.patch create mode 100644 debian/patches/0005-Resolver-fixed-CNAME-processing-for-several-requests.patch create mode 100644 debian/patches/0006-Resolver-changed-the-ngx_resolver_create_-_query-arg.patch create mode 100644 debian/patches/0007-Resolver-fixed-use-after-free-memory-accesses-with-C.patch create mode 100644 debian/patches/0008-Resolver-limited-CNAME-recursion.patch diff --git a/debian/changelog b/debian/changelog index be7399f..62e28fb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +nginx (1.6.2-5+deb8u1) UNRELEASED; urgency=medium + + [ Christos Trochalakis ] + * Fixes multiple resolver CVEs, + CVE-2016-0742, CVE-2016-0746, CVE-2016-0747 + Closes: #812806 + + -- Christos Trochalakis Wed, 27 Jan 2016 12:19:54 +0200 + nginx (1.6.2-5) unstable; urgency=medium [ Christos Trochalakis ] diff --git a/debian/patches/0003-Resolver-fixed-possible-segmentation-fault-on-DNS-fo.patch b/debian/patches/0003-Resolver-fixed-possible-segmentation-fault-on-DNS-fo.patch new file mode 100644 index 0000000..976e0ba --- /dev/null +++ b/debian/patches/0003-Resolver-fixed-possible-segmentation-fault-on-DNS-fo.patch @@ -0,0 +1,21 @@ +From: Roman Arutyunyan +Date: Tue, 26 Jan 2016 16:46:18 +0300 +Subject: Resolver: fixed possible segmentation fault on DNS format error. + +--- + src/core/ngx_resolver.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c +index 5a944fc..726de9b 100644 +--- a/src/core/ngx_resolver.c ++++ b/src/core/ngx_resolver.c +@@ -1287,7 +1287,7 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n) + times = 0; + + for (q = ngx_queue_head(&r->name_resend_queue); +- q != ngx_queue_sentinel(&r->name_resend_queue) || times++ < 100; ++ q != ngx_queue_sentinel(&r->name_resend_queue) && times++ < 100; + q = ngx_queue_next(q)) + { + rn = ngx_queue_data(q, ngx_resolver_node_t, queue); diff --git a/debian/patches/0004-Resolver-fixed-crashes-in-timeout-handler.patch b/debian/patches/0004-Resolver-fixed-crashes-in-timeout-handler.patch new file mode 100644 index 0000000..8ec666a --- /dev/null +++ b/debian/patches/0004-Resolver-fixed-crashes-in-timeout-handler.patch @@ -0,0 +1,128 @@ +From: Ruslan Ermilov +Date: Tue, 26 Jan 2016 16:46:31 +0300 +Subject: Resolver: fixed crashes in timeout handler. + +If one or more requests were waiting for a response, then after +getting a CNAME response, the timeout event on the first request +remained active, pointing to the wrong node with an empty +rn->waiting list, and that could cause either null pointer +dereference or use-after-free memory access if this timeout +expired. + +If several requests were waiting for a response, and the first +request terminated (e.g., due to client closing a connection), +other requests were left without a timeout and could potentially +wait indefinitely. + +This is fixed by introducing per-request independent timeouts. +This change also reverts 954867a2f0a6 and 5004210e8c78. +--- + src/core/ngx_resolver.c | 50 +++++++++++++++++++++++++++++++++---------------- + 1 file changed, 34 insertions(+), 16 deletions(-) + +diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c +index 726de9b..8ebef6f 100644 +--- a/src/core/ngx_resolver.c ++++ b/src/core/ngx_resolver.c +@@ -417,7 +417,7 @@ ngx_resolve_name_done(ngx_resolver_ctx_t *ctx) + + /* lock name mutex */ + +- if (ctx->state == NGX_AGAIN) { ++ if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) { + + hash = ngx_crc32_short(ctx->name.data, ctx->name.len); + +@@ -571,6 +571,20 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) + + if (rn->waiting) { + ++ if (ctx->event == NULL) { ++ ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); ++ if (ctx->event == NULL) { ++ return NGX_ERROR; ++ } ++ ++ ctx->event->handler = ngx_resolver_timeout_handler; ++ ctx->event->data = ctx; ++ ctx->event->log = r->log; ++ ctx->ident = -1; ++ ++ ngx_add_timer(ctx->event, ctx->timeout); ++ } ++ + ctx->next = rn->waiting; + rn->waiting = ctx; + ctx->state = NGX_AGAIN; +@@ -664,7 +678,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) + } + + ctx->event->handler = ngx_resolver_timeout_handler; +- ctx->event->data = rn; ++ ctx->event->data = ctx; + ctx->event->log = r->log; + ctx->ident = -1; + +@@ -794,6 +808,18 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) + + if (rn->waiting) { + ++ ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); ++ if (ctx->event == NULL) { ++ return NGX_ERROR; ++ } ++ ++ ctx->event->handler = ngx_resolver_timeout_handler; ++ ctx->event->data = ctx; ++ ctx->event->log = r->log; ++ ctx->ident = -1; ++ ++ ngx_add_timer(ctx->event, ctx->timeout); ++ + ctx->next = rn->waiting; + rn->waiting = ctx; + ctx->state = NGX_AGAIN; +@@ -857,7 +883,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) + } + + ctx->event->handler = ngx_resolver_timeout_handler; +- ctx->event->data = rn; ++ ctx->event->data = ctx; + ctx->event->log = r->log; + ctx->ident = -1; + +@@ -949,7 +975,7 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx) + + /* lock addr mutex */ + +- if (ctx->state == NGX_AGAIN) { ++ if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) { + + switch (ctx->addr.sockaddr->sa_family) { + +@@ -2791,21 +2817,13 @@ done: + static void + ngx_resolver_timeout_handler(ngx_event_t *ev) + { +- ngx_resolver_ctx_t *ctx, *next; +- ngx_resolver_node_t *rn; ++ ngx_resolver_ctx_t *ctx; + +- rn = ev->data; +- ctx = rn->waiting; +- rn->waiting = NULL; ++ ctx = ev->data; + +- do { +- ctx->state = NGX_RESOLVE_TIMEDOUT; +- next = ctx->next; +- +- ctx->handler(ctx); ++ ctx->state = NGX_RESOLVE_TIMEDOUT; + +- ctx = next; +- } while (ctx); ++ ctx->handler(ctx); + } + + diff --git a/debian/patches/0005-Resolver-fixed-CNAME-processing-for-several-requests.patch b/debian/patches/0005-Resolver-fixed-CNAME-processing-for-several-requests.patch new file mode 100644 index 0000000..d8759fe --- /dev/null +++ b/debian/patches/0005-Resolver-fixed-CNAME-processing-for-several-requests.patch @@ -0,0 +1,78 @@ +From: Ruslan Ermilov +Date: Tue, 26 Jan 2016 16:46:38 +0300 +Subject: Resolver: fixed CNAME processing for several requests. + +When several requests were waiting for a response, then after getting +a CNAME response only the last request was properly processed, while +others were left waiting. +--- + src/core/ngx_resolver.c | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c +index 8ebef6f..3c01584 100644 +--- a/src/core/ngx_resolver.c ++++ b/src/core/ngx_resolver.c +@@ -468,7 +468,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) + ngx_int_t rc; + ngx_uint_t naddrs; + ngx_addr_t *addrs; +- ngx_resolver_ctx_t *next; ++ ngx_resolver_ctx_t *next, *last; + ngx_resolver_node_t *rn; + + ngx_strlow(ctx->name.data, ctx->name.data, ctx->name.len); +@@ -479,6 +479,9 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) + + if (rn) { + ++ /* ctx can be a list after NGX_RESOLVE_CNAME */ ++ for (last = ctx; last->next; last = last->next); ++ + if (rn->valid >= ngx_time()) { + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached"); +@@ -506,7 +509,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) + } + } + +- ctx->next = rn->waiting; ++ last->next = rn->waiting; + rn->waiting = NULL; + + /* unlock name mutex */ +@@ -552,7 +555,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) + return ngx_resolve_name_locked(r, ctx); + } + +- ctx->next = rn->waiting; ++ last->next = rn->waiting; + rn->waiting = NULL; + + /* unlock name mutex */ +@@ -585,7 +588,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) + ngx_add_timer(ctx->event, ctx->timeout); + } + +- ctx->next = rn->waiting; ++ last->next = rn->waiting; + rn->waiting = ctx; + ctx->state = NGX_AGAIN; + +@@ -656,8 +659,14 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) + ngx_resolver_free(r, rn->name); + ngx_resolver_free(r, rn); + +- ctx->state = NGX_RESOLVE_NXDOMAIN; +- ctx->handler(ctx); ++ do { ++ ctx->state = NGX_RESOLVE_NXDOMAIN; ++ next = ctx->next; ++ ++ ctx->handler(ctx); ++ ++ ctx = next; ++ } while (ctx); + + return NGX_OK; + } diff --git a/debian/patches/0006-Resolver-changed-the-ngx_resolver_create_-_query-arg.patch b/debian/patches/0006-Resolver-changed-the-ngx_resolver_create_-_query-arg.patch new file mode 100644 index 0000000..4364ccf --- /dev/null +++ b/debian/patches/0006-Resolver-changed-the-ngx_resolver_create_-_query-arg.patch @@ -0,0 +1,179 @@ +From: Roman Arutyunyan +Date: Tue, 26 Jan 2016 16:46:48 +0300 +Subject: Resolver: changed the ngx_resolver_create_*_query() arguments. + +No functional changes. + +This is needed by the following change. +--- + src/core/ngx_resolver.c | 57 +++++++++++++++++++++++-------------------------- + 1 file changed, 27 insertions(+), 30 deletions(-) + +diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c +index 3c01584..1899564 100644 +--- a/src/core/ngx_resolver.c ++++ b/src/core/ngx_resolver.c +@@ -59,10 +59,10 @@ static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, + ngx_queue_t *queue); + static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r, + ngx_resolver_node_t *rn); +-static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_node_t *rn, +- ngx_resolver_ctx_t *ctx); +-static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, +- ngx_resolver_ctx_t *ctx); ++static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r, ++ ngx_resolver_node_t *rn, ngx_str_t *name); ++static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r, ++ ngx_resolver_node_t *rn, ngx_addr_t *addr); + static void ngx_resolver_resend_handler(ngx_event_t *ev); + static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, + ngx_queue_t *queue); +@@ -646,7 +646,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) + ngx_rbtree_insert(&r->name_rbtree, &rn->node); + } + +- rc = ngx_resolver_create_name_query(rn, ctx); ++ rc = ngx_resolver_create_name_query(r, rn, &ctx->name); + + if (rc == NGX_ERROR) { + goto failed; +@@ -873,7 +873,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) + ngx_rbtree_insert(tree, &rn->node); + } + +- if (ngx_resolver_create_addr_query(rn, ctx) != NGX_OK) { ++ if (ngx_resolver_create_addr_query(r, rn, &ctx->addr) != NGX_OK) { + goto failed; + } + +@@ -2506,27 +2506,23 @@ ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp, + + + static ngx_int_t +-ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) ++ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, ++ ngx_str_t *name) + { + u_char *p, *s; + size_t len, nlen; + ngx_uint_t ident; +-#if (NGX_HAVE_INET6) +- ngx_resolver_t *r; +-#endif + ngx_resolver_qs_t *qs; + ngx_resolver_hdr_t *query; + +- nlen = ctx->name.len ? (1 + ctx->name.len + 1) : 1; ++ nlen = name->len ? (1 + name->len + 1) : 1; + + len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t); + + #if (NGX_HAVE_INET6) +- r = ctx->resolver; +- +- p = ngx_resolver_alloc(ctx->resolver, r->ipv6 ? len * 2 : len); ++ p = ngx_resolver_alloc(r, r->ipv6 ? len * 2 : len); + #else +- p = ngx_resolver_alloc(ctx->resolver, len); ++ p = ngx_resolver_alloc(r, len); + #endif + if (p == NULL) { + return NGX_ERROR; +@@ -2545,8 +2541,8 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) + + ident = ngx_random(); + +- ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0, +- "resolve: \"%V\" A %i", &ctx->name, ident & 0xffff); ++ ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0, ++ "resolve: \"%V\" A %i", name, ident & 0xffff); + + query->ident_hi = (u_char) ((ident >> 8) & 0xff); + query->ident_lo = (u_char) (ident & 0xff); +@@ -2576,11 +2572,11 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) + p--; + *p-- = '\0'; + +- if (ctx->name.len == 0) { ++ if (name->len == 0) { + return NGX_DECLINED; + } + +- for (s = ctx->name.data + ctx->name.len - 1; s >= ctx->name.data; s--) { ++ for (s = name->data + name->len - 1; s >= name->data; s--) { + if (*s != '.') { + *p = *s; + len++; +@@ -2616,8 +2612,8 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) + + ident = ngx_random(); + +- ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0, +- "resolve: \"%V\" AAAA %i", &ctx->name, ident & 0xffff); ++ ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0, ++ "resolve: \"%V\" AAAA %i", name, ident & 0xffff); + + query->ident_hi = (u_char) ((ident >> 8) & 0xff); + query->ident_lo = (u_char) (ident & 0xff); +@@ -2634,11 +2630,12 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) + + + static ngx_int_t +-ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) ++ngx_resolver_create_addr_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, ++ ngx_addr_t *addr) + { + u_char *p, *d; + size_t len; +- in_addr_t addr; ++ in_addr_t inaddr; + ngx_int_t n; + ngx_uint_t ident; + ngx_resolver_hdr_t *query; +@@ -2647,7 +2644,7 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) + struct sockaddr_in6 *sin6; + #endif + +- switch (ctx->addr.sockaddr->sa_family) { ++ switch (addr->sockaddr->sa_family) { + + #if (NGX_HAVE_INET6) + case AF_INET6: +@@ -2664,7 +2661,7 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) + + sizeof(ngx_resolver_qs_t); + } + +- p = ngx_resolver_alloc(ctx->resolver, len); ++ p = ngx_resolver_alloc(r, len); + if (p == NULL) { + return NGX_ERROR; + } +@@ -2688,11 +2685,11 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) + + p += sizeof(ngx_resolver_hdr_t); + +- switch (ctx->addr.sockaddr->sa_family) { ++ switch (addr->sockaddr->sa_family) { + + #if (NGX_HAVE_INET6) + case AF_INET6: +- sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr; ++ sin6 = (struct sockaddr_in6 *) addr->sockaddr; + + for (n = 15; n >= 0; n--) { + p = ngx_sprintf(p, "\1%xd\1%xd", +@@ -2707,11 +2704,11 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) + + default: /* AF_INET */ + +- sin = (struct sockaddr_in *) ctx->addr.sockaddr; +- addr = ntohl(sin->sin_addr.s_addr); ++ sin = (struct sockaddr_in *) addr->sockaddr; ++ inaddr = ntohl(sin->sin_addr.s_addr); + + for (n = 0; n < 32; n += 8) { +- d = ngx_sprintf(&p[1], "%ud", (addr >> n) & 0xff); ++ d = ngx_sprintf(&p[1], "%ud", (inaddr >> n) & 0xff); + *p = (u_char) (d - &p[1]); + p = d; + } diff --git a/debian/patches/0007-Resolver-fixed-use-after-free-memory-accesses-with-C.patch b/debian/patches/0007-Resolver-fixed-use-after-free-memory-accesses-with-C.patch new file mode 100644 index 0000000..c2f7b07 --- /dev/null +++ b/debian/patches/0007-Resolver-fixed-use-after-free-memory-accesses-with-C.patch @@ -0,0 +1,248 @@ +From: Roman Arutyunyan +Date: Tue, 26 Jan 2016 16:46:59 +0300 +Subject: Resolver: fixed use-after-free memory accesses with CNAME. + +When several requests were waiting for a response, then after getting +a CNAME response only the last request's context had the name updated. +Contexts of other requests had the wrong name. This name was used by +ngx_resolve_name_done() to find the node to remove the request context +from. When the name was wrong, the request could not be properly +cancelled, its context was freed but stayed linked to the node's waiting +list. This happened e.g. when the first request was aborted or timed +out before the resolving completed. When it completed, this triggered +a use-after-free memory access by calling ctx->handler of already freed +request context. The bug manifests itself by +"could not cancel resolving" alerts in error_log. + +When a request was responded with a CNAME, the request context kept +the pointer to the original node's rn->u.cname. If the original node +expired before the resolving timed out or completed with an error, +this would trigger a use-after-free memory access via ctx->name in +ctx->handler(). + +The fix is to keep ctx->name unmodified. The name from context +is no longer used by ngx_resolve_name_done(). Instead, we now keep +the pointer to resolver node to which this request is linked. +Keeping the original name intact also improves logging. +--- + src/core/ngx_resolver.c | 72 +++++++++++++++++++++++-------------------------- + src/core/ngx_resolver.h | 2 ++ + 2 files changed, 35 insertions(+), 39 deletions(-) + +diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c +index 1899564..2bd754c 100644 +--- a/src/core/ngx_resolver.c ++++ b/src/core/ngx_resolver.c +@@ -54,7 +54,7 @@ ngx_int_t ngx_udp_connect(ngx_udp_connection_t *uc); + static void ngx_resolver_cleanup(void *data); + static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree); + static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r, +- ngx_resolver_ctx_t *ctx); ++ ngx_resolver_ctx_t *ctx, ngx_str_t *name); + static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, + ngx_queue_t *queue); + static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r, +@@ -370,7 +370,7 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx) + + /* lock name mutex */ + +- rc = ngx_resolve_name_locked(r, ctx); ++ rc = ngx_resolve_name_locked(r, ctx, &ctx->name); + + if (rc == NGX_OK) { + return NGX_OK; +@@ -397,7 +397,6 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx) + void + ngx_resolve_name_done(ngx_resolver_ctx_t *ctx) + { +- uint32_t hash; + ngx_resolver_t *r; + ngx_resolver_ctx_t *w, **p; + ngx_resolver_node_t *rn; +@@ -419,9 +418,7 @@ ngx_resolve_name_done(ngx_resolver_ctx_t *ctx) + + if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) { + +- hash = ngx_crc32_short(ctx->name.data, ctx->name.len); +- +- rn = ngx_resolver_lookup_name(r, &ctx->name, hash); ++ rn = ctx->node; + + if (rn) { + p = &rn->waiting; +@@ -462,20 +459,22 @@ done: + + + static ngx_int_t +-ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) ++ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, ++ ngx_str_t *name) + { + uint32_t hash; + ngx_int_t rc; ++ ngx_str_t cname; + ngx_uint_t naddrs; + ngx_addr_t *addrs; + ngx_resolver_ctx_t *next, *last; + ngx_resolver_node_t *rn; + +- ngx_strlow(ctx->name.data, ctx->name.data, ctx->name.len); ++ ngx_strlow(name->data, name->data, name->len); + +- hash = ngx_crc32_short(ctx->name.data, ctx->name.len); ++ hash = ngx_crc32_short(name->data, name->len); + +- rn = ngx_resolver_lookup_name(r, &ctx->name, hash); ++ rn = ngx_resolver_lookup_name(r, name, hash); + + if (rn) { + +@@ -549,10 +548,10 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) + + if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) { + +- ctx->name.len = rn->cnlen; +- ctx->name.data = rn->u.cname; ++ cname.len = rn->cnlen; ++ cname.data = rn->u.cname; + +- return ngx_resolve_name_locked(r, ctx); ++ return ngx_resolve_name_locked(r, ctx, &cname); + } + + last->next = rn->waiting; +@@ -592,6 +591,11 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) + rn->waiting = ctx; + ctx->state = NGX_AGAIN; + ++ do { ++ ctx->node = rn; ++ ctx = ctx->next; ++ } while (ctx); ++ + return NGX_AGAIN; + } + +@@ -630,14 +634,14 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) + return NGX_ERROR; + } + +- rn->name = ngx_resolver_dup(r, ctx->name.data, ctx->name.len); ++ rn->name = ngx_resolver_dup(r, name->data, name->len); + if (rn->name == NULL) { + ngx_resolver_free(r, rn); + return NGX_ERROR; + } + + rn->node.key = hash; +- rn->nlen = (u_short) ctx->name.len; ++ rn->nlen = (u_short) name->len; + rn->query = NULL; + #if (NGX_HAVE_INET6) + rn->query6 = NULL; +@@ -646,7 +650,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) + ngx_rbtree_insert(&r->name_rbtree, &rn->node); + } + +- rc = ngx_resolver_create_name_query(r, rn, &ctx->name); ++ rc = ngx_resolver_create_name_query(r, rn, name); + + if (rc == NGX_ERROR) { + goto failed; +@@ -710,6 +714,11 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) + + ctx->state = NGX_AGAIN; + ++ do { ++ ctx->node = rn; ++ ctx = ctx->next; ++ } while (ctx); ++ + return NGX_AGAIN; + + failed: +@@ -832,6 +841,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) + ctx->next = rn->waiting; + rn->waiting = ctx; + ctx->state = NGX_AGAIN; ++ ctx->node = rn; + + /* unlock addr mutex */ + +@@ -917,6 +927,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) + /* unlock addr mutex */ + + ctx->state = NGX_AGAIN; ++ ctx->node = rn; + + return NGX_OK; + +@@ -947,17 +958,11 @@ failed: + void + ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx) + { +- in_addr_t addr; + ngx_queue_t *expire_queue; + ngx_rbtree_t *tree; + ngx_resolver_t *r; + ngx_resolver_ctx_t *w, **p; +- struct sockaddr_in *sin; + ngx_resolver_node_t *rn; +-#if (NGX_HAVE_INET6) +- uint32_t hash; +- struct sockaddr_in6 *sin6; +-#endif + + r = ctx->resolver; + +@@ -986,21 +991,7 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx) + + if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) { + +- switch (ctx->addr.sockaddr->sa_family) { +- +-#if (NGX_HAVE_INET6) +- case AF_INET6: +- sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr; +- hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16); +- rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash); +- break; +-#endif +- +- default: /* AF_INET */ +- sin = (struct sockaddr_in *) ctx->addr.sockaddr; +- addr = ntohl(sin->sin_addr.s_addr); +- rn = ngx_resolver_lookup_addr(r, addr); +- } ++ rn = ctx->node; + + if (rn) { + p = &rn->waiting; +@@ -1989,9 +1980,12 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, + rn->waiting = NULL; + + if (ctx) { +- ctx->name = name; + +- (void) ngx_resolve_name_locked(r, ctx); ++ for (next = ctx; next; next = next->next) { ++ next->node = NULL; ++ } ++ ++ (void) ngx_resolve_name_locked(r, ctx, &name); + } + + ngx_resolver_free(r, rn->query); +diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h +index 264c8c4..0186e22 100644 +--- a/src/core/ngx_resolver.h ++++ b/src/core/ngx_resolver.h +@@ -161,6 +161,8 @@ struct ngx_resolver_ctx_s { + ngx_uint_t quick; /* unsigned quick:1; */ + ngx_uint_t recursion; + ngx_event_t *event; ++ ++ ngx_resolver_node_t *node; + }; + + diff --git a/debian/patches/0008-Resolver-limited-CNAME-recursion.patch b/debian/patches/0008-Resolver-limited-CNAME-recursion.patch new file mode 100644 index 0000000..dbe95a2 --- /dev/null +++ b/debian/patches/0008-Resolver-limited-CNAME-recursion.patch @@ -0,0 +1,60 @@ +From: Ruslan Ermilov +Date: Tue, 26 Jan 2016 16:47:14 +0300 +Subject: Resolver: limited CNAME recursion. + +Previously, the recursion was only limited for cached responses. +--- + src/core/ngx_resolver.c | 28 ++++++++++++++++++++++------ + 1 file changed, 22 insertions(+), 6 deletions(-) + +diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c +index 2bd754c..25d643d 100644 +--- a/src/core/ngx_resolver.c ++++ b/src/core/ngx_resolver.c +@@ -1976,11 +1976,33 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, + + ngx_queue_insert_head(&r->name_expire_queue, &rn->queue); + ++ ngx_resolver_free(r, rn->query); ++ rn->query = NULL; ++#if (NGX_HAVE_INET6) ++ rn->query6 = NULL; ++#endif ++ + ctx = rn->waiting; + rn->waiting = NULL; + + if (ctx) { + ++ if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) { ++ ++ /* unlock name mutex */ ++ ++ do { ++ ctx->state = NGX_RESOLVE_NXDOMAIN; ++ next = ctx->next; ++ ++ ctx->handler(ctx); ++ ++ ctx = next; ++ } while (ctx); ++ ++ return; ++ } ++ + for (next = ctx; next; next = next->next) { + next->node = NULL; + } +@@ -1988,12 +2010,6 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, + (void) ngx_resolve_name_locked(r, ctx, &name); + } + +- ngx_resolver_free(r, rn->query); +- rn->query = NULL; +-#if (NGX_HAVE_INET6) +- rn->query6 = NULL; +-#endif +- + /* unlock name mutex */ + + return; diff --git a/debian/patches/series b/debian/patches/series index 73f535e..93af595 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1 +1,7 @@ perl-use-dpkg-buildflags.patch +0003-Resolver-fixed-possible-segmentation-fault-on-DNS-fo.patch +0004-Resolver-fixed-crashes-in-timeout-handler.patch +0005-Resolver-fixed-CNAME-processing-for-several-requests.patch +0006-Resolver-changed-the-ngx_resolver_create_-_query-arg.patch +0007-Resolver-fixed-use-after-free-memory-accesses-with-C.patch +0008-Resolver-limited-CNAME-recursion.patch From 1079d2a2777e66b37552e99091e5be9888c526f7 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 27 Jan 2016 12:22:12 +0200 Subject: [PATCH 077/651] Release 1.6.2-5+deb8u1 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 62e28fb..f1aaee0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,11 +1,11 @@ -nginx (1.6.2-5+deb8u1) UNRELEASED; urgency=medium +nginx (1.6.2-5+deb8u1) jessie-security; urgency=high [ Christos Trochalakis ] * Fixes multiple resolver CVEs, CVE-2016-0742, CVE-2016-0746, CVE-2016-0747 Closes: #812806 - -- Christos Trochalakis Wed, 27 Jan 2016 12:19:54 +0200 + -- Christos Trochalakis Wed, 27 Jan 2016 12:22:00 +0200 nginx (1.6.2-5) unstable; urgency=medium From 0e20bccf292c0206de80d792ed9dc8a082d7573c Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 11 Feb 2016 15:06:14 +0200 Subject: [PATCH 078/651] Imported Upstream version 1.9.11 --- CHANGES | 12 + CHANGES.ru | 12 + auto/cc/conf | 22 + auto/cc/msvc | 6 + auto/cc/sunc | 3 + auto/init | 1 + auto/install | 24 + auto/lib/conf | 6 +- auto/lib/geoip/conf | 7 +- auto/lib/libgd/conf | 7 +- auto/lib/libxslt/conf | 13 +- auto/lib/openssl/conf | 3 +- auto/make | 209 +++- auto/module | 122 +++ auto/modules | 1092 ++++++++++++++++---- auto/options | 26 +- auto/os/darwin | 3 + auto/os/win32 | 5 + auto/sources | 356 +------ auto/summary | 1 + auto/unix | 6 +- src/core/nginx.c | 116 ++- src/core/nginx.h | 4 +- src/core/ngx_conf_file.c | 14 +- src/core/ngx_conf_file.h | 51 - src/core/ngx_core.h | 2 + src/core/ngx_cycle.c | 33 +- src/core/ngx_cycle.h | 4 + src/core/ngx_module.c | 361 +++++++ src/core/ngx_module.h | 307 ++++++ src/core/ngx_resolver.c | 876 +++++++++++++--- src/core/ngx_resolver.h | 29 +- src/event/ngx_event.c | 53 +- src/http/modules/ngx_http_rewrite_module.c | 8 +- src/http/ngx_http.c | 37 +- src/http/ngx_http_core_module.c | 28 +- src/http/ngx_http_upstream.c | 10 +- src/http/v2/ngx_http_v2.c | 25 +- src/http/v2/ngx_http_v2.h | 1 - src/http/v2/ngx_http_v2_filter_module.c | 4 +- src/mail/ngx_mail.c | 25 +- src/mail/ngx_mail_core_module.c | 20 +- src/os/unix/ngx_darwin_config.h | 2 + src/os/unix/ngx_dlopen.c | 28 + src/os/unix/ngx_dlopen.h | 31 + src/os/unix/ngx_freebsd_config.h | 2 + src/os/unix/ngx_linux_config.h | 2 + src/os/unix/ngx_posix_config.h | 5 + src/os/unix/ngx_process_cycle.c | 30 +- src/os/unix/ngx_solaris_config.h | 2 + src/stream/ngx_stream.c | 31 +- src/stream/ngx_stream_core_module.c | 8 +- src/stream/ngx_stream_upstream.c | 8 +- 53 files changed, 3116 insertions(+), 977 deletions(-) create mode 100644 auto/module create mode 100644 src/core/ngx_module.c create mode 100644 src/core/ngx_module.h create mode 100644 src/os/unix/ngx_dlopen.c create mode 100644 src/os/unix/ngx_dlopen.h diff --git a/CHANGES b/CHANGES index 3827f90..da1fa00 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,16 @@ +Changes with nginx 1.9.11 09 Feb 2016 + + *) Feature: TCP support in resolver. + + *) Feature: dynamic modules. + + *) Bugfix: the $request_length variable did not include size of request + headers when using HTTP/2. + + *) Bugfix: in the ngx_http_v2_module. + + Changes with nginx 1.9.10 26 Jan 2016 *) Security: invalid pointer dereference might occur during DNS server diff --git a/CHANGES.ru b/CHANGES.ru index 563163a..33302e2 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,16 @@ +Изменения в nginx 1.9.11 09.02.2016 + + *) Добавление: теперь resolver поддерживает TCP. + + *) Добавление: динамические модули. + + *) Исправление: при использовании HTTP/2 переменная $request_length не + учитывала размер заголовков запроса. + + *) Исправление: в модуле ngx_http_v2_module. + + Изменения в nginx 1.9.10 26.01.2016 *) Безопасность: при использовании директивы resolver во время обработки diff --git a/auto/cc/conf b/auto/cc/conf index edc6d74..35fd39c 100644 --- a/auto/cc/conf +++ b/auto/cc/conf @@ -5,12 +5,17 @@ LINK="\$(CC)" +MAIN_LINK= +MODULE_LINK="-shared" + ngx_include_opt="-I " ngx_compile_opt="-c" +ngx_pic_opt="-fPIC" ngx_objout="-o " ngx_binout="-o " ngx_objext="o" ngx_binext= +ngx_modext=".so" ngx_long_start= ngx_long_end= @@ -45,6 +50,9 @@ if test -n "$CFLAGS"; then sunc) + MAIN_LINK= + MODULE_LINK="-G" + case "$NGX_MACHINE" in i86pc) @@ -156,6 +164,20 @@ if [ "$NGX_PLATFORM" != win32 ]; then fi + ngx_feature="-Wl,-E switch" + ngx_feature_name= + ngx_feature_run=no + ngx_feature_incs= + ngx_feature_path= + ngx_feature_libs=-Wl,-E + ngx_feature_test= + . auto/feature + + if [ $ngx_found = yes ]; then + MAIN_LINK="-Wl,-E" + fi + + ngx_feature="gcc builtin atomic operations" ngx_feature_name=NGX_HAVE_GCC_ATOMIC ngx_feature_run=yes diff --git a/auto/cc/msvc b/auto/cc/msvc index 393ba32..e588c48 100644 --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -118,6 +118,12 @@ NGX_RCC="rc -fo$NGX_RES \$(CORE_INCS) $NGX_WIN32_RC" CORE_LINK="$NGX_RES $CORE_LINK" +# dynamic modules +#MAIN_LINK="-link -def:$NGX_OBJS/nginx.def" +#MODULE_LINK="-LD $NGX_OBJS/nginx.lib" + + +ngx_pic_opt= ngx_objout="-Fo" ngx_binout="-Fe" ngx_objext="obj" diff --git a/auto/cc/sunc b/auto/cc/sunc index 8f12d7c..8360c49 100644 --- a/auto/cc/sunc +++ b/auto/cc/sunc @@ -57,6 +57,9 @@ case "$NGX_MACHINE" in esac +MAIN_LINK= +MODULE_LINK="-G" + # optimizations diff --git a/auto/init b/auto/init index 910f529..c593eda 100644 --- a/auto/init +++ b/auto/init @@ -5,6 +5,7 @@ NGX_MAKEFILE=$NGX_OBJS/Makefile NGX_MODULES_C=$NGX_OBJS/ngx_modules.c +NGX_MODULES= NGX_AUTO_HEADERS_H=$NGX_OBJS/ngx_auto_headers.h NGX_AUTO_CONFIG_H=$NGX_OBJS/ngx_auto_config.h diff --git a/auto/install b/auto/install index f7f686c..4dcc743 100644 --- a/auto/install +++ b/auto/install @@ -26,6 +26,18 @@ case ".$NGX_SBIN_PATH" in esac +case ".$NGX_MODULES_PATH" in + ./*) + ;; + + *) + NGX_MODULES_PATH=$NGX_PREFIX/$NGX_MODULES_PATH + ;; +esac + +NGX_MODULES_PATH=`dirname $NGX_MODULES_PATH/.` + + case ".$NGX_CONF_PATH" in ./*) ;; @@ -158,12 +170,24 @@ END fi +if test -n "$NGX_MODULES"; then + cat << END >> $NGX_MAKEFILE + + test -d '\$(DESTDIR)$NGX_MODULES_PATH' \ + || mkdir -p '\$(DESTDIR)$NGX_MODULES_PATH' + cp $NGX_MODULES '\$(DESTDIR)$NGX_MODULES_PATH' +END + +fi + + # create Makefile cat << END >> Makefile build: \$(MAKE) -f $NGX_MAKEFILE + \$(MAKE) -f $NGX_MAKEFILE modules \$(MAKE) -f $NGX_MAKEFILE manpage install: diff --git a/auto/lib/conf b/auto/lib/conf index e1e4475..6aaa43a 100644 --- a/auto/lib/conf +++ b/auto/lib/conf @@ -58,11 +58,11 @@ if [ $USE_ZLIB = YES ]; then . auto/lib/zlib/conf fi -if [ $USE_LIBXSLT = YES ]; then +if [ $USE_LIBXSLT != NO ]; then . auto/lib/libxslt/conf fi -if [ $USE_LIBGD = YES ]; then +if [ $USE_LIBGD != NO ]; then . auto/lib/libgd/conf fi @@ -70,7 +70,7 @@ if [ $USE_PERL = YES ]; then . auto/lib/perl/conf fi -if [ $HTTP_GEOIP = YES ]; then +if [ $USE_GEOIP != NO ]; then . auto/lib/geoip/conf fi diff --git a/auto/lib/geoip/conf b/auto/lib/geoip/conf index 53c274d..ebd2e15 100644 --- a/auto/lib/geoip/conf +++ b/auto/lib/geoip/conf @@ -67,7 +67,12 @@ fi if [ $ngx_found = yes ]; then CORE_INCS="$CORE_INCS $ngx_feature_path" - CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + + if [ $USE_GEOIP = YES ]; then + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + fi + + NGX_LIB_GEOIP=$ngx_feature_libs if [ $NGX_IPV6 = YES ]; then ngx_feature="GeoIP IPv6 support" diff --git a/auto/lib/libgd/conf b/auto/lib/libgd/conf index ff99054..6e4e91c 100644 --- a/auto/lib/libgd/conf +++ b/auto/lib/libgd/conf @@ -67,7 +67,12 @@ fi if [ $ngx_found = yes ]; then CORE_INCS="$CORE_INCS $ngx_feature_path" - CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + + if [ $USE_LIBGD = YES ]; then + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + fi + + NGX_LIB_LIBGD=$ngx_feature_libs else diff --git a/auto/lib/libxslt/conf b/auto/lib/libxslt/conf index bc19d83..3a0f37b 100644 --- a/auto/lib/libxslt/conf +++ b/auto/lib/libxslt/conf @@ -76,7 +76,12 @@ fi if [ $ngx_found = yes ]; then CORE_INCS="$CORE_INCS $ngx_feature_path" - CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + + if [ $USE_LIBXSLT = YES ]; then + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + fi + + NGX_LIB_LIBXSLT=$ngx_feature_libs else @@ -152,5 +157,9 @@ fi if [ $ngx_found = yes ]; then - CORE_LIBS="$CORE_LIBS -lexslt" + if [ $USE_LIBXSLT = YES ]; then + CORE_LIBS="$CORE_LIBS -lexslt" + fi + + NGX_LIB_LIBXSLT="$NGX_LIB_LIBXSLT -lexslt" fi diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf index 28a99b2..2187e5c 100644 --- a/auto/lib/openssl/conf +++ b/auto/lib/openssl/conf @@ -32,7 +32,6 @@ if [ $OPENSSL != NONE ]; then CORE_DEPS="$CORE_DEPS $OPENSSL/.openssl/include/openssl/ssl.h" CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libssl.a" CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libcrypto.a" - CORE_LIBS="$CORE_LIBS $NGX_LIBDL" if [ "$NGX_PLATFORM" = win32 ]; then CORE_LIBS="$CORE_LIBS -lgdi32 -lcrypt32 -lws2_32" @@ -106,7 +105,7 @@ else if [ $ngx_found = yes ]; then have=NGX_SSL . auto/have CORE_INCS="$CORE_INCS $ngx_feature_path" - CORE_LIBS="$CORE_LIBS $ngx_feature_libs $NGX_LIBDL" + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" OPENSSL=YES fi fi diff --git a/auto/make b/auto/make index dca011c..039a70f 100644 --- a/auto/make +++ b/auto/make @@ -98,9 +98,11 @@ fi # the mail dependencies and include paths -if [ $MAIL = YES ]; then +if [ $MAIL != NO ]; then - ngx_all_srcs="$ngx_all_srcs $MAIL_SRCS" + if [ $MAIL = YES ]; then + ngx_all_srcs="$ngx_all_srcs $MAIL_SRCS" + fi ngx_deps=`echo $MAIL_DEPS \ | sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont\1/g" \ @@ -124,9 +126,11 @@ fi # the stream dependencies and include paths -if [ $STREAM = YES ]; then +if [ $STREAM != NO ]; then - ngx_all_srcs="$ngx_all_srcs $STREAM_SRCS" + if [ $STREAM = YES ]; then + ngx_all_srcs="$ngx_all_srcs $STREAM_SRCS" + fi ngx_deps=`echo $STREAM_DEPS \ | sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont\1/g" \ @@ -148,7 +152,7 @@ END fi -ngx_all_srcs="$ngx_all_srcs $NGX_MISC_SRCS" +ngx_all_srcs="$ngx_all_srcs $MISC_SRCS" if test -n "$NGX_ADDON_SRCS"; then @@ -204,6 +208,7 @@ ngx_objs=`echo $ngx_all_objs $ngx_modules_obj \ | sed -e "s/ *\([^ ][^ ]*\)/$ngx_long_regex_cont\1/g" \ -e "s/\//$ngx_regex_dirsep/g"` +ngx_libs= if test -n "$NGX_LD_OPT$CORE_LIBS"; then ngx_libs=`echo $NGX_LD_OPT $CORE_LIBS \ | sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"` @@ -212,13 +217,18 @@ fi ngx_link=${CORE_LINK:+`echo $CORE_LINK \ | sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`} +ngx_main_link=${MAIN_LINK:+`echo $MAIN_LINK \ + | sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`} + cat << END >> $NGX_MAKEFILE $NGX_OBJS${ngx_dirsep}nginx${ngx_binext}: $ngx_deps$ngx_spacer - \$(LINK) ${ngx_long_start}${ngx_binout}$NGX_OBJS${ngx_dirsep}nginx$ngx_long_cont$ngx_objs$ngx_libs$ngx_link + \$(LINK) ${ngx_long_start}${ngx_binout}$NGX_OBJS${ngx_dirsep}nginx$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link $ngx_rcc ${ngx_long_end} + +modules: END @@ -365,11 +375,11 @@ fi # the misc sources -if test -n "$NGX_MISC_SRCS"; then +if test -n "$MISC_SRCS"; then ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)" - for ngx_src in $NGX_MISC_SRCS + for ngx_src in $MISC_SRCS do ngx_src=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"` ngx_obj=`echo $ngx_src \ @@ -472,3 +482,186 @@ $ngx_pch END fi + + +# dynamic modules + +if test -n "$NGX_PCH"; then + ngx_cc="\$(CC) $ngx_compile_opt $ngx_pic_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)" +else + ngx_cc="\$(CC) $ngx_compile_opt $ngx_pic_opt \$(CFLAGS) \$(ALL_INCS)" +fi + +ngx_obj_deps="\$(CORE_DEPS)" +if [ $HTTP != NO ]; then + ngx_obj_deps="$ngx_obj_deps \$(HTTP_DEPS)" +fi +if [ $MAIL != NO ]; then + ngx_obj_deps="$ngx_obj_deps \$(MAIL_DEPS)" +fi +if [ $STREAM != NO ]; then + ngx_obj_deps="$ngx_obj_deps \$(STREAM_DEPS)" +fi + +for ngx_module in $DYNAMIC_MODULES +do + eval ngx_module_srcs="\$${ngx_module}_SRCS" + eval eval ngx_module_libs="\\\"\$${ngx_module}_LIBS\\\"" + + eval ngx_module_modules="\$${ngx_module}_MODULES" + eval ngx_module_order="\$${ngx_module}_ORDER" + + ngx_modules_c=$NGX_OBJS/${ngx_module}_modules.c + + cat << END > $ngx_modules_c + +#include +#include + +END + + for mod in $ngx_module_modules + do + echo "extern ngx_module_t $mod;" >> $ngx_modules_c + done + + echo >> $ngx_modules_c + echo 'ngx_module_t *ngx_modules[] = {' >> $ngx_modules_c + + for mod in $ngx_module_modules + do + echo " &$mod," >> $ngx_modules_c + done + + cat << END >> $ngx_modules_c + NULL +}; + +END + + echo 'char *ngx_module_names[] = {' >> $ngx_modules_c + + for mod in $ngx_module_modules + do + echo " \"$mod\"," >> $ngx_modules_c + done + + cat << END >> $ngx_modules_c + NULL +}; + +END + + echo 'char *ngx_module_order[] = {' >> $ngx_modules_c + + for mod in $ngx_module_order + do + echo " \"$mod\"," >> $ngx_modules_c + done + + cat << END >> $ngx_modules_c + NULL +}; + +END + + ngx_modules_c=`echo $ngx_modules_c | sed -e "s/\//$ngx_regex_dirsep/g"` + + ngx_modules_obj=`echo $ngx_modules_c \ + | sed -e "s/\(.*\.\)c/\1$ngx_objext/"` + + ngx_module_objs= + for ngx_src in $ngx_module_srcs + do + case "$ngx_src" in + src/*) + ngx_obj=$ngx_src + ;; + *) + ngx_obj="addon/`basename \`dirname $ngx_src\``" + mkdir -p $NGX_OBJS/$ngx_obj + ngx_obj="$ngx_obj/`basename $ngx_src`" + ;; + esac + + ngx_module_objs="$ngx_module_objs $ngx_obj" + done + + ngx_module_objs=`echo $ngx_module_objs \ + | sed -e "s#\([^ ]*\.\)cpp#$NGX_OBJS\/\1$ngx_objext#g" \ + -e "s#\([^ ]*\.\)cc#$NGX_OBJS\/\1$ngx_objext#g" \ + -e "s#\([^ ]*\.\)c#$NGX_OBJS\/\1$ngx_objext#g" \ + -e "s#\([^ ]*\.\)S#$NGX_OBJS\/\1$ngx_objext#g"` + + ngx_deps=`echo $ngx_module_objs $ngx_modules_obj $LINK_DEPS \ + | sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont\1/g" \ + -e "s/\//$ngx_regex_dirsep/g"` + + ngx_objs=`echo $ngx_module_objs $ngx_modules_obj \ + | sed -e "s/ *\([^ ][^ ]*\)/$ngx_long_regex_cont\1/g" \ + -e "s/\//$ngx_regex_dirsep/g"` + + ngx_obj=$NGX_OBJS${ngx_dirsep}${ngx_module}${ngx_modext} + + NGX_MODULES="$NGX_MODULES $ngx_obj" + + if [ "$NGX_PLATFORM" = win32 ]; then + ngx_module_libs="$CORE_LIBS $ngx_module_libs" + fi + + ngx_libs= + if test -n "$NGX_LD_OPT$ngx_module_libs"; then + ngx_libs=`echo $NGX_LD_OPT $ngx_module_libs \ + | sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"` + fi + + ngx_link=${CORE_LINK:+`echo $CORE_LINK \ + | sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`} + + ngx_module_link=${MODULE_LINK:+`echo $MODULE_LINK \ + | sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`} + + + cat << END >> $NGX_MAKEFILE + +modules: $ngx_obj + +$ngx_obj: $ngx_deps$ngx_spacer + \$(LINK) $ngx_long_start$ngx_binout$ngx_obj$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_module_link +$ngx_long_end + +$ngx_modules_obj: \$(CORE_DEPS)$ngx_cont$ngx_modules_c + $ngx_cc$ngx_tab$ngx_objout$ngx_modules_obj$ngx_tab$ngx_modules_c$NGX_AUX + +END + + for ngx_src in $ngx_module_srcs + do + case "$ngx_src" in + src/*) + ngx_obj=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"` + ;; + *) + ngx_obj="addon/`basename \`dirname $ngx_src\``" + ngx_obj=`echo $ngx_obj/\`basename $ngx_src\` \ + | sed -e "s/\//$ngx_regex_dirsep/g"` + ;; + esac + + ngx_obj=`echo $ngx_obj \ + | sed -e "s#^\(.*\.\)cpp\\$#$ngx_objs_dir\1$ngx_objext#g" \ + -e "s#^\(.*\.\)cc\\$#$ngx_objs_dir\1$ngx_objext#g" \ + -e "s#^\(.*\.\)c\\$#$ngx_objs_dir\1$ngx_objext#g" \ + -e "s#^\(.*\.\)S\\$#$ngx_objs_dir\1$ngx_objext#g"` + + ngx_src=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"` + + cat << END >> $NGX_MAKEFILE + +$ngx_obj: $ngx_obj_deps$ngx_cont$ngx_src + $ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX + +END + + done +done diff --git a/auto/module b/auto/module new file mode 100644 index 0000000..908f0c6 --- /dev/null +++ b/auto/module @@ -0,0 +1,122 @@ + +# Copyright (C) Ruslan Ermilov +# Copyright (C) Nginx, Inc. + + +case $ngx_module_type in + HTTP_*) ngx_var=HTTP ;; + *) ngx_var=$ngx_module_type ;; +esac + + +if [ "$ngx_module_link" = DYNAMIC ]; then + + for ngx_module in $ngx_module_name; do + # extract the first name + break + done + + DYNAMIC_MODULES="$DYNAMIC_MODULES $ngx_module" + eval ${ngx_module}_SRCS=\"$ngx_module_srcs\" + + eval ${ngx_module}_MODULES=\"$ngx_module_name\" + + if [ -z "$ngx_module_order" -a \ + \( "$ngx_module_type" = "HTTP_FILTER" \ + -o "$ngx_module_type" = "HTTP_AUX_FILTER" \) ] + then + eval ${ngx_module}_ORDER=\"$ngx_module_name \ + ngx_http_copy_filter_module\" + else + eval ${ngx_module}_ORDER=\"$ngx_module_order\" + fi + + if test -n "$ngx_module_incs"; then + CORE_INCS="$CORE_INCS $ngx_module_incs" + fi + + libs= + for lib in $ngx_module_libs + do + case $lib in + + LIBXSLT | LIBGD | GEOIP) + libs="$libs \$NGX_LIB_$lib" + + if eval [ "\$USE_${lib}" = NO ] ; then + eval USE_${lib}=DYNAMIC + fi + ;; + + PCRE | OPENSSL | MD5 | SHA1 | ZLIB | PERL) + eval USE_${lib}=YES + ;; + + *) + libs="$libs $lib" + ;; + + esac + done + eval ${ngx_module}_LIBS=\'$libs\' + +elif [ "$ngx_module_link" = YES ]; then + + eval ${ngx_module_type}_MODULES=\"\$${ngx_module_type}_MODULES \ + $ngx_module_name\" + + eval ${ngx_var}_SRCS=\"\$${ngx_var}_SRCS $ngx_module_srcs\" + + if test -n "$ngx_module_incs"; then + eval ${ngx_var}_INCS=\"\$${ngx_var}_INCS $ngx_module_incs\" + fi + + if test -n "$ngx_module_deps"; then + eval ${ngx_var}_DEPS=\"\$${ngx_var}_DEPS $ngx_module_deps\" + fi + + for lib in $ngx_module_libs + do + case $lib in + + PCRE | OPENSSL | MD5 | SHA1 | ZLIB | LIBXSLT | LIBGD | PERL | GEOIP) + eval USE_${lib}=YES + ;; + + *) + CORE_LIBS="$CORE_LIBS $lib" + ;; + + esac + done + +elif [ "$ngx_module_link" = ADDON ]; then + + eval ${ngx_module_type}_MODULES=\"\$${ngx_module_type}_MODULES \ + $ngx_module_name\" + + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_module_srcs" + + if test -n "$ngx_module_incs"; then + eval ${ngx_var}_INCS=\"\$${ngx_var}_INCS $ngx_module_incs\" + fi + + if test -n "$ngx_module_deps"; then + NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_module_deps" + fi + + for lib in $ngx_module_libs + do + case $lib in + + PCRE | OPENSSL | MD5 | SHA1 | ZLIB | LIBXSLT | LIBGD | PERL | GEOIP) + eval USE_${lib}=YES + ;; + + *) + CORE_LIBS="$CORE_LIBS $lib" + ;; + + esac + done +fi diff --git a/auto/modules b/auto/modules index b2d2ee4..2074778 100644 --- a/auto/modules +++ b/auto/modules @@ -55,6 +55,45 @@ if [ $NGX_TEST_BUILD_SOLARIS_SENDFILEV = YES ]; then fi +HTTP_MODULES= +HTTP_DEPS= +HTTP_INCS= + +ngx_module_type=HTTP + +if :; then + ngx_module_name="ngx_http_module \ + ngx_http_core_module \ + ngx_http_log_module \ + ngx_http_upstream_module" + ngx_module_incs="src/http src/http/modules" + ngx_module_deps="src/http/ngx_http.h \ + src/http/ngx_http_request.h \ + src/http/ngx_http_config.h \ + src/http/ngx_http_core_module.h \ + src/http/ngx_http_cache.h \ + src/http/ngx_http_variables.h \ + src/http/ngx_http_script.h \ + src/http/ngx_http_upstream.h \ + src/http/ngx_http_upstream_round_robin.h" + ngx_module_srcs="src/http/ngx_http.c \ + src/http/ngx_http_core_module.c \ + src/http/ngx_http_special_response.c \ + src/http/ngx_http_request.c \ + src/http/ngx_http_parse.c \ + src/http/modules/ngx_http_log_module.c \ + src/http/ngx_http_request_body.c \ + src/http/ngx_http_variables.c \ + src/http/ngx_http_script.c \ + src/http/ngx_http_upstream.c \ + src/http/ngx_http_upstream_round_robin.c" + ngx_module_libs= + ngx_module_link=YES + + . auto/module +fi + + if [ $HTTP != YES ]; then have=NGX_CRYPT . auto/nohave CRYPT_LIB= @@ -117,297 +156,903 @@ fi # ngx_http_not_modified_filter # ngx_http_slice_filter -HTTP_FILTER_MODULES="$HTTP_WRITE_FILTER_MODULE \ - $HTTP_HEADER_FILTER_MODULE \ - $HTTP_CHUNKED_FILTER_MODULE" +ngx_module_type=HTTP_FILTER +HTTP_FILTER_MODULES= -if [ $HTTP_V2 = YES ]; then - HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_V2_FILTER_MODULE" +ngx_module_order="ngx_http_static_module \ + ngx_http_gzip_static_module \ + ngx_http_dav_module \ + ngx_http_autoindex_module \ + ngx_http_index_module \ + ngx_http_random_index_module \ + ngx_http_access_module \ + ngx_http_realip_module \ + ngx_http_write_filter_module \ + ngx_http_header_filter_module \ + ngx_http_chunked_filter_module \ + ngx_http_v2_filter_module \ + ngx_http_range_header_filter_module \ + ngx_http_gzip_filter_module \ + ngx_http_postpone_filter_module \ + ngx_http_ssi_filter_module \ + ngx_http_charset_filter_module \ + ngx_http_xslt_filter_module \ + ngx_http_image_filter_module \ + ngx_http_sub_filter_module \ + ngx_http_addition_filter_module \ + ngx_http_gunzip_filter_module \ + ngx_http_userid_filter_module \ + ngx_http_headers_filter_module \ + ngx_http_copy_filter_module \ + ngx_http_range_body_filter_module \ + ngx_http_not_modified_filter_module \ + ngx_http_slice_filter_module" + +if :; then + ngx_module_name=ngx_http_write_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/ngx_http_write_filter_module.c + ngx_module_libs= + ngx_module_link=YES + + . auto/module fi -HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_RANGE_HEADER_FILTER_MODULE" +if :; then + ngx_module_name=ngx_http_header_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/ngx_http_header_filter_module.c + ngx_module_libs= + ngx_module_link=YES + + . auto/module +fi + +if :; then + ngx_module_name=ngx_http_chunked_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_chunked_filter_module.c + ngx_module_libs= + ngx_module_link=YES + + . auto/module +fi + +if [ $HTTP_V2 = YES ]; then + ngx_module_name=ngx_http_v2_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/v2/ngx_http_v2_filter_module.c + ngx_module_libs= + ngx_module_link=$HTTP_V2 + + . auto/module +fi + +if :; then + ngx_module_name=ngx_http_range_header_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_range_filter_module.c + ngx_module_libs= + ngx_module_link=YES + + . auto/module +fi if [ $HTTP_GZIP = YES ]; then have=NGX_HTTP_GZIP . auto/have USE_ZLIB=YES - HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_GZIP_FILTER_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_GZIP_SRCS" + + ngx_module_name=ngx_http_gzip_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_gzip_filter_module.c + ngx_module_libs= + ngx_module_link=$HTTP_GZIP + + . auto/module fi if [ $HTTP_POSTPONE = YES ]; then - HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_POSTPONE_FILTER_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_POSTPONE_FILTER_SRCS" + ngx_module_name=ngx_http_postpone_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/ngx_http_postpone_filter_module.c + ngx_module_libs= + ngx_module_link=$HTTP_POSTPONE + + . auto/module fi if [ $HTTP_SSI = YES ]; then have=NGX_HTTP_SSI . auto/have - HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_SSI_FILTER_MODULE" - HTTP_DEPS="$HTTP_DEPS $HTTP_SSI_DEPS" - HTTP_SRCS="$HTTP_SRCS $HTTP_SSI_SRCS" + + ngx_module_name=ngx_http_ssi_filter_module + ngx_module_incs= + ngx_module_deps=src/http/modules/ngx_http_ssi_filter_module.h + ngx_module_srcs=src/http/modules/ngx_http_ssi_filter_module.c + ngx_module_libs= + ngx_module_link=$HTTP_SSI + + . auto/module fi if [ $HTTP_CHARSET = YES ]; then - HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_CHARSET_FILTER_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_CHARSET_SRCS" + ngx_module_name=ngx_http_charset_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_charset_filter_module.c + ngx_module_libs= + ngx_module_link=$HTTP_CHARSET + + . auto/module fi -if [ $HTTP_XSLT = YES ]; then - USE_LIBXSLT=YES - HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_XSLT_FILTER_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_XSLT_SRCS" +if [ $HTTP_XSLT != NO ]; then + ngx_module_name=ngx_http_xslt_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_xslt_filter_module.c + ngx_module_libs=LIBXSLT + ngx_module_link=$HTTP_XSLT + + . auto/module fi -if [ $HTTP_IMAGE_FILTER = YES ]; then - USE_LIBGD=YES - HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_IMAGE_FILTER_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_IMAGE_SRCS" +if [ $HTTP_IMAGE_FILTER != NO ]; then + ngx_module_name=ngx_http_image_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_image_filter_module.c + ngx_module_libs=LIBGD + ngx_module_link=$HTTP_IMAGE_FILTER + + . auto/module fi if [ $HTTP_SUB = YES ]; then - HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_SUB_FILTER_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_SUB_SRCS" + ngx_module_name=ngx_http_sub_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_sub_filter_module.c + ngx_module_libs= + ngx_module_link=$HTTP_SUB + + . auto/module fi if [ $HTTP_ADDITION = YES ]; then - HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_ADDITION_FILTER_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_ADDITION_SRCS" + ngx_module_name=ngx_http_addition_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_addition_filter_module.c + ngx_module_libs= + ngx_module_link=$HTTP_ADDITION + + . auto/module fi if [ $HTTP_GUNZIP = YES ]; then have=NGX_HTTP_GZIP . auto/have USE_ZLIB=YES - HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_GUNZIP_FILTER_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_GUNZIP_SRCS" + + ngx_module_name=ngx_http_gunzip_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_gunzip_filter_module.c + ngx_module_libs= + ngx_module_link=$HTTP_GUNZIP + + . auto/module fi if [ $HTTP_USERID = YES ]; then - HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_USERID_FILTER_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_USERID_SRCS" + ngx_module_name=ngx_http_userid_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_userid_filter_module.c + ngx_module_libs= + ngx_module_link=$HTTP_USERID + + . auto/module +fi + +if :; then + ngx_module_name=ngx_http_headers_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_headers_filter_module.c + ngx_module_libs= + ngx_module_link=YES + + . auto/module +fi + + +ngx_module_type=HTTP_INIT_FILTER +HTTP_INIT_FILTER_MODULES= + +if :; then + ngx_module_name=ngx_http_copy_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/ngx_http_copy_filter_module.c + ngx_module_libs= + ngx_module_link=YES + + . auto/module +fi + +if :; then + ngx_module_name=ngx_http_range_body_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs= + ngx_module_libs= + ngx_module_link=YES + + . auto/module +fi + +if :; then + ngx_module_name=ngx_http_not_modified_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_not_modified_filter_module.c + ngx_module_libs= + ngx_module_link=YES + + . auto/module fi if [ $HTTP_SLICE = YES ]; then - HTTP_SRCS="$HTTP_SRCS $HTTP_SLICE_SRCS" -else - HTTP_SLICE_FILTER_MODULE="" + ngx_module_name=ngx_http_slice_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_slice_filter_module.c + ngx_module_libs= + ngx_module_link=$HTTP_SLICE + + . auto/module fi +ngx_module_type=HTTP + if [ $HTTP_V2 = YES ]; then have=NGX_HTTP_V2 . auto/have - HTTP_MODULES="$HTTP_MODULES $HTTP_V2_MODULE" - HTTP_INCS="$HTTP_INCS $HTTP_V2_INCS" - HTTP_DEPS="$HTTP_DEPS $HTTP_V2_DEPS" - HTTP_SRCS="$HTTP_SRCS $HTTP_V2_SRCS" + + ngx_module_name=ngx_http_v2_module + ngx_module_incs=src/http/v2 + ngx_module_deps="src/http/v2/ngx_http_v2.h src/http/v2/ngx_http_v2_module.h" + ngx_module_srcs="src/http/v2/ngx_http_v2.c \ + src/http/v2/ngx_http_v2_table.c \ + src/http/v2/ngx_http_v2_huff_decode.c \ + src/http/v2/ngx_http_v2_huff_encode.c \ + src/http/v2/ngx_http_v2_module.c" + ngx_module_libs= + ngx_module_link=$HTTP_V2 + + . auto/module fi -HTTP_MODULES="$HTTP_MODULES $HTTP_STATIC_MODULE" +if :; then + ngx_module_name=ngx_http_static_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_static_module.c + ngx_module_libs= + ngx_module_link=YES + + . auto/module +fi if [ $HTTP_GZIP_STATIC = YES ]; then have=NGX_HTTP_GZIP . auto/have - HTTP_MODULES="$HTTP_MODULES $HTTP_GZIP_STATIC_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_GZIP_STATIC_SRCS" + + ngx_module_name=ngx_http_gzip_static_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_gzip_static_module.c + ngx_module_libs= + ngx_module_link=$HTTP_GZIP_STATIC + + . auto/module fi if [ $HTTP_DAV = YES ]; then have=NGX_HTTP_DAV . auto/have - HTTP_MODULES="$HTTP_MODULES $HTTP_DAV_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_DAV_SRCS" + + ngx_module_name=ngx_http_dav_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_dav_module.c + ngx_module_libs= + ngx_module_link=$HTTP_DAV + + . auto/module fi if [ $HTTP_AUTOINDEX = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_AUTOINDEX_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_AUTOINDEX_SRCS" + ngx_module_name=ngx_http_autoindex_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_autoindex_module.c + ngx_module_libs= + ngx_module_link=$HTTP_AUTOINDEX + + . auto/module fi -HTTP_MODULES="$HTTP_MODULES $HTTP_INDEX_MODULE" +if :; then + ngx_module_name=ngx_http_index_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_index_module.c + ngx_module_libs= + ngx_module_link=YES + + . auto/module +fi if [ $HTTP_RANDOM_INDEX = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_RANDOM_INDEX_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_RANDOM_INDEX_SRCS" + ngx_module_name=ngx_http_random_index_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_random_index_module.c + ngx_module_libs= + ngx_module_link=$HTTP_RANDOM_INDEX + + . auto/module fi if [ $HTTP_AUTH_REQUEST = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_AUTH_REQUEST_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_AUTH_REQUEST_SRCS" + ngx_module_name=ngx_http_auth_request_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_auth_request_module.c + ngx_module_libs= + ngx_module_link=$HTTP_AUTH_REQUEST + + . auto/module fi if [ $HTTP_AUTH_BASIC = YES ]; then USE_MD5=YES USE_SHA1=YES have=NGX_CRYPT . auto/have - HTTP_MODULES="$HTTP_MODULES $HTTP_AUTH_BASIC_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_AUTH_BASIC_SRCS" + + ngx_module_name=ngx_http_auth_basic_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_auth_basic_module.c + ngx_module_libs= + ngx_module_link=$HTTP_AUTH_BASIC + + . auto/module CORE_LIBS="$CORE_LIBS $CRYPT_LIB" fi if [ $HTTP_ACCESS = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_ACCESS_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_ACCESS_SRCS" + ngx_module_name=ngx_http_access_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_access_module.c + ngx_module_libs= + ngx_module_link=$HTTP_ACCESS + + . auto/module fi if [ $HTTP_LIMIT_CONN = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_LIMIT_CONN_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_LIMIT_CONN_SRCS" + ngx_module_name=ngx_http_limit_conn_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_limit_conn_module.c + ngx_module_libs= + ngx_module_link=$HTTP_LIMIT_CONN + + . auto/module fi if [ $HTTP_LIMIT_REQ = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_LIMIT_REQ_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_LIMIT_REQ_SRCS" + ngx_module_name=ngx_http_limit_req_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_limit_req_module.c + ngx_module_libs= + ngx_module_link=$HTTP_LIMIT_REQ + + . auto/module fi if [ $HTTP_REALIP = YES ]; then have=NGX_HTTP_REALIP . auto/have have=NGX_HTTP_X_FORWARDED_FOR . auto/have - HTTP_MODULES="$HTTP_MODULES $HTTP_REALIP_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_REALIP_SRCS" + + ngx_module_name=ngx_http_realip_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_realip_module.c + ngx_module_libs= + ngx_module_link=$HTTP_REALIP + + . auto/module fi if [ $HTTP_STATUS = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_STATUS_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_STATUS_SRCS" + ngx_module_name=ngx_http_status_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_status_module.c + ngx_module_libs= + ngx_module_link=$HTTP_STATUS + + . auto/module fi if [ $HTTP_GEO = YES ]; then have=NGX_HTTP_X_FORWARDED_FOR . auto/have - HTTP_MODULES="$HTTP_MODULES $HTTP_GEO_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_GEO_SRCS" + + ngx_module_name=ngx_http_geo_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_geo_module.c + ngx_module_libs= + ngx_module_link=$HTTP_GEO + + . auto/module fi -if [ $HTTP_GEOIP = YES ]; then +if [ $HTTP_GEOIP != NO ]; then have=NGX_HTTP_X_FORWARDED_FOR . auto/have - HTTP_MODULES="$HTTP_MODULES $HTTP_GEOIP_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_GEOIP_SRCS" + + ngx_module_name=ngx_http_geoip_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_geoip_module.c + ngx_module_libs=GEOIP + ngx_module_link=$HTTP_GEOIP + + . auto/module fi if [ $HTTP_MAP = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_MAP_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_MAP_SRCS" + ngx_module_name=ngx_http_map_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_map_module.c + ngx_module_libs= + ngx_module_link=$HTTP_MAP + + . auto/module fi if [ $HTTP_SPLIT_CLIENTS = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_SPLIT_CLIENTS_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_SPLIT_CLIENTS_SRCS" + ngx_module_name=ngx_http_split_clients_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_split_clients_module.c + ngx_module_libs= + ngx_module_link=$HTTP_SPLIT_CLIENTS + + . auto/module fi if [ $HTTP_REFERER = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_REFERER_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_REFERER_SRCS" + ngx_module_name=ngx_http_referer_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_referer_module.c + ngx_module_libs= + ngx_module_link=$HTTP_REFERER + + . auto/module fi if [ $HTTP_REWRITE = YES -a $USE_PCRE != DISABLED ]; then USE_PCRE=YES - HTTP_MODULES="$HTTP_MODULES $HTTP_REWRITE_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_REWRITE_SRCS" + + ngx_module_name=ngx_http_rewrite_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_rewrite_module.c + ngx_module_libs= + ngx_module_link=$HTTP_REWRITE + + . auto/module fi if [ $HTTP_SSL = YES ]; then USE_OPENSSL=YES have=NGX_HTTP_SSL . auto/have - HTTP_MODULES="$HTTP_MODULES $HTTP_SSL_MODULE" - HTTP_DEPS="$HTTP_DEPS $HTTP_SSL_DEPS" - HTTP_SRCS="$HTTP_SRCS $HTTP_SSL_SRCS" + + ngx_module_name=ngx_http_ssl_module + ngx_module_incs= + ngx_module_deps=src/http/modules/ngx_http_ssl_module.h + ngx_module_srcs=src/http/modules/ngx_http_ssl_module.c + ngx_module_libs= + ngx_module_link=$HTTP_SSL + + . auto/module fi if [ $HTTP_PROXY = YES ]; then have=NGX_HTTP_X_FORWARDED_FOR . auto/have #USE_MD5=YES - HTTP_MODULES="$HTTP_MODULES $HTTP_PROXY_MODULE" - HTTP_DEPS="$HTTP_DEPS $HTTP_PROXY_DEPS" - HTTP_SRCS="$HTTP_SRCS $HTTP_PROXY_SRCS" + + ngx_module_name=ngx_http_proxy_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_proxy_module.c + ngx_module_libs= + ngx_module_link=$HTTP_PROXY + + . auto/module fi if [ $HTTP_FASTCGI = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_FASTCGI_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_FASTCGI_SRCS" + ngx_module_name=ngx_http_fastcgi_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_fastcgi_module.c + ngx_module_libs= + ngx_module_link=$HTTP_FASTCGI + + . auto/module fi if [ $HTTP_UWSGI = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_UWSGI_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_UWSGI_SRCS" + ngx_module_name=ngx_http_uwsgi_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_uwsgi_module.c + ngx_module_libs= + ngx_module_link=$HTTP_UWSGI + + . auto/module fi if [ $HTTP_SCGI = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_SCGI_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_SCGI_SRCS" + ngx_module_name=ngx_http_scgi_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_scgi_module.c + ngx_module_libs= + ngx_module_link=$HTTP_SCGI + + . auto/module fi if [ $HTTP_PERL = YES ]; then USE_PERL=YES - HTTP_MODULES="$HTTP_MODULES $HTTP_PERL_MODULE" - HTTP_INCS="$HTTP_INCS $HTTP_PERL_INCS" - HTTP_DEPS="$HTTP_DEPS $HTTP_PERL_DEPS" - HTTP_SRCS="$HTTP_SRCS $HTTP_PERL_SRCS" + + ngx_module_name=ngx_http_perl_module + ngx_module_incs=src/http/modules/perl + ngx_module_deps=src/http/modules/perl/ngx_http_perl_module.h + ngx_module_srcs=src/http/modules/perl/ngx_http_perl_module.c + ngx_module_libs= + ngx_module_link=$HTTP_PERL + + . auto/module fi if [ $HTTP_MEMCACHED = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_MEMCACHED_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_MEMCACHED_SRCS" + ngx_module_name=ngx_http_memcached_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_memcached_module.c + ngx_module_libs= + ngx_module_link=$HTTP_MEMCACHED + + . auto/module fi if [ $HTTP_EMPTY_GIF = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_EMPTY_GIF_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_EMPTY_GIF_SRCS" + ngx_module_name=ngx_http_empty_gif_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_empty_gif_module.c + ngx_module_libs= + ngx_module_link=$HTTP_EMPTY_GIF + + . auto/module fi if [ $HTTP_BROWSER = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_BROWSER_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_BROWSER_SRCS" + ngx_module_name=ngx_http_browser_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_browser_module.c + ngx_module_libs= + ngx_module_link=$HTTP_BROWSER + + . auto/module fi if [ $HTTP_SECURE_LINK = YES ]; then USE_MD5=YES - HTTP_MODULES="$HTTP_MODULES $HTTP_SECURE_LINK_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_SECURE_LINK_SRCS" + + ngx_module_name=ngx_http_secure_link_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_secure_link_module.c + ngx_module_libs= + ngx_module_link=$HTTP_SECURE_LINK + + . auto/module fi if [ $HTTP_DEGRADATION = YES ]; then have=NGX_HTTP_DEGRADATION . auto/have - HTTP_MODULES="$HTTP_MODULES $HTTP_DEGRADATION_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_DEGRADATION_SRCS" + + ngx_module_name=ngx_http_degradation_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_degradation_module.c + ngx_module_libs= + ngx_module_link=$HTTP_DEGRADATION + + . auto/module fi if [ $HTTP_FLV = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_FLV_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_FLV_SRCS" + ngx_module_name=ngx_http_flv_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_flv_module.c + ngx_module_libs= + ngx_module_link=$HTTP_FLV + + . auto/module fi if [ $HTTP_MP4 = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_MP4_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_MP4_SRCS" + ngx_module_name=ngx_http_mp4_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_mp4_module.c + ngx_module_libs= + ngx_module_link=$HTTP_MP4 + + . auto/module fi if [ $HTTP_UPSTREAM_HASH = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_UPSTREAM_HASH_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_HASH_SRCS" + ngx_module_name=ngx_http_upstream_hash_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_upstream_hash_module.c + ngx_module_libs= + ngx_module_link=$HTTP_UPSTREAM_HASH + + . auto/module fi if [ $HTTP_UPSTREAM_IP_HASH = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_UPSTREAM_IP_HASH_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_IP_HASH_SRCS" + ngx_module_name=ngx_http_upstream_ip_hash_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_upstream_ip_hash_module.c + ngx_module_libs= + ngx_module_link=$HTTP_UPSTREAM_IP_HASH + + . auto/module fi if [ $HTTP_UPSTREAM_LEAST_CONN = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_UPSTREAM_LEAST_CONN_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_LEAST_CONN_SRCS" + ngx_module_name=ngx_http_upstream_least_conn_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_upstream_least_conn_module.c + ngx_module_libs= + ngx_module_link=$HTTP_UPSTREAM_LEAST_CONN + + . auto/module fi if [ $HTTP_UPSTREAM_KEEPALIVE = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_UPSTREAM_KEEPALIVE_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_KEEPALIVE_SRCS" + ngx_module_name=ngx_http_upstream_keepalive_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_upstream_keepalive_module.c + ngx_module_libs= + ngx_module_link=$HTTP_UPSTREAM_KEEPALIVE + + . auto/module fi if [ $HTTP_UPSTREAM_ZONE = YES ]; then have=NGX_HTTP_UPSTREAM_ZONE . auto/have - HTTP_MODULES="$HTTP_MODULES $HTTP_UPSTREAM_ZONE_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_ZONE_SRCS" + + ngx_module_name=ngx_http_upstream_zone_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_upstream_zone_module.c + ngx_module_libs= + ngx_module_link=$HTTP_UPSTREAM_ZONE + + . auto/module fi if [ $HTTP_STUB_STATUS = YES ]; then have=NGX_STAT_STUB . auto/have - HTTP_MODULES="$HTTP_MODULES ngx_http_stub_status_module" - HTTP_SRCS="$HTTP_SRCS src/http/modules/ngx_http_stub_status_module.c" + + ngx_module_name=ngx_http_stub_status_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_stub_status_module.c + ngx_module_libs= + ngx_module_link=$HTTP_STUB_STATUS + + . auto/module fi + +if [ $MAIL != NO ]; then + MAIL_MODULES= + MAIL_DEPS= + MAIL_INCS= + + ngx_module_type=MAIL + ngx_module_libs= + ngx_module_link=YES + + ngx_module_order= + + ngx_module_name="ngx_mail_module ngx_mail_core_module" + ngx_module_incs="src/mail" + ngx_module_deps="src/mail/ngx_mail.h" + ngx_module_srcs="src/mail/ngx_mail.c \ + src/mail/ngx_mail_core_module.c \ + src/mail/ngx_mail_handler.c \ + src/mail/ngx_mail_parse.c" + + . auto/module + + ngx_module_incs= + + if [ $MAIL_SSL = YES ]; then + USE_OPENSSL=YES + have=NGX_MAIL_SSL . auto/have + + ngx_module_name=ngx_mail_ssl_module + ngx_module_deps=src/mail/ngx_mail_ssl_module.h + ngx_module_srcs=src/mail/ngx_mail_ssl_module.c + + . auto/module + fi + + if [ $MAIL_POP3 = YES ]; then + ngx_module_name=ngx_mail_pop3_module + ngx_module_deps=src/mail/ngx_mail_pop3_module.h + ngx_module_srcs="src/mail/ngx_mail_pop3_module.c \ + src/mail/ngx_mail_pop3_handler.c" + + . auto/module + fi + + if [ $MAIL_IMAP = YES ]; then + ngx_module_name=ngx_mail_imap_module + ngx_module_deps=src/mail/ngx_mail_imap_module.h + ngx_module_srcs="src/mail/ngx_mail_imap_module.c \ + src/mail/ngx_mail_imap_handler.c" + + . auto/module + fi + + if [ $MAIL_SMTP = YES ]; then + ngx_module_name=ngx_mail_smtp_module + ngx_module_deps=src/mail/ngx_mail_smtp_module.h + ngx_module_srcs="src/mail/ngx_mail_smtp_module.c \ + src/mail/ngx_mail_smtp_handler.c" + + . auto/module + fi + + ngx_module_name=ngx_mail_auth_http_module + ngx_module_deps= + ngx_module_srcs=src/mail/ngx_mail_auth_http_module.c + + . auto/module + + ngx_module_name=ngx_mail_proxy_module + ngx_module_deps= + ngx_module_srcs=src/mail/ngx_mail_proxy_module.c + + . auto/module +fi + + +if [ $STREAM != NO ]; then + STREAM_MODULES= + STREAM_DEPS= + STREAM_INCS= + + ngx_module_type=STREAM + ngx_module_libs= + ngx_module_link=YES + + ngx_module_order= + + ngx_module_name="ngx_stream_module \ + ngx_stream_core_module \ + ngx_stream_proxy_module \ + ngx_stream_upstream_module" + ngx_module_incs="src/stream" + ngx_module_deps="src/stream/ngx_stream.h \ + src/stream/ngx_stream_upstream.h \ + src/stream/ngx_stream_upstream_round_robin.h" + ngx_module_srcs="src/stream/ngx_stream.c \ + src/stream/ngx_stream_handler.c \ + src/stream/ngx_stream_core_module.c \ + src/stream/ngx_stream_proxy_module.c \ + src/stream/ngx_stream_upstream.c \ + src/stream/ngx_stream_upstream_round_robin.c" + + . auto/module + + ngx_module_incs= + + if [ $STREAM_SSL = YES ]; then + USE_OPENSSL=YES + have=NGX_STREAM_SSL . auto/have + + ngx_module_name=ngx_stream_ssl_module + ngx_module_deps=src/stream/ngx_stream_ssl_module.h + ngx_module_srcs=src/stream/ngx_stream_ssl_module.c + + . auto/module + fi + + if [ $STREAM_LIMIT_CONN = YES ]; then + ngx_module_name=ngx_stream_limit_conn_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_limit_conn_module.c + + . auto/module + fi + + if [ $STREAM_ACCESS = YES ]; then + ngx_module_name=ngx_stream_access_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_access_module.c + + . auto/module + fi + + if [ $STREAM_UPSTREAM_HASH = YES ]; then + ngx_module_name=ngx_stream_upstream_hash_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_upstream_hash_module.c + + . auto/module + fi + + if [ $STREAM_UPSTREAM_LEAST_CONN = YES ]; then + ngx_module_name=ngx_stream_upstream_least_conn_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_upstream_least_conn_module.c + + . auto/module + fi + + if [ $STREAM_UPSTREAM_ZONE = YES ]; then + have=NGX_STREAM_UPSTREAM_ZONE . auto/have + + ngx_module_name=ngx_stream_upstream_zone_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_upstream_zone_module.c + + . auto/module + fi +fi + + #if [ -r $NGX_OBJS/auto ]; then # . $NGX_OBJS/auto #fi @@ -421,6 +1066,15 @@ if test -n "$NGX_ADDONS"; then do echo "adding module in $ngx_addon_dir" + ngx_module_type= + ngx_module_name= + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs= + ngx_module_libs= + ngx_module_order= + ngx_module_link=ADDON + if test -f $ngx_addon_dir/config; then . $ngx_addon_dir/config @@ -434,15 +1088,62 @@ if test -n "$NGX_ADDONS"; then fi -if [ $MAIL_SSL = YES ]; then - have=NGX_MAIL_SSL . auto/have - USE_OPENSSL=YES +if test -n "$DYNAMIC_ADDONS"; then + + echo configuring additional dynamic modules + + for ngx_addon_dir in $DYNAMIC_ADDONS + do + echo "adding module in $ngx_addon_dir" + + ngx_module_type= + ngx_module_name= + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs= + ngx_module_libs= + ngx_module_order= + ngx_module_link=DYNAMIC + + if test -f $ngx_addon_dir/config; then + . $ngx_addon_dir/config + + echo " + $ngx_addon_name was configured" + + else + echo "$0: error: no $ngx_addon_dir/config was found" + exit 1 + fi + done fi -if [ $STREAM_SSL = YES ]; then - have=NGX_STREAM_SSL . auto/have - USE_OPENSSL=YES +if [ $USE_OPENSSL = YES ]; then + ngx_module_type=CORE + ngx_module_name=ngx_openssl_module + ngx_module_incs= + ngx_module_deps=src/event/ngx_event_openssl.h + ngx_module_srcs="src/event/ngx_event_openssl.c + src/event/ngx_event_openssl_stapling.c" + ngx_module_libs= + ngx_module_link=YES + ngx_module_order= + + . auto/module +fi + + +if [ $USE_PCRE = YES ]; then + ngx_module_type=CORE + ngx_module_name=ngx_regex_module + ngx_module_incs= + ngx_module_deps=src/core/ngx_regex.h + ngx_module_srcs=src/core/ngx_regex.c + ngx_module_libs= + ngx_module_link=YES + ngx_module_order= + + . auto/module fi @@ -455,119 +1156,81 @@ if [ $USE_THREADS = YES ]; then fi -if [ $USE_OPENSSL = YES ]; then - modules="$modules $OPENSSL_MODULE" - CORE_DEPS="$CORE_DEPS $OPENSSL_DEPS" - 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 \ - $HTTP_AUX_FILTER_MODULES \ - $HTTP_COPY_FILTER_MODULE \ - $HTTP_RANGE_BODY_FILTER_MODULE \ - $HTTP_NOT_MODIFIED_FILTER_MODULE \ - $HTTP_SLICE_FILTER_MODULE" + $HTTP_AUX_FILTER_MODULES $HTTP_INIT_FILTER_MODULES" NGX_ADDON_DEPS="$NGX_ADDON_DEPS \$(HTTP_DEPS)" fi -if [ $MAIL = YES ]; then - modules="$modules $MAIL_MODULES" +if [ $MAIL != NO ]; then - if [ $MAIL_SSL = YES ]; then - modules="$modules $MAIL_SSL_MODULE" - MAIL_DEPS="$MAIL_DEPS $MAIL_SSL_DEPS" - MAIL_SRCS="$MAIL_SRCS $MAIL_SSL_SRCS" + if [ $MAIL = YES ]; then + modules="$modules $MAIL_MODULES" + + elif [ $MAIL = DYNAMIC ]; then + ngx_module_name=$MAIL_MODULES + ngx_module_incs= + ngx_module_deps=$MAIL_DEPS + ngx_module_srcs=$MAIL_SRCS + ngx_module_libs= + ngx_module_link=DYNAMIC + + . auto/module fi - if [ $MAIL_POP3 = YES ]; then - modules="$modules $MAIL_POP3_MODULE" - MAIL_DEPS="$MAIL_DEPS $MAIL_POP3_DEPS" - MAIL_SRCS="$MAIL_SRCS $MAIL_POP3_SRCS" - fi - - if [ $MAIL_IMAP = YES ]; then - modules="$modules $MAIL_IMAP_MODULE" - MAIL_DEPS="$MAIL_DEPS $MAIL_IMAP_DEPS" - MAIL_SRCS="$MAIL_SRCS $MAIL_IMAP_SRCS" - fi - - if [ $MAIL_SMTP = YES ]; then - modules="$modules $MAIL_SMTP_MODULE" - MAIL_DEPS="$MAIL_DEPS $MAIL_SMTP_DEPS" - MAIL_SRCS="$MAIL_SRCS $MAIL_SMTP_SRCS" - fi - - modules="$modules $MAIL_AUTH_HTTP_MODULE" - MAIL_SRCS="$MAIL_SRCS $MAIL_AUTH_HTTP_SRCS" - - modules="$modules $MAIL_PROXY_MODULE" - MAIL_SRCS="$MAIL_SRCS $MAIL_PROXY_SRCS" - NGX_ADDON_DEPS="$NGX_ADDON_DEPS \$(MAIL_DEPS)" fi -if [ $STREAM = YES ]; then - have=NGX_STREAM . auto/have - modules="$modules $STREAM_MODULES" +if [ $STREAM != NO ]; then - if [ $STREAM_SSL = YES ]; then - modules="$modules $STREAM_SSL_MODULE" - STREAM_DEPS="$STREAM_DEPS $STREAM_SSL_DEPS" - STREAM_SRCS="$STREAM_SRCS $STREAM_SSL_SRCS" - fi + if [ $STREAM = YES ]; then + modules="$modules $STREAM_MODULES" - if [ $STREAM_LIMIT_CONN = YES ]; then - modules="$modules $STREAM_LIMIT_CONN_MODULE" - STREAM_SRCS="$STREAM_SRCS $STREAM_LIMIT_CONN_SRCS" - fi + elif [ $STREAM = DYNAMIC ]; then + ngx_module_name=$STREAM_MODULES + ngx_module_incs= + ngx_module_deps=$STREAM_DEPS + ngx_module_srcs=$STREAM_SRCS + ngx_module_libs= + ngx_module_link=DYNAMIC - if [ $STREAM_ACCESS = YES ]; then - modules="$modules $STREAM_ACCESS_MODULE" - STREAM_SRCS="$STREAM_SRCS $STREAM_ACCESS_SRCS" - fi - - if [ $STREAM_UPSTREAM_HASH = YES ]; then - modules="$modules $STREAM_UPSTREAM_HASH_MODULE" - STREAM_SRCS="$STREAM_SRCS $STREAM_UPSTREAM_HASH_SRCS" - fi - - if [ $STREAM_UPSTREAM_LEAST_CONN = YES ]; then - modules="$modules $STREAM_UPSTREAM_LEAST_CONN_MODULE" - STREAM_SRCS="$STREAM_SRCS $STREAM_UPSTREAM_LEAST_CONN_SRCS" - fi - - if [ $STREAM_UPSTREAM_ZONE = YES ]; then - have=NGX_STREAM_UPSTREAM_ZONE . auto/have - modules="$modules $STREAM_UPSTREAM_ZONE_MODULE" - STREAM_SRCS="$STREAM_SRCS $STREAM_UPSTREAM_ZONE_SRCS" + . auto/module fi NGX_ADDON_DEPS="$NGX_ADDON_DEPS \$(STREAM_DEPS)" fi -if [ $NGX_GOOGLE_PERFTOOLS = YES ]; then - modules="$modules $NGX_GOOGLE_PERFTOOLS_MODULE" - NGX_MISC_SRCS="$NGX_MISC_SRCS $NGX_GOOGLE_PERFTOOLS_SRCS" -fi +ngx_module_type=MISC +MISC_MODULES= +if [ $NGX_GOOGLE_PERFTOOLS = YES ]; then + ngx_module_name=ngx_google_perftools_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/misc/ngx_google_perftools_module.c + ngx_module_libs= + ngx_module_link=$NGX_GOOGLE_PERFTOOLS + + . auto/module +fi if [ $NGX_CPP_TEST = YES ]; then - NGX_MISC_SRCS="$NGX_MISC_SRCS $NGX_CPP_TEST_SRCS" - CORE_LIBS="$CORE_LIBS -lstdc++" + ngx_module_name= + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/misc/ngx_cpp_test_module.cpp + ngx_module_libs=-lstdc++ + ngx_module_link=$NGX_CPP_TEST + + . auto/module fi +modules="$modules $MISC_MODULES" + cat << END > $NGX_MODULES_C @@ -596,3 +1259,16 @@ cat << END >> $NGX_MODULES_C }; END + +echo 'char *ngx_module_names[] = {' >> $NGX_MODULES_C + +for mod in $modules +do + echo " \"$mod\"," >> $NGX_MODULES_C +done + +cat << END >> $NGX_MODULES_C + NULL +}; + +END diff --git a/auto/options b/auto/options index 931dabb..36b34bc 100644 --- a/auto/options +++ b/auto/options @@ -7,6 +7,7 @@ help=no NGX_PREFIX= NGX_SBIN_PATH= +NGX_MODULES_PATH= NGX_CONF_PREFIX= NGX_CONF_PATH= NGX_ERROR_LOG_PATH= @@ -120,7 +121,11 @@ STREAM_UPSTREAM_HASH=YES STREAM_UPSTREAM_LEAST_CONN=YES STREAM_UPSTREAM_ZONE=YES +DYNAMIC_MODULES= + NGX_ADDONS= +NGX_ADDON_DEPS= +DYNAMIC_ADDONS= USE_PCRE=NO PCRE=NONE @@ -151,6 +156,7 @@ NGX_PERL=perl USE_LIBXSLT=NO USE_LIBGD=NO +USE_GEOIP=NO NGX_GOOGLE_PERFTOOLS=NO NGX_CPP_TEST=NO @@ -178,6 +184,7 @@ do --prefix=) NGX_PREFIX="!" ;; --prefix=*) NGX_PREFIX="$value" ;; --sbin-path=*) NGX_SBIN_PATH="$value" ;; + --modules-path=*) NGX_MODULES_PATH="$value" ;; --conf-path=*) NGX_CONF_PATH="$value" ;; --error-log-path=*) NGX_ERROR_LOG_PATH="$value";; --pid-path=*) NGX_PID_PATH="$value" ;; @@ -215,8 +222,13 @@ do --with-http_realip_module) HTTP_REALIP=YES ;; --with-http_addition_module) HTTP_ADDITION=YES ;; --with-http_xslt_module) HTTP_XSLT=YES ;; + --with-http_xslt_module=dynamic) HTTP_XSLT=DYNAMIC ;; --with-http_image_filter_module) HTTP_IMAGE_FILTER=YES ;; + --with-http_image_filter_module=dynamic) + HTTP_IMAGE_FILTER=DYNAMIC ;; --with-http_geoip_module) HTTP_GEOIP=YES ;; + --with-http_geoip_module=dynamic) + HTTP_GEOIP=DYNAMIC ;; --with-http_sub_module) HTTP_SUB=YES ;; --with-http_dav_module) HTTP_DAV=YES ;; --with-http_flv_module) HTTP_FLV=YES ;; @@ -266,6 +278,7 @@ do --with-http_stub_status_module) HTTP_STUB_STATUS=YES ;; --with-mail) MAIL=YES ;; + --with-mail=dynamic) MAIL=DYNAMIC ;; --with-mail_ssl_module) MAIL_SSL=YES ;; # STUB --with-imap) @@ -285,6 +298,7 @@ use the \"--with-mail_ssl_module\" option instead" --without-mail_smtp_module) MAIL_SMTP=NO ;; --with-stream) STREAM=YES ;; + --with-stream=dynamic) STREAM=DYNAMIC ;; --with-stream_ssl_module) STREAM_SSL=YES ;; --without-stream_limit_conn_module) STREAM_LIMIT_CONN=NO ;; @@ -300,6 +314,7 @@ use the \"--with-mail_ssl_module\" option instead" --with-cpp_test_module) NGX_CPP_TEST=YES ;; --add-module=*) NGX_ADDONS="$NGX_ADDONS $value" ;; + --add-dynamic-module=*) DYNAMIC_ADDONS="$DYNAMIC_ADDONS $value" ;; --with-cc=*) CC="$value" ;; --with-cpp=*) CPP="$value" ;; @@ -356,6 +371,7 @@ cat << END --prefix=PATH set installation prefix --sbin-path=PATH set nginx binary pathname + --modules-path=PATH set modules path --conf-path=PATH set nginx.conf pathname --error-log-path=PATH set error log pathname --pid-path=PATH set nginx.pid pathname @@ -384,8 +400,12 @@ cat << END --with-http_realip_module enable ngx_http_realip_module --with-http_addition_module enable ngx_http_addition_module --with-http_xslt_module enable ngx_http_xslt_module + --with-http_xslt_module=dynamic enable dynamic ngx_http_xslt_module --with-http_image_filter_module enable ngx_http_image_filter_module + --with-http_image_filter_module=dynamic + enable dynamic ngx_http_image_filter_module --with-http_geoip_module enable ngx_http_geoip_module + --with-http_geoip_module=dynamic enable dynamic ngx_http_geoip_module --with-http_sub_module enable ngx_http_sub_module --with-http_dav_module enable ngx_http_dav_module --with-http_flv_module enable ngx_http_flv_module @@ -451,12 +471,14 @@ cat << END --without-http-cache disable HTTP cache --with-mail enable POP3/IMAP4/SMTP proxy module + --with-mail=dynamic enable dynamic POP3/IMAP4/SMTP proxy module --with-mail_ssl_module enable ngx_mail_ssl_module --without-mail_pop3_module disable ngx_mail_pop3_module --without-mail_imap_module disable ngx_mail_imap_module --without-mail_smtp_module disable ngx_mail_smtp_module --with-stream enable TCP proxy module + --with-stream=dynamic enable dynamic TCP proxy module --with-stream_ssl_module enable ngx_stream_ssl_module --without-stream_limit_conn_module disable ngx_stream_limit_conn_module --without-stream_access_module disable ngx_stream_access_module @@ -470,7 +492,8 @@ cat << END --with-google_perftools_module enable ngx_google_perftools_module --with-cpp_test_module enable ngx_cpp_test_module - --add-module=PATH enable an external module + --add-module=PATH enable external module + --add-dynamic-module=PATH enable dynamic external module --with-cc=PATH set C compiler pathname --with-cpp=PATH set C preprocessor pathname @@ -533,6 +556,7 @@ fi NGX_SBIN_PATH=${NGX_SBIN_PATH:-sbin/nginx} +NGX_MODULES_PATH=${NGX_MODULES_PATH:-modules} NGX_CONF_PATH=${NGX_CONF_PATH:-conf/nginx.conf} NGX_CONF_PREFIX=`dirname $NGX_CONF_PATH` NGX_PID_PATH=${NGX_PID_PATH:-logs/nginx.pid} diff --git a/auto/os/darwin b/auto/os/darwin index 1d3e3d3..9b31b1f 100644 --- a/auto/os/darwin +++ b/auto/os/darwin @@ -14,6 +14,9 @@ CORE_SRCS="$UNIX_SRCS $DARWIN_SRCS" ngx_spacer=' ' +MAIN_LINK= +MODULE_LINK="-shared -Wl,-undefined,dynamic_lookup" + # kqueue echo " + kqueue found" diff --git a/auto/os/win32 b/auto/os/win32 index 82fc212..14ae3b8 100644 --- a/auto/os/win32 +++ b/auto/os/win32 @@ -12,10 +12,15 @@ OS_CONFIG="$WIN32_CONFIG" NGX_ICONS="$NGX_WIN32_ICONS" SELECT_SRCS=$WIN32_SELECT_SRCS +ngx_pic_opt= + case "$NGX_CC_NAME" in gcc) CORE_LIBS="$CORE_LIBS -ladvapi32 -lws2_32" + MAIN_LINK="$MAIN_LINK -Wl,--export-all-symbols" + MAIN_LINK="$MAIN_LINK -Wl,--out-implib=$NGX_OBJS/libnginx.a" + MODULE_LINK="-shared -L $NGX_OBJS -lnginx" ;; *) diff --git a/auto/sources b/auto/sources index 2e44ce1..e08e863 100644 --- a/auto/sources +++ b/auto/sources @@ -36,6 +36,7 @@ CORE_DEPS="src/core/nginx.h \ src/core/ngx_connection.h \ src/core/ngx_cycle.h \ src/core/ngx_conf_file.h \ + src/core/ngx_module.h \ src/core/ngx_resolver.h \ src/core/ngx_open_file_cache.h \ src/core/ngx_crypt.h \ @@ -71,6 +72,7 @@ CORE_SRCS="src/core/nginx.c \ src/core/ngx_rwlock.c \ src/core/ngx_cpuinfo.c \ src/core/ngx_conf_file.c \ + src/core/ngx_module.c \ src/core/ngx_resolver.c \ src/core/ngx_open_file_cache.c \ src/core/ngx_crypt.c \ @@ -78,17 +80,6 @@ CORE_SRCS="src/core/nginx.c \ src/core/ngx_syslog.c" -REGEX_MODULE=ngx_regex_module -REGEX_DEPS=src/core/ngx_regex.h -REGEX_SRCS=src/core/ngx_regex.c - - -OPENSSL_MODULE=ngx_openssl_module -OPENSSL_DEPS=src/event/ngx_event_openssl.h -OPENSSL_SRCS="src/event/ngx_event_openssl.c \ - src/event/ngx_event_openssl_stapling.c" - - EVENT_MODULES="ngx_events_module ngx_event_core_module" EVENT_INCS="src/event src/event/modules" @@ -150,6 +141,7 @@ UNIX_DEPS="$CORE_DEPS $EVENT_DEPS \ src/os/unix/ngx_socket.h \ src/os/unix/ngx_os.h \ src/os/unix/ngx_user.h \ + src/os/unix/ngx_dlopen.h \ src/os/unix/ngx_process_cycle.h" # add to UNIX_DEPS @@ -181,6 +173,7 @@ UNIX_SRCS="$CORE_SRCS $EVENT_SRCS \ src/os/unix/ngx_setproctitle.c \ src/os/unix/ngx_posix_init.c \ src/os/unix/ngx_user.c \ + src/os/unix/ngx_dlopen.c \ src/os/unix/ngx_process_cycle.c" POSIX_DEPS=src/os/unix/ngx_posix_config.h @@ -226,6 +219,7 @@ WIN32_DEPS="$CORE_DEPS $EVENT_DEPS \ src/os/win32/ngx_socket.h \ src/os/win32/ngx_os.h \ src/os/win32/ngx_user.h \ + src/os/win32/ngx_dlopen.h \ src/os/win32/ngx_process_cycle.h" WIN32_CONFIG=src/os/win32/ngx_win32_config.h @@ -246,6 +240,7 @@ WIN32_SRCS="$CORE_SRCS $EVENT_SRCS \ src/os/win32/ngx_wsasend_chain.c \ src/os/win32/ngx_win32_init.c \ src/os/win32/ngx_user.c \ + src/os/win32/ngx_dlopen.c \ src/os/win32/ngx_event_log.c \ src/os/win32/ngx_process_cycle.c \ src/event/ngx_event_acceptex.c" @@ -254,343 +249,4 @@ NGX_WIN32_ICONS="src/os/win32/nginx.ico" NGX_WIN32_RC="src/os/win32/nginx.rc" -HTTP_MODULES="ngx_http_module \ - ngx_http_core_module \ - ngx_http_log_module \ - ngx_http_upstream_module" - -HTTP_WRITE_FILTER_MODULE="ngx_http_write_filter_module" -HTTP_HEADER_FILTER_MODULE="ngx_http_header_filter_module" - -HTTP_POSTPONE_FILTER_MODULE=ngx_http_postpone_filter_module -HTTP_COPY_FILTER_MODULE=ngx_http_copy_filter_module - -HTTP_CHUNKED_FILTER_MODULE=ngx_http_chunked_filter_module -HTTP_HEADERS_FILTER_MODULE=ngx_http_headers_filter_module - -HTTP_RANGE_HEADER_FILTER_MODULE=ngx_http_range_header_filter_module -HTTP_RANGE_BODY_FILTER_MODULE=ngx_http_range_body_filter_module - -HTTP_NOT_MODIFIED_FILTER_MODULE=ngx_http_not_modified_filter_module - -HTTP_STATIC_MODULE=ngx_http_static_module -HTTP_INDEX_MODULE=ngx_http_index_module - -HTTP_INCS="src/http src/http/modules" - -HTTP_DEPS="src/http/ngx_http.h \ - src/http/ngx_http_request.h \ - src/http/ngx_http_config.h \ - src/http/ngx_http_core_module.h \ - src/http/ngx_http_cache.h \ - src/http/ngx_http_variables.h \ - src/http/ngx_http_script.h \ - src/http/ngx_http_upstream.h \ - src/http/ngx_http_upstream_round_robin.h" - -HTTP_SRCS="src/http/ngx_http.c \ - src/http/ngx_http_core_module.c \ - src/http/ngx_http_special_response.c \ - src/http/ngx_http_request.c \ - src/http/ngx_http_parse.c \ - src/http/ngx_http_header_filter_module.c \ - src/http/ngx_http_write_filter_module.c \ - src/http/ngx_http_copy_filter_module.c \ - src/http/modules/ngx_http_log_module.c \ - src/http/ngx_http_request_body.c \ - src/http/ngx_http_variables.c \ - src/http/ngx_http_script.c \ - src/http/ngx_http_upstream.c \ - src/http/ngx_http_upstream_round_robin.c \ - src/http/modules/ngx_http_static_module.c \ - src/http/modules/ngx_http_index_module.c \ - src/http/modules/ngx_http_chunked_filter_module.c \ - src/http/modules/ngx_http_range_filter_module.c \ - src/http/modules/ngx_http_headers_filter_module.c \ - src/http/modules/ngx_http_not_modified_filter_module.c" - -HTTP_POSTPONE_FILTER_SRCS=src/http/ngx_http_postpone_filter_module.c - HTTP_FILE_CACHE_SRCS=src/http/ngx_http_file_cache.c - - -HTTP_V2_MODULE=ngx_http_v2_module -HTTP_V2_FILTER_MODULE=ngx_http_v2_filter_module -HTTP_V2_INCS="src/http/v2" -HTTP_V2_DEPS="src/http/v2/ngx_http_v2.h \ - src/http/v2/ngx_http_v2_module.h" -HTTP_V2_SRCS="src/http/v2/ngx_http_v2.c \ - src/http/v2/ngx_http_v2_table.c \ - src/http/v2/ngx_http_v2_huff_decode.c \ - src/http/v2/ngx_http_v2_huff_encode.c \ - src/http/v2/ngx_http_v2_module.c \ - src/http/v2/ngx_http_v2_filter_module.c" - - -HTTP_CHARSET_FILTER_MODULE=ngx_http_charset_filter_module -HTTP_CHARSET_SRCS=src/http/modules/ngx_http_charset_filter_module.c - - -HTTP_GZIP_FILTER_MODULE=ngx_http_gzip_filter_module -HTTP_GZIP_SRCS=src/http/modules/ngx_http_gzip_filter_module.c - - -HTTP_GUNZIP_FILTER_MODULE=ngx_http_gunzip_filter_module -HTTP_GUNZIP_SRCS=src/http/modules/ngx_http_gunzip_filter_module.c - - -HTTP_SSI_FILTER_MODULE=ngx_http_ssi_filter_module -HTTP_SSI_DEPS=src/http/modules/ngx_http_ssi_filter_module.h -HTTP_SSI_SRCS=src/http/modules/ngx_http_ssi_filter_module.c - - -HTTP_XSLT_FILTER_MODULE=ngx_http_xslt_filter_module -HTTP_XSLT_SRCS=src/http/modules/ngx_http_xslt_filter_module.c - - -HTTP_IMAGE_FILTER_MODULE=ngx_http_image_filter_module -HTTP_IMAGE_SRCS=src/http/modules/ngx_http_image_filter_module.c - - -HTTP_SUB_FILTER_MODULE=ngx_http_sub_filter_module -HTTP_SUB_SRCS=src/http/modules/ngx_http_sub_filter_module.c - - -HTTP_USERID_FILTER_MODULE=ngx_http_userid_filter_module -HTTP_USERID_SRCS=src/http/modules/ngx_http_userid_filter_module.c - - -HTTP_SLICE_FILTER_MODULE=ngx_http_slice_filter_module -HTTP_SLICE_SRCS=src/http/modules/ngx_http_slice_filter_module.c - - -HTTP_REALIP_MODULE=ngx_http_realip_module -HTTP_REALIP_SRCS=src/http/modules/ngx_http_realip_module.c - - -HTTP_ADDITION_FILTER_MODULE=ngx_http_addition_filter_module -HTTP_ADDITION_SRCS=src/http/modules/ngx_http_addition_filter_module.c - - -HTTP_DAV_MODULE=ngx_http_dav_module -HTTP_DAV_SRCS=src/http/modules/ngx_http_dav_module.c - - -HTTP_ACCESS_MODULE=ngx_http_access_module -HTTP_ACCESS_SRCS=src/http/modules/ngx_http_access_module.c - - -HTTP_AUTH_BASIC_MODULE=ngx_http_auth_basic_module -HTTP_AUTH_BASIC_SRCS=src/http/modules/ngx_http_auth_basic_module.c - - -HTTP_AUTH_REQUEST_MODULE=ngx_http_auth_request_module -HTTP_AUTH_REQUEST_SRCS=src/http/modules/ngx_http_auth_request_module.c - - -HTTP_AUTOINDEX_MODULE=ngx_http_autoindex_module -HTTP_AUTOINDEX_SRCS=src/http/modules/ngx_http_autoindex_module.c - - -HTTP_RANDOM_INDEX_MODULE=ngx_http_random_index_module -HTTP_RANDOM_INDEX_SRCS=src/http/modules/ngx_http_random_index_module.c - - -HTTP_STATUS_MODULE=ngx_http_status_module -HTTP_STATUS_SRCS=src/http/modules/ngx_http_status_module.c - - -HTTP_GEO_MODULE=ngx_http_geo_module -HTTP_GEO_SRCS=src/http/modules/ngx_http_geo_module.c - - -HTTP_GEOIP_MODULE=ngx_http_geoip_module -HTTP_GEOIP_SRCS=src/http/modules/ngx_http_geoip_module.c - - -HTTP_MAP_MODULE=ngx_http_map_module -HTTP_MAP_SRCS=src/http/modules/ngx_http_map_module.c - - -HTTP_SPLIT_CLIENTS_MODULE=ngx_http_split_clients_module -HTTP_SPLIT_CLIENTS_SRCS=src/http/modules/ngx_http_split_clients_module.c - - -HTTP_REFERER_MODULE=ngx_http_referer_module -HTTP_REFERER_SRCS=src/http/modules/ngx_http_referer_module.c - - -HTTP_REWRITE_MODULE=ngx_http_rewrite_module -HTTP_REWRITE_SRCS=src/http/modules/ngx_http_rewrite_module.c - - -HTTP_SSL_MODULE=ngx_http_ssl_module -HTTP_SSL_DEPS=src/http/modules/ngx_http_ssl_module.h -HTTP_SSL_SRCS=src/http/modules/ngx_http_ssl_module.c - - -HTTP_PROXY_MODULE=ngx_http_proxy_module -HTTP_PROXY_SRCS=src/http/modules/ngx_http_proxy_module.c - - -HTTP_FASTCGI_MODULE=ngx_http_fastcgi_module -HTTP_FASTCGI_SRCS=src/http/modules/ngx_http_fastcgi_module.c - - -HTTP_UWSGI_MODULE=ngx_http_uwsgi_module -HTTP_UWSGI_SRCS=src/http/modules/ngx_http_uwsgi_module.c - - -HTTP_SCGI_MODULE=ngx_http_scgi_module -HTTP_SCGI_SRCS=src/http/modules/ngx_http_scgi_module.c - - -HTTP_PERL_MODULE=ngx_http_perl_module -HTTP_PERL_INCS=src/http/modules/perl -HTTP_PERL_DEPS=src/http/modules/perl/ngx_http_perl_module.h -HTTP_PERL_SRCS=src/http/modules/perl/ngx_http_perl_module.c - - -HTTP_MEMCACHED_MODULE=ngx_http_memcached_module -HTTP_MEMCACHED_SRCS=src/http/modules/ngx_http_memcached_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 -HTTP_LIMIT_REQ_SRCS=src/http/modules/ngx_http_limit_req_module.c - - -HTTP_EMPTY_GIF_MODULE=ngx_http_empty_gif_module -HTTP_EMPTY_GIF_SRCS=src/http/modules/ngx_http_empty_gif_module.c - - -HTTP_BROWSER_MODULE=ngx_http_browser_module -HTTP_BROWSER_SRCS=src/http/modules/ngx_http_browser_module.c - - -HTTP_SECURE_LINK_MODULE=ngx_http_secure_link_module -HTTP_SECURE_LINK_SRCS=src/http/modules/ngx_http_secure_link_module.c - - -HTTP_DEGRADATION_MODULE=ngx_http_degradation_module -HTTP_DEGRADATION_SRCS=src/http/modules/ngx_http_degradation_module.c - - -HTTP_FLV_MODULE=ngx_http_flv_module -HTTP_FLV_SRCS=src/http/modules/ngx_http_flv_module.c - - -HTTP_MP4_MODULE=ngx_http_mp4_module -HTTP_MP4_SRCS=src/http/modules/ngx_http_mp4_module.c - - -HTTP_GZIP_STATIC_MODULE=ngx_http_gzip_static_module -HTTP_GZIP_STATIC_SRCS=src/http/modules/ngx_http_gzip_static_module.c - - -HTTP_UPSTREAM_HASH_MODULE=ngx_http_upstream_hash_module -HTTP_UPSTREAM_HASH_SRCS=src/http/modules/ngx_http_upstream_hash_module.c - - -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_LEAST_CONN_MODULE=ngx_http_upstream_least_conn_module -HTTP_UPSTREAM_LEAST_CONN_SRCS=" \ - src/http/modules/ngx_http_upstream_least_conn_module.c" - - -HTTP_UPSTREAM_KEEPALIVE_MODULE=ngx_http_upstream_keepalive_module -HTTP_UPSTREAM_KEEPALIVE_SRCS=" \ - src/http/modules/ngx_http_upstream_keepalive_module.c" - - -HTTP_UPSTREAM_ZONE_MODULE=ngx_http_upstream_zone_module -HTTP_UPSTREAM_ZONE_SRCS=" \ - src/http/modules/ngx_http_upstream_zone_module.c" - - -MAIL_INCS="src/mail" - -MAIL_DEPS="src/mail/ngx_mail.h" - -MAIL_MODULES="ngx_mail_module ngx_mail_core_module" - -MAIL_SRCS="src/mail/ngx_mail.c \ - src/mail/ngx_mail_core_module.c \ - src/mail/ngx_mail_handler.c \ - src/mail/ngx_mail_parse.c" - -MAIL_POP3_MODULE="ngx_mail_pop3_module" -MAIL_POP3_DEPS="src/mail/ngx_mail_pop3_module.h" -MAIL_POP3_SRCS="src/mail/ngx_mail_pop3_module.c \ - src/mail/ngx_mail_pop3_handler.c" - -MAIL_IMAP_MODULE="ngx_mail_imap_module" -MAIL_IMAP_DEPS="src/mail/ngx_mail_imap_module.h" -MAIL_IMAP_SRCS="src/mail/ngx_mail_imap_module.c \ - src/mail/ngx_mail_imap_handler.c" - -MAIL_SMTP_MODULE="ngx_mail_smtp_module" -MAIL_SMTP_DEPS="src/mail/ngx_mail_smtp_module.h" -MAIL_SMTP_SRCS="src/mail/ngx_mail_smtp_module.c \ - src/mail/ngx_mail_smtp_handler.c" - -MAIL_SSL_MODULE="ngx_mail_ssl_module" -MAIL_SSL_DEPS="src/mail/ngx_mail_ssl_module.h" -MAIL_SSL_SRCS="src/mail/ngx_mail_ssl_module.c" - -MAIL_AUTH_HTTP_MODULE="ngx_mail_auth_http_module" -MAIL_AUTH_HTTP_SRCS="src/mail/ngx_mail_auth_http_module.c" - -MAIL_PROXY_MODULE="ngx_mail_proxy_module" -MAIL_PROXY_SRCS="src/mail/ngx_mail_proxy_module.c" - - -STREAM_INCS="src/stream" - -STREAM_DEPS="src/stream/ngx_stream.h \ - src/stream/ngx_stream_upstream.h \ - src/stream/ngx_stream_upstream_round_robin.h" - -STREAM_MODULES="ngx_stream_module \ - ngx_stream_core_module \ - ngx_stream_proxy_module \ - ngx_stream_upstream_module" - -STREAM_SRCS="src/stream/ngx_stream.c \ - src/stream/ngx_stream_handler.c \ - src/stream/ngx_stream_core_module.c \ - src/stream/ngx_stream_proxy_module.c \ - src/stream/ngx_stream_upstream.c \ - src/stream/ngx_stream_upstream_round_robin.c" - -STREAM_SSL_MODULE="ngx_stream_ssl_module" -STREAM_SSL_DEPS="src/stream/ngx_stream_ssl_module.h" -STREAM_SSL_SRCS="src/stream/ngx_stream_ssl_module.c" - -STREAM_LIMIT_CONN_MODULE=ngx_stream_limit_conn_module -STREAM_LIMIT_CONN_SRCS=src/stream/ngx_stream_limit_conn_module.c - -STREAM_ACCESS_MODULE=ngx_stream_access_module -STREAM_ACCESS_SRCS=src/stream/ngx_stream_access_module.c - -STREAM_UPSTREAM_HASH_MODULE=ngx_stream_upstream_hash_module -STREAM_UPSTREAM_HASH_SRCS=src/stream/ngx_stream_upstream_hash_module.c - -STREAM_UPSTREAM_LEAST_CONN_MODULE=ngx_stream_upstream_least_conn_module -STREAM_UPSTREAM_LEAST_CONN_SRCS=" \ - src/stream/ngx_stream_upstream_least_conn_module.c" - -STREAM_UPSTREAM_ZONE_MODULE=ngx_stream_upstream_zone_module -STREAM_UPSTREAM_ZONE_SRCS=src/stream/ngx_stream_upstream_zone_module.c - - -NGX_GOOGLE_PERFTOOLS_MODULE=ngx_google_perftools_module -NGX_GOOGLE_PERFTOOLS_SRCS=src/misc/ngx_google_perftools_module.c - -NGX_CPP_TEST_SRCS=src/misc/ngx_cpp_test_module.cpp diff --git a/auto/summary b/auto/summary index 1be975d..dc8fe4f 100644 --- a/auto/summary +++ b/auto/summary @@ -60,6 +60,7 @@ echo cat << END nginx path prefix: "$NGX_PREFIX" nginx binary file: "$NGX_SBIN_PATH" + nginx modules path: "$NGX_MODULES_PATH" nginx configuration prefix: "$NGX_CONF_PREFIX" nginx configuration file: "$NGX_CONF_PATH" nginx pid file: "$NGX_PID_PATH" diff --git a/auto/unix b/auto/unix index 7bfca8f..e07df08 100755 --- a/auto/unix +++ b/auto/unix @@ -255,12 +255,12 @@ ngx_feature_test="struct statvfs fs; ngx_feature="dlopen()" -ngx_feature_name= +ngx_feature_name="NGX_HAVE_DLOPEN" ngx_feature_run=no ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs= -ngx_feature_test="dlopen(NULL, 0)" +ngx_feature_test="dlopen(NULL, 0); dlsym(NULL, NULL)" . auto/feature @@ -271,7 +271,7 @@ if [ $ngx_found != yes ]; then . auto/feature if [ $ngx_found = yes ]; then - NGX_LIBDL="-ldl" + CORE_LIBS="$CORE_LIBS -ldl" fi fi diff --git a/src/core/nginx.c b/src/core/nginx.c index 64db381..6ce030c 100644 --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -24,6 +24,10 @@ static char *ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_set_worker_processes(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_load_module(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +#if (NGX_HAVE_DLOPEN) +static void ngx_unload_module(void *data); +#endif static ngx_conf_enum_t ngx_debug_points[] = { @@ -133,6 +137,13 @@ static ngx_command_t ngx_core_commands[] = { 0, NULL }, + { ngx_string("load_module"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, + ngx_load_module, + 0, + 0, + NULL }, + ngx_null_command }; @@ -160,8 +171,6 @@ ngx_module_t ngx_core_module = { }; -ngx_uint_t ngx_max_module; - static ngx_uint_t ngx_show_help; static ngx_uint_t ngx_show_version; static ngx_uint_t ngx_show_configure; @@ -260,9 +269,8 @@ main(int argc, char *const *argv) return 1; } - ngx_max_module = 0; - for (i = 0; ngx_modules[i]; i++) { - ngx_modules[i]->index = ngx_max_module++; + if (ngx_preinit_modules() != NGX_OK) { + return 1; } cycle = ngx_init_cycle(&init_cycle); @@ -1406,3 +1414,101 @@ ngx_set_worker_processes(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_OK; } + + +static char * +ngx_load_module(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ +#if (NGX_HAVE_DLOPEN) + void *handle; + char **names, **order; + ngx_str_t *value, file; + ngx_uint_t i; + ngx_module_t *module, **modules; + ngx_pool_cleanup_t *cln; + + if (cf->cycle->modules_used) { + return "is specified too late"; + } + + value = cf->args->elts; + + file = value[1]; + + if (ngx_conf_full_name(cf->cycle, &file, 0) != NGX_OK) { + return NGX_CONF_ERROR; + } + + cln = ngx_pool_cleanup_add(cf->cycle->pool, 0); + if (cln == NULL) { + return NGX_CONF_ERROR; + } + + handle = ngx_dlopen(file.data); + if (handle == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + ngx_dlopen_n " \"%s\" failed (%s)", + file.data, ngx_dlerror()); + return NGX_CONF_ERROR; + } + + cln->handler = ngx_unload_module; + cln->data = handle; + + modules = ngx_dlsym(handle, "ngx_modules"); + if (modules == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + ngx_dlsym_n " \"%V\", \"%s\" failed (%s)", + &value[1], "ngx_modules", ngx_dlerror()); + return NGX_CONF_ERROR; + } + + names = ngx_dlsym(handle, "ngx_module_names"); + if (names == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + ngx_dlsym_n " \"%V\", \"%s\" failed (%s)", + &value[1], "ngx_module_names", ngx_dlerror()); + return NGX_CONF_ERROR; + } + + order = ngx_dlsym(handle, "ngx_module_order"); + + for (i = 0; modules[i]; i++) { + module = modules[i]; + module->name = names[i]; + + if (ngx_add_module(cf, &file, module, order) != NGX_OK) { + return NGX_CONF_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, cf->log, 0, "module: %s i:%i", + module->name, module->index); + } + + return NGX_CONF_OK; + +#else + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"load_module\" is not supported " + "on this platform"); + return NGX_CONF_ERROR; + +#endif +} + + +#if (NGX_HAVE_DLOPEN) + +static void +ngx_unload_module(void *data) +{ + void *handle = data; + + if (ngx_dlclose(handle) != 0) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + ngx_dlclose_n " failed (%s)", ngx_dlerror()); + } +} + +#endif diff --git a/src/core/nginx.h b/src/core/nginx.h index 0960afb..e416e90 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1009010 -#define NGINX_VERSION "1.9.10" +#define nginx_version 1009011 +#define NGINX_VERSION "1.9.11" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c index 1c3238c..fb72656 100644 --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -329,9 +329,9 @@ ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last) found = 0; - for (i = 0; ngx_modules[i]; i++) { + for (i = 0; cf->cycle->modules[i]; i++) { - cmd = ngx_modules[i]->commands; + cmd = cf->cycle->modules[i]->commands; if (cmd == NULL) { continue; } @@ -348,8 +348,8 @@ ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last) found = 1; - if (ngx_modules[i]->type != NGX_CONF_MODULE - && ngx_modules[i]->type != cf->module_type) + if (cf->cycle->modules[i]->type != NGX_CONF_MODULE + && cf->cycle->modules[i]->type != cf->module_type) { continue; } @@ -411,16 +411,16 @@ ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last) conf = NULL; if (cmd->type & NGX_DIRECT_CONF) { - conf = ((void **) cf->ctx)[ngx_modules[i]->index]; + conf = ((void **) cf->ctx)[cf->cycle->modules[i]->index]; } else if (cmd->type & NGX_MAIN_CONF) { - conf = &(((void **) cf->ctx)[ngx_modules[i]->index]); + conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]); } else if (cf->ctx) { confp = *(void **) ((char *) cf->ctx + cmd->conf); if (confp) { - conf = confp[ngx_modules[i]->ctx_index]; + conf = confp[cf->cycle->modules[i]->ctx_index]; } } diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h index 2d03f43..9ccee36 100644 --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -96,53 +96,6 @@ struct ngx_open_file_s { }; -#define NGX_MODULE_V1 0, 0, 0, 0, 0, 0, 1 -#define NGX_MODULE_V1_PADDING 0, 0, 0, 0, 0, 0, 0, 0 - -struct ngx_module_s { - ngx_uint_t ctx_index; - ngx_uint_t index; - - ngx_uint_t spare0; - ngx_uint_t spare1; - ngx_uint_t spare2; - ngx_uint_t spare3; - - ngx_uint_t version; - - void *ctx; - ngx_command_t *commands; - ngx_uint_t type; - - ngx_int_t (*init_master)(ngx_log_t *log); - - ngx_int_t (*init_module)(ngx_cycle_t *cycle); - - ngx_int_t (*init_process)(ngx_cycle_t *cycle); - ngx_int_t (*init_thread)(ngx_cycle_t *cycle); - void (*exit_thread)(ngx_cycle_t *cycle); - void (*exit_process)(ngx_cycle_t *cycle); - - void (*exit_master)(ngx_cycle_t *cycle); - - uintptr_t spare_hook0; - uintptr_t spare_hook1; - uintptr_t spare_hook2; - uintptr_t spare_hook3; - uintptr_t spare_hook4; - uintptr_t spare_hook5; - uintptr_t spare_hook6; - uintptr_t spare_hook7; -}; - - -typedef struct { - ngx_str_t name; - void *(*create_conf)(ngx_cycle_t *cycle); - char *(*init_conf)(ngx_cycle_t *cycle, void *conf); -} ngx_core_module_t; - - typedef struct { ngx_file_t file; ngx_buf_t *buffer; @@ -340,8 +293,4 @@ char *ngx_conf_set_enum_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); char *ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -extern ngx_uint_t ngx_max_module; -extern ngx_module_t *ngx_modules[]; - - #endif /* _NGX_CONF_FILE_H_INCLUDED_ */ diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h index 6b31705..2819c1a 100644 --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -53,6 +53,7 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c); #include #include #include +#include #include #include #include @@ -83,6 +84,7 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c); #endif #include #include +#include #include #include #include diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c index ad4bf92..f103266 100644 --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -212,12 +212,18 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len); - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->type != NGX_CORE_MODULE) { + if (ngx_cycle_modules(cycle) != NGX_OK) { + ngx_destroy_pool(pool); + return NULL; + } + + + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->type != NGX_CORE_MODULE) { continue; } - module = ngx_modules[i]->ctx; + module = cycle->modules[i]->ctx; if (module->create_conf) { rv = module->create_conf(cycle); @@ -225,7 +231,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) ngx_destroy_pool(pool); return NULL; } - cycle->conf_ctx[ngx_modules[i]->index] = rv; + cycle->conf_ctx[cycle->modules[i]->index] = rv; } } @@ -276,15 +282,16 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) cycle->conf_file.data); } - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->type != NGX_CORE_MODULE) { + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->type != NGX_CORE_MODULE) { continue; } - module = ngx_modules[i]->ctx; + module = cycle->modules[i]->ctx; if (module->init_conf) { - if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index]) + if (module->init_conf(cycle, + cycle->conf_ctx[cycle->modules[i]->index]) == NGX_CONF_ERROR) { environ = senv; @@ -612,13 +619,9 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) pool->log = cycle->log; - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->init_module) { - if (ngx_modules[i]->init_module(cycle) != NGX_OK) { - /* fatal */ - exit(1); - } - } + if (ngx_init_modules(cycle) != NGX_OK) { + /* fatal */ + exit(1); } diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h index a730efe..27401d0 100644 --- a/src/core/ngx_cycle.h +++ b/src/core/ngx_cycle.h @@ -48,6 +48,10 @@ struct ngx_cycle_s { ngx_connection_t *free_connections; ngx_uint_t free_connection_n; + ngx_module_t **modules; + ngx_uint_t modules_n; + ngx_uint_t modules_used; /* unsigned modules_used:1; */ + ngx_queue_t reusable_connections_queue; ngx_array_t listening; diff --git a/src/core/ngx_module.c b/src/core/ngx_module.c new file mode 100644 index 0000000..1e947c9 --- /dev/null +++ b/src/core/ngx_module.c @@ -0,0 +1,361 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Maxim Dounin + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +#define NGX_MAX_DYNAMIC_MODULES 128 + + +static ngx_uint_t ngx_module_index(ngx_cycle_t *cycle); +static ngx_uint_t ngx_module_ctx_index(ngx_cycle_t *cycle, ngx_uint_t type, + ngx_uint_t index); + + +ngx_uint_t ngx_max_module; +static ngx_uint_t ngx_modules_n; + + +ngx_int_t +ngx_preinit_modules() +{ + ngx_uint_t i; + + ngx_max_module = 0; + for (i = 0; ngx_modules[i]; i++) { + ngx_modules[i]->index = i; + ngx_modules[i]->name = ngx_module_names[i]; + } + + ngx_modules_n = i; + ngx_max_module = ngx_modules_n + NGX_MAX_DYNAMIC_MODULES; + + return NGX_OK; +} + + +ngx_int_t +ngx_cycle_modules(ngx_cycle_t *cycle) +{ + /* + * create a list of modules to be used for this cycle, + * copy static modules to it + */ + + cycle->modules = ngx_pcalloc(cycle->pool, (ngx_max_module + 1) + * sizeof(ngx_module_t *)); + if (cycle->modules == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(cycle->modules, ngx_modules, + ngx_modules_n * sizeof(ngx_module_t *)); + + cycle->modules_n = ngx_modules_n; + + return NGX_OK; +} + + +ngx_int_t +ngx_init_modules(ngx_cycle_t *cycle) +{ + ngx_uint_t i; + + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->init_module) { + if (cycle->modules[i]->init_module(cycle) != NGX_OK) { + return NGX_ERROR; + } + } + } + + return NGX_OK; +} + + +ngx_int_t +ngx_count_modules(ngx_cycle_t *cycle, ngx_uint_t type) +{ + ngx_uint_t i, next, max; + ngx_module_t *module; + + next = 0; + max = 0; + + /* count appropriate modules, set up their indices */ + + for (i = 0; cycle->modules[i]; i++) { + module = cycle->modules[i]; + + if (module->type != type) { + continue; + } + + if (module->ctx_index != NGX_MODULE_UNSET_INDEX) { + + /* if ctx_index was assigned, preserve it */ + + if (module->ctx_index > max) { + max = module->ctx_index; + } + + if (module->ctx_index == next) { + next++; + } + + continue; + } + + /* search for some free index */ + + module->ctx_index = ngx_module_ctx_index(cycle, type, next); + + if (module->ctx_index > max) { + max = module->ctx_index; + } + + next = module->ctx_index + 1; + } + + /* + * make sure the number returned is big enough for previous + * cycle as well, else there will be problems if the number + * will be stored in a global variable (as it's used to be) + * and we'll have to roll back to the previous cycle + */ + + if (cycle->old_cycle && cycle->old_cycle->modules) { + + for (i = 0; cycle->old_cycle->modules[i]; i++) { + module = cycle->old_cycle->modules[i]; + + if (module->type != type) { + continue; + } + + if (module->ctx_index > max) { + max = module->ctx_index; + } + } + } + + /* prevent loading of additional modules */ + + cycle->modules_used = 1; + + return max + 1; +} + + +ngx_int_t +ngx_add_module(ngx_conf_t *cf, ngx_str_t *file, ngx_module_t *module, + char **order) +{ + void *rv; + ngx_uint_t i, m, before; + ngx_core_module_t *core_module; + + if (cf->cycle->modules_n >= ngx_max_module) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "too many modules loaded"); + return NGX_ERROR; + } + + if (module->version != nginx_version) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "module \"%V\" version %ui instead of %ui", + file, module->version, nginx_version); + return NGX_ERROR; + } + + if (ngx_strcmp(module->signature, NGX_MODULE_SIGNATURE) != 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "module \"%V\" is not binary compatible", + file); + return NGX_ERROR; + } + + for (m = 0; cf->cycle->modules[m]; m++) { + if (ngx_strcmp(cf->cycle->modules[m]->name, module->name) == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "module \"%s\" is already loaded", + module->name); + return NGX_ERROR; + } + } + + /* + * if the module wasn't previously loaded, assign an index + */ + + if (module->index == NGX_MODULE_UNSET_INDEX) { + module->index = ngx_module_index(cf->cycle); + + if (module->index >= ngx_max_module) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "too many modules loaded"); + return NGX_ERROR; + } + } + + /* + * put the module into the cycle->modules array + */ + + before = cf->cycle->modules_n; + + if (order) { + for (i = 0; order[i]; i++) { + if (ngx_strcmp(order[i], module->name) == 0) { + i++; + break; + } + } + + for ( /* void */ ; order[i]; i++) { + +#if 0 + ngx_log_debug2(NGX_LOG_DEBUG_CORE, cf->log, 0, + "module: %s before %s", + module->name, order[i]); +#endif + + for (m = 0; m < before; m++) { + if (ngx_strcmp(cf->cycle->modules[m]->name, order[i]) == 0) { + + ngx_log_debug3(NGX_LOG_DEBUG_CORE, cf->log, 0, + "module: %s before %s:%i", + module->name, order[i], m); + + before = m; + break; + } + } + } + } + + /* put the module before modules[before] */ + + if (before != cf->cycle->modules_n) { + ngx_memmove(&cf->cycle->modules[before + 1], + &cf->cycle->modules[before], + (cf->cycle->modules_n - before) * sizeof(ngx_module_t *)); + } + + cf->cycle->modules[before] = module; + cf->cycle->modules_n++; + + if (module->type == NGX_CORE_MODULE) { + + /* + * we are smart enough to initialize core modules; + * other modules are expected to be loaded before + * initialization - e.g., http modules must be loaded + * before http{} block + */ + + core_module = module->ctx; + + if (core_module->create_conf) { + rv = core_module->create_conf(cf->cycle); + if (rv == NULL) { + return NGX_ERROR; + } + + cf->cycle->conf_ctx[module->index] = rv; + } + } + + return NGX_OK; +} + + +static ngx_uint_t +ngx_module_index(ngx_cycle_t *cycle) +{ + ngx_uint_t i, index; + ngx_module_t *module; + + index = 0; + +again: + + /* find an unused index */ + + for (i = 0; cycle->modules[i]; i++) { + module = cycle->modules[i]; + + if (module->index == index) { + index++; + goto again; + } + } + + /* check previous cycle */ + + if (cycle->old_cycle && cycle->old_cycle->modules) { + + for (i = 0; cycle->old_cycle->modules[i]; i++) { + module = cycle->old_cycle->modules[i]; + + if (module->index == index) { + index++; + goto again; + } + } + } + + return index; +} + + +static ngx_uint_t +ngx_module_ctx_index(ngx_cycle_t *cycle, ngx_uint_t type, ngx_uint_t index) +{ + ngx_uint_t i; + ngx_module_t *module; + +again: + + /* find an unused ctx_index */ + + for (i = 0; cycle->modules[i]; i++) { + module = cycle->modules[i]; + + if (module->type != type) { + continue; + } + + if (module->ctx_index == index) { + index++; + goto again; + } + } + + /* check previous cycle */ + + if (cycle->old_cycle && cycle->old_cycle->modules) { + + for (i = 0; cycle->old_cycle->modules[i]; i++) { + module = cycle->old_cycle->modules[i]; + + if (module->type != type) { + continue; + } + + if (module->ctx_index == index) { + index++; + goto again; + } + } + } + + return index; +} diff --git a/src/core/ngx_module.h b/src/core/ngx_module.h new file mode 100644 index 0000000..cd28c49 --- /dev/null +++ b/src/core/ngx_module.h @@ -0,0 +1,307 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Maxim Dounin + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_MODULE_H_INCLUDED_ +#define _NGX_MODULE_H_INCLUDED_ + + +#include +#include +#include + + +#define NGX_MODULE_UNSET_INDEX (ngx_uint_t) -1 + + +#define NGX_MODULE_SIGNATURE_0 \ + ngx_value(NGX_PTR_SIZE) "," \ + ngx_value(NGX_SIG_ATOMIC_T_SIZE) "," \ + ngx_value(NGX_TIME_T_SIZE) "," + +#if (NGX_HAVE_KQUEUE) +#define NGX_MODULE_SIGNATURE_1 "1" +#else +#define NGX_MODULE_SIGNATURE_1 "0" +#endif + +#if (NGX_HAVE_IOCP) +#define NGX_MODULE_SIGNATURE_2 "1" +#else +#define NGX_MODULE_SIGNATURE_2 "0" +#endif + +#if (NGX_HAVE_FILE_AIO) +#define NGX_MODULE_SIGNATURE_3 "1" +#else +#define NGX_MODULE_SIGNATURE_3 "0" +#endif + +#if (NGX_HAVE_AIO_SENDFILE) +#define NGX_MODULE_SIGNATURE_4 "1" +#else +#define NGX_MODULE_SIGNATURE_4 "0" +#endif + +#if (NGX_HAVE_EVENTFD) +#define NGX_MODULE_SIGNATURE_5 "1" +#else +#define NGX_MODULE_SIGNATURE_5 "0" +#endif + +#if (NGX_HAVE_EPOLL) +#define NGX_MODULE_SIGNATURE_6 "1" +#else +#define NGX_MODULE_SIGNATURE_6 "0" +#endif + +#if (NGX_HAVE_KEEPALIVE_TUNABLE) +#define NGX_MODULE_SIGNATURE_7 "1" +#else +#define NGX_MODULE_SIGNATURE_7 "0" +#endif + +#if (NGX_HAVE_INET6) +#define NGX_MODULE_SIGNATURE_8 "1" +#else +#define NGX_MODULE_SIGNATURE_8 "0" +#endif + +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) +#define NGX_MODULE_SIGNATURE_9 "1" +#else +#define NGX_MODULE_SIGNATURE_9 "0" +#endif + +#if (NGX_HAVE_REUSEPORT) +#define NGX_MODULE_SIGNATURE_10 "1" +#else +#define NGX_MODULE_SIGNATURE_10 "0" +#endif + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) +#define NGX_MODULE_SIGNATURE_11 "1" +#else +#define NGX_MODULE_SIGNATURE_11 "0" +#endif + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) +#define NGX_MODULE_SIGNATURE_12 "1" +#else +#define NGX_MODULE_SIGNATURE_12 "0" +#endif + +#if (NGX_HAVE_SETFIB) +#define NGX_MODULE_SIGNATURE_13 "1" +#else +#define NGX_MODULE_SIGNATURE_13 "0" +#endif + +#if (NGX_HAVE_TCP_FASTOPEN) +#define NGX_MODULE_SIGNATURE_14 "1" +#else +#define NGX_MODULE_SIGNATURE_14 "0" +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) +#define NGX_MODULE_SIGNATURE_15 "1" +#else +#define NGX_MODULE_SIGNATURE_15 "0" +#endif + +#if (NGX_HAVE_VARIADIC_MACROS) +#define NGX_MODULE_SIGNATURE_16 "1" +#else +#define NGX_MODULE_SIGNATURE_16 "0" +#endif + +#if (NGX_HAVE_MD5) +#define NGX_MODULE_SIGNATURE_17 "1" +#else +#define NGX_MODULE_SIGNATURE_17 "0" +#endif + +#if (NGX_HAVE_SHA1) +#define NGX_MODULE_SIGNATURE_18 "1" +#else +#define NGX_MODULE_SIGNATURE_18 "0" +#endif + +#if (NGX_HAVE_OPENAT) +#define NGX_MODULE_SIGNATURE_19 "1" +#else +#define NGX_MODULE_SIGNATURE_19 "0" +#endif + +#if (NGX_HAVE_ATOMIC_OPS) +#define NGX_MODULE_SIGNATURE_20 "1" +#else +#define NGX_MODULE_SIGNATURE_20 "0" +#endif + +#if (NGX_HAVE_POSIX_SEM) +#define NGX_MODULE_SIGNATURE_21 "1" +#else +#define NGX_MODULE_SIGNATURE_21 "0" +#endif + +#if (NGX_THREADS) +#define NGX_MODULE_SIGNATURE_22 "1" +#else +#define NGX_MODULE_SIGNATURE_22 "0" +#endif + +#if (NGX_PCRE) +#define NGX_MODULE_SIGNATURE_23 "1" +#else +#define NGX_MODULE_SIGNATURE_23 "0" +#endif + +#if (NGX_HTTP_SSL) +#define NGX_MODULE_SIGNATURE_24 "1" +#else +#define NGX_MODULE_SIGNATURE_24 "0" +#endif + +#if (NGX_HTTP_V2) +#define NGX_MODULE_SIGNATURE_25 "1" +#else +#define NGX_MODULE_SIGNATURE_25 "0" +#endif + +#if (NGX_HTTP_GZIP) +#define NGX_MODULE_SIGNATURE_26 "1" +#else +#define NGX_MODULE_SIGNATURE_26 "0" +#endif + +#if (NGX_HTTP_DEGRADATION) +#define NGX_MODULE_SIGNATURE_27 "1" +#else +#define NGX_MODULE_SIGNATURE_27 "0" +#endif + +#if (NGX_HTTP_X_FORWARDED_FOR) +#define NGX_MODULE_SIGNATURE_28 "1" +#else +#define NGX_MODULE_SIGNATURE_28 "0" +#endif + +#if (NGX_HTTP_REALIP) +#define NGX_MODULE_SIGNATURE_29 "1" +#else +#define NGX_MODULE_SIGNATURE_29 "0" +#endif + +#if (NGX_HTTP_HEADERS) +#define NGX_MODULE_SIGNATURE_30 "1" +#else +#define NGX_MODULE_SIGNATURE_30 "0" +#endif + +#if (NGX_HTTP_DAV) +#define NGX_MODULE_SIGNATURE_31 "1" +#else +#define NGX_MODULE_SIGNATURE_31 "0" +#endif + +#if (NGX_HTTP_CACHE) +#define NGX_MODULE_SIGNATURE_32 "1" +#else +#define NGX_MODULE_SIGNATURE_32 "0" +#endif + +#if (NGX_HTTP_UPSTREAM_ZONE) +#define NGX_MODULE_SIGNATURE_33 "1" +#else +#define NGX_MODULE_SIGNATURE_33 "0" +#endif + +#define NGX_MODULE_SIGNATURE \ + NGX_MODULE_SIGNATURE_0 NGX_MODULE_SIGNATURE_1 NGX_MODULE_SIGNATURE_2 \ + NGX_MODULE_SIGNATURE_3 NGX_MODULE_SIGNATURE_4 NGX_MODULE_SIGNATURE_5 \ + NGX_MODULE_SIGNATURE_6 NGX_MODULE_SIGNATURE_7 NGX_MODULE_SIGNATURE_8 \ + NGX_MODULE_SIGNATURE_9 NGX_MODULE_SIGNATURE_10 NGX_MODULE_SIGNATURE_11 \ + NGX_MODULE_SIGNATURE_12 NGX_MODULE_SIGNATURE_13 NGX_MODULE_SIGNATURE_14 \ + NGX_MODULE_SIGNATURE_15 NGX_MODULE_SIGNATURE_16 NGX_MODULE_SIGNATURE_17 \ + NGX_MODULE_SIGNATURE_18 NGX_MODULE_SIGNATURE_19 NGX_MODULE_SIGNATURE_20 \ + NGX_MODULE_SIGNATURE_21 NGX_MODULE_SIGNATURE_22 NGX_MODULE_SIGNATURE_23 \ + NGX_MODULE_SIGNATURE_24 NGX_MODULE_SIGNATURE_25 NGX_MODULE_SIGNATURE_26 \ + NGX_MODULE_SIGNATURE_27 NGX_MODULE_SIGNATURE_28 NGX_MODULE_SIGNATURE_29 \ + NGX_MODULE_SIGNATURE_30 NGX_MODULE_SIGNATURE_31 NGX_MODULE_SIGNATURE_32 \ + NGX_MODULE_SIGNATURE_33 + + +#define NGX_MODULE_V1 \ + NGX_MODULE_UNSET_INDEX, NGX_MODULE_UNSET_INDEX, \ + NULL, 0, 0, nginx_version, NGX_MODULE_SIGNATURE + +#define NGX_MODULE_V1_PADDING 0, 0, 0, 0, 0, 0, 0, 0 + + +struct ngx_module_s { + ngx_uint_t ctx_index; + ngx_uint_t index; + + char *name; + + ngx_uint_t spare0; + ngx_uint_t spare1; + + ngx_uint_t version; + char *signature; + + void *ctx; + ngx_command_t *commands; + ngx_uint_t type; + + ngx_int_t (*init_master)(ngx_log_t *log); + + ngx_int_t (*init_module)(ngx_cycle_t *cycle); + + ngx_int_t (*init_process)(ngx_cycle_t *cycle); + ngx_int_t (*init_thread)(ngx_cycle_t *cycle); + void (*exit_thread)(ngx_cycle_t *cycle); + void (*exit_process)(ngx_cycle_t *cycle); + + void (*exit_master)(ngx_cycle_t *cycle); + + uintptr_t spare_hook0; + uintptr_t spare_hook1; + uintptr_t spare_hook2; + uintptr_t spare_hook3; + uintptr_t spare_hook4; + uintptr_t spare_hook5; + uintptr_t spare_hook6; + uintptr_t spare_hook7; +}; + + +typedef struct { + ngx_str_t name; + void *(*create_conf)(ngx_cycle_t *cycle); + char *(*init_conf)(ngx_cycle_t *cycle, void *conf); +} ngx_core_module_t; + + +ngx_int_t ngx_preinit_modules(); +ngx_int_t ngx_cycle_modules(ngx_cycle_t *cycle); +ngx_int_t ngx_init_modules(ngx_cycle_t *cycle); +ngx_int_t ngx_count_modules(ngx_cycle_t *cycle, ngx_uint_t type); + + +ngx_int_t ngx_add_module(ngx_conf_t *cf, ngx_str_t *file, + ngx_module_t *module, char **order); + + +extern ngx_module_t *ngx_modules[]; +extern ngx_uint_t ngx_max_module; + +extern char *ngx_module_names[]; + + +#endif /* _NGX_MODULE_H_INCLUDED_ */ diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index 7b60abd..7f0d3ad 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -12,6 +12,9 @@ #define NGX_RESOLVER_UDP_SIZE 4096 +#define NGX_RESOLVER_TCP_RSIZE (2 + 65535) +#define NGX_RESOLVER_TCP_WSIZE 8192 + typedef struct { u_char ident_hi; @@ -53,7 +56,8 @@ typedef struct { ((u_char *) (n) - offsetof(ngx_resolver_node_t, node)) -ngx_int_t ngx_udp_connect(ngx_udp_connection_t *uc); +ngx_int_t ngx_udp_connect(ngx_resolver_connection_t *rec); +ngx_int_t ngx_tcp_connect(ngx_resolver_connection_t *rec); static void ngx_resolver_cleanup(void *data); @@ -64,6 +68,10 @@ static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue); static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn); +static ngx_int_t ngx_resolver_send_udp_query(ngx_resolver_t *r, + ngx_resolver_connection_t *rec, u_char *query, u_short qlen); +static ngx_int_t ngx_resolver_send_tcp_query(ngx_resolver_t *r, + ngx_resolver_connection_t *rec, u_char *query, u_short qlen); static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, ngx_str_t *name); static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r, @@ -72,12 +80,14 @@ static void ngx_resolver_resend_handler(ngx_event_t *ev); static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue); static ngx_uint_t ngx_resolver_resend_empty(ngx_resolver_t *r); -static void ngx_resolver_read_response(ngx_event_t *rev); +static void ngx_resolver_udp_read(ngx_event_t *rev); +static void ngx_resolver_tcp_write(ngx_event_t *wev); +static void ngx_resolver_tcp_read(ngx_event_t *rev); static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, - size_t n); + size_t n, ngx_uint_t tcp); static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype, - ngx_uint_t nan, ngx_uint_t ans); + ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans); static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan); static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r, @@ -110,12 +120,12 @@ static ngx_resolver_node_t *ngx_resolver_lookup_addr6(ngx_resolver_t *r, ngx_resolver_t * 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, j; - ngx_resolver_t *r; - ngx_pool_cleanup_t *cln; - ngx_udp_connection_t *uc; + ngx_str_t s; + ngx_url_t u; + ngx_uint_t i, j; + ngx_resolver_t *r; + ngx_pool_cleanup_t *cln; + ngx_resolver_connection_t *rec; cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { @@ -165,6 +175,7 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) r->ident = -1; r->resend_timeout = 5; + r->tcp_timeout = 5; r->expire = 30; r->valid = 0; @@ -172,8 +183,8 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) r->log_level = NGX_LOG_ERR; if (n) { - if (ngx_array_init(&r->udp_connections, cf->pool, n, - sizeof(ngx_udp_connection_t)) + if (ngx_array_init(&r->connections, cf->pool, n, + sizeof(ngx_resolver_connection_t)) != NGX_OK) { return NULL; @@ -230,17 +241,18 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) return NULL; } - uc = ngx_array_push_n(&r->udp_connections, u.naddrs); - if (uc == NULL) { + rec = ngx_array_push_n(&r->connections, u.naddrs); + if (rec == NULL) { return NULL; } - ngx_memzero(uc, u.naddrs * sizeof(ngx_udp_connection_t)); + ngx_memzero(rec, u.naddrs * sizeof(ngx_resolver_connection_t)); for (j = 0; j < u.naddrs; j++) { - uc[j].sockaddr = u.addrs[j].sockaddr; - uc[j].socklen = u.addrs[j].socklen; - uc[j].server = u.addrs[j].name; + rec[j].sockaddr = u.addrs[j].sockaddr; + rec[j].socklen = u.addrs[j].socklen; + rec[j].server = u.addrs[j].name; + rec[j].resolver = r; } } @@ -253,8 +265,8 @@ ngx_resolver_cleanup(void *data) { ngx_resolver_t *r = data; - ngx_uint_t i; - ngx_udp_connection_t *uc; + ngx_uint_t i; + ngx_resolver_connection_t *rec; if (r) { ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, @@ -273,11 +285,25 @@ ngx_resolver_cleanup(void *data) } - uc = r->udp_connections.elts; + rec = r->connections.elts; - for (i = 0; i < r->udp_connections.nelts; i++) { - if (uc[i].connection) { - ngx_close_connection(uc[i].connection); + for (i = 0; i < r->connections.nelts; i++) { + if (rec[i].udp) { + ngx_close_connection(rec[i].udp); + } + + if (rec[i].tcp) { + ngx_close_connection(rec[i].tcp); + } + + if (rec[i].read_buf) { + ngx_resolver_free(r, rec[i].read_buf->start); + ngx_resolver_free(r, rec[i].read_buf); + } + + if (rec[i].write_buf) { + ngx_resolver_free(r, rec[i].write_buf->start); + ngx_resolver_free(r, rec[i].write_buf); } } @@ -340,7 +366,7 @@ ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp) } } - if (r->udp_connections.nelts == 0) { + if (r->connections.nelts == 0) { return NGX_NO_RESOLVER; } @@ -685,9 +711,16 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, return NGX_OK; } + rn->last_connection = r->last_connection++; + if (r->last_connection == r->connections.nelts) { + r->last_connection = 0; + } + rn->naddrs = (u_short) -1; + rn->tcp = 0; #if (NGX_HAVE_INET6) rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0; + rn->tcp6 = 0; #endif if (ngx_resolver_send_query(r, rn) != NGX_OK) { @@ -897,9 +930,16 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) goto failed; } + rn->last_connection = r->last_connection++; + if (r->last_connection == r->connections.nelts) { + r->last_connection = 0; + } + rn->naddrs = (u_short) -1; + rn->tcp = 0; #if (NGX_HAVE_INET6) rn->naddrs6 = (u_short) -1; + rn->tcp6 = 0; #endif if (ngx_resolver_send_query(r, rn) != NGX_OK) { @@ -1094,64 +1134,163 @@ ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue) static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn) { - ssize_t n; - ngx_udp_connection_t *uc; + ngx_int_t rc; + ngx_resolver_connection_t *rec; - uc = r->udp_connections.elts; + rec = r->connections.elts; + rec = &rec[rn->last_connection]; - uc = &uc[r->last_connection++]; - if (r->last_connection == r->udp_connections.nelts) { - r->last_connection = 0; - } - - if (uc->connection == NULL) { - - uc->log = *r->log; - uc->log.handler = ngx_resolver_log_error; - uc->log.data = uc; - uc->log.action = "resolving"; - - if (ngx_udp_connect(uc) != NGX_OK) { - return NGX_ERROR; - } - - uc->connection->data = r; - uc->connection->read->handler = ngx_resolver_read_response; - uc->connection->read->resolver = 1; + if (rec->log.handler == NULL) { + rec->log = *r->log; + rec->log.handler = ngx_resolver_log_error; + rec->log.data = rec; + rec->log.action = "resolving"; } if (rn->naddrs == (u_short) -1) { - n = ngx_send(uc->connection, rn->query, rn->qlen); + rc = rn->tcp ? ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen) + : ngx_resolver_send_udp_query(r, rec, rn->query, rn->qlen); - if (n == -1) { - return NGX_ERROR; - } - - if ((size_t) n != (size_t) rn->qlen) { - ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete"); - return NGX_ERROR; + if (rc != NGX_OK) { + return rc; } } #if (NGX_HAVE_INET6) + if (rn->query6 && rn->naddrs6 == (u_short) -1) { - n = ngx_send(uc->connection, rn->query6, rn->qlen); + rc = rn->tcp6 + ? ngx_resolver_send_tcp_query(r, rec, rn->query6, rn->qlen) + : ngx_resolver_send_udp_query(r, rec, rn->query6, rn->qlen); - if (n == -1) { - return NGX_ERROR; - } - - if ((size_t) n != (size_t) rn->qlen) { - ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete"); - return NGX_ERROR; + if (rc != NGX_OK) { + return rc; } } + #endif return NGX_OK; } +static ngx_int_t +ngx_resolver_send_udp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec, + u_char *query, u_short qlen) +{ + ssize_t n; + + if (rec->udp == NULL) { + if (ngx_udp_connect(rec) != NGX_OK) { + return NGX_ERROR; + } + + rec->udp->data = rec; + rec->udp->read->handler = ngx_resolver_udp_read; + rec->udp->read->resolver = 1; + } + + n = ngx_send(rec->udp, query, qlen); + + if (n == -1) { + return NGX_ERROR; + } + + if ((size_t) n != (size_t) qlen) { + ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "send() incomplete"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_resolver_send_tcp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec, + u_char *query, u_short qlen) +{ + ngx_buf_t *b; + ngx_int_t rc; + + rc = NGX_OK; + + if (rec->tcp == NULL) { + b = rec->read_buf; + + if (b == NULL) { + b = ngx_resolver_calloc(r, sizeof(ngx_buf_t)); + if (b == NULL) { + return NGX_ERROR; + } + + b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_RSIZE); + if (b->start == NULL) { + ngx_resolver_free(r, b); + return NGX_ERROR; + } + + b->end = b->start + NGX_RESOLVER_TCP_RSIZE; + + rec->read_buf = b; + } + + b->pos = b->start; + b->last = b->start; + + b = rec->write_buf; + + if (b == NULL) { + b = ngx_resolver_calloc(r, sizeof(ngx_buf_t)); + if (b == NULL) { + return NGX_ERROR; + } + + b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_WSIZE); + if (b->start == NULL) { + ngx_resolver_free(r, b); + return NGX_ERROR; + } + + b->end = b->start + NGX_RESOLVER_TCP_WSIZE; + + rec->write_buf = b; + } + + b->pos = b->start; + b->last = b->start; + + rc = ngx_tcp_connect(rec); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + rec->tcp->data = rec; + rec->tcp->write->handler = ngx_resolver_tcp_write; + rec->tcp->read->handler = ngx_resolver_tcp_read; + rec->tcp->read->resolver = 1; + + ngx_add_timer(rec->tcp->write, (ngx_msec_t) (r->tcp_timeout * 1000)); + } + + b = rec->write_buf; + + if (b->end - b->last < 2 + qlen) { + ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "buffer overflow"); + return NGX_ERROR; + } + + *b->last++ = (u_char) (qlen >> 8); + *b->last++ = (u_char) qlen; + b->last = ngx_cpymem(b->last, query, qlen); + + if (rc == NGX_OK) { + ngx_resolver_tcp_write(rec->tcp->write); + } + + return NGX_OK; +} + + static void ngx_resolver_resend_handler(ngx_event_t *ev) { @@ -1244,6 +1383,10 @@ ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue) if (rn->waiting) { + if (++rn->last_connection == r->connections.nelts) { + rn->last_connection = 0; + } + (void) ngx_resolver_send_query(r, rn); rn->expire = now + r->resend_timeout; @@ -1272,13 +1415,15 @@ ngx_resolver_resend_empty(ngx_resolver_t *r) static void -ngx_resolver_read_response(ngx_event_t *rev) +ngx_resolver_udp_read(ngx_event_t *rev) { - ssize_t n; - ngx_connection_t *c; - u_char buf[NGX_RESOLVER_UDP_SIZE]; + ssize_t n; + ngx_connection_t *c; + ngx_resolver_connection_t *rec; + u_char buf[NGX_RESOLVER_UDP_SIZE]; c = rev->data; + rec = c->data; do { n = ngx_udp_recv(c, buf, NGX_RESOLVER_UDP_SIZE); @@ -1287,17 +1432,144 @@ ngx_resolver_read_response(ngx_event_t *rev) return; } - ngx_resolver_process_response(c->data, buf, n); + ngx_resolver_process_response(rec->resolver, buf, n, 0); } while (rev->ready); } static void -ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n) +ngx_resolver_tcp_write(ngx_event_t *wev) +{ + off_t sent; + ssize_t n; + ngx_buf_t *b; + ngx_resolver_t *r; + ngx_connection_t *c; + ngx_resolver_connection_t *rec; + + c = wev->data; + rec = c->data; + b = rec->write_buf; + r = rec->resolver; + + if (wev->timedout) { + goto failed; + } + + sent = c->sent; + + while (wev->ready && b->pos < b->last) { + n = ngx_send(c, b->pos, b->last - b->pos); + + if (n == NGX_AGAIN) { + break; + } + + if (n == NGX_ERROR) { + goto failed; + } + + b->pos += n; + } + + if (b->pos != b->start) { + b->last = ngx_movemem(b->start, b->pos, b->last - b->pos); + b->pos = b->start; + } + + if (c->sent != sent) { + ngx_add_timer(wev, (ngx_msec_t) (r->tcp_timeout * 1000)); + } + + if (ngx_handle_write_event(wev, 0) != NGX_OK) { + goto failed; + } + + return; + +failed: + + ngx_close_connection(c); + rec->tcp = NULL; +} + + +static void +ngx_resolver_tcp_read(ngx_event_t *rev) +{ + u_char *p; + size_t size; + ssize_t n; + u_short qlen; + ngx_buf_t *b; + ngx_resolver_t *r; + ngx_connection_t *c; + ngx_resolver_connection_t *rec; + + c = rev->data; + rec = c->data; + b = rec->read_buf; + r = rec->resolver; + + while (rev->ready) { + n = ngx_recv(c, b->last, b->end - b->last); + + if (n == NGX_AGAIN) { + break; + } + + if (n == NGX_ERROR || n == 0) { + goto failed; + } + + b->last += n; + + for ( ;; ) { + p = b->pos; + size = b->last - p; + + if (size < 2) { + break; + } + + qlen = (u_short) *p++ << 8; + qlen += *p++; + + if (size < (size_t) (2 + qlen)) { + break; + } + + ngx_resolver_process_response(r, p, qlen, 1); + + b->pos += 2 + qlen; + } + + if (b->pos != b->start) { + b->last = ngx_movemem(b->start, b->pos, b->last - b->pos); + b->pos = b->start; + } + } + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + goto failed; + } + + return; + +failed: + + ngx_close_connection(c); + rec->tcp = NULL; +} + + +static void +ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n, + ngx_uint_t tcp) { char *err; - ngx_uint_t i, times, ident, qident, flags, code, nqs, nan, + ngx_uint_t i, times, ident, qident, flags, code, nqs, nan, trunc, qtype, qclass; #if (NGX_HAVE_INET6) ngx_uint_t qident6; @@ -1317,6 +1589,7 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n) flags = (response->flags_hi << 8) + response->flags_lo; nqs = (response->nqs_hi << 8) + response->nqs_lo; nan = (response->nan_hi << 8) + response->nan_lo; + trunc = flags & 0x0200; ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver DNS response %ui fl:%04Xui %ui/%ui/%ud/%ud", @@ -1325,9 +1598,10 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n) (response->nar_hi << 8) + response->nar_lo); /* response to a standard query */ - if ((flags & 0xf870) != 0x8000) { + if ((flags & 0xf870) != 0x8000 || (trunc && tcp)) { ngx_log_error(r->log_level, r->log, 0, - "invalid DNS response %ui fl:%04Xui", ident, flags); + "invalid %s DNS response %ui fl:%04Xui", + tcp ? "TCP" : "UDP", ident, flags); return; } @@ -1417,7 +1691,7 @@ found: case NGX_RESOLVE_AAAA: #endif - ngx_resolver_process_a(r, buf, n, ident, code, qtype, nan, + ngx_resolver_process_a(r, buf, n, ident, code, qtype, nan, trunc, i + sizeof(ngx_resolver_qs_t)); break; @@ -1464,28 +1738,29 @@ dns_error: static void -ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, +ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype, - ngx_uint_t nan, ngx_uint_t ans) + ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans) { - char *err; - u_char *cname; - size_t len; - int32_t ttl; - uint32_t hash; - in_addr_t *addr; - ngx_str_t name; - ngx_addr_t *addrs; - ngx_uint_t type, class, qident, naddrs, a, i, n, start; + char *err; + u_char *cname; + size_t len; + int32_t ttl; + uint32_t hash; + in_addr_t *addr; + ngx_str_t name; + ngx_addr_t *addrs; + ngx_uint_t type, class, qident, naddrs, a, i, j, start; #if (NGX_HAVE_INET6) - struct in6_addr *addr6; + struct in6_addr *addr6; #endif - ngx_resolver_an_t *an; - ngx_resolver_ctx_t *ctx, *next; - ngx_resolver_node_t *rn; + ngx_resolver_an_t *an; + ngx_resolver_ctx_t *ctx, *next; + ngx_resolver_node_t *rn; + ngx_resolver_connection_t *rec; if (ngx_resolver_copy(r, &name, buf, - buf + sizeof(ngx_resolver_hdr_t), buf + last) + buf + sizeof(ngx_resolver_hdr_t), buf + n) != NGX_OK) { return; @@ -1518,6 +1793,11 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, goto failed; } + if (trunc && rn->tcp6) { + ngx_resolver_free(r, name.data); + goto failed; + } + qident = (rn->query6[0] << 8) + rn->query6[1]; break; @@ -1532,6 +1812,11 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, goto failed; } + if (trunc && rn->tcp) { + ngx_resolver_free(r, name.data); + goto failed; + } + qident = (rn->query[0] << 8) + rn->query[1]; } @@ -1545,6 +1830,45 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, ngx_resolver_free(r, name.data); + if (trunc) { + + ngx_queue_remove(&rn->queue); + + if (rn->waiting == NULL) { + ngx_rbtree_delete(&r->name_rbtree, &rn->node); + ngx_resolver_free_node(r, rn); + goto next; + } + + rec = r->connections.elts; + rec = &rec[rn->last_connection]; + + switch (qtype) { + +#if (NGX_HAVE_INET6) + case NGX_RESOLVE_AAAA: + + rn->tcp6 = 1; + + (void) ngx_resolver_send_tcp_query(r, rec, rn->query6, rn->qlen); + + break; +#endif + + default: /* NGX_RESOLVE_A */ + + rn->tcp = 1; + + (void) ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen); + } + + rn->expire = ngx_time() + r->resend_timeout; + + ngx_queue_insert_head(&r->name_resend_queue, &rn->queue); + + goto next; + } + if (code == 0 && rn->code) { code = rn->code; } @@ -1642,7 +1966,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, start = i; - while (i < last) { + while (i < n) { if (buf[i] & 0xc0) { i += 2; @@ -1668,7 +1992,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, found: - if (i + sizeof(ngx_resolver_an_t) >= last) { + if (i + sizeof(ngx_resolver_an_t) >= n) { goto short_response; } @@ -1708,7 +2032,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, goto invalid; } - if (i + 4 > last) { + if (i + 4 > n) { goto short_response; } @@ -1729,7 +2053,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, goto invalid; } - if (i + 16 > last) { + if (i + 16 > n) { goto short_response; } @@ -1810,7 +2134,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, #endif } - n = 0; + j = 0; i = ans; for (a = 0; a < nan; a++) { @@ -1839,10 +2163,10 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, if (type == NGX_RESOLVE_A) { - addr[n] = htonl((buf[i] << 24) + (buf[i + 1] << 16) + addr[j] = htonl((buf[i] << 24) + (buf[i + 1] << 16) + (buf[i + 2] << 8) + (buf[i + 3])); - if (++n == naddrs) { + if (++j == naddrs) { #if (NGX_HAVE_INET6) if (rn->naddrs6 == (u_short) -1) { @@ -1857,9 +2181,9 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, #if (NGX_HAVE_INET6) else if (type == NGX_RESOLVE_AAAA) { - ngx_memcpy(addr6[n].s6_addr, &buf[i], 16); + ngx_memcpy(addr6[j].s6_addr, &buf[i], 16); - if (++n == naddrs) { + if (++j == naddrs) { if (rn->naddrs == (u_short) -1) { goto next; @@ -1984,7 +2308,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, goto next; } - if (ngx_resolver_copy(r, &name, buf, cname, buf + last) != NGX_OK) { + if (ngx_resolver_copy(r, &name, buf, cname, buf + n) != NGX_OK) { goto failed; } @@ -2072,12 +2396,11 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, { char *err; size_t len; - u_char text[NGX_SOCKADDR_STRLEN]; in_addr_t addr; int32_t ttl; ngx_int_t octet; ngx_str_t name; - ngx_uint_t i, mask, qident, class; + ngx_uint_t mask, type, class, qident, a, i, start; ngx_queue_t *expire_queue; ngx_rbtree_t *tree; ngx_resolver_an_t *an; @@ -2089,13 +2412,15 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, struct in6_addr addr6; #endif - if (ngx_resolver_copy(r, NULL, buf, + if (ngx_resolver_copy(r, &name, buf, buf + sizeof(ngx_resolver_hdr_t), buf + n) != NGX_OK) { return; } + ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name); + /* AF_INET */ addr = 0; @@ -2123,10 +2448,6 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, tree = &r->addr_rbtree; expire_queue = &r->addr_expire_queue; - addr = htonl(addr); - name.len = ngx_inet_ntop(AF_INET, &addr, text, NGX_SOCKADDR_STRLEN); - name.data = text; - goto valid; } @@ -2171,9 +2492,6 @@ invalid_in_addr_arpa: tree = &r->addr6_rbtree; expire_queue = &r->addr6_expire_queue; - name.len = ngx_inet6_ntop(addr6.s6_addr, text, NGX_SOCKADDR_STRLEN); - name.data = text; - goto valid; } @@ -2182,6 +2500,7 @@ invalid_ip6_arpa: ngx_log_error(r->log_level, r->log, 0, "invalid in-addr.arpa or ip6.arpa name in DNS response"); + ngx_resolver_free(r, name.data); return; valid: @@ -2189,6 +2508,7 @@ valid: if (rn == NULL || rn->query == NULL) { ngx_log_error(r->log_level, r->log, 0, "unexpected response for %V", &name); + ngx_resolver_free(r, name.data); goto failed; } @@ -2198,9 +2518,12 @@ valid: ngx_log_error(r->log_level, r->log, 0, "wrong ident %ui response for %V, expect %ui", ident, &name, qident); + ngx_resolver_free(r, name.data); goto failed; } + ngx_resolver_free(r, name.data); + if (code == 0 && nan == 0) { code = NGX_RESOLVE_NXDOMAIN; } @@ -2230,44 +2553,90 @@ valid: i += sizeof(ngx_resolver_qs_t); - if (i + 2 + sizeof(ngx_resolver_an_t) >= n) { + for (a = 0; a < nan; a++) { + + start = i; + + while (i < n) { + + if (buf[i] & 0xc0) { + i += 2; + goto found; + } + + if (buf[i] == 0) { + i++; + goto test_length; + } + + i += 1 + buf[i]; + } + goto short_response; + + test_length: + + if (i - start < 2) { + err = "invalid name in DNS response"; + goto invalid; + } + + found: + + if (i + sizeof(ngx_resolver_an_t) >= n) { + goto short_response; + } + + an = (ngx_resolver_an_t *) &buf[i]; + + type = (an->type_hi << 8) + an->type_lo; + class = (an->class_hi << 8) + an->class_lo; + len = (an->len_hi << 8) + an->len_lo; + ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16) + + (an->ttl[2] << 8) + (an->ttl[3]); + + if (class != 1) { + ngx_log_error(r->log_level, r->log, 0, + "unexpected RR class %ui", class); + goto failed; + } + + if (ttl < 0) { + ttl = 0; + } + + ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolver qt:%ui cl:%ui len:%uz", + type, class, len); + + i += sizeof(ngx_resolver_an_t); + + switch (type) { + + case NGX_RESOLVE_PTR: + + goto ptr; + + case NGX_RESOLVE_CNAME: + + break; + + default: + + ngx_log_error(r->log_level, r->log, 0, + "unexpected RR type %ui", type); + } + + i += len; } - /* compression pointer to *.arpa */ + /* unlock addr mutex */ - if (buf[i] != 0xc0 || buf[i + 1] != sizeof(ngx_resolver_hdr_t)) { - err = "invalid in-addr.arpa or ip6.arpa name in DNS response"; - goto invalid; - } + ngx_log_error(r->log_level, r->log, 0, + "no PTR type in DNS response"); + return; - an = (ngx_resolver_an_t *) &buf[i + 2]; - - class = (an->class_hi << 8) + an->class_lo; - len = (an->len_hi << 8) + an->len_lo; - ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16) - + (an->ttl[2] << 8) + (an->ttl[3]); - - if (class != 1) { - ngx_log_error(r->log_level, r->log, 0, - "unexpected RR class %ui", class); - goto failed; - } - - if (ttl < 0) { - ttl = 0; - } - - ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0, - "resolver qt:%ui cl:%ui len:%uz", - (an->type_hi << 8) + an->type_lo, - class, len); - - i += 2 + sizeof(ngx_resolver_an_t); - - if (i + len > n) { - goto short_response; - } +ptr: if (ngx_resolver_copy(r, &name, buf, buf + i, buf + n) != NGX_OK) { goto failed; @@ -3074,8 +3443,8 @@ ngx_resolver_strerror(ngx_int_t err) static u_char * ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len) { - u_char *p; - ngx_udp_connection_t *uc; + u_char *p; + ngx_resolver_connection_t *rec; p = buf; @@ -3084,10 +3453,10 @@ ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len) len -= p - buf; } - uc = log->data; + rec = log->data; - if (uc) { - p = ngx_snprintf(p, len, ", resolver: %V", &uc->server); + if (rec) { + p = ngx_snprintf(p, len, ", resolver: %V", &rec->server); } return p; @@ -3095,7 +3464,7 @@ ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len) ngx_int_t -ngx_udp_connect(ngx_udp_connection_t *uc) +ngx_udp_connect(ngx_resolver_connection_t *rec) { int rc; ngx_int_t event; @@ -3103,21 +3472,21 @@ ngx_udp_connect(ngx_udp_connection_t *uc) ngx_socket_t s; ngx_connection_t *c; - s = ngx_socket(uc->sockaddr->sa_family, SOCK_DGRAM, 0); + s = ngx_socket(rec->sockaddr->sa_family, SOCK_DGRAM, 0); - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "UDP socket %d", s); + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "UDP socket %d", s); if (s == (ngx_socket_t) -1) { - ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno, ngx_socket_n " failed"); return NGX_ERROR; } - c = ngx_get_connection(s, &uc->log); + c = ngx_get_connection(s, &rec->log); if (c == NULL) { if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno, ngx_close_socket_n "failed"); } @@ -3125,7 +3494,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc) } if (ngx_nonblocking(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno, ngx_nonblocking_n " failed"); goto failed; @@ -3134,22 +3503,22 @@ ngx_udp_connect(ngx_udp_connection_t *uc) rev = c->read; wev = c->write; - rev->log = &uc->log; - wev->log = &uc->log; + rev->log = &rec->log; + wev->log = &rec->log; - uc->connection = c; + rec->udp = c; c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &uc->log, 0, - "connect to %V, fd:%d #%uA", &uc->server, s, c->number); + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &rec->log, 0, + "connect to %V, fd:%d #%uA", &rec->server, s, c->number); - rc = connect(s, uc->sockaddr, uc->socklen); + rc = connect(s, rec->sockaddr, rec->socklen); /* TODO: iocp */ if (rc == -1) { - ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_CRIT, &rec->log, ngx_socket_errno, "connect() failed"); goto failed; @@ -3172,7 +3541,190 @@ ngx_udp_connect(ngx_udp_connection_t *uc) failed: ngx_close_connection(c); - uc->connection = NULL; + rec->udp = NULL; + + return NGX_ERROR; +} + + +ngx_int_t +ngx_tcp_connect(ngx_resolver_connection_t *rec) +{ + int rc; + ngx_int_t event; + ngx_err_t err; + ngx_uint_t level; + ngx_socket_t s; + ngx_event_t *rev, *wev; + ngx_connection_t *c; + + s = ngx_socket(rec->sockaddr->sa_family, SOCK_STREAM, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "TCP socket %d", s); + + if (s == (ngx_socket_t) -1) { + ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno, + ngx_socket_n " failed"); + return NGX_ERROR; + } + + c = ngx_get_connection(s, &rec->log); + + if (c == NULL) { + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno, + ngx_close_socket_n "failed"); + } + + return NGX_ERROR; + } + + if (ngx_nonblocking(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno, + ngx_nonblocking_n " failed"); + + goto failed; + } + + rev = c->read; + wev = c->write; + + rev->log = &rec->log; + wev->log = &rec->log; + + rec->tcp = c; + + c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); + + if (ngx_add_conn) { + if (ngx_add_conn(c) == NGX_ERROR) { + goto failed; + } + } + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &rec->log, 0, + "connect to %V, fd:%d #%uA", &rec->server, s, c->number); + + rc = connect(s, rec->sockaddr, rec->socklen); + + if (rc == -1) { + err = ngx_socket_errno; + + + if (err != NGX_EINPROGRESS +#if (NGX_WIN32) + /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */ + && err != NGX_EAGAIN +#endif + ) + { + if (err == NGX_ECONNREFUSED +#if (NGX_LINUX) + /* + * Linux returns EAGAIN instead of ECONNREFUSED + * for unix sockets if listen queue is full + */ + || err == NGX_EAGAIN +#endif + || err == NGX_ECONNRESET + || err == NGX_ENETDOWN + || err == NGX_ENETUNREACH + || err == NGX_EHOSTDOWN + || err == NGX_EHOSTUNREACH) + { + level = NGX_LOG_ERR; + + } else { + level = NGX_LOG_CRIT; + } + + ngx_log_error(level, c->log, err, "connect() to %V failed", + &rec->server); + + ngx_close_connection(c); + rec->tcp = NULL; + + return NGX_ERROR; + } + } + + if (ngx_add_conn) { + if (rc == -1) { + + /* NGX_EINPROGRESS */ + + return NGX_AGAIN; + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "connected"); + + wev->ready = 1; + + return NGX_OK; + } + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, ngx_socket_errno, + "connect(): %d", rc); + + if (ngx_blocking(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno, + ngx_blocking_n " failed"); + goto failed; + } + + /* + * FreeBSD's aio allows to post an operation on non-connected socket. + * NT does not support it. + * + * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT + */ + + rev->ready = 1; + wev->ready = 1; + + return NGX_OK; + } + + if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { + + /* kqueue */ + + event = NGX_CLEAR_EVENT; + + } else { + + /* select, poll, /dev/poll */ + + event = NGX_LEVEL_EVENT; + } + + if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { + goto failed; + } + + if (rc == -1) { + + /* NGX_EINPROGRESS */ + + if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) { + goto failed; + } + + return NGX_AGAIN; + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "connected"); + + wev->ready = 1; + + return NGX_OK; + +failed: + + ngx_close_connection(c); + rec->tcp = NULL; return NGX_ERROR; } diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h index 07fa257..3165abd 100644 --- a/src/core/ngx_resolver.h +++ b/src/core/ngx_resolver.h @@ -36,13 +36,20 @@ #define NGX_RESOLVER_MAX_RECURSION 50 +typedef struct ngx_resolver_s ngx_resolver_t; + + typedef struct { - ngx_connection_t *connection; + ngx_connection_t *udp; + ngx_connection_t *tcp; struct sockaddr *sockaddr; socklen_t socklen; ngx_str_t server; ngx_log_t log; -} ngx_udp_connection_t; + ngx_buf_t *read_buf; + ngx_buf_t *write_buf; + ngx_resolver_t *resolver; +} ngx_resolver_connection_t; typedef struct ngx_resolver_ctx_s ngx_resolver_ctx_t; @@ -93,11 +100,18 @@ typedef struct { time_t valid; uint32_t ttl; + unsigned tcp:1; +#if (NGX_HAVE_INET6) + unsigned tcp6:1; +#endif + + ngx_uint_t last_connection; + ngx_resolver_ctx_t *waiting; } ngx_resolver_node_t; -typedef struct { +struct ngx_resolver_s { /* has to be pointer because of "incomplete type" */ ngx_event_t *event; void *dummy; @@ -107,7 +121,7 @@ typedef struct { ngx_int_t ident; /* simple round robin DNS peers balancer */ - ngx_array_t udp_connections; + ngx_array_t connections; ngx_uint_t last_connection; ngx_rbtree_t name_rbtree; @@ -131,17 +145,18 @@ typedef struct { #endif time_t resend_timeout; + time_t tcp_timeout; time_t expire; time_t valid; ngx_uint_t log_level; -} ngx_resolver_t; +}; struct ngx_resolver_ctx_s { ngx_resolver_ctx_t *next; ngx_resolver_t *resolver; - ngx_udp_connection_t *udp_connection; + ngx_resolver_node_t *node; /* event ident must be after 3 pointers as in ngx_connection_t */ ngx_int_t ident; @@ -161,8 +176,6 @@ struct ngx_resolver_ctx_s { ngx_uint_t quick; /* unsigned quick:1; */ ngx_uint_t recursion; ngx_event_t *event; - - ngx_resolver_node_t *node; }; diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index 15da213..955622b 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -606,16 +606,16 @@ ngx_event_process_init(ngx_cycle_t *cycle) return NGX_ERROR; } - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_EVENT_MODULE) { + for (m = 0; cycle->modules[m]; m++) { + if (cycle->modules[m]->type != NGX_EVENT_MODULE) { continue; } - if (ngx_modules[m]->ctx_index != ecf->use) { + if (cycle->modules[m]->ctx_index != ecf->use) { continue; } - module = ngx_modules[m]->ctx; + module = cycle->modules[m]->ctx; if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) { /* fatal */ @@ -891,14 +891,7 @@ ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) /* count the number of the event modules and set up their indices */ - ngx_event_max_module = 0; - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->type != NGX_EVENT_MODULE) { - continue; - } - - ngx_modules[i]->ctx_index = ngx_event_max_module++; - } + ngx_event_max_module = ngx_count_modules(cf->cycle, NGX_EVENT_MODULE); ctx = ngx_pcalloc(cf->pool, sizeof(void *)); if (ctx == NULL) { @@ -912,16 +905,17 @@ ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) *(void **) conf = ctx; - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->type != NGX_EVENT_MODULE) { + for (i = 0; cf->cycle->modules[i]; i++) { + if (cf->cycle->modules[i]->type != NGX_EVENT_MODULE) { continue; } - m = ngx_modules[i]->ctx; + m = cf->cycle->modules[i]->ctx; if (m->create_conf) { - (*ctx)[ngx_modules[i]->ctx_index] = m->create_conf(cf->cycle); - if ((*ctx)[ngx_modules[i]->ctx_index] == NULL) { + (*ctx)[cf->cycle->modules[i]->ctx_index] = + m->create_conf(cf->cycle); + if ((*ctx)[cf->cycle->modules[i]->ctx_index] == NULL) { return NGX_CONF_ERROR; } } @@ -940,15 +934,16 @@ ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return rv; } - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->type != NGX_EVENT_MODULE) { + for (i = 0; cf->cycle->modules[i]; i++) { + if (cf->cycle->modules[i]->type != NGX_EVENT_MODULE) { continue; } - m = ngx_modules[i]->ctx; + m = cf->cycle->modules[i]->ctx; if (m->init_conf) { - rv = m->init_conf(cf->cycle, (*ctx)[ngx_modules[i]->ctx_index]); + rv = m->init_conf(cf->cycle, + (*ctx)[cf->cycle->modules[i]->ctx_index]); if (rv != NGX_CONF_OK) { return rv; } @@ -1009,15 +1004,15 @@ ngx_event_use(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_EVENT_MODULE) { + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_EVENT_MODULE) { continue; } - module = ngx_modules[m]->ctx; + module = cf->cycle->modules[m]->ctx; if (module->name->len == value[1].len) { if (ngx_strcmp(module->name->data, value[1].data) == 0) { - ecf->use = ngx_modules[m]->ctx_index; + ecf->use = cf->cycle->modules[m]->ctx_index; ecf->name = module->name->data; if (ngx_process == NGX_PROCESS_SINGLE @@ -1232,20 +1227,20 @@ ngx_event_core_init_conf(ngx_cycle_t *cycle, void *conf) #endif if (module == NULL) { - for (i = 0; ngx_modules[i]; i++) { + for (i = 0; cycle->modules[i]; i++) { - if (ngx_modules[i]->type != NGX_EVENT_MODULE) { + if (cycle->modules[i]->type != NGX_EVENT_MODULE) { continue; } - event_module = ngx_modules[i]->ctx; + event_module = cycle->modules[i]->ctx; if (ngx_strcmp(event_module->name->data, event_core_name.data) == 0) { continue; } - module = ngx_modules[i]; + module = cycle->modules[i]; break; } } diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c index 754512f..2ec7f5d 100644 --- a/src/http/modules/ngx_http_rewrite_module.c +++ b/src/http/modules/ngx_http_rewrite_module.c @@ -560,12 +560,12 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->type != NGX_HTTP_MODULE) { + for (i = 0; cf->cycle->modules[i]; i++) { + if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) { continue; } - module = ngx_modules[i]->ctx; + module = cf->cycle->modules[i]->ctx; if (module->create_loc_conf) { @@ -574,7 +574,7 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf; + ctx->loc_conf[cf->cycle->modules[i]->ctx_index] = mconf; } } diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index 64af447..0ceb613 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -144,14 +144,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) /* count the number of the http modules and set up their indices */ - ngx_http_max_module = 0; - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_HTTP_MODULE) { - continue; - } - - ngx_modules[m]->ctx_index = ngx_http_max_module++; - } + ngx_http_max_module = ngx_count_modules(cf->cycle, NGX_HTTP_MODULE); /* the http main_conf context, it is the same in the all http contexts */ @@ -190,13 +183,13 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) * of the all http modules */ - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_HTTP_MODULE) { + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) { continue; } - module = ngx_modules[m]->ctx; - mi = ngx_modules[m]->ctx_index; + module = cf->cycle->modules[m]->ctx; + mi = cf->cycle->modules[m]->ctx_index; if (module->create_main_conf) { ctx->main_conf[mi] = module->create_main_conf(cf); @@ -223,12 +216,12 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) pcf = *cf; cf->ctx = ctx; - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_HTTP_MODULE) { + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) { continue; } - module = ngx_modules[m]->ctx; + module = cf->cycle->modules[m]->ctx; if (module->preconfiguration) { if (module->preconfiguration(cf) != NGX_OK) { @@ -255,13 +248,13 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) cmcf = ctx->main_conf[ngx_http_core_module.ctx_index]; cscfp = cmcf->servers.elts; - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_HTTP_MODULE) { + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) { continue; } - module = ngx_modules[m]->ctx; - mi = ngx_modules[m]->ctx_index; + module = cf->cycle->modules[m]->ctx; + mi = cf->cycle->modules[m]->ctx_index; /* init http{} main_conf's */ @@ -304,12 +297,12 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_HTTP_MODULE) { + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) { continue; } - module = ngx_modules[m]->ctx; + module = cf->cycle->modules[m]->ctx; if (module->postconfiguration) { if (module->postconfiguration(cf) != NGX_OK) { diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 4b8dd4c..df7e8d4 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -2968,12 +2968,12 @@ ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) return NGX_CONF_ERROR; } - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->type != NGX_HTTP_MODULE) { + for (i = 0; cf->cycle->modules[i]; i++) { + if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) { continue; } - module = ngx_modules[i]->ctx; + module = cf->cycle->modules[i]->ctx; if (module->create_srv_conf) { mconf = module->create_srv_conf(cf); @@ -2981,7 +2981,7 @@ ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) return NGX_CONF_ERROR; } - ctx->srv_conf[ngx_modules[i]->ctx_index] = mconf; + ctx->srv_conf[cf->cycle->modules[i]->ctx_index] = mconf; } if (module->create_loc_conf) { @@ -2990,7 +2990,7 @@ ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) return NGX_CONF_ERROR; } - ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf; + ctx->loc_conf[cf->cycle->modules[i]->ctx_index] = mconf; } } @@ -3086,17 +3086,17 @@ ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) return NGX_CONF_ERROR; } - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->type != NGX_HTTP_MODULE) { + for (i = 0; cf->cycle->modules[i]; i++) { + if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) { continue; } - module = ngx_modules[i]->ctx; + module = cf->cycle->modules[i]->ctx; if (module->create_loc_conf) { - ctx->loc_conf[ngx_modules[i]->ctx_index] = + ctx->loc_conf[cf->cycle->modules[i]->ctx_index] = module->create_loc_conf(cf); - if (ctx->loc_conf[ngx_modules[i]->ctx_index] == NULL) { + if (ctx->loc_conf[cf->cycle->modules[i]->ctx_index] == NULL) { return NGX_CONF_ERROR; } } @@ -4607,12 +4607,12 @@ ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->type != NGX_HTTP_MODULE) { + for (i = 0; cf->cycle->modules[i]; i++) { + if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) { continue; } - module = ngx_modules[i]->ctx; + module = cf->cycle->modules[i]->ctx; if (module->create_loc_conf) { @@ -4621,7 +4621,7 @@ ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf; + ctx->loc_conf[cf->cycle->modules[i]->ctx_index] = mconf; } } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 7f377b6..dbaa956 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -5331,12 +5331,12 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) return NGX_CONF_ERROR; } - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_HTTP_MODULE) { + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) { continue; } - module = ngx_modules[m]->ctx; + module = cf->cycle->modules[m]->ctx; if (module->create_srv_conf) { mconf = module->create_srv_conf(cf); @@ -5344,7 +5344,7 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) return NGX_CONF_ERROR; } - ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf; + ctx->srv_conf[cf->cycle->modules[m]->ctx_index] = mconf; } if (module->create_loc_conf) { @@ -5353,7 +5353,7 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) return NGX_CONF_ERROR; } - ctx->loc_conf[ngx_modules[m]->ctx_index] = mconf; + ctx->loc_conf[cf->cycle->modules[m]->ctx_index] = mconf; } } diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 869ce08..4e378c9 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -251,7 +251,7 @@ ngx_http_v2_init(ngx_event_t *rev) return; } - cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_pool_cleanup_file_t)); + cln = ngx_pool_cleanup_add(c->pool, 0); if (cln == NULL) { ngx_http_close_connection(c); return; @@ -1185,6 +1185,8 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); } + stream->request->request_length = h2c->state.length; + stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; stream->node = node; @@ -1731,11 +1733,21 @@ ngx_http_v2_handle_continuation(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end, ngx_http_v2_handler_pt handler) { u_char *p; - size_t len; + size_t len, skip; uint32_t head; len = h2c->state.length; + if (h2c->state.padding && (size_t) (end - pos) > len) { + skip = ngx_min(h2c->state.padding, (end - pos) - len); + + h2c->state.padding -= skip; + + p = pos; + pos += skip; + ngx_memmove(pos, p, len); + } + if ((size_t) (end - pos) < len + NGX_HTTP_V2_FRAME_HEADER_SIZE) { return ngx_http_v2_state_save(h2c, pos, end, handler); } @@ -1751,7 +1763,6 @@ ngx_http_v2_handle_continuation(ngx_http_v2_connection_t *h2c, u_char *pos, return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); } - h2c->state.length += ngx_http_v2_parse_length(head); h2c->state.flags |= p[4]; if (h2c->state.sid != ngx_http_v2_parse_sid(&p[5])) { @@ -1766,6 +1777,14 @@ ngx_http_v2_handle_continuation(ngx_http_v2_connection_t *h2c, u_char *pos, ngx_memcpy(pos, p, len); + len = ngx_http_v2_parse_length(head); + + h2c->state.length += len; + + if (h2c->state.stream) { + h2c->state.stream->request->request_length += len; + } + h2c->state.handler = handler; return pos; } diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 4c63b21..0f03922 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -167,7 +167,6 @@ struct ngx_http_v2_stream_s { ngx_http_v2_connection_t *connection; ngx_http_v2_node_t *node; - ngx_uint_t header_buffers; ngx_uint_t queued; /* diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index ed30fe5..ea58979 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -215,8 +215,8 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->headers_out.server == NULL) { - len += 1 + clcf->server_tokens ? ngx_http_v2_literal_size(NGINX_VER) - : ngx_http_v2_literal_size("nginx"); + len += 1 + (clcf->server_tokens ? ngx_http_v2_literal_size(NGINX_VER) + : ngx_http_v2_literal_size("nginx")); } if (r->headers_out.date == NULL) { diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c index 962ae8b..6ad5a67 100644 --- a/src/mail/ngx_mail.c +++ b/src/mail/ngx_mail.c @@ -91,14 +91,7 @@ ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) /* count the number of the mail modules and set up their indices */ - ngx_mail_max_module = 0; - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_MAIL_MODULE) { - continue; - } - - ngx_modules[m]->ctx_index = ngx_mail_max_module++; - } + ngx_mail_max_module = ngx_count_modules(cf->cycle, NGX_MAIL_MODULE); /* the mail main_conf context, it is the same in the all mail contexts */ @@ -125,13 +118,13 @@ ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) * create the main_conf's and the null srv_conf's of the all mail modules */ - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_MAIL_MODULE) { + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) { continue; } - module = ngx_modules[m]->ctx; - mi = ngx_modules[m]->ctx_index; + module = cf->cycle->modules[m]->ctx; + mi = cf->cycle->modules[m]->ctx_index; if (module->create_main_conf) { ctx->main_conf[mi] = module->create_main_conf(cf); @@ -169,13 +162,13 @@ ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index]; cscfp = cmcf->servers.elts; - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_MAIL_MODULE) { + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) { continue; } - module = ngx_modules[m]->ctx; - mi = ngx_modules[m]->ctx_index; + module = cf->cycle->modules[m]->ctx; + mi = cf->cycle->modules[m]->ctx_index; /* init mail{} main_conf's */ diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index c219296..8ea8ea9 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -237,12 +237,12 @@ ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_MAIL_MODULE) { + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) { continue; } - module = ngx_modules[m]->ctx; + module = cf->cycle->modules[m]->ctx; if (module->create_srv_conf) { mconf = module->create_srv_conf(cf); @@ -250,7 +250,7 @@ ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf; + ctx->srv_conf[cf->cycle->modules[m]->ctx_index] = mconf; } } @@ -392,12 +392,12 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif if (cscf->protocol == NULL) { - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_MAIL_MODULE) { + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) { continue; } - module = ngx_modules[m]->ctx; + module = cf->cycle->modules[m]->ctx; if (module->protocol == NULL) { continue; @@ -595,12 +595,12 @@ ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) value = cf->args->elts; - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_MAIL_MODULE) { + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) { continue; } - module = ngx_modules[m]->ctx; + module = cf->cycle->modules[m]->ctx; if (module->protocol && ngx_strcmp(module->protocol->name.data, value[1].data) == 0) diff --git a/src/os/unix/ngx_darwin_config.h b/src/os/unix/ngx_darwin_config.h index bbad977..cfe3ce2 100644 --- a/src/os/unix/ngx_darwin_config.h +++ b/src/os/unix/ngx_darwin_config.h @@ -48,6 +48,8 @@ #include #include +#include + #ifndef IOV_MAX #define IOV_MAX 64 diff --git a/src/os/unix/ngx_dlopen.c b/src/os/unix/ngx_dlopen.c new file mode 100644 index 0000000..a0efc69 --- /dev/null +++ b/src/os/unix/ngx_dlopen.c @@ -0,0 +1,28 @@ + +/* + * Copyright (C) Maxim Dounin + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +#if (NGX_HAVE_DLOPEN) + +char * +ngx_dlerror(void) +{ + char *err; + + err = (char *) dlerror(); + + if (err == NULL) { + return ""; + } + + return err; +} + +#endif diff --git a/src/os/unix/ngx_dlopen.h b/src/os/unix/ngx_dlopen.h new file mode 100644 index 0000000..7a3159f --- /dev/null +++ b/src/os/unix/ngx_dlopen.h @@ -0,0 +1,31 @@ + +/* + * Copyright (C) Maxim Dounin + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_DLOPEN_H_INCLUDED_ +#define _NGX_DLOPEN_H_INCLUDED_ + + +#include +#include + + +#define ngx_dlopen(path) dlopen((char *) path, RTLD_NOW | RTLD_GLOBAL) +#define ngx_dlopen_n "dlopen()" + +#define ngx_dlsym(handle, symbol) dlsym(handle, symbol) +#define ngx_dlsym_n "dlsym()" + +#define ngx_dlclose(handle) dlclose(handle) +#define ngx_dlclose_n "dlclose()" + + +#if (NGX_HAVE_DLOPEN) +char *ngx_dlerror(void); +#endif + + +#endif /* _NGX_DLOPEN_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h index 9a25788..b7da48c 100644 --- a/src/os/unix/ngx_freebsd_config.h +++ b/src/os/unix/ngx_freebsd_config.h @@ -49,6 +49,8 @@ #include #include +#include + #if __FreeBSD_version < 400017 diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h index 162a992..2f6129d 100644 --- a/src/os/unix/ngx_linux_config.h +++ b/src/os/unix/ngx_linux_config.h @@ -55,6 +55,8 @@ #include #include /* uname() */ +#include + #include diff --git a/src/os/unix/ngx_posix_config.h b/src/os/unix/ngx_posix_config.h index 443c4b0..bf75997 100644 --- a/src/os/unix/ngx_posix_config.h +++ b/src/os/unix/ngx_posix_config.h @@ -108,6 +108,11 @@ #include +#if (NGX_HAVE_DLOPEN) +#include +#endif + + #if (NGX_HAVE_POSIX_SEM) #include #endif diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c index 5da0911..7c6bf7a 100644 --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -294,9 +294,9 @@ ngx_single_process_cycle(ngx_cycle_t *cycle) exit(2); } - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->init_process) { - if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->init_process) { + if (cycle->modules[i]->init_process(cycle) == NGX_ERROR) { /* fatal */ exit(2); } @@ -310,9 +310,9 @@ ngx_single_process_cycle(ngx_cycle_t *cycle) if (ngx_terminate || ngx_quit) { - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->exit_process) { - ngx_modules[i]->exit_process(cycle); + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->exit_process) { + cycle->modules[i]->exit_process(cycle); } } @@ -689,9 +689,9 @@ ngx_master_process_exit(ngx_cycle_t *cycle) ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exit"); - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->exit_master) { - ngx_modules[i]->exit_master(cycle); + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->exit_master) { + cycle->modules[i]->exit_master(cycle); } } @@ -895,9 +895,9 @@ ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker) ls[i].previous = NULL; } - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->init_process) { - if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->init_process) { + if (cycle->modules[i]->init_process(cycle) == NGX_ERROR) { /* fatal */ exit(2); } @@ -949,9 +949,9 @@ ngx_worker_process_exit(ngx_cycle_t *cycle) ngx_uint_t i; ngx_connection_t *c; - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->exit_process) { - ngx_modules[i]->exit_process(cycle); + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->exit_process) { + cycle->modules[i]->exit_process(cycle); } } diff --git a/src/os/unix/ngx_solaris_config.h b/src/os/unix/ngx_solaris_config.h index ddfd984..ffa01c8 100644 --- a/src/os/unix/ngx_solaris_config.h +++ b/src/os/unix/ngx_solaris_config.h @@ -55,6 +55,8 @@ #include #include +#include + #define NGX_ALIGNMENT _MAX_ALIGNMENT #include diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c index f0aa532..caaf38a 100644 --- a/src/stream/ngx_stream.c +++ b/src/stream/ngx_stream.c @@ -91,14 +91,7 @@ ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) /* count the number of the stream modules and set up their indices */ - ngx_stream_max_module = 0; - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_STREAM_MODULE) { - continue; - } - - ngx_modules[m]->ctx_index = ngx_stream_max_module++; - } + ngx_stream_max_module = ngx_count_modules(cf->cycle, NGX_STREAM_MODULE); /* the stream main_conf context, it's the same in the all stream contexts */ @@ -126,13 +119,13 @@ ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) * create the main_conf's and the null srv_conf's of the all stream modules */ - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_STREAM_MODULE) { + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_STREAM_MODULE) { continue; } - module = ngx_modules[m]->ctx; - mi = ngx_modules[m]->ctx_index; + module = cf->cycle->modules[m]->ctx; + mi = cf->cycle->modules[m]->ctx_index; if (module->create_main_conf) { ctx->main_conf[mi] = module->create_main_conf(cf); @@ -170,13 +163,13 @@ ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) cmcf = ctx->main_conf[ngx_stream_core_module.ctx_index]; cscfp = cmcf->servers.elts; - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_STREAM_MODULE) { + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_STREAM_MODULE) { continue; } - module = ngx_modules[m]->ctx; - mi = ngx_modules[m]->ctx_index; + module = cf->cycle->modules[m]->ctx; + mi = cf->cycle->modules[m]->ctx_index; /* init stream{} main_conf's */ @@ -208,12 +201,12 @@ ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_STREAM_MODULE) { + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_STREAM_MODULE) { continue; } - module = ngx_modules[m]->ctx; + module = cf->cycle->modules[m]->ctx; if (module->postconfiguration) { if (module->postconfiguration(cf) != NGX_OK) { diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c index 4fe6818..0ecc448 100644 --- a/src/stream/ngx_stream_core_module.c +++ b/src/stream/ngx_stream_core_module.c @@ -199,12 +199,12 @@ ngx_stream_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_STREAM_MODULE) { + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_STREAM_MODULE) { continue; } - module = ngx_modules[m]->ctx; + module = cf->cycle->modules[m]->ctx; if (module->create_srv_conf) { mconf = module->create_srv_conf(cf); @@ -212,7 +212,7 @@ ngx_stream_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf; + ctx->srv_conf[cf->cycle->modules[m]->ctx_index] = mconf; } } diff --git a/src/stream/ngx_stream_upstream.c b/src/stream/ngx_stream_upstream.c index f21e17d..805ee70 100644 --- a/src/stream/ngx_stream_upstream.c +++ b/src/stream/ngx_stream_upstream.c @@ -116,12 +116,12 @@ ngx_stream_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) uscf->srv_conf = ctx->srv_conf; - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_STREAM_MODULE) { + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_STREAM_MODULE) { continue; } - module = ngx_modules[m]->ctx; + module = cf->cycle->modules[m]->ctx; if (module->create_srv_conf) { mconf = module->create_srv_conf(cf); @@ -129,7 +129,7 @@ ngx_stream_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) return NGX_CONF_ERROR; } - ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf; + ctx->srv_conf[cf->cycle->modules[m]->ctx_index] = mconf; } } From 586dea93587b32afc4e69a8ac53295f54c9c778d Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 11 Feb 2016 15:07:08 +0200 Subject: [PATCH 079/651] New upstream release (1.9.11) --- debian/changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index 5b341ce..b176a32 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.9.11-1) UNRELEASED; urgency=medium + + [ Christos Trochalakis ] + * New upstream release (1.9.11) (Closes: #812806) + + -- Christos Trochalakis Thu, 11 Feb 2016 15:06:38 +0200 + nginx (1.9.10-1) unstable; urgency=medium [ Christos Trochalakis ] From 3c7520faddbf9caa0320a68676110b0fb1122762 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 12 Feb 2016 12:37:52 +0200 Subject: [PATCH 080/651] Update nginx-lua module to v0.10.1rc0-5-g01727a3 Fixes building issues with nginx 1.9.11. --- debian/changelog | 3 + debian/modules/README.Modules-versions | 2 +- debian/modules/nginx-lua/README.markdown | 171 +++++---- debian/modules/nginx-lua/config | 247 ++++++------ .../modules/nginx-lua/doc/HttpLuaModule.wiki | 163 ++++---- .../nginx-lua/src/api/ngx_http_lua_api.h | 2 +- .../nginx-lua/src/ngx_http_lua_accessby.c | 9 + .../nginx-lua/src/ngx_http_lua_balancer.c | 37 +- .../nginx-lua/src/ngx_http_lua_config.c | 5 +- .../nginx-lua/src/ngx_http_lua_contentby.c | 9 + .../nginx-lua/src/ngx_http_lua_headers.c | 6 + .../nginx-lua/src/ngx_http_lua_initworkerby.c | 19 +- .../modules/nginx-lua/src/ngx_http_lua_log.c | 16 + .../nginx-lua/src/ngx_http_lua_module.c | 14 +- .../modules/nginx-lua/src/ngx_http_lua_ndk.c | 13 +- .../nginx-lua/src/ngx_http_lua_output.c | 1 + .../nginx-lua/src/ngx_http_lua_regex.c | 36 +- .../nginx-lua/src/ngx_http_lua_req_body.c | 14 +- .../nginx-lua/src/ngx_http_lua_rewriteby.c | 9 + .../nginx-lua/src/ngx_http_lua_script.h | 6 +- .../nginx-lua/src/ngx_http_lua_semaphore.c | 2 +- .../nginx-lua/src/ngx_http_lua_shdict.c | 4 +- .../nginx-lua/src/ngx_http_lua_socket_tcp.c | 7 +- .../nginx-lua/src/ngx_http_lua_socket_udp.c | 8 +- .../nginx-lua/src/ngx_http_lua_socket_udp.h | 11 +- .../nginx-lua/src/ngx_http_lua_ssl_certby.c | 25 +- .../modules/nginx-lua/src/ngx_http_lua_util.c | 11 +- debian/modules/nginx-lua/t/008-today.t | 4 +- debian/modules/nginx-lua/t/009-log.t | 107 +++++- debian/modules/nginx-lua/t/011-md5_bin.t | 4 +- debian/modules/nginx-lua/t/013-base64.t | 1 - debian/modules/nginx-lua/t/016-resp-header.t | 5 - debian/modules/nginx-lua/t/034-match.t | 31 +- debian/modules/nginx-lua/t/035-gmatch.t | 8 +- debian/modules/nginx-lua/t/036-sub.t | 25 +- debian/modules/nginx-lua/t/037-gsub.t | 27 +- debian/modules/nginx-lua/t/038-match-o.t | 10 +- debian/modules/nginx-lua/t/043-shdict.t | 19 + debian/modules/nginx-lua/t/044-req-body.t | 26 +- debian/modules/nginx-lua/t/048-match-dfa.t | 39 +- debian/modules/nginx-lua/t/050-gmatch-dfa.t | 50 +++ debian/modules/nginx-lua/t/052-sub-dfa.t | 37 +- debian/modules/nginx-lua/t/054-gsub-dfa.t | 37 +- debian/modules/nginx-lua/t/058-tcp-socket.t | 2 +- debian/modules/nginx-lua/t/059-unix-socket.t | 67 ++++ debian/modules/nginx-lua/t/062-count.t | 4 +- debian/modules/nginx-lua/t/081-bytecode.t | 57 +++ debian/modules/nginx-lua/t/101-on-abort.t | 1 + debian/modules/nginx-lua/t/106-timer.t | 1 - debian/modules/nginx-lua/t/114-config.t | 16 + .../modules/nginx-lua/t/116-raw-req-socket.t | 1 - debian/modules/nginx-lua/t/138-balancer.t | 103 +++++ debian/modules/nginx-lua/t/140-ssl-c-api.t | 363 ++++++++++++++++++ debian/modules/nginx-lua/t/cert/test2.crt | 16 + debian/modules/nginx-lua/t/cert/test2.key | 15 + .../modules/nginx-lua/t/cert/test_ecdsa.crt | 12 + .../modules/nginx-lua/t/cert/test_ecdsa.key | 5 + .../nginx-lua/util/{build2.sh => build.sh} | 0 58 files changed, 1551 insertions(+), 392 deletions(-) create mode 100644 debian/modules/nginx-lua/t/140-ssl-c-api.t create mode 100644 debian/modules/nginx-lua/t/cert/test2.crt create mode 100644 debian/modules/nginx-lua/t/cert/test2.key create mode 100644 debian/modules/nginx-lua/t/cert/test_ecdsa.crt create mode 100644 debian/modules/nginx-lua/t/cert/test_ecdsa.key rename debian/modules/nginx-lua/util/{build2.sh => build.sh} (100%) diff --git a/debian/changelog b/debian/changelog index b176a32..0f8009f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,9 @@ nginx (1.9.11-1) UNRELEASED; urgency=medium [ Christos Trochalakis ] * New upstream release (1.9.11) (Closes: #812806) + * debian/modules/nginx-lua: + + Update nginx-lua to v0.10.1rc0-5-g01727a3. + Fixes buiding failures with nginx 1.9.11. -- Christos Trochalakis Thu, 11 Feb 2016 15:06:38 +0200 diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index eb35054..dbff74d 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -22,7 +22,7 @@ README for Modules versions nginx-lua Homepage: https://github.com/openresty/lua-nginx-module - Version: v0.10.0 + Version: v0.10.1rc0-5-g01727a3 nginx-upstream-fair Homepage: https://github.com/gnosek/nginx-upstream-fair diff --git a/debian/modules/nginx-lua/README.markdown b/debian/modules/nginx-lua/README.markdown index 64adc0e..94e67ad 100644 --- a/debian/modules/nginx-lua/README.markdown +++ b/debian/modules/nginx-lua/README.markdown @@ -61,7 +61,7 @@ Production ready. Version ======= -This document describes ngx_lua [v0.10.0](https://github.com/openresty/lua-nginx-module/tags) released on 11 January 2015. +This document describes ngx_lua [v0.10.0](https://github.com/openresty/lua-nginx-module/tags) released on 11 January 2016. Synopsis ======== @@ -216,6 +216,10 @@ The Lua interpreter or LuaJIT instance is shared across all the requests in a si Loaded Lua modules persist in the nginx worker process level resulting in a small memory footprint in Lua even when under heavy loads. +This module is plugged into NGINX's "http" subsystem so it can only speaks downstream communication protocols in the HTTP family (HTTP 0.9/1.0/1.1/2.0, WebSockets, and etc). +If you want to do generic TCP communications with the downstream clients, then you should use the [ngx_stream_lua](https://github.com/openresty/stream-lua-nginx-module#readme) module instead +which has a compatible Lua API. + [Back to TOC](#table-of-contents) Typical Uses @@ -256,7 +260,7 @@ Nginx cores older than 1.6.0 (exclusive) are *not* supported. Installation ============ -It is highly recommended to use the [ngx_openresty bundle](http://openresty.org) that bundles Nginx, ngx_lua, LuaJIT 2.0/2.1 (or the optional standard Lua 5.1 interpreter), as well as a package of powerful companion Nginx modules. The basic installation step is a simple command: `./configure --with-luajit && make && make install`. +It is highly recommended to use the [OpenResty bundle](http://openresty.org) that bundles Nginx, ngx_lua, LuaJIT 2.0/2.1 (or the optional standard Lua 5.1 interpreter), as well as a package of powerful companion Nginx modules. The basic installation step is a simple command: `./configure --with-luajit && make && make install`. Alternatively, ngx_lua can be manually compiled into Nginx: @@ -295,6 +299,14 @@ Build the source with this module: make install ``` +Starting from NGINX 1.9.11, you can also compile this module as a dynamic module, by using the `--add-dynamic-module=PATH` option instead of `--add-module=PATH` on the +`./configure` command line above. And then you can explicitly load the module in your `nginx.conf` via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module) +directive, for example, + +```nginx +load_module /path/to/modules/ngx_http_lua_module.so; +``` + [Back to TOC](#table-of-contents) C Macro Configurations @@ -591,7 +603,7 @@ If server-wide data sharing is required, then use one or more of the following a 1. Use the [ngx.shared.DICT](#ngxshareddict) API provided by this module. 1. Use only a single nginx worker and a single server (this is however not recommended when there is a multi core CPU or multiple CPUs in a single machine). -1. Use data storage mechanisms such as `memcached`, `redis`, `MySQL` or `PostgreSQL`. [The ngx_openresty bundle](http://openresty.org) associated with this module comes with a set of companion Nginx modules and Lua libraries that provide interfaces with these data storage mechanisms. +1. Use data storage mechanisms such as `memcached`, `redis`, `MySQL` or `PostgreSQL`. [The OpenResty bundle](http://openresty.org) associated with this module comes with a set of companion Nginx modules and Lua libraries that provide interfaces with these data storage mechanisms. [Back to TOC](#table-of-contents) @@ -861,7 +873,6 @@ TODO * cosocket: pool-based backend concurrency level control: implement automatic `connect` queueing when the backend concurrency exceeds its connection pool limit. * cosocket: review and merge aviramc's [patch](https://github.com/openresty/lua-nginx-module/pull/290) for adding the `bsdrecv` method. * add new API function `ngx.resp.add_header` to emulate the standard `add_header` config directive. -* [ngx.re](#ngxrematch) API: use `false` instead of `nil` in the resulting match table to indicate non-existent submatch captures, such that we can avoid "holes" in the array table. * review and apply Jader H. Silva's patch for `ngx.re.split()`. * review and apply vadim-pavlov's patch for [ngx.location.capture](#ngxlocationcapture)'s `extra_headers` option * use `ngx_hash_t` to optimize the built-in header look-up process for [ngx.req.set_header](#ngxreqset_header), [ngx.header.HEADER](#ngxheaderheader), and etc. @@ -876,7 +887,7 @@ TODO Changes ======= -The changes of every release of this module can be obtained from the ngx_openresty bundle's change logs: +The changes of every release of this module can be obtained from the OpenResty bundle's change logs: @@ -945,9 +956,9 @@ Copyright and License This module is licensed under the BSD license. -Copyright (C) 2009-2015, by Xiaozhe Wang (chaoslawful) . +Copyright (C) 2009-2016, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2015, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +Copyright (C) 2009-2016, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. All rights reserved. @@ -964,6 +975,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND See Also ======== +* [ngx_stream_lua_module](https://github.com/openresty/stream-lua-nginx-module#readme) for an official port of this module for the NGINX "stream" subsystem (doing generic downstream TCP communications). * [lua-resty-memcached](https://github.com/openresty/lua-resty-memcached) library based on ngx_lua cosocket. * [lua-resty-redis](https://github.com/openresty/lua-resty-redis) library based on ngx_lua cosocket. * [lua-resty-mysql](https://github.com/openresty/lua-resty-mysql) library based on ngx_lua cosocket. @@ -982,7 +994,7 @@ See Also * [drizzle-nginx-module](http://github.com/openresty/drizzle-nginx-module) * [postgres-nginx-module](https://github.com/FRiCKLE/ngx_postgres) * [memc-nginx-module](http://github.com/openresty/memc-nginx-module) -* [The ngx_openresty bundle](http://openresty.org) +* [The OpenResty bundle](http://openresty.org) * [Nginx Systemtap Toolkit](https://github.com/openresty/nginx-systemtap-toolkit) [Back to TOC](#table-of-contents) @@ -2116,7 +2128,7 @@ log_by_lua **WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; use the new [log_by_lua_block](#log_by_lua_block) directive instead. -Runs the Lua source code inlined as the `` at the `log` request processing phase. This does not replace the current access logs, but runs after. +Runs the Lua source code inlined as the `` at the `log` request processing phase. This does not replace the current access logs, but runs before. Note that the following API functions are currently disabled within this context: @@ -2915,6 +2927,7 @@ Nginx API for Lua * [udpsock:receive](#udpsockreceive) * [udpsock:close](#udpsockclose) * [udpsock:settimeout](#udpsocksettimeout) +* [ngx.socket.stream](#ngxsocketstream) * [ngx.socket.tcp](#ngxsockettcp) * [tcpsock:connect](#tcpsockconnect) * [tcpsock:sslhandshake](#tcpsocksslhandshake) @@ -2935,6 +2948,7 @@ Nginx API for Lua * [ngx.timer.at](#ngxtimerat) * [ngx.timer.running_count](#ngxtimerrunning_count) * [ngx.timer.pending_count](#ngxtimerpending_count) +* [ngx.config.subsystem](#ngxconfigsubsystem) * [ngx.config.debug](#ngxconfigdebug) * [ngx.config.prefix](#ngxconfigprefix) * [ngx.config.nginx_version](#ngxconfignginx_version) @@ -3094,7 +3108,7 @@ This API requires a relatively expensive metamethod call and it is recommended t Core constants -------------- -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, *log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, *log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** ```lua @@ -3120,7 +3134,7 @@ The `ngx.DECLINED` constant was first introduced in the `v0.5.0rc19` release. HTTP method constants --------------------- -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** ngx.HTTP_GET @@ -3146,7 +3160,7 @@ These constants are usually used in [ngx.location.capture](#ngxlocationcapture) HTTP status constants --------------------- -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** ```nginx @@ -3190,7 +3204,7 @@ HTTP status constants Nginx log level constants ------------------------- -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** ```lua @@ -3932,7 +3946,7 @@ ngx.req.http_version Returns the HTTP version number for the current request as a Lua number. -Current possible values are 1.0, 1.1, and 0.9. Returns `nil` for unrecognized values. +Current possible values are 2.0, 1.0, 1.1, and 0.9. Returns `nil` for unrecognized values. This method was first introduced in the `v0.7.17` release. @@ -4522,7 +4536,7 @@ ngx.req.discard_body **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** -Explicitly discard the request body, i.e., read the data on the connection and throw it away immediately. Please note that ignoring request body is not the right way to discard it, and that this function must be called to avoid breaking things under HTTP 1.1 keepalive or HTTP 1.1 pipelining. +Explicitly discard the request body, i.e., read the data on the connection and throw it away immediately (without using the request body by any means). This function is an asynchronous call and returns immediately. @@ -4538,7 +4552,7 @@ ngx.req.get_body_data --------------------- **syntax:** *data = ngx.req.get_body_data()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, log_by_lua** Retrieves in-memory request body data. It returns a Lua string rather than a Lua table holding all the parsed query arguments. Use the [ngx.req.get_post_args](#ngxreqget_post_args) function instead if a Lua table is required. @@ -5085,7 +5099,7 @@ ngx.escape_uri -------------- **syntax:** *newstr = ngx.escape_uri(str)* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Escape `str` as a URI component. @@ -5095,7 +5109,7 @@ ngx.unescape_uri ---------------- **syntax:** *newstr = ngx.unescape_uri(str)* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Unescape `str` as an escaped URI component. @@ -5118,7 +5132,7 @@ ngx.encode_args --------------- **syntax:** *str = ngx.encode_args(table)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Encode the Lua table to a query args string according to the URI encoded rules. @@ -5175,7 +5189,7 @@ ngx.decode_args --------------- **syntax:** *table = ngx.decode_args(str, max_args?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Decodes a URI encoded query-string into a Lua table. This is the inverse function of [ngx.encode_args](#ngxencode_args). @@ -5198,11 +5212,11 @@ ngx.encode_base64 ----------------- **syntax:** *newstr = ngx.encode_base64(str, no_padding?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Encodes `str` to a base64 digest. -Since the `0.9.16` release, an optional boolean-typed `no_padding` argument can be specified to control whether the base64 padding should be appended to the resulting digest (default to `false`, i.e., with padding enabled). This enables streaming base64 digest calculation by (data chunks) though it would be the caller's responsibility to append an appropriate padding at the end of data stream. +Since the `0.9.16` release, an optional boolean-typed `no_padding` argument can be specified to control whether the base64 padding should be appended to the resulting digest (default to `false`, i.e., with padding enabled). [Back to TOC](#nginx-api-for-lua) @@ -5210,7 +5224,7 @@ ngx.decode_base64 ----------------- **syntax:** *newstr = ngx.decode_base64(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Decodes the `str` argument as a base64 digest to the raw form. Returns `nil` if `str` is not well formed. @@ -5220,7 +5234,7 @@ ngx.crc32_short --------------- **syntax:** *intval = ngx.crc32_short(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Calculates the CRC-32 (Cyclic Redundancy Code) digest for the `str` argument. @@ -5236,7 +5250,7 @@ ngx.crc32_long -------------- **syntax:** *intval = ngx.crc32_long(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Calculates the CRC-32 (Cyclic Redundancy Code) digest for the `str` argument. @@ -5252,7 +5266,7 @@ ngx.hmac_sha1 ------------- **syntax:** *digest = ngx.hmac_sha1(secret_key, str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Computes the [HMAC-SHA1](http://en.wikipedia.org/wiki/HMAC) digest of the argument `str` and turns the result using the secret key ``. @@ -5284,7 +5298,7 @@ ngx.md5 ------- **syntax:** *digest = ngx.md5(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Returns the hexadecimal representation of the MD5 digest of the `str` argument. @@ -5311,7 +5325,7 @@ ngx.md5_bin ----------- **syntax:** *digest = ngx.md5_bin(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Returns the binary form of the MD5 digest of the `str` argument. @@ -5323,7 +5337,7 @@ ngx.sha1_bin ------------ **syntax:** *digest = ngx.sha1_bin(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Returns the binary form of the SHA-1 digest of the `str` argument. @@ -5337,7 +5351,7 @@ ngx.quote_sql_str ----------------- **syntax:** *quoted_value = ngx.quote_sql_str(raw_value)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Returns a quoted SQL string literal according to the MySQL quoting rules. @@ -5347,7 +5361,7 @@ ngx.today --------- **syntax:** *str = ngx.today()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Returns current date (in the format `yyyy-mm-dd`) from the nginx cached time (no syscall involved unlike Lua's date library). @@ -5359,7 +5373,7 @@ ngx.time -------- **syntax:** *secs = ngx.time()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Returns the elapsed seconds from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -5371,7 +5385,7 @@ ngx.now ------- **syntax:** *secs = ngx.now()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Returns a floating-point number for the elapsed time in seconds (including milliseconds as the decimal part) from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -5385,7 +5399,7 @@ ngx.update_time --------------- **syntax:** *ngx.update_time()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Forcibly updates the Nginx current time cache. This call involves a syscall and thus has some overhead, so do not abuse it. @@ -5397,7 +5411,7 @@ ngx.localtime ------------- **syntax:** *str = ngx.localtime()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Returns the current time stamp (in the format `yyyy-mm-dd hh:mm:ss`) of the nginx cached time (no syscall involved unlike Lua's [os.date](http://www.lua.org/manual/5.1/manual.html#pdf-os.date) function). @@ -5409,7 +5423,7 @@ ngx.utctime ----------- **syntax:** *str = ngx.utctime()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Returns the current time stamp (in the format `yyyy-mm-dd hh:mm:ss`) of the nginx cached time (no syscall involved unlike Lua's [os.date](http://www.lua.org/manual/5.1/manual.html#pdf-os.date) function). @@ -5421,7 +5435,7 @@ ngx.cookie_time --------------- **syntax:** *str = ngx.cookie_time(sec)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Returns a formatted string can be used as the cookie expiration time. The parameter `sec` is the time stamp in seconds (like those returned from [ngx.time](#ngxtime)). @@ -5437,7 +5451,7 @@ ngx.http_time ------------- **syntax:** *str = ngx.http_time(sec)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Returns a formated string can be used as the http header time (for example, being used in `Last-Modified` header). The parameter `sec` is the time stamp in seconds (like those returned from [ngx.time](#ngxtime)). @@ -5453,7 +5467,7 @@ ngx.parse_http_time ------------------- **syntax:** *sec = ngx.parse_http_time(str)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Parse the http time string (as returned by [ngx.http_time](#ngxhttp_time)) into seconds. Returns the seconds or `nil` if the input string is in bad forms. @@ -5481,7 +5495,7 @@ ngx.re.match ------------ **syntax:** *captures, err = ngx.re.match(subject, regex, options?, ctx?, res_table?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Matches the `subject` string using the Perl compatible regular expression `regex` with the optional `options`. @@ -5524,16 +5538,16 @@ and are returned in the same Lua table as key-value pairs as the numbered captur -- m["remaining"] == "234" ``` -Unmatched subpatterns will have `nil` values in their `captures` table fields. +Unmatched subpatterns will have `false` values in their `captures` table fields. ```lua local m, err = ngx.re.match("hello, world", "(world)|(hello)|(?howdy)") -- m[0] == "hello" - -- m[1] == nil + -- m[1] == false -- m[2] == "hello" - -- m[3] == nil - -- m["named"] == nil + -- m[3] == false + -- m["named"] == false ``` Specify `options` to control how the match operation will be performed. The following option characters are supported: @@ -5623,7 +5637,7 @@ Note that, the `options` argument is not optional when the `ctx` argument is spe This method requires the PCRE library enabled in Nginx. ([Known Issue With Special Escaping Sequences](#special-escaping-sequences)). -To confirm that PCRE JIT is enabled, activate the Nginx debug log by adding the `--with-debug` option to Nginx or ngx_openresty's `./configure` script. Then, enable the "debug" error log level in `error_log` directive. The following message will be generated if PCRE JIT is enabled: +To confirm that PCRE JIT is enabled, activate the Nginx debug log by adding the `--with-debug` option to Nginx or OpenResty's `./configure` script. Then, enable the "debug" error log level in `error_log` directive. The following message will be generated if PCRE JIT is enabled: pcre JIT compiling result: 1 @@ -5639,7 +5653,7 @@ ngx.re.find ----------- **syntax:** *from, to, err = ngx.re.find(subject, regex, options?, ctx?, nth?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Similar to [ngx.re.match](#ngxrematch) but only returns the begining index (`from`) and end index (`to`) of the matched substring. The returned indexes are 1-based and can be fed directly into the [string.sub](http://www.lua.org/manual/5.1/manual.html#pdf-string.sub) API function to obtain the matched substring. @@ -5693,7 +5707,7 @@ ngx.re.gmatch ------------- **syntax:** *iterator, err = ngx.re.gmatch(subject, regex, options?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Similar to [ngx.re.match](#ngxrematch), but returns a Lua iterator instead, so as to let the user programmer iterate all the matches over the `` string argument with the PCRE `regex`. @@ -5771,7 +5785,7 @@ ngx.re.sub ---------- **syntax:** *newstr, n, err = ngx.re.sub(subject, regex, replace, options?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Substitutes the first match of the Perl compatible regular expression `regex` on the `subject` argument string with the string or function argument `replace`. The optional `options` argument has exactly the same meaning as in [ngx.re.match](#ngxrematch). @@ -5837,7 +5851,7 @@ ngx.re.gsub ----------- **syntax:** *newstr, n, err = ngx.re.gsub(subject, regex, replace, options?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Just like [ngx.re.sub](#ngxresub), but does global substitution. @@ -5877,7 +5891,7 @@ ngx.shared.DICT **syntax:** *dict = ngx.shared\[name_var\]* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Fetching the shm-based Lua dictionary object for the shared memory zone named `DICT` defined by the [lua_shared_dict](#lua_shared_dict) directive. @@ -5950,7 +5964,7 @@ ngx.shared.DICT.get ------------------- **syntax:** *value, flags = ngx.shared.DICT:get(key)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Retrieving the value in the dictionary [ngx.shared.DICT](#ngxshareddict) for the key `key`. If the key does not exist or has been expired, then `nil` will be returned. @@ -5988,7 +6002,7 @@ ngx.shared.DICT.get_stale ------------------------- **syntax:** *value, flags, stale = ngx.shared.DICT:get_stale(key)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Similar to the [get](#ngxshareddictget) method but returns the value even if the key has already expired. @@ -6006,7 +6020,7 @@ ngx.shared.DICT.set ------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:set(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Unconditionally sets a key-value pair into the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). Returns three values: @@ -6054,7 +6068,7 @@ ngx.shared.DICT.safe_set ------------------------ **syntax:** *ok, err = ngx.shared.DICT:safe_set(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Similar to the [set](#ngxshareddictset) method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return `nil` and the string "no memory". @@ -6068,7 +6082,7 @@ ngx.shared.DICT.add ------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:add(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Just like the [set](#ngxshareddictset) method, but only stores the key-value pair into the dictionary [ngx.shared.DICT](#ngxshareddict) if the key does *not* exist. @@ -6084,7 +6098,7 @@ ngx.shared.DICT.safe_add ------------------------ **syntax:** *ok, err = ngx.shared.DICT:safe_add(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Similar to the [add](#ngxshareddictadd) method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return `nil` and the string "no memory". @@ -6098,7 +6112,7 @@ ngx.shared.DICT.replace ----------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:replace(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Just like the [set](#ngxshareddictset) method, but only stores the key-value pair into the dictionary [ngx.shared.DICT](#ngxshareddict) if the key *does* exist. @@ -6114,7 +6128,7 @@ ngx.shared.DICT.delete ---------------------- **syntax:** *ngx.shared.DICT:delete(key)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Unconditionally removes the key-value pair from the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). @@ -6130,7 +6144,7 @@ ngx.shared.DICT.incr -------------------- **syntax:** *newval, err = ngx.shared.DICT:incr(key, value)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Increments the (numerical) value for `key` in the shm-based dictionary [ngx.shared.DICT](#ngxshareddict) by the step value `value`. Returns the new resulting number if the operation is successfully completed or `nil` and an error message otherwise. @@ -6150,7 +6164,7 @@ ngx.shared.DICT.flush_all ------------------------- **syntax:** *ngx.shared.DICT:flush_all()* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Flushes out all the items in the dictionary. This method does not actuall free up all the memory blocks in the dictionary but just marks all the existing items as expired. @@ -6164,7 +6178,7 @@ ngx.shared.DICT.flush_expired ----------------------------- **syntax:** *flushed = ngx.shared.DICT:flush_expired(max_count?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Flushes out the expired items in the dictionary, up to the maximal number specified by the optional `max_count` argument. When the `max_count` argument is given `0` or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. @@ -6180,7 +6194,7 @@ ngx.shared.DICT.get_keys ------------------------ **syntax:** *keys = ngx.shared.DICT:get_keys(max_count?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Fetch a list of the keys from the dictionary, up to ``. @@ -6314,7 +6328,7 @@ Timeout for the reading operation is controlled by the [lua_socket_read_timeout] sock:settimeout(1000) -- one second timeout local data, err = sock:receive() if not data then - ngx.say("failed to read a packet: ", data) + ngx.say("failed to read a packet: ", err) return end ngx.say("successfully read a packet: ", data) @@ -6354,6 +6368,16 @@ This feature was first introduced in the `v0.5.7` release. [Back to TOC](#nginx-api-for-lua) +ngx.socket.stream +----------------- + +Just an alias to [ngx.socket.tcp](#ngxsockettcp). If the stream-typed cosocket may also connect to a unix domain +socket, then this API name is preferred. + +This API function was first added to the `v0.10.1` release. + +[Back to TOC](#nginx-api-for-lua) + ngx.socket.tcp -------------- **syntax:** *tcpsock = ngx.socket.tcp()* @@ -7141,7 +7165,7 @@ ngx.timer.at ------------ **syntax:** *ok, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Creates an Nginx timer with a user callback function as well as optional user arguments. @@ -7267,7 +7291,7 @@ ngx.timer.running_count ----------------------- **syntax:** *count = ngx.timer.running_count()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Returns the number of timers currently running. @@ -7279,7 +7303,7 @@ ngx.timer.pending_count ----------------------- **syntax:** *count = ngx.timer.pending_count()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** Returns the number of pending timers. @@ -7287,6 +7311,19 @@ This directive was first introduced in the `v0.9.20` release. [Back to TOC](#nginx-api-for-lua) +ngx.config.subsystem +-------------------- +**syntax:** *subsystem = ngx.config.subsystem* + +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua** + +This string field indicates the current NGINX subsystem the current Lua environment is based on. For this module, this field always takes the string value `"http"`. For +[ngx_stream_lua_module](https://github.com/openresty/stream-lua-nginx-module#readme), however, this field takes the value `"stream"`. + +This field was first introduced in the `0.10.1`. + +[Back to TOC](#nginx-api-for-lua) + ngx.config.debug ---------------- **syntax:** *debug = ngx.config.debug* @@ -7497,7 +7534,7 @@ ndk.set_var.DIRECTIVE --------------------- **syntax:** *res = ndk.set_var.DIRECTIVE_NAME* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** This mechanism allows calling other nginx C modules' directives that are implemented by [Nginx Devel Kit](https://github.com/simpl/ngx_devel_kit) (NDK)'s set_var submodule's `ndk_set_var_value`. diff --git a/debian/modules/nginx-lua/config b/debian/modules/nginx-lua/config index 030788c..3c2548b 100644 --- a/debian/modules/nginx-lua/config +++ b/debian/modules/nginx-lua/config @@ -284,14 +284,17 @@ END fi fi +ngx_module_incs= +ngx_module_libs= + if [ $ngx_found = yes ]; then # this is a hack to persuade nginx's build system to favor # the paths set by our user environments: CFLAGS="$ngx_lua_opt_I $CFLAGS" NGX_LD_OPT="$ngx_lua_opt_L $NGX_LD_OPT" - CORE_INCS="$CORE_INCS $ngx_feature_path" - CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + ngx_module_incs="$ngx_module_incs $ngx_feature_path" + ngx_module_libs="$ngx_module_libs $ngx_feature_libs" else cat << END $0: error: ngx_http_lua_module requires the Lua library. @@ -300,119 +303,118 @@ END fi ngx_addon_name=ngx_http_lua_module -HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_lua_module" -NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ - $ngx_addon_dir/src/ngx_http_lua_script.c \ - $ngx_addon_dir/src/ngx_http_lua_log.c \ - $ngx_addon_dir/src/ngx_http_lua_subrequest.c \ - $ngx_addon_dir/src/ngx_http_lua_ndk.c \ - $ngx_addon_dir/src/ngx_http_lua_control.c \ - $ngx_addon_dir/src/ngx_http_lua_time.c \ - $ngx_addon_dir/src/ngx_http_lua_misc.c \ - $ngx_addon_dir/src/ngx_http_lua_variable.c \ - $ngx_addon_dir/src/ngx_http_lua_string.c \ - $ngx_addon_dir/src/ngx_http_lua_output.c \ - $ngx_addon_dir/src/ngx_http_lua_headers.c \ - $ngx_addon_dir/src/ngx_http_lua_req_body.c \ - $ngx_addon_dir/src/ngx_http_lua_uri.c \ - $ngx_addon_dir/src/ngx_http_lua_args.c \ - $ngx_addon_dir/src/ngx_http_lua_ctx.c \ - $ngx_addon_dir/src/ngx_http_lua_regex.c \ - $ngx_addon_dir/src/ngx_http_lua_module.c \ - $ngx_addon_dir/src/ngx_http_lua_headers_out.c \ - $ngx_addon_dir/src/ngx_http_lua_headers_in.c \ - $ngx_addon_dir/src/ngx_http_lua_directive.c \ - $ngx_addon_dir/src/ngx_http_lua_consts.c \ - $ngx_addon_dir/src/ngx_http_lua_exception.c \ - $ngx_addon_dir/src/ngx_http_lua_util.c \ - $ngx_addon_dir/src/ngx_http_lua_cache.c \ - $ngx_addon_dir/src/ngx_http_lua_contentby.c \ - $ngx_addon_dir/src/ngx_http_lua_rewriteby.c \ - $ngx_addon_dir/src/ngx_http_lua_accessby.c \ - $ngx_addon_dir/src/ngx_http_lua_setby.c \ - $ngx_addon_dir/src/ngx_http_lua_capturefilter.c \ - $ngx_addon_dir/src/ngx_http_lua_clfactory.c \ - $ngx_addon_dir/src/ngx_http_lua_pcrefix.c \ - $ngx_addon_dir/src/ngx_http_lua_headerfilterby.c \ - $ngx_addon_dir/src/ngx_http_lua_shdict.c \ - $ngx_addon_dir/src/ngx_http_lua_socket_tcp.c \ - $ngx_addon_dir/src/ngx_http_lua_api.c \ - $ngx_addon_dir/src/ngx_http_lua_logby.c \ - $ngx_addon_dir/src/ngx_http_lua_sleep.c \ - $ngx_addon_dir/src/ngx_http_lua_semaphore.c\ - $ngx_addon_dir/src/ngx_http_lua_coroutine.c \ - $ngx_addon_dir/src/ngx_http_lua_bodyfilterby.c \ - $ngx_addon_dir/src/ngx_http_lua_initby.c \ - $ngx_addon_dir/src/ngx_http_lua_initworkerby.c \ - $ngx_addon_dir/src/ngx_http_lua_socket_udp.c \ - $ngx_addon_dir/src/ngx_http_lua_req_method.c \ - $ngx_addon_dir/src/ngx_http_lua_phase.c \ - $ngx_addon_dir/src/ngx_http_lua_uthread.c \ - $ngx_addon_dir/src/ngx_http_lua_timer.c \ - $ngx_addon_dir/src/ngx_http_lua_config.c \ - $ngx_addon_dir/src/ngx_http_lua_worker.c \ - $ngx_addon_dir/src/ngx_http_lua_ssl_certby.c \ - $ngx_addon_dir/src/ngx_http_lua_ssl_ocsp.c \ - $ngx_addon_dir/src/ngx_http_lua_lex.c \ - $ngx_addon_dir/src/ngx_http_lua_balancer.c \ - " +HTTP_LUA_SRCS=" \ + $ngx_addon_dir/src/ngx_http_lua_script.c \ + $ngx_addon_dir/src/ngx_http_lua_log.c \ + $ngx_addon_dir/src/ngx_http_lua_subrequest.c \ + $ngx_addon_dir/src/ngx_http_lua_ndk.c \ + $ngx_addon_dir/src/ngx_http_lua_control.c \ + $ngx_addon_dir/src/ngx_http_lua_time.c \ + $ngx_addon_dir/src/ngx_http_lua_misc.c \ + $ngx_addon_dir/src/ngx_http_lua_variable.c \ + $ngx_addon_dir/src/ngx_http_lua_string.c \ + $ngx_addon_dir/src/ngx_http_lua_output.c \ + $ngx_addon_dir/src/ngx_http_lua_headers.c \ + $ngx_addon_dir/src/ngx_http_lua_req_body.c \ + $ngx_addon_dir/src/ngx_http_lua_uri.c \ + $ngx_addon_dir/src/ngx_http_lua_args.c \ + $ngx_addon_dir/src/ngx_http_lua_ctx.c \ + $ngx_addon_dir/src/ngx_http_lua_regex.c \ + $ngx_addon_dir/src/ngx_http_lua_module.c \ + $ngx_addon_dir/src/ngx_http_lua_headers_out.c \ + $ngx_addon_dir/src/ngx_http_lua_headers_in.c \ + $ngx_addon_dir/src/ngx_http_lua_directive.c \ + $ngx_addon_dir/src/ngx_http_lua_consts.c \ + $ngx_addon_dir/src/ngx_http_lua_exception.c \ + $ngx_addon_dir/src/ngx_http_lua_util.c \ + $ngx_addon_dir/src/ngx_http_lua_cache.c \ + $ngx_addon_dir/src/ngx_http_lua_contentby.c \ + $ngx_addon_dir/src/ngx_http_lua_rewriteby.c \ + $ngx_addon_dir/src/ngx_http_lua_accessby.c \ + $ngx_addon_dir/src/ngx_http_lua_setby.c \ + $ngx_addon_dir/src/ngx_http_lua_capturefilter.c \ + $ngx_addon_dir/src/ngx_http_lua_clfactory.c \ + $ngx_addon_dir/src/ngx_http_lua_pcrefix.c \ + $ngx_addon_dir/src/ngx_http_lua_headerfilterby.c \ + $ngx_addon_dir/src/ngx_http_lua_shdict.c \ + $ngx_addon_dir/src/ngx_http_lua_socket_tcp.c \ + $ngx_addon_dir/src/ngx_http_lua_api.c \ + $ngx_addon_dir/src/ngx_http_lua_logby.c \ + $ngx_addon_dir/src/ngx_http_lua_sleep.c \ + $ngx_addon_dir/src/ngx_http_lua_semaphore.c\ + $ngx_addon_dir/src/ngx_http_lua_coroutine.c \ + $ngx_addon_dir/src/ngx_http_lua_bodyfilterby.c \ + $ngx_addon_dir/src/ngx_http_lua_initby.c \ + $ngx_addon_dir/src/ngx_http_lua_initworkerby.c \ + $ngx_addon_dir/src/ngx_http_lua_socket_udp.c \ + $ngx_addon_dir/src/ngx_http_lua_req_method.c \ + $ngx_addon_dir/src/ngx_http_lua_phase.c \ + $ngx_addon_dir/src/ngx_http_lua_uthread.c \ + $ngx_addon_dir/src/ngx_http_lua_timer.c \ + $ngx_addon_dir/src/ngx_http_lua_config.c \ + $ngx_addon_dir/src/ngx_http_lua_worker.c \ + $ngx_addon_dir/src/ngx_http_lua_ssl_certby.c \ + $ngx_addon_dir/src/ngx_http_lua_ssl_ocsp.c \ + $ngx_addon_dir/src/ngx_http_lua_lex.c \ + $ngx_addon_dir/src/ngx_http_lua_balancer.c \ + " -NGX_ADDON_DEPS="$NGX_ADDON_DEPS \ - $ngx_addon_dir/src/ddebug.h \ - $ngx_addon_dir/src/ngx_http_lua_script.h \ - $ngx_addon_dir/src/ngx_http_lua_log.h \ - $ngx_addon_dir/src/ngx_http_lua_subrequest.h \ - $ngx_addon_dir/src/ngx_http_lua_ndk.h \ - $ngx_addon_dir/src/ngx_http_lua_control.h \ - $ngx_addon_dir/src/ngx_http_lua_time.h \ - $ngx_addon_dir/src/ngx_http_lua_string.h \ - $ngx_addon_dir/src/ngx_http_lua_misc.h \ - $ngx_addon_dir/src/ngx_http_lua_variable.h \ - $ngx_addon_dir/src/ngx_http_lua_output.h \ - $ngx_addon_dir/src/ngx_http_lua_headers.h \ - $ngx_addon_dir/src/ngx_http_lua_uri.h \ - $ngx_addon_dir/src/ngx_http_lua_req_body.h \ - $ngx_addon_dir/src/ngx_http_lua_args.h \ - $ngx_addon_dir/src/ngx_http_lua_ctx.h \ - $ngx_addon_dir/src/ngx_http_lua_regex.h \ - $ngx_addon_dir/src/ngx_http_lua_common.h \ - $ngx_addon_dir/src/ngx_http_lua_directive.h \ - $ngx_addon_dir/src/ngx_http_lua_headers_out.h \ - $ngx_addon_dir/src/ngx_http_lua_headers_in.h \ - $ngx_addon_dir/src/ngx_http_lua_consts.h \ - $ngx_addon_dir/src/ngx_http_lua_exception.h \ - $ngx_addon_dir/src/ngx_http_lua_util.h \ - $ngx_addon_dir/src/ngx_http_lua_cache.h \ - $ngx_addon_dir/src/ngx_http_lua_contentby.h \ - $ngx_addon_dir/src/ngx_http_lua_rewriteby.h \ - $ngx_addon_dir/src/ngx_http_lua_accessby.h \ - $ngx_addon_dir/src/ngx_http_lua_setby.h \ - $ngx_addon_dir/src/ngx_http_lua_capturefilter.h \ - $ngx_addon_dir/src/ngx_http_lua_clfactory.h \ - $ngx_addon_dir/src/ngx_http_lua_pcrefix.h \ - $ngx_addon_dir/src/ngx_http_lua_headerfilterby.h \ - $ngx_addon_dir/src/ngx_http_lua_shdict.h \ - $ngx_addon_dir/src/ngx_http_lua_socket_tcp.h \ - $ngx_addon_dir/src/api/ngx_http_lua_api.h \ - $ngx_addon_dir/src/ngx_http_lua_logby.h \ - $ngx_addon_dir/src/ngx_http_lua_sleep.h \ - $ngx_addon_dir/src/ngx_http_lua_semaphore.h\ - $ngx_addon_dir/src/ngx_http_lua_coroutine.h \ - $ngx_addon_dir/src/ngx_http_lua_bodyfilterby.h \ - $ngx_addon_dir/src/ngx_http_lua_initby.h \ - $ngx_addon_dir/src/ngx_http_lua_initworkerby.h \ - $ngx_addon_dir/src/ngx_http_lua_socket_udp.h \ - $ngx_addon_dir/src/ngx_http_lua_req_method.h \ - $ngx_addon_dir/src/ngx_http_lua_phase.h \ - $ngx_addon_dir/src/ngx_http_lua_probe.h \ - $ngx_addon_dir/src/ngx_http_lua_uthread.h \ - $ngx_addon_dir/src/ngx_http_lua_timer.h \ - $ngx_addon_dir/src/ngx_http_lua_config.h \ - $ngx_addon_dir/src/ngx_http_lua_worker.h \ - $ngx_addon_dir/src/ngx_http_lua_ssl_certby.h \ - $ngx_addon_dir/src/ngx_http_lua_lex.h \ - $ngx_addon_dir/src/ngx_http_lua_balancer.h \ - " +HTTP_LUA_DEPS=" \ + $ngx_addon_dir/src/ddebug.h \ + $ngx_addon_dir/src/ngx_http_lua_script.h \ + $ngx_addon_dir/src/ngx_http_lua_log.h \ + $ngx_addon_dir/src/ngx_http_lua_subrequest.h \ + $ngx_addon_dir/src/ngx_http_lua_ndk.h \ + $ngx_addon_dir/src/ngx_http_lua_control.h \ + $ngx_addon_dir/src/ngx_http_lua_time.h \ + $ngx_addon_dir/src/ngx_http_lua_string.h \ + $ngx_addon_dir/src/ngx_http_lua_misc.h \ + $ngx_addon_dir/src/ngx_http_lua_variable.h \ + $ngx_addon_dir/src/ngx_http_lua_output.h \ + $ngx_addon_dir/src/ngx_http_lua_headers.h \ + $ngx_addon_dir/src/ngx_http_lua_uri.h \ + $ngx_addon_dir/src/ngx_http_lua_req_body.h \ + $ngx_addon_dir/src/ngx_http_lua_args.h \ + $ngx_addon_dir/src/ngx_http_lua_ctx.h \ + $ngx_addon_dir/src/ngx_http_lua_regex.h \ + $ngx_addon_dir/src/ngx_http_lua_common.h \ + $ngx_addon_dir/src/ngx_http_lua_directive.h \ + $ngx_addon_dir/src/ngx_http_lua_headers_out.h \ + $ngx_addon_dir/src/ngx_http_lua_headers_in.h \ + $ngx_addon_dir/src/ngx_http_lua_consts.h \ + $ngx_addon_dir/src/ngx_http_lua_exception.h \ + $ngx_addon_dir/src/ngx_http_lua_util.h \ + $ngx_addon_dir/src/ngx_http_lua_cache.h \ + $ngx_addon_dir/src/ngx_http_lua_contentby.h \ + $ngx_addon_dir/src/ngx_http_lua_rewriteby.h \ + $ngx_addon_dir/src/ngx_http_lua_accessby.h \ + $ngx_addon_dir/src/ngx_http_lua_setby.h \ + $ngx_addon_dir/src/ngx_http_lua_capturefilter.h \ + $ngx_addon_dir/src/ngx_http_lua_clfactory.h \ + $ngx_addon_dir/src/ngx_http_lua_pcrefix.h \ + $ngx_addon_dir/src/ngx_http_lua_headerfilterby.h \ + $ngx_addon_dir/src/ngx_http_lua_shdict.h \ + $ngx_addon_dir/src/ngx_http_lua_socket_tcp.h \ + $ngx_addon_dir/src/api/ngx_http_lua_api.h \ + $ngx_addon_dir/src/ngx_http_lua_logby.h \ + $ngx_addon_dir/src/ngx_http_lua_sleep.h \ + $ngx_addon_dir/src/ngx_http_lua_semaphore.h\ + $ngx_addon_dir/src/ngx_http_lua_coroutine.h \ + $ngx_addon_dir/src/ngx_http_lua_bodyfilterby.h \ + $ngx_addon_dir/src/ngx_http_lua_initby.h \ + $ngx_addon_dir/src/ngx_http_lua_initworkerby.h \ + $ngx_addon_dir/src/ngx_http_lua_socket_udp.h \ + $ngx_addon_dir/src/ngx_http_lua_req_method.h \ + $ngx_addon_dir/src/ngx_http_lua_phase.h \ + $ngx_addon_dir/src/ngx_http_lua_probe.h \ + $ngx_addon_dir/src/ngx_http_lua_uthread.h \ + $ngx_addon_dir/src/ngx_http_lua_timer.h \ + $ngx_addon_dir/src/ngx_http_lua_config.h \ + $ngx_addon_dir/src/ngx_http_lua_worker.h \ + $ngx_addon_dir/src/ngx_http_lua_ssl_certby.h \ + $ngx_addon_dir/src/ngx_http_lua_lex.h \ + $ngx_addon_dir/src/ngx_http_lua_balancer.h \ + " CFLAGS="$CFLAGS -DNDK_SET_VAR" @@ -464,6 +466,21 @@ ngx_feature_test='setsockopt(1, SOL_SOCKET, SO_PASSCRED, NULL, 0);' . auto/feature +if test -n "$ngx_module_link"; then + ngx_module_type=HTTP_AUX_FILTER + ngx_module_name=$ngx_addon_name + ngx_module_deps="$HTTP_LUA_DEPS" + ngx_module_srcs="$HTTP_LUA_SRCS" + + . auto/module +else + HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES $ngx_addon_name" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $HTTP_LUA_SRCS" + NGX_ADDON_DEPS="$NGX_ADDON_DEPS $HTTP_LUA_DEPS" + + CORE_INCS="$CORE_INCS $ngx_module_incs" + CORE_LIBS="$CORE_LIBS $ngx_module_libs" +fi + #CFLAGS=$"$CFLAGS -DLUA_DEFAULT_PATH='\"/usr/local/openresty/lualib/?.lua\"'" #CFLAGS=$"$CFLAGS -DLUA_DEFAULT_CPATH='\"/usr/local/openresty/lualib/?.so\"'" - diff --git a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki index f3bf06e..3a39ef8 100644 --- a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.0] released on 11 January 2015. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.0] released on 11 January 2016. = Synopsis = @@ -160,6 +160,10 @@ The Lua interpreter or LuaJIT instance is shared across all the requests in a si Loaded Lua modules persist in the nginx worker process level resulting in a small memory footprint in Lua even when under heavy loads. +This module is plugged into NGINX's "http" subsystem so it can only speaks downstream communication protocols in the HTTP family (HTTP 0.9/1.0/1.1/2.0, WebSockets, and etc). +If you want to do generic TCP communications with the downstream clients, then you should use the [https://github.com/openresty/stream-lua-nginx-module#readme ngx_stream_lua] module instead +which has a compatible Lua API. + = Typical Uses = Just to name a few: @@ -191,7 +195,7 @@ Nginx cores older than 1.6.0 (exclusive) are *not* supported. = Installation = -It is highly recommended to use the [http://openresty.org ngx_openresty bundle] that bundles Nginx, ngx_lua, LuaJIT 2.0/2.1 (or the optional standard Lua 5.1 interpreter), as well as a package of powerful companion Nginx modules. The basic installation step is a simple command: ./configure --with-luajit && make && make install. +It is highly recommended to use the [http://openresty.org OpenResty bundle] that bundles Nginx, ngx_lua, LuaJIT 2.0/2.1 (or the optional standard Lua 5.1 interpreter), as well as a package of powerful companion Nginx modules. The basic installation step is a simple command: ./configure --with-luajit && make && make install. Alternatively, ngx_lua can be manually compiled into Nginx: @@ -229,6 +233,14 @@ Build the source with this module: make install +Starting from NGINX 1.9.11, you can also compile this module as a dynamic module, by using the `--add-dynamic-module=PATH` option instead of `--add-module=PATH` on the +`./configure` command line above. And then you can explicitly load the module in your `nginx.conf` via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module) +directive, for example, + +```nginx +load_module /path/to/modules/ngx_http_lua_module.so; +``` + == C Macro Configurations == While building this module either via OpenResty or with the NGINX core, you can define the following C macros via the C compiler options: @@ -473,7 +485,7 @@ If server-wide data sharing is required, then use one or more of the following a # Use the [[#ngx.shared.DICT|ngx.shared.DICT]] API provided by this module. # Use only a single nginx worker and a single server (this is however not recommended when there is a multi core CPU or multiple CPUs in a single machine). -# Use data storage mechanisms such as memcached, redis, MySQL or PostgreSQL. [http://openresty.org The ngx_openresty bundle] associated with this module comes with a set of companion Nginx modules and Lua libraries that provide interfaces with these data storage mechanisms. +# Use data storage mechanisms such as memcached, redis, MySQL or PostgreSQL. [http://openresty.org The OpenResty bundle] associated with this module comes with a set of companion Nginx modules and Lua libraries that provide interfaces with these data storage mechanisms. = Known Issues = @@ -698,7 +710,6 @@ phases. * cosocket: pool-based backend concurrency level control: implement automatic connect queueing when the backend concurrency exceeds its connection pool limit. * cosocket: review and merge aviramc's [https://github.com/openresty/lua-nginx-module/pull/290 patch] for adding the bsdrecv method. * add new API function ngx.resp.add_header to emulate the standard add_header config directive. -* [[#ngx.re.match|ngx.re]] API: use false instead of nil in the resulting match table to indicate non-existent submatch captures, such that we can avoid "holes" in the array table. * review and apply Jader H. Silva's patch for ngx.re.split(). * review and apply vadim-pavlov's patch for [[#ngx.location.capture|ngx.location.capture]]'s extra_headers option * use ngx_hash_t to optimize the built-in header look-up process for [[#ngx.req.set_header|ngx.req.set_header]], [[#ngx.header.HEADER|ngx.header.HEADER]], and etc. @@ -710,7 +721,7 @@ phases. = Changes = -The changes of every release of this module can be obtained from the ngx_openresty bundle's change logs: +The changes of every release of this module can be obtained from the OpenResty bundle's change logs: http://openresty.org/#Changes @@ -773,9 +784,9 @@ There are also various testing modes based on mockeagain, valgrind, and etc. Ref This module is licensed under the BSD license. -Copyright (C) 2009-2015, by Xiaozhe Wang (chaoslawful) . +Copyright (C) 2009-2016, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2015, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +Copyright (C) 2009-2016, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. All rights reserved. @@ -789,6 +800,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND = See Also = +* [https://github.com/openresty/stream-lua-nginx-module#readme ngx_stream_lua_module] for an official port of this module for the NGINX "stream" subsystem (doing generic downstream TCP communications). * [https://github.com/openresty/lua-resty-memcached lua-resty-memcached] library based on ngx_lua cosocket. * [https://github.com/openresty/lua-resty-redis lua-resty-redis] library based on ngx_lua cosocket. * [https://github.com/openresty/lua-resty-mysql lua-resty-mysql] library based on ngx_lua cosocket. @@ -807,7 +819,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * [[HttpDrizzleModule]] * [https://github.com/FRiCKLE/ngx_postgres postgres-nginx-module] * [[HttpMemcModule]] -* [http://openresty.org The ngx_openresty bundle] +* [http://openresty.org The OpenResty bundle] * [https://github.com/openresty/nginx-systemtap-toolkit Nginx Systemtap Toolkit] = Directives = @@ -1758,7 +1770,7 @@ This directive was first introduced in the v0.5.0rc32 release. '''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; use the new [[#log_by_lua_block|log_by_lua_block]] directive instead. -Runs the Lua source code inlined as the at the log request processing phase. This does not replace the current access logs, but runs after. +Runs the Lua source code inlined as the at the log request processing phase. This does not replace the current access logs, but runs before. Note that the following API functions are currently disabled within this context: @@ -2488,7 +2500,7 @@ Undefined NGINX variables are evaluated to `nil` while uninitialized (but define This API requires a relatively expensive metamethod call and it is recommended to avoid using it on hot code paths. == Core constants == -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, *log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, *log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' ngx.OK (0) @@ -2509,7 +2521,7 @@ The ngx.null constant is a NULL light userdata usually The ngx.DECLINED constant was first introduced in the v0.5.0rc19 release. == HTTP method constants == -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' ngx.HTTP_GET @@ -2532,7 +2544,7 @@ The ngx.DECLINED constant was first introduced in the v0.5.0r These constants are usually used in [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] method calls. == HTTP status constants == -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' value = ngx.HTTP_CONTINUE (100) (first added in the v0.9.20 release) @@ -2572,7 +2584,7 @@ These constants are usually used in [[#ngx.location.capture|ngx.location.capture == Nginx log level constants == -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' ngx.STDERR @@ -3246,7 +3258,7 @@ See also [[#ngx.now|ngx.now]] and [[#ngx.update_time|ngx.update_time]]. Returns the HTTP version number for the current request as a Lua number. -Current possible values are 1.0, 1.1, and 0.9. Returns nil for unrecognized values. +Current possible values are 2.0, 1.0, 1.1, and 0.9. Returns nil for unrecognized values. This method was first introduced in the v0.7.17 release. @@ -3754,7 +3766,7 @@ This function was first introduced in the v0.3.1rc17 release. '''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' -Explicitly discard the request body, i.e., read the data on the connection and throw it away immediately. Please note that ignoring request body is not the right way to discard it, and that this function must be called to avoid breaking things under HTTP 1.1 keepalive or HTTP 1.1 pipelining. +Explicitly discard the request body, i.e., read the data on the connection and throw it away immediately (without using the request body by any means). This function is an asynchronous call and returns immediately. @@ -3767,7 +3779,7 @@ See also [[#ngx.req.read_body|ngx.req.read_body]]. == ngx.req.get_body_data == '''syntax:''' ''data = ngx.req.get_body_data()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, log_by_lua*'' Retrieves in-memory request body data. It returns a Lua string rather than a Lua table holding all the parsed query arguments. Use the [[#ngx.req.get_post_args|ngx.req.get_post_args]] function instead if a Lua table is required. @@ -4236,14 +4248,14 @@ This method was introduced in the 0.5.0rc30 release. == ngx.escape_uri == '''syntax:''' ''newstr = ngx.escape_uri(str)'' -'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Escape str as a URI component. == ngx.unescape_uri == '''syntax:''' ''newstr = ngx.unescape_uri(str)'' -'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Unescape str as an escaped URI component. @@ -4262,7 +4274,7 @@ gives the output == ngx.encode_args == '''syntax:''' ''str = ngx.encode_args(table)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Encode the Lua table to a query args string according to the URI encoded rules. @@ -4313,7 +4325,7 @@ This method was first introduced in the v0.3.1rc27 release. == ngx.decode_args == '''syntax:''' ''table = ngx.decode_args(str, max_args?)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Decodes a URI encoded query-string into a Lua table. This is the inverse function of [[#ngx.encode_args|ngx.encode_args]]. @@ -4332,23 +4344,23 @@ This method was introduced in the v0.5.0rc29. == ngx.encode_base64 == '''syntax:''' ''newstr = ngx.encode_base64(str, no_padding?)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Encodes str to a base64 digest. -Since the 0.9.16 release, an optional boolean-typed no_padding argument can be specified to control whether the base64 padding should be appended to the resulting digest (default to false, i.e., with padding enabled). This enables streaming base64 digest calculation by (data chunks) though it would be the caller's responsibility to append an appropriate padding at the end of data stream. +Since the 0.9.16 release, an optional boolean-typed no_padding argument can be specified to control whether the base64 padding should be appended to the resulting digest (default to false, i.e., with padding enabled). == ngx.decode_base64 == '''syntax:''' ''newstr = ngx.decode_base64(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Decodes the str argument as a base64 digest to the raw form. Returns nil if str is not well formed. == ngx.crc32_short == '''syntax:''' ''intval = ngx.crc32_short(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Calculates the CRC-32 (Cyclic Redundancy Code) digest for the str argument. @@ -4361,7 +4373,7 @@ This API was first introduced in the v0.3.1rc8 release. == ngx.crc32_long == '''syntax:''' ''intval = ngx.crc32_long(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Calculates the CRC-32 (Cyclic Redundancy Code) digest for the str argument. @@ -4374,7 +4386,7 @@ This API was first introduced in the v0.3.1rc8 release. == ngx.hmac_sha1 == '''syntax:''' ''digest = ngx.hmac_sha1(secret_key, str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Computes the [http://en.wikipedia.org/wiki/HMAC HMAC-SHA1] digest of the argument str and turns the result using the secret key . @@ -4402,7 +4414,7 @@ This function was first introduced in the v0.3.1rc29 release. == ngx.md5 == '''syntax:''' ''digest = ngx.md5(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Returns the hexadecimal representation of the MD5 digest of the str argument. @@ -4425,7 +4437,7 @@ See [[#ngx.md5_bin|ngx.md5_bin]] if the raw binary MD5 digest is required. == ngx.md5_bin == '''syntax:''' ''digest = ngx.md5_bin(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Returns the binary form of the MD5 digest of the str argument. @@ -4434,7 +4446,7 @@ See [[#ngx.md5|ngx.md5]] if the hexadecimal form of the MD5 digest is required. == ngx.sha1_bin == '''syntax:''' ''digest = ngx.sha1_bin(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Returns the binary form of the SHA-1 digest of the str argument. @@ -4445,14 +4457,14 @@ This function was first introduced in the v0.5.0rc6. == ngx.quote_sql_str == '''syntax:''' ''quoted_value = ngx.quote_sql_str(raw_value)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Returns a quoted SQL string literal according to the MySQL quoting rules. == ngx.today == '''syntax:''' ''str = ngx.today()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Returns current date (in the format yyyy-mm-dd) from the nginx cached time (no syscall involved unlike Lua's date library). @@ -4461,7 +4473,7 @@ This is the local time. == ngx.time == '''syntax:''' ''secs = ngx.time()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Returns the elapsed seconds from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -4470,7 +4482,7 @@ Updates of the Nginx time cache an be forced by calling [[#ngx.update_time|ngx.u == ngx.now == '''syntax:''' ''secs = ngx.now()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Returns a floating-point number for the elapsed time in seconds (including milliseconds as the decimal part) from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -4481,7 +4493,7 @@ This API was first introduced in v0.3.1rc32. == ngx.update_time == '''syntax:''' ''ngx.update_time()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Forcibly updates the Nginx current time cache. This call involves a syscall and thus has some overhead, so do not abuse it. @@ -4490,7 +4502,7 @@ This API was first introduced in v0.3.1rc32. == ngx.localtime == '''syntax:''' ''str = ngx.localtime()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Returns the current time stamp (in the format yyyy-mm-dd hh:mm:ss) of the nginx cached time (no syscall involved unlike Lua's [http://www.lua.org/manual/5.1/manual.html#pdf-os.date os.date] function). @@ -4499,7 +4511,7 @@ This is the local time. == ngx.utctime == '''syntax:''' ''str = ngx.utctime()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Returns the current time stamp (in the format yyyy-mm-dd hh:mm:ss) of the nginx cached time (no syscall involved unlike Lua's [http://www.lua.org/manual/5.1/manual.html#pdf-os.date os.date] function). @@ -4508,7 +4520,7 @@ This is the UTC time. == ngx.cookie_time == '''syntax:''' ''str = ngx.cookie_time(sec)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Returns a formatted string can be used as the cookie expiration time. The parameter sec is the time stamp in seconds (like those returned from [[#ngx.time|ngx.time]]). @@ -4520,7 +4532,7 @@ Returns a formatted string can be used as the cookie expiration time. The parame == ngx.http_time == '''syntax:''' ''str = ngx.http_time(sec)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Returns a formated string can be used as the http header time (for example, being used in Last-Modified header). The parameter sec is the time stamp in seconds (like those returned from [[#ngx.time|ngx.time]]). @@ -4532,7 +4544,7 @@ Returns a formated string can be used as the http header time (for example, bein == ngx.parse_http_time == '''syntax:''' ''sec = ngx.parse_http_time(str)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Parse the http time string (as returned by [[#ngx.http_time|ngx.http_time]]) into seconds. Returns the seconds or nil if the input string is in bad forms. @@ -4553,7 +4565,7 @@ Returns true if the current request is an nginx subrequest, or subject string using the Perl compatible regular expression regex with the optional options. @@ -4593,15 +4605,15 @@ and are returned in the same Lua table as key-value pairs as the numbered captur -- m["remaining"] == "234" -Unmatched subpatterns will have nil values in their captures table fields. +Unmatched subpatterns will have false values in their captures table fields. local m, err = ngx.re.match("hello, world", "(world)|(hello)|(?howdy)") -- m[0] == "hello" - -- m[1] == nil + -- m[1] == false -- m[2] == "hello" - -- m[3] == nil - -- m["named"] == nil + -- m[3] == false + -- m["named"] == false Specify options to control how the match operation will be performed. The following option characters are supported: @@ -4687,7 +4699,7 @@ Note that, the options argument is not optional when the ctx< This method requires the PCRE library enabled in Nginx. ([[#Special Escaping Sequences|Known Issue With Special Escaping Sequences]]). -To confirm that PCRE JIT is enabled, activate the Nginx debug log by adding the --with-debug option to Nginx or ngx_openresty's ./configure script. Then, enable the "debug" error log level in error_log directive. The following message will be generated if PCRE JIT is enabled: +To confirm that PCRE JIT is enabled, activate the Nginx debug log by adding the --with-debug option to Nginx or OpenResty's ./configure script. Then, enable the "debug" error log level in error_log directive. The following message will be generated if PCRE JIT is enabled: pcre JIT compiling result: 1 @@ -4700,7 +4712,7 @@ This feature was introduced in the v0.2.1rc11 release. == ngx.re.find == '''syntax:''' ''from, to, err = ngx.re.find(subject, regex, options?, ctx?, nth?)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Similar to [[#ngx.re.match|ngx.re.match]] but only returns the begining index (from) and end index (to) of the matched substring. The returned indexes are 1-based and can be fed directly into the [http://www.lua.org/manual/5.1/manual.html#pdf-string.sub string.sub] API function to obtain the matched substring. @@ -4749,7 +4761,7 @@ This API function was first introduced in the v0.9.2 release. == ngx.re.gmatch == '''syntax:''' ''iterator, err = ngx.re.gmatch(subject, regex, options?)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Similar to [[#ngx.re.match|ngx.re.match]], but returns a Lua iterator instead, so as to let the user programmer iterate all the matches over the string argument with the PCRE regex. @@ -4822,7 +4834,7 @@ This feature was first introduced in the v0.2.1rc12 release. == ngx.re.sub == '''syntax:''' ''newstr, n, err = ngx.re.sub(subject, regex, replace, options?)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Substitutes the first match of the Perl compatible regular expression regex on the subject argument string with the string or function argument replace. The optional options argument has exactly the same meaning as in [[#ngx.re.match|ngx.re.match]]. @@ -4881,7 +4893,7 @@ This feature was first introduced in the v0.2.1rc13 release. == ngx.re.gsub == '''syntax:''' ''newstr, n, err = ngx.re.gsub(subject, regex, replace, options?)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Just like [[#ngx.re.sub|ngx.re.sub]], but does global substitution. @@ -4916,7 +4928,7 @@ This feature was first introduced in the v0.2.1rc15 release. '''syntax:''' ''dict = ngx.shared[name_var]'' -'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Fetching the shm-based Lua dictionary object for the shared memory zone named DICT defined by the [[#lua_shared_dict|lua_shared_dict]] directive. @@ -4984,7 +4996,7 @@ This feature was first introduced in the v0.3.1rc22 release. == ngx.shared.DICT.get == '''syntax:''' ''value, flags = ngx.shared.DICT:get(key)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Retrieving the value in the dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] for the key key. If the key does not exist or has been expired, then nil will be returned. @@ -5017,7 +5029,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.get_stale == '''syntax:''' ''value, flags, stale = ngx.shared.DICT:get_stale(key)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Similar to the [[#ngx.shared.DICT.get|get]] method but returns the value even if the key has already expired. @@ -5032,7 +5044,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.set == '''syntax:''' ''success, err, forcible = ngx.shared.DICT:set(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Unconditionally sets a key-value pair into the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. Returns three values: @@ -5075,7 +5087,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.safe_set == '''syntax:''' ''ok, err = ngx.shared.DICT:safe_set(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Similar to the [[#ngx.shared.DICT.set|set]] method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return nil and the string "no memory". @@ -5086,7 +5098,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.add == '''syntax:''' ''success, err, forcible = ngx.shared.DICT:add(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Just like the [[#ngx.shared.DICT.set|set]] method, but only stores the key-value pair into the dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] if the key does ''not'' exist. @@ -5099,7 +5111,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.safe_add == '''syntax:''' ''ok, err = ngx.shared.DICT:safe_add(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Similar to the [[#ngx.shared.DICT.add|add]] method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return nil and the string "no memory". @@ -5110,7 +5122,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.replace == '''syntax:''' ''success, err, forcible = ngx.shared.DICT:replace(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Just like the [[#ngx.shared.DICT.set|set]] method, but only stores the key-value pair into the dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] if the key ''does'' exist. @@ -5123,7 +5135,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.delete == '''syntax:''' ''ngx.shared.DICT:delete(key)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Unconditionally removes the key-value pair from the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. @@ -5136,7 +5148,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.incr == '''syntax:''' ''newval, err = ngx.shared.DICT:incr(key, value)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Increments the (numerical) value for key in the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] by the step value value. Returns the new resulting number if the operation is successfully completed or nil and an error message otherwise. @@ -5153,7 +5165,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.flush_all == '''syntax:''' ''ngx.shared.DICT:flush_all()'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Flushes out all the items in the dictionary. This method does not actuall free up all the memory blocks in the dictionary but just marks all the existing items as expired. @@ -5164,7 +5176,7 @@ See also [[#ngx.shared.DICT.flush_expired|ngx.shared.DICT.flush_expired]] and [[ == ngx.shared.DICT.flush_expired == '''syntax:''' ''flushed = ngx.shared.DICT:flush_expired(max_count?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Flushes out the expired items in the dictionary, up to the maximal number specified by the optional max_count argument. When the max_count argument is given 0 or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. @@ -5177,7 +5189,7 @@ See also [[#ngx.shared.DICT.flush_all|ngx.shared.DICT.flush_all]] and [[#ngx.sha == ngx.shared.DICT.get_keys == '''syntax:''' ''keys = ngx.shared.DICT:get_keys(max_count?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Fetch a list of the keys from the dictionary, up to . @@ -5295,7 +5307,7 @@ Timeout for the reading operation is controlled by the [[#lua_socket_read_timeou sock:settimeout(1000) -- one second timeout local data, err = sock:receive() if not data then - ngx.say("failed to read a packet: ", data) + ngx.say("failed to read a packet: ", err) return end ngx.say("successfully read a packet: ", data) @@ -5327,6 +5339,13 @@ Settings done by this method takes priority over those config directives, like [ This feature was first introduced in the v0.5.7 release. +== ngx.socket.stream == + +Just an alias to [[#ngx.socket.tcp|ngx.socket.tcp]]. If the stream-typed cosocket may also connect to a unix domain +socket, then this API name is preferred. + +This API function was first added to the v0.10.1 release. + == ngx.socket.tcp == '''syntax:''' ''tcpsock = ngx.socket.tcp()'' @@ -6046,7 +6065,7 @@ See also [[#lua_check_client_abort|lua_check_client_abort]]. == ngx.timer.at == '''syntax:''' ''ok, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Creates an Nginx timer with a user callback function as well as optional user arguments. @@ -6167,7 +6186,7 @@ This API was first introduced in the v0.8.0 release. == ngx.timer.running_count == '''syntax:''' ''count = ngx.timer.running_count()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Returns the number of timers currently running. @@ -6176,12 +6195,22 @@ This directive was first introduced in the v0.9.20 release. == ngx.timer.pending_count == '''syntax:''' ''count = ngx.timer.pending_count()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' Returns the number of pending timers. This directive was first introduced in the v0.9.20 release. +== ngx.config.subsystem == +'''syntax:''' ''subsystem = ngx.config.subsystem'' + +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua*'' + +This string field indicates the current NGINX subsystem the current Lua environment is based on. For this module, this field always takes the string value `"http"`. For +[https://github.com/openresty/stream-lua-nginx-module#readme ngx_stream_lua_module], however, this field takes the value `"stream"`. + +This field was first introduced in the 0.10.1. + == ngx.config.debug == '''syntax:''' ''debug = ngx.config.debug'' @@ -6352,7 +6381,7 @@ This feature requires at least ngx_lua v0.10.0. == ndk.set_var.DIRECTIVE == '''syntax:''' ''res = ndk.set_var.DIRECTIVE_NAME'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' This mechanism allows calling other nginx C modules' directives that are implemented by [https://github.com/simpl/ngx_devel_kit Nginx Devel Kit] (NDK)'s set_var submodule's ndk_set_var_value. diff --git a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h index 84a0579..a15d40e 100644 --- a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10000 +#define ngx_http_lua_version 10001 typedef struct { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c b/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c index 14cc342..bd09def 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c @@ -239,6 +239,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) int co_ref; ngx_int_t rc; lua_State *co; + ngx_event_t *rev; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; @@ -308,6 +309,14 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) if (llcf->check_client_abort) { r->read_event_handler = ngx_http_lua_rd_check_broken_connection; + rev = r->connection->read; + + if (!rev->active) { + if (ngx_add_event(rev, NGX_READ_EVENT, 0) != NGX_OK) { + return NGX_ERROR; + } + } + } else { r->read_event_handler = ngx_http_block_reading; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c b/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c index 4fa91fc..1201d26 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c @@ -262,7 +262,24 @@ ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) ngx_http_lua_assert(lscf->balancer.handler && r); - L = ngx_http_lua_get_lua_vm(r, NULL); + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + if (ctx == NULL) { + ctx = ngx_http_lua_create_ctx(r); + if (ctx == NULL) { + return NGX_ERROR; + } + + L = ngx_http_lua_get_lua_vm(r, ctx); + + } else { + L = ngx_http_lua_get_lua_vm(r, ctx); + + dd("reset ctx"); + ngx_http_lua_reset_ctx(r, L, ctx); + } + + ctx->context = NGX_HTTP_LUA_CONTEXT_BALANCER; bp->sockaddr = NULL; bp->socklen = 0; @@ -283,8 +300,6 @@ ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) return NGX_ERROR; } - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx->exited && ctx->exit_code != NGX_OK) { rc = ctx->exit_code; if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) { @@ -321,22 +336,6 @@ ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r) u_char *err_msg; size_t len; ngx_int_t rc; - ngx_http_lua_ctx_t *ctx; - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - - if (ctx == NULL) { - ctx = ngx_http_lua_create_ctx(r); - if (ctx == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - } else { - dd("reset ctx"); - ngx_http_lua_reset_ctx(r, L, ctx); - } - - ctx->context = NGX_HTTP_LUA_CONTEXT_BALANCER; /* init nginx context in Lua VM */ ngx_http_lua_set_req(L, r); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_config.c b/debian/modules/nginx-lua/src/ngx_http_lua_config.c index 00594be..3323175 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_config.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_config.c @@ -23,7 +23,7 @@ ngx_http_lua_inject_config_api(lua_State *L) { /* ngx.config */ - lua_createtable(L, 0, 5 /* nrec */); /* .config */ + lua_createtable(L, 0, 6 /* nrec */); /* .config */ #if (NGX_DEBUG) lua_pushboolean(L, 1); @@ -44,6 +44,9 @@ ngx_http_lua_inject_config_api(lua_State *L) lua_pushcfunction(L, ngx_http_lua_config_configure); lua_setfield(L, -2, "nginx_configure"); + lua_pushliteral(L, "http"); + lua_setfield(L, -2, "subsystem"); + lua_setfield(L, -2, "config"); } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c b/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c index 666b549..6718885 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c @@ -27,6 +27,7 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) int co_ref; ngx_int_t rc; lua_State *co; + ngx_event_t *rev; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; @@ -96,6 +97,14 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) if (llcf->check_client_abort) { r->read_event_handler = ngx_http_lua_rd_check_broken_connection; + rev = r->connection->read; + + if (!rev->active) { + if (ngx_add_event(rev, NGX_READ_EVENT, 0) != NGX_OK) { + return NGX_ERROR; + } + } + } else { r->read_event_handler = ngx_http_block_reading; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers.c b/debian/modules/nginx-lua/src/ngx_http_lua_headers.c index a9e45d3..45be168 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headers.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headers.c @@ -53,6 +53,12 @@ ngx_http_lua_ngx_req_http_version(lua_State *L) lua_pushnumber(L, 1.1); break; +#ifdef NGX_HTTP_VERSION_20 + case NGX_HTTP_VERSION_20: + lua_pushnumber(L, 2.0); + break; +#endif + default: lua_pushnil(L); break; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c b/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c index 0876f26..8a374c2 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c @@ -26,6 +26,7 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) ngx_uint_t i; ngx_conf_t conf; ngx_cycle_t *fake_cycle; + ngx_module_t **modules; ngx_open_file_t *file, *ofile; ngx_list_part_t *part; ngx_connection_t *c = NULL; @@ -46,7 +47,7 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) return NGX_OK; } - conf_ctx = ((ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index]); + conf_ctx = (ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index]; http_ctx.main_conf = conf_ctx->main_conf; top_clcf = conf_ctx->loc_conf[ngx_http_core_module.ctx_index]; @@ -154,12 +155,18 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) return NGX_ERROR; } - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->type != NGX_HTTP_MODULE) { +#if defined(nginx_version) && nginx_version >= 1009011 + modules = cycle->modules; +#else + modules = ngx_modules; +#endif + + for (i = 0; modules[i]; i++) { + if (modules[i]->type != NGX_HTTP_MODULE) { continue; } - module = ngx_modules[i]->ctx; + module = modules[i]->ctx; if (module->create_srv_conf) { cur = module->create_srv_conf(&conf); @@ -167,7 +174,7 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) return NGX_ERROR; } - http_ctx.srv_conf[ngx_modules[i]->ctx_index] = cur; + http_ctx.srv_conf[modules[i]->ctx_index] = cur; if (module->merge_srv_conf) { prev = module->create_srv_conf(&conf); @@ -188,7 +195,7 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) return NGX_ERROR; } - http_ctx.loc_conf[ngx_modules[i]->ctx_index] = cur; + http_ctx.loc_conf[modules[i]->ctx_index] = cur; if (module->merge_loc_conf) { prev = module->create_loc_conf(&conf); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_log.c b/debian/modules/nginx-lua/src/ngx_http_lua_log.c index daca3fd..c2b2269 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_log.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_log.c @@ -160,6 +160,16 @@ log_wrapper(ngx_log_t *log, const char *ident, ngx_uint_t level, break; + case LUA_TTABLE: + if (!luaL_callmeta(L, i, "__tostring")) { + return luaL_argerror(L, i, "expected table to have " + "__tostring metamethod"); + } + + lua_tolstring(L, -1, &len); + size += len; + break; + case LUA_TLIGHTUSERDATA: if (lua_touserdata(L, i) == NULL) { size += sizeof("null") - 1; @@ -227,6 +237,12 @@ log_wrapper(ngx_log_t *log, const char *ident, ngx_uint_t level, break; + case LUA_TTABLE: + luaL_callmeta(L, i, "__tostring"); + q = (u_char *) lua_tolstring(L, -1, &len); + p = ngx_copy(p, q, len); + break; + case LUA_TLIGHTUSERDATA: *p++ = 'n'; *p++ = 'u'; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_module.c b/debian/modules/nginx-lua/src/ngx_http_lua_module.c index c72a705..4cfee82 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_module.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_module.c @@ -503,8 +503,6 @@ static ngx_command_t ngx_http_lua_cmds[] = { offsetof(ngx_http_lua_loc_conf_t, ssl_ciphers), NULL }, -#if (NGX_HTTP_SSL) - { ngx_string("ssl_certificate_by_lua_block"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, ngx_http_lua_ssl_cert_by_lua_block, @@ -519,8 +517,6 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, (void *) ngx_http_lua_ssl_cert_handler_file }, -#endif /* NGX_HTTP_SSL */ - { ngx_string("lua_ssl_verify_depth"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, @@ -941,11 +937,11 @@ ngx_http_lua_create_loc_conf(ngx_conf_t *cf) * conf->body_filter_src_key = NULL * conf->body_filter_handler = NULL; * - * conf->ssl = 0; - * conf->ssl_protocols = 0; - * conf->ssl_ciphers = { 0, NULL }; - * conf->ssl_trusted_certificate = { 0, NULL }; - * conf->ssl_crl = { 0, NULL }; + * conf->ssl = 0; + * conf->ssl_protocols = 0; + * conf->ssl_ciphers = { 0, NULL }; + * conf->ssl_trusted_certificate = { 0, NULL }; + * conf->ssl_crl = { 0, NULL }; */ conf->force_read_body = NGX_CONF_UNSET; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ndk.c b/debian/modules/nginx-lua/src/ngx_http_lua_ndk.c index d942296..24b80b4 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ndk.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ndk.c @@ -116,15 +116,22 @@ ngx_http_lookup_ndk_set_var_directive(u_char *name, ndk_set_var_t *filter; ngx_uint_t i; ngx_module_t *module; + ngx_module_t **modules; ngx_command_t *cmd; - for (i = 0; ngx_modules[i]; i++) { - module = ngx_modules[i]; +#if defined(nginx_version) && nginx_version >= 1009011 + modules = ngx_cycle->modules; +#else + modules = ngx_modules; +#endif + + for (i = 0; modules[i]; i++) { + module = modules[i]; if (module->type != NGX_HTTP_MODULE) { continue; } - cmd = ngx_modules[i]->commands; + cmd = modules[i]->commands; if (cmd == NULL) { continue; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_output.c b/debian/modules/nginx-lua/src/ngx_http_lua_output.c index dca5fb9..ef816d2 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_output.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_output.c @@ -3,6 +3,7 @@ #endif #include "ddebug.h" + #include "ngx_http_lua_output.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_contentby.h" diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c b/debian/modules/nginx-lua/src/ngx_http_lua_regex.c index 8b4a668..be110e3 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_regex.c @@ -420,6 +420,7 @@ ngx_http_lua_ngx_re_match_helper(lua_State *L, int wantcaps) if (flags & NGX_LUA_RE_MODE_DFA) { ovecsize = 2; + re_comp.captures = 0; } else { ovecsize = (re_comp.captures + 1) * 3; @@ -592,14 +593,15 @@ exec: } if (res_tb_idx == 0) { - lua_createtable(L, rc /* narr */, 0 /* nrec */); + lua_createtable(L, re_comp.captures || 1 /* narr */, + name_count /* nrec */); res_tb_idx = lua_gettop(L); } - for (i = 0, n = 0; i < rc; i++, n += 2) { + for (i = 0, n = 0; i <= re_comp.captures; i++, n += 2) { dd("capture %d: %d %d", i, cap[n], cap[n + 1]); - if (cap[n] < 0) { - lua_pushnil(L); + if (i >= rc || cap[n] < 0) { + lua_pushboolean(L, 0); } else { lua_pushlstring(L, (char *) &subj.data[cap[n]], @@ -881,6 +883,7 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) if (flags & NGX_LUA_RE_MODE_DFA) { ovecsize = 2; + re_comp.captures = 0; } else { ovecsize = (re_comp.captures + 1) * 3; @@ -1116,12 +1119,12 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) dd("rc = %d", (int) rc); - lua_createtable(L, rc /* narr */, 0 /* nrec */); + lua_createtable(L, ctx->ncaptures || 1 /* narr */, name_count /* nrec */); - for (i = 0, n = 0; i < rc; i++, n += 2) { + for (i = 0, n = 0; i <= ctx->ncaptures; i++, n += 2) { dd("capture %d: %d %d", i, cap[n], cap[n + 1]); - if (cap[n] < 0) { - lua_pushnil(L); + if (i >= rc || cap[n] < 0) { + lua_pushboolean(L, 0); } else { lua_pushlstring(L, (char *) &subj.data[cap[n]], @@ -1564,6 +1567,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) if (flags & NGX_LUA_RE_MODE_DFA) { ovecsize = 2; + re_comp.captures = 0; } else { ovecsize = (re_comp.captures + 1) * 3; @@ -1750,12 +1754,13 @@ exec: if (func) { lua_pushvalue(L, 3); - lua_createtable(L, rc - 1 /* narr */, 1 /* nrec */); + lua_createtable(L, re_comp.captures || 1 /* narr */, + name_count /* nrec */); - for (i = 0, n = 0; i < rc; i++, n += 2) { + for (i = 0, n = 0; i <= re_comp.captures; i++, n += 2) { dd("capture %d: %d %d", (int) i, cap[n], cap[n + 1]); - if (cap[n] < 0) { - lua_pushnil(L); + if (i >= rc || cap[n] < 0) { + lua_pushboolean(L, 0); } else { lua_pushlstring(L, (char *) &subj.data[cap[n]], @@ -2071,6 +2076,11 @@ ngx_http_lua_re_collect_named_captures(lua_State *L, int res_tb_idx, } if (flags & NGX_LUA_RE_MODE_DUPNAMES) { + /* unmatched groups are not stored in tables in DUPNAMES mode */ + if (!lua_toboolean(L, -1)) { + lua_pop(L, 1); + continue; + } lua_getfield(L, -2, name); /* big_tb cap small_tb */ @@ -2201,6 +2211,7 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, if (flags & NGX_LUA_RE_MODE_DFA) { ovecsize = 2; + re_comp.captures = 0; } else { ovecsize = (re_comp.captures + 1) * 3; @@ -2279,6 +2290,7 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, if (flags & NGX_LUA_RE_MODE_DFA) { ovecsize = 2; + re->ncaptures = 0; } else { ovecsize = (re->ncaptures + 1) * 3; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c b/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c index a916396..591d2cd 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c @@ -619,9 +619,9 @@ ngx_http_lua_ngx_req_append_body(lua_State *L) ngx_http_request_t *r; int n; ngx_http_request_body_t *rb; - ngx_str_t body; - size_t size, rest; - size_t offset = 0; + ngx_str_t body; + size_t size, rest; + size_t offset = 0; n = lua_gettop(L); @@ -683,10 +683,10 @@ ngx_http_lua_ngx_req_body_finish(lua_State *L) int n; ngx_http_request_body_t *rb; ngx_buf_t *b; - size_t size; - ngx_str_t value; - ngx_str_t key; - ngx_int_t rc; + size_t size; + ngx_str_t value; + ngx_str_t key; + ngx_int_t rc; n = lua_gettop(L); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c b/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c index da30b8b..2ef59c5 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c @@ -235,6 +235,7 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) int co_ref; lua_State *co; ngx_int_t rc; + ngx_event_t *rev; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; @@ -303,6 +304,14 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) if (llcf->check_client_abort) { r->read_event_handler = ngx_http_lua_rd_check_broken_connection; + rev = r->connection->read; + + if (!rev->active) { + if (ngx_add_event(rev, NGX_READ_EVENT, 0) != NGX_OK) { + return NGX_ERROR; + } + } + } else { r->read_event_handler = ngx_http_block_reading; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_script.h b/debian/modules/nginx-lua/src/ngx_http_lua_script.h index b6dbcd4..9fdca96 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_script.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_script.h @@ -75,10 +75,10 @@ typedef struct { ngx_int_t ngx_http_lua_compile_complex_value( - ngx_http_lua_compile_complex_value_t *ccv); + ngx_http_lua_compile_complex_value_t *ccv); ngx_int_t ngx_http_lua_complex_value(ngx_http_request_t *r, ngx_str_t *subj, - size_t offset, ngx_int_t count, int *cap, - ngx_http_lua_complex_value_t *val, luaL_Buffer *luabuf); + size_t offset, ngx_int_t count, int *cap, + ngx_http_lua_complex_value_t *val, luaL_Buffer *luabuf); #endif /* _NGX_HTTP_LUA_SCRIPT_H_INCLUDED_ */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c b/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c index b022604..8d4ac07 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c @@ -249,7 +249,7 @@ ngx_http_lua_semaphore_resume(ngx_http_request_t *r) } else { lua_pushboolean(ctx->cur_co_ctx->co, 0); - lua_pushstring(ctx->cur_co_ctx->co, "timeout"); + lua_pushliteral(ctx->cur_co_ctx->co, "timeout"); } rc = ngx_http_lua_run_thread(vm, r, ctx, 2); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c b/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c index d853382..43f5f9e 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c @@ -140,7 +140,7 @@ void ngx_http_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) { - ngx_rbtree_node_t **p; + ngx_rbtree_node_t **p; ngx_http_lua_shdict_node_t *sdn, *sdnt; for ( ;; ) { @@ -949,7 +949,7 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) if (n >= 4) { exptime = luaL_checknumber(L, 4); if (exptime < 0) { - exptime = 0; + return luaL_error(L, "bad \"exptime\" argument"); } } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c index 98801f5..1a6594d 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c @@ -197,10 +197,12 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) { ngx_int_t rc; - lua_createtable(L, 0, 3 /* nrec */); /* ngx.socket */ + lua_createtable(L, 0, 4 /* nrec */); /* ngx.socket */ lua_pushcfunction(L, ngx_http_lua_socket_tcp); - lua_setfield(L, -2, "tcp"); + lua_pushvalue(L, -1); + lua_setfield(L, -3, "tcp"); + lua_setfield(L, -2, "stream"); { const char buf[] = "local sock = ngx.socket.tcp()" @@ -2874,6 +2876,7 @@ ngx_http_lua_socket_send(ngx_http_request_t *r, } if (n == NGX_ERROR) { + c->error = 1; u->socket_errno = ngx_socket_errno; ngx_http_lua_socket_handle_write_error(r, u, NGX_HTTP_LUA_SOCKET_FT_ERROR); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c b/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c index bfb122f..1ec0c00 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c @@ -54,7 +54,7 @@ static void ngx_http_lua_socket_udp_read_handler(ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u); static void ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u); -static ngx_int_t ngx_http_lua_udp_connect(ngx_udp_connection_t *uc); +static ngx_int_t ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc); static int ngx_http_lua_socket_udp_close(lua_State *L); static ngx_int_t ngx_http_lua_socket_udp_resume(ngx_http_request_t *r); static void ngx_http_lua_udp_resolve_cleanup(void *data); @@ -170,10 +170,10 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) ngx_url_t url; ngx_int_t rc; ngx_http_lua_loc_conf_t *llcf; - ngx_udp_connection_t *uc; int timeout; ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_udp_connection_t *uc; ngx_http_lua_socket_udp_upstream_t *u; /* @@ -642,11 +642,11 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, { ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; - ngx_udp_connection_t *uc; ngx_connection_t *c; ngx_http_cleanup_t *cln; ngx_http_upstream_resolved_t *ur; ngx_int_t rc; + ngx_http_lua_udp_connection_t *uc; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket resolve retval handler"); @@ -1348,7 +1348,7 @@ ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, static ngx_int_t -ngx_http_lua_udp_connect(ngx_udp_connection_t *uc) +ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc) { int rc; ngx_int_t event; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.h b/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.h index dd75b2d..8333346 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.h @@ -24,6 +24,15 @@ typedef void (*ngx_http_lua_socket_udp_upstream_handler_pt) (ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u); +typedef struct { + ngx_connection_t *connection; + struct sockaddr *sockaddr; + socklen_t socklen; + ngx_str_t server; + ngx_log_t log; +} ngx_http_lua_udp_connection_t; + + struct ngx_http_lua_socket_udp_upstream_s { ngx_http_lua_socket_udp_retval_handler prepare_retvals; ngx_http_lua_socket_udp_upstream_handler_pt read_event_handler; @@ -31,7 +40,7 @@ struct ngx_http_lua_socket_udp_upstream_s { ngx_http_lua_loc_conf_t *conf; ngx_http_cleanup_pt *cleanup; ngx_http_request_t *request; - ngx_udp_connection_t udp_connection; + ngx_http_lua_udp_connection_t udp_connection; ngx_msec_t read_timeout; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c index f8648a7..32675b2 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c @@ -585,24 +585,24 @@ ngx_http_lua_ffi_ssl_set_der_certificate(ngx_http_request_t *r, bio = BIO_new_mem_buf((char *) data, len); if (bio == NULL) { - *err = " BIO_new_mem_buf() failed"; + *err = "BIO_new_mem_buf() failed"; goto failed; } x509 = d2i_X509_bio(bio, NULL); if (x509 == NULL) { - *err = " d2i_X509_bio() failed"; + *err = "d2i_X509_bio() failed"; goto failed; } if (SSL_use_certificate(ssl_conn, x509) == 0) { - *err = " SSL_use_certificate() failed"; + *err = "SSL_use_certificate() failed"; goto failed; } #if 0 if (SSL_set_ex_data(ssl_conn, ngx_ssl_certificate_index, x509) == 0) { - *err = " SSL_set_ex_data() failed"; + *err = "SSL_set_ex_data() failed"; goto failed; } #endif @@ -837,6 +837,7 @@ ngx_http_lua_ffi_cert_pem_to_der(const u_char *pem, size_t pem_len, u_char *der, total = i2d_X509(x509, &der); if (total < 0) { + *err = "i2d_X509() failed"; X509_free(x509); BIO_free(bio); return NGX_ERROR; @@ -892,7 +893,6 @@ ngx_http_lua_ffi_priv_key_pem_to_der(const u_char *pem, size_t pem_len, { int len; BIO *in; - RSA *rsa; EVP_PKEY *pkey; in = BIO_new_mem_buf((char *) pem, (int) pem_len); @@ -910,24 +910,15 @@ ngx_http_lua_ffi_priv_key_pem_to_der(const u_char *pem, size_t pem_len, BIO_free(in); - rsa = EVP_PKEY_get1_RSA(pkey); - if (rsa == NULL) { + len = i2d_PrivateKey(pkey, &der); + if (len < 0) { EVP_PKEY_free(pkey); - *err = "EVP_PKEY_get1_RSA failed"; + *err = "i2d_PrivateKey failed"; return NGX_ERROR; } EVP_PKEY_free(pkey); - len = i2d_RSAPrivateKey(rsa, &der); - if (len < 0) { - RSA_free(rsa); - *err = "i2d_RSAPrivateKey failed"; - return NGX_ERROR; - } - - RSA_free(rsa); - return len; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.c b/debian/modules/nginx-lua/src/ngx_http_lua_util.c index afb7655..69eccae 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_util.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_util.c @@ -1649,6 +1649,8 @@ ngx_http_lua_process_flushing_coroutines(ngx_http_request_t *r, if (coctx[i].flushing) { coctx[i].flushing = 0; + ctx->flushing_coros--; + n--; ctx->cur_co_ctx = &coctx[i]; rc = ngx_http_lua_flush_resume_helper(r, ctx); @@ -1658,8 +1660,6 @@ ngx_http_lua_process_flushing_coroutines(ngx_http_request_t *r, /* rc == NGX_DONE */ - ctx->flushing_coros--; - n--; if (n == 0) { return NGX_DONE; } @@ -1694,6 +1694,8 @@ ngx_http_lua_flush_pending_output(ngx_http_request_t *r, c->buffered); if (ctx->busy_bufs) { + /* FIXME since cosockets also share this busy_bufs chain, this condition + * might not be strong enough. better use separate busy_bufs chains. */ rc = ngx_http_lua_output_filter(r, NULL); } else { @@ -3782,8 +3784,9 @@ ngx_http_lua_cleanup_vm(void *data) #endif if (state) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "decrementing " - "the reference count for Lua VM: %i", state->count); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua decrementing the reference count for Lua VM: %i", + state->count); if (--state->count == 0) { L = state->vm; diff --git a/debian/modules/nginx-lua/t/008-today.t b/debian/modules/nginx-lua/t/008-today.t index 02169c8..54bd949 100644 --- a/debian/modules/nginx-lua/t/008-today.t +++ b/debian/modules/nginx-lua/t/008-today.t @@ -1,4 +1,4 @@ -# vim:set ft=perl ts=4 sw=4 et fdm=marker: +# vim:set ft= ts=4 sw=4 et fdm=marker: use Test::Nginx::Socket::Lua; @@ -6,7 +6,7 @@ use Test::Nginx::Socket::Lua; #master_process_enabled(1); log_level('warn'); -repeat_each(1); +repeat_each(2); plan tests => repeat_each() * (blocks() * 2); diff --git a/debian/modules/nginx-lua/t/009-log.t b/debian/modules/nginx-lua/t/009-log.t index e06c799..053dd45 100644 --- a/debian/modules/nginx-lua/t/009-log.t +++ b/debian/modules/nginx-lua/t/009-log.t @@ -265,7 +265,96 @@ qr/\[error\] \S+: \S+ \[lua\] set_by_lua:2: truefalsenil,/ -=== TEST 14: print() in header filter +=== TEST 14: test table with metamethod +--- config + location /log { + content_by_lua_block { + ngx.say("before log") + local t = setmetatable({v = "value"}, { + __tostring = function(self) + return "tostring "..self.v + end + }) + ngx.log(ngx.ERR, t) + ngx.say("after log") + } + } +--- request +GET /log +--- response_body +before log +after log +--- error_log eval +qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):8: tostring value,/ + + + +=== TEST 15: test table without metamethod +--- config + location /log { + content_by_lua_block { + ngx.log(ngx.ERR, {}) + ngx.say("done") + } + } +--- request +GET /log +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log +bad argument #1 to 'log' (expected table to have __tostring metamethod) + + + +=== TEST 16: test tables mixed with other types +--- config + location /log { + content_by_lua_block { + ngx.say("before log") + local t = setmetatable({v = "value"}, { + __tostring = function(self) + return "tostring: "..self.v + end + }) + ngx.log(ngx.ERR, t, " hello ", t) + ngx.say("after log") + } + } +--- request +GET /log +--- response_body +before log +after log +--- error_log eval +qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):8: tostring: value hello tostring: value,/ + + + +=== TEST 17: test print with tables +--- config + location /log { + content_by_lua_block { + ngx.say("before log") + local t = setmetatable({v = "value"}, { + __tostring = function(self) + return "tostring: "..self.v + end + }) + print(t, " hello ", t) + ngx.say("after log") + } + } +--- request +GET /log +--- response_body +before log +after log +--- error_log eval +qr/\[notice\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):8: tostring: value hello tostring: value,/ + + + +=== TEST 18: print() in header filter --- config location /log { header_filter_by_lua ' @@ -285,7 +374,7 @@ hi -=== TEST 15: ngx.log() in header filter +=== TEST 19: ngx.log in header filter --- config location /log { header_filter_by_lua ' @@ -305,7 +394,7 @@ qr/\[error\] .*? \[lua\] header_filter_by_lua:2: howdy, lua!/ -=== TEST 16: ngx.log() big data +=== TEST 20: ngx.log big data --- config location /log { content_by_lua ' @@ -321,7 +410,7 @@ GET /log -=== TEST 17: ngx.log in Lua function calls & inlined lua +=== TEST 21: ngx.log in Lua function calls & inlined lua --- config location /log { content_by_lua ' @@ -346,7 +435,7 @@ qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):7: bar\(\): hell -=== TEST 18: ngx.log in Lua function tail-calls & inlined lua +=== TEST 22: ngx.log in Lua function tail-calls & inlined lua --- config location /log { content_by_lua ' @@ -376,7 +465,7 @@ qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):8:(?: foo\(\):)? -=== TEST 19: ngx.log in Lua files +=== TEST 23: ngx.log in Lua files --- config location /log { content_by_lua_file 'html/test.lua'; @@ -403,7 +492,7 @@ qr/\[error\] \S+: \S+ \[lua\] test.lua:6: bar\(\): hello, log12343.14159/ -=== TEST 20: ngx.log with bad levels (ngx.ERROR, -1) +=== TEST 24: ngx.log with bad levels (ngx.ERROR, -1) --- config location /log { content_by_lua ' @@ -420,7 +509,7 @@ bad log level: -1 -=== TEST 21: ngx.log with bad levels (9) +=== TEST 25: ngx.log with bad levels (9) --- config location /log { content_by_lua ' @@ -437,7 +526,7 @@ bad log level: 9 -=== TEST 22: \0 in the log message +=== TEST 26: \0 in the log message --- config location = /t { content_by_lua ' diff --git a/debian/modules/nginx-lua/t/011-md5_bin.t b/debian/modules/nginx-lua/t/011-md5_bin.t index 48b8c61..ae7c974 100644 --- a/debian/modules/nginx-lua/t/011-md5_bin.t +++ b/debian/modules/nginx-lua/t/011-md5_bin.t @@ -160,11 +160,11 @@ d41d8cd98f00b204e9800998ecf8427e s = string.gsub(s, ".", function (c) return string.format("%02x", string.byte(c)) end) - return s + ngx.say(s) '; } --- request GET /t --- response_body - +6c8349cc7260ae62e3b1396831a8398f diff --git a/debian/modules/nginx-lua/t/013-base64.t b/debian/modules/nginx-lua/t/013-base64.t index 6903218..1cc27de 100644 --- a/debian/modules/nginx-lua/t/013-base64.t +++ b/debian/modules/nginx-lua/t/013-base64.t @@ -14,7 +14,6 @@ plan tests => repeat_each() * (blocks() * 2 + 4); #no_long_string(); run_tests(); - __DATA__ === TEST 1: base64 encode hello diff --git a/debian/modules/nginx-lua/t/016-resp-header.t b/debian/modules/nginx-lua/t/016-resp-header.t index e23b48f..b1f5e2a 100644 --- a/debian/modules/nginx-lua/t/016-resp-header.t +++ b/debian/modules/nginx-lua/t/016-resp-header.t @@ -1226,7 +1226,6 @@ bar: baz === TEST 60: built-in Content-Type header ---- main_config --- config location = /t { content_by_lua ' @@ -1255,7 +1254,6 @@ my content_type: text/plain === TEST 61: built-in Content-Length header ---- main_config --- config location = /t { content_by_lua ' @@ -1284,7 +1282,6 @@ my content_length: 3 === TEST 62: built-in Connection header ---- main_config --- config location = /t { content_by_lua ' @@ -1311,7 +1308,6 @@ my connection: close === TEST 63: built-in Transfer-Encoding header (chunked) ---- main_config --- config location = /t { content_by_lua ' @@ -1339,7 +1335,6 @@ my transfer-encoding: chunked === TEST 64: built-in Transfer-Encoding header (none) ---- main_config --- config location = /t { content_by_lua ' diff --git a/debian/modules/nginx-lua/t/034-match.t b/debian/modules/nginx-lua/t/034-match.t index 172c1b3..4792ae6 100644 --- a/debian/modules/nginx-lua/t/034-match.t +++ b/debian/modules/nginx-lua/t/034-match.t @@ -409,7 +409,7 @@ error: .*?unknown flag "H" \(flags "Hm"\) GET /re --- response_body hello -nil +false hello @@ -814,7 +814,7 @@ hello-1234 -=== TEST 38: named captures are nil +=== TEST 38: named captures are false --- config location /re { content_by_lua ' @@ -834,10 +834,10 @@ hello-1234 GET /re --- response_body hello -nil +false hello -nil -nil +false +false @@ -1148,3 +1148,24 @@ failed to match 1234 --- SKIP + + +=== TEST 49: trailing captures are false +--- config + location /re { + content_by_lua ' + local m = ngx.re.match("hello", "(hello)(.+)?") + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m[2]) + end + '; + } +--- request + GET /re +--- response_body +hello +hello +false + diff --git a/debian/modules/nginx-lua/t/035-gmatch.t b/debian/modules/nginx-lua/t/035-gmatch.t index 04a06ed..69b9512 100644 --- a/debian/modules/nginx-lua/t/035-gmatch.t +++ b/debian/modules/nginx-lua/t/035-gmatch.t @@ -582,13 +582,13 @@ matched: [] --- response_body 1234 1234 -nil +false 1234 -nil +false abcd -nil +false abcd -nil +false abcd diff --git a/debian/modules/nginx-lua/t/036-sub.t b/debian/modules/nginx-lua/t/036-sub.t index 88dc8d6..f08c50f 100644 --- a/debian/modules/nginx-lua/t/036-sub.t +++ b/debian/modules/nginx-lua/t/036-sub.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 18); +plan tests => repeat_each() * (blocks() * 2 + 19); #no_diff(); no_long_string(); @@ -732,3 +732,26 @@ GET /t bad argument type NYI + + +=== TEST 33: function replace (false for groups) +--- config + location /re { + content_by_lua ' + local repl = function (m) + print("group 1: ", m[2]) + return "[" .. m[0] .. "] [" .. m[1] .. "]" + end + + local s, n = ngx.re.sub("hello, 34", "([0-9])|(world)", repl) + ngx.say(s) + ngx.say(n) + '; + } +--- request + GET /re +--- response_body +hello, [3] [3]4 +1 +--- error_log +group 1: false diff --git a/debian/modules/nginx-lua/t/037-gsub.t b/debian/modules/nginx-lua/t/037-gsub.t index b3bb04e..2a1e00f 100644 --- a/debian/modules/nginx-lua/t/037-gsub.t +++ b/debian/modules/nginx-lua/t/037-gsub.t @@ -4,11 +4,11 @@ use Test::Nginx::Socket::Lua; #worker_connections(1014); #master_on(); #workers(2); -log_level('warn'); +#log_level('warn'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 16); +plan tests => repeat_each() * (blocks() * 2 + 17); #no_diff(); no_long_string(); @@ -674,3 +674,26 @@ GET /t --- no_error_log [error] + + +=== TEST 29: function replace (false for groups) +--- config + location /re { + content_by_lua ' + local repl = function (m) + print("group 1: ", m[2]) + return "[" .. m[0] .. "] [" .. m[1] .. "]" + end + + local s, n = ngx.re.gsub("hello, 34", "([0-9])|(world)", repl) + ngx.say(s) + ngx.say(n) + '; + } +--- request + GET /re +--- response_body +hello, [3] [3][4] [4] +2 +--- error_log +group 1: false diff --git a/debian/modules/nginx-lua/t/038-match-o.t b/debian/modules/nginx-lua/t/038-match-o.t index 4ccd73a..628e27f 100644 --- a/debian/modules/nginx-lua/t/038-match-o.t +++ b/debian/modules/nginx-lua/t/038-match-o.t @@ -384,7 +384,7 @@ error: pcre_compile() failed: missing ) in "(abc" GET /re --- response_body hello -nil +false hello @@ -716,7 +716,7 @@ hello-1234 -=== TEST 33: named captures are nil +=== TEST 33: named captures are false --- config location /re { content_by_lua ' @@ -736,8 +736,8 @@ hello-1234 GET /re --- response_body hello -nil +false hello -nil -nil +false +false diff --git a/debian/modules/nginx-lua/t/043-shdict.t b/debian/modules/nginx-lua/t/043-shdict.t index 4c4d121..91a4196 100644 --- a/debian/modules/nginx-lua/t/043-shdict.t +++ b/debian/modules/nginx-lua/t/043-shdict.t @@ -2429,3 +2429,22 @@ nil nil --- no_error_log [error] + + + +=== TEST 92: invalid expire time +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua ' + local dogs = ngx.shared.dogs + dogs:set("foo", 32, -1) + '; + } +--- request +GET /test +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log +bad "exptime" argument diff --git a/debian/modules/nginx-lua/t/044-req-body.t b/debian/modules/nginx-lua/t/044-req-body.t index f0d0a4d..1c1be40 100644 --- a/debian/modules/nginx-lua/t/044-req-body.t +++ b/debian/modules/nginx-lua/t/044-req-body.t @@ -7,7 +7,7 @@ log_level('warn'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 51); +plan tests => repeat_each() * (blocks() * 4 + 52 ); #no_diff(); no_long_string(); @@ -1606,3 +1606,27 @@ hiya, world"] --- no_error_log [error] [alert] + + + +=== TEST 49: get body data at log phase +--- config + location = /test { + content_by_lua_block { + ngx.req.read_body() + ngx.say(ngx.req.get_body_data()) + } + log_by_lua_block { + ngx.log(ngx.WARN, "request body:", ngx.req.get_body_data()) + } + } +--- request +POST /test +hello, world +--- response_body +hello, world +--- error_log +request body:hello, world +--- no_error_log +[error] +[alert] diff --git a/debian/modules/nginx-lua/t/048-match-dfa.t b/debian/modules/nginx-lua/t/048-match-dfa.t index 8350a73..8a0a328 100644 --- a/debian/modules/nginx-lua/t/048-match-dfa.t +++ b/debian/modules/nginx-lua/t/048-match-dfa.t @@ -23,6 +23,8 @@ __DATA__ m = ngx.re.match("hello", "(he|hell)", "d") if m then ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m[2]) else ngx.say("not matched!") end @@ -32,10 +34,35 @@ __DATA__ GET /re --- response_body hell +nil +nil -=== TEST 2: matched with d + j +=== TEST 2: matched with d + o +--- config + location /re { + content_by_lua ' + m = ngx.re.match("hello", "(he|hell)", "do") + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m[2]) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +hell +nil +nil + + + +=== TEST 3: matched with d + j --- config location /re { content_by_lua ' @@ -54,7 +81,7 @@ hell -=== TEST 3: not matched with j +=== TEST 4: not matched with j --- config location /re { content_by_lua ' @@ -73,7 +100,7 @@ not matched! -=== TEST 4: matched with do +=== TEST 5: matched with do --- config location /re { content_by_lua ' @@ -96,7 +123,7 @@ nil -=== TEST 5: not matched with do +=== TEST 6: not matched with do --- config location /re { content_by_lua ' @@ -115,7 +142,7 @@ not matched! -=== TEST 6: UTF-8 mode without UTF-8 sequence checks +=== TEST 7: UTF-8 mode without UTF-8 sequence checks --- config location /re { content_by_lua ' @@ -149,7 +176,7 @@ exec opts: 2000 -=== TEST 7: UTF-8 mode with UTF-8 sequence checks +=== TEST 8: UTF-8 mode with UTF-8 sequence checks --- config location /re { content_by_lua ' diff --git a/debian/modules/nginx-lua/t/050-gmatch-dfa.t b/debian/modules/nginx-lua/t/050-gmatch-dfa.t index c6b87e1..d2ac2bc 100644 --- a/debian/modules/nginx-lua/t/050-gmatch-dfa.t +++ b/debian/modules/nginx-lua/t/050-gmatch-dfa.t @@ -23,6 +23,7 @@ __DATA__ for m in ngx.re.gmatch("hello, halo", "h[a-z]|h[a-z][a-z]", "d") do if m then ngx.say(m[0]) + ngx.say(m[1]) else ngx.say("not matched: ", m) end @@ -33,7 +34,9 @@ __DATA__ GET /re --- response_body hel +nil hal +nil @@ -286,3 +289,50 @@ exec opts: 0 --- no_error_log [error] + + +=== TEST 13: gmatched with submatch captures +--- config + location /re { + content_by_lua ' + for m in ngx.re.gmatch("hello", "(he|hell)", "d") do + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m[2]) + else + ngx.say("not matched!") + end + end + '; + } +--- request + GET /re +--- response_body +hell +nil +nil + + + +=== TEST 14: gmatched with submatch captures (compile once) +--- config + location /re { + content_by_lua ' + for m in ngx.re.gmatch("hello", "(he|hell)", "od") do + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m[2]) + else + ngx.say("not matched!") + end + end + '; + } +--- request + GET /re +--- response_body +hell +nil +nil diff --git a/debian/modules/nginx-lua/t/052-sub-dfa.t b/debian/modules/nginx-lua/t/052-sub-dfa.t index f4de4d2..254913b 100644 --- a/debian/modules/nginx-lua/t/052-sub-dfa.t +++ b/debian/modules/nginx-lua/t/052-sub-dfa.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 6); +plan tests => repeat_each() * (blocks() * 2 + 8); #no_diff(); no_long_string(); @@ -198,3 +198,38 @@ s: a好 --- no_error_log [error] + + +=== TEST 9: sub with d +--- config + location /re { + content_by_lua ' + ngx.say(ngx.re.sub("hello", "(he|hell)", function (m) ngx.say(m[0]) ngx.say(m[1]) return "x" end, "d")) + '; + } +--- request + GET /re +--- response_body +hell +nil +xo1 +--- no_error_log +[error] + + + +=== TEST 10: sub with d + o +--- config + location /re { + content_by_lua ' + ngx.say(ngx.re.sub("hello", "(he|hell)", function (m) ngx.say(m[0]) ngx.say(m[1]) return "x" end, "do")) + '; + } +--- request + GET /re +--- response_body +hell +nil +xo1 +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/054-gsub-dfa.t b/debian/modules/nginx-lua/t/054-gsub-dfa.t index 9c471a9..937aa1c 100644 --- a/debian/modules/nginx-lua/t/054-gsub-dfa.t +++ b/debian/modules/nginx-lua/t/054-gsub-dfa.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 5); +plan tests => repeat_each() * (blocks() * 2 + 7); #no_diff(); no_long_string(); @@ -199,3 +199,38 @@ s: aa --- no_error_log [error] + + +=== TEST 9: gsub with d +--- config + location /re { + content_by_lua ' + ngx.say(ngx.re.gsub("hello", "(he|hell)", function (m) ngx.say(m[0]) ngx.say(m[1]) return "x" end, "d")) + '; + } +--- request + GET /re +--- response_body +hell +nil +xo1 +--- no_error_log +[error] + + + +=== TEST 10: gsub with d + o +--- config + location /re { + content_by_lua ' + ngx.say(ngx.re.gsub("hello", "(he|hell)", function (m) ngx.say(m[0]) ngx.say(m[1]) return "x" end, "do")) + '; + } +--- request + GET /re +--- response_body +hell +nil +xo1 +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/058-tcp-socket.t b/debian/modules/nginx-lua/t/058-tcp-socket.t index 3368589..b9e4175 100644 --- a/debian/modules/nginx-lua/t/058-tcp-socket.t +++ b/debian/modules/nginx-lua/t/058-tcp-socket.t @@ -432,7 +432,7 @@ attempt to send data on a closed socket --- request GET /t --- response_body_like -^failed to connect: blah-blah-not-found\.agentzh\.org could not be resolved(?: \(\d+: Operation timed out\))? +^failed to connect: blah-blah-not-found\.agentzh\.org could not be resolved(?: \(\d+: (?:Operation timed out|Host not found)\))? connected: nil failed to send request: closed$ --- error_log diff --git a/debian/modules/nginx-lua/t/059-unix-socket.t b/debian/modules/nginx-lua/t/059-unix-socket.t index 9e9e6df..b06ba6e 100644 --- a/debian/modules/nginx-lua/t/059-unix-socket.t +++ b/debian/modules/nginx-lua/t/059-unix-socket.t @@ -134,3 +134,70 @@ received: foo failed to receive a line: closed close: 1 nil + + +=== TEST 4: ngx.socket.stream +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock; + default_type 'text/plain'; + + server_tokens off; + location /foo { + content_by_lua_block { ngx.say("foo") } + more_clear_headers Date; + } + } +--- config + location /test { + content_by_lua_block { + local sock = ngx.socket.stream() + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local req = "GET /foo HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n" + -- req = "OK" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + ngx.say("request sent: ", bytes) + + while true do + print("calling receive") + local line, err = sock:receive() + if line then + ngx.say("received: ", line) + + else + ngx.say("failed to receive a line: ", err) + break + end + end + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + } + } +--- request + GET /test +--- response_body +connected: 1 +request sent: 57 +received: HTTP/1.1 200 OK +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +failed to receive a line: closed +close: 1 nil diff --git a/debian/modules/nginx-lua/t/062-count.t b/debian/modules/nginx-lua/t/062-count.t index c94491c..a24611c 100644 --- a/debian/modules/nginx-lua/t/062-count.t +++ b/debian/modules/nginx-lua/t/062-count.t @@ -212,7 +212,7 @@ n = 2 --- request GET /test --- response_body -n = 3 +n = 4 --- no_error_log [error] @@ -343,7 +343,7 @@ n = 3 --- request GET /test --- response_body -n = 5 +n = 6 --- no_error_log [error] diff --git a/debian/modules/nginx-lua/t/081-bytecode.t b/debian/modules/nginx-lua/t/081-bytecode.t index 93139e2..cb50e94 100644 --- a/debian/modules/nginx-lua/t/081-bytecode.t +++ b/debian/modules/nginx-lua/t/081-bytecode.t @@ -314,3 +314,60 @@ ngx.status = 201 ngx.say("hello from Lua!") [error] --- error_code: 201 + + +=== TEST 9: bytecode (not stripped) +--- config + location = /t { + content_by_lua_block { + local f = assert(loadstring("a = a and a + 1 or 1 ngx.say('a = ', a)", "=code")) + local bc = string.dump(f) + local f = assert(io.open("t/servroot/html/a.luac", "w")) + f:write(bc) + f:close() + } + } + + location = /t2 { + content_by_lua_file html/a.luac; + } + + location = /main { + echo_location /t; + echo_location /t2; + } +--- request +GET /main +--- response_body +a = 1 +--- no_error_log +[error] + + + +=== TEST 10: bytecode (stripped) +--- config + location = /t { + content_by_lua_block { + local f = assert(loadstring("a = a and a + 1 or 1 ngx.say('a = ', a)", "=code")) + local bc = string.dump(f, true) + local f = assert(io.open("t/servroot/html/a.luac", "w")) + f:write(bc) + f:close() + } + } + + location = /t2 { + content_by_lua_file html/a.luac; + } + + location = /main { + echo_location /t; + echo_location /t2; + } +--- request +GET /main +--- response_body +a = 1 +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/101-on-abort.t b/debian/modules/nginx-lua/t/101-on-abort.t index bb74204..81cec78 100644 --- a/debian/modules/nginx-lua/t/101-on-abort.t +++ b/debian/modules/nginx-lua/t/101-on-abort.t @@ -107,6 +107,7 @@ lua req cleanup delete thread 2 delete thread 1 +--- wait: 0.1 --- timeout: 0.2 --- abort --- ignore_response diff --git a/debian/modules/nginx-lua/t/106-timer.t b/debian/modules/nginx-lua/t/106-timer.t index 5cfc01b..d0f6f36 100644 --- a/debian/modules/nginx-lua/t/106-timer.t +++ b/debian/modules/nginx-lua/t/106-timer.t @@ -2141,7 +2141,6 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:4[4-9]|5[0-6]) end ngx.say("registered timer") '; - log_by_lua return; } --- request GET /t diff --git a/debian/modules/nginx-lua/t/114-config.t b/debian/modules/nginx-lua/t/114-config.t index e6d75fc..9d6680d 100644 --- a/debian/modules/nginx-lua/t/114-config.t +++ b/debian/modules/nginx-lua/t/114-config.t @@ -1,4 +1,5 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: + use Test::Nginx::Socket::Lua; #worker_connections(1014); @@ -30,3 +31,18 @@ GET /t --- no_error_log [error] + + +=== TEST 2: ngx.config.subystem +--- config + location /t { + content_by_lua ' + ngx.say("subsystem: ", ngx.config.subsystem) + '; + } +--- request +GET /t +--- response_body +subsystem: http +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/116-raw-req-socket.t b/debian/modules/nginx-lua/t/116-raw-req-socket.t index c2ff8f7..6518f0e 100644 --- a/debian/modules/nginx-lua/t/116-raw-req-socket.t +++ b/debian/modules/nginx-lua/t/116-raw-req-socket.t @@ -783,7 +783,6 @@ server: failed to get raw req socket: pending request body reading in some other === TEST 15: read chunked request body with raw req socket ---- main_config --- config location = /t { content_by_lua ' diff --git a/debian/modules/nginx-lua/t/138-balancer.t b/debian/modules/nginx-lua/t/138-balancer.t index 076465a..e44cf8e 100644 --- a/debian/modules/nginx-lua/t/138-balancer.t +++ b/debian/modules/nginx-lua/t/138-balancer.t @@ -302,3 +302,106 @@ I am in phase balancer qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\.0\.1:80/t"} --- no_error_log [error] + + + +=== TEST 12: code cache off +--- http_config + lua_package_path "t/servroot/html/?.lua;;"; + + lua_code_cache off; + + upstream backend { + server 127.0.0.1:$TEST_NGINX_SERVER_PORT; + balancer_by_lua_block { + require("test") + } + } +--- config + location = /t { + echo_location /main; + echo_location /update; + echo_location /main; + } + + location = /update { + content_by_lua_block { + -- os.execute("(echo HERE; pwd) > /dev/stderr") + local f = assert(io.open("t/servroot/html/test.lua", "w")) + f:write("print('me: ', 101)") + f:close() + ngx.say("updated") + } + } + + location = /main { + proxy_pass http://backend/back; + } + + location = /back { + echo ok; + } +--- request + GET /t +--- user_files +>>> test.lua +print("me: ", 32) +return {} +--- response_body +ok +updated +ok +--- grep_error_log eval: qr/\bme: \w+/ +--- grep_error_log_out +me: 32 +me: 101 +--- no_error_log +[error] + + + +=== TEST 13: lua subrequests +--- http_config + lua_package_path "t/servroot/html/?.lua;;"; + + lua_code_cache off; + + upstream backend { + server 127.0.0.1:$TEST_NGINX_SERVER_PORT; + balancer_by_lua_block { + print("ctx counter: ", ngx.ctx.count) + if not ngx.ctx.count then + ngx.ctx.count = 1 + else + ngx.ctx.count = ngx.ctx.count + 1 + end + } + } +--- config + location = /t { + content_by_lua_block { + local res = ngx.location.capture("/main") + ngx.print(res.body) + res = ngx.location.capture("/main") + ngx.print(res.body) + } + } + + location = /main { + proxy_pass http://backend/back; + } + + location = /back { + echo ok; + } +--- request + GET /t +--- response_body +ok +ok +--- grep_error_log eval: qr/\bctx counter: \w+/ +--- grep_error_log_out +ctx counter: nil +ctx counter: nil +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/140-ssl-c-api.t b/debian/modules/nginx-lua/t/140-ssl-c-api.t new file mode 100644 index 0000000..9812de2 --- /dev/null +++ b/debian/modules/nginx-lua/t/140-ssl-c-api.t @@ -0,0 +1,363 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +repeat_each(3); + +# All these tests need to have new openssl +my $NginxBinary = $ENV{'TEST_NGINX_BINARY'} || 'nginx'; +my $openssl_version = eval { `$NginxBinary -V 2>&1` }; + +if ($openssl_version =~ m/built with OpenSSL (0|1\.0\.(?:0|1[^\d]|2[a-d]).*)/) { + plan(skip_all => "too old OpenSSL, need 1.0.2e, was $1"); +} else { + plan tests => repeat_each() * (blocks() * 5); +} + +$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); + +#log_level 'warn'; +log_level 'debug'; + +no_long_string(); +#no_diff(); + +run_tests(); + +__DATA__ + +=== TEST 1: simple cert + private key +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate_by_lua_block { + collectgarbage() + + local ffi = require "ffi" + + ffi.cdef[[ + int ngx_http_lua_ffi_cert_pem_to_der(const unsigned char *pem, + size_t pem_len, unsigned char *der, char **err); + + int ngx_http_lua_ffi_priv_key_pem_to_der(const unsigned char *pem, + size_t pem_len, unsigned char *der, char **err); + + int ngx_http_lua_ffi_ssl_set_der_certificate(void *r, + const char *data, size_t len, char **err); + + int ngx_http_lua_ffi_ssl_set_der_private_key(void *r, + const char *data, size_t len, char **err); + + int ngx_http_lua_ffi_ssl_clear_certs(void *r, char **err); + ]] + + local errmsg = ffi.new("char *[1]") + + local r = getfenv(0).__ngx_req + if not r then + ngx.log(ngx.ERR, "no request found") + return + end + + ffi.C.ngx_http_lua_ffi_ssl_clear_certs(r, errmsg) + + local f = assert(io.open("t/cert/test.crt", "rb")) + local cert = f:read("*all") + f:close() + + local out = ffi.new("char [?]", #cert) + + local rc = ffi.C.ngx_http_lua_ffi_cert_pem_to_der(cert, #cert, out, errmsg) + if rc < 1 then + ngx.log(ngx.ERR, "failed to parse PEM cert: ", + ffi.string(errmsg[0])) + return + end + + local cert_der = ffi.string(out, rc) + + local rc = ffi.C.ngx_http_lua_ffi_ssl_set_der_certificate(r, cert_der, #cert_der, errmsg) + if rc ~= 0 then + ngx.log(ngx.ERR, "failed to set DER cert: ", + ffi.string(errmsg[0])) + return + end + + f = assert(io.open("t/cert/test.key", "rb")) + local pkey = f:read("*all") + f:close() + + out = ffi.new("char [?]", #pkey) + + local rc = ffi.C.ngx_http_lua_ffi_priv_key_pem_to_der(pkey, #pkey, out, errmsg) + if rc < 1 then + ngx.log(ngx.ERR, "failed to parse PEM priv key: ", + ffi.string(errmsg[0])) + return + end + + local pkey_der = ffi.string(out, rc) + + local rc = ffi.C.ngx_http_lua_ffi_ssl_set_der_private_key(r, pkey_der, #pkey_der, errmsg) + if rc ~= 0 then + ngx.log(ngx.ERR, "failed to set DER priv key: ", + ffi.string(errmsg[0])) + return + end + } + + ssl_certificate ../../cert/test2.crt; + ssl_certificate_key ../../cert/test2.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to recieve response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- error_log +lua ssl server name: "test.com" + +--- no_error_log +[error] +[alert] + + + +=== TEST 2: ECDSA cert + private key +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate_by_lua_block { + collectgarbage() + + local ffi = require "ffi" + + ffi.cdef[[ + int ngx_http_lua_ffi_cert_pem_to_der(const unsigned char *pem, + size_t pem_len, unsigned char *der, char **err); + + int ngx_http_lua_ffi_priv_key_pem_to_der(const unsigned char *pem, + size_t pem_len, unsigned char *der, char **err); + + int ngx_http_lua_ffi_ssl_set_der_certificate(void *r, + const char *data, size_t len, char **err); + + int ngx_http_lua_ffi_ssl_set_der_private_key(void *r, + const char *data, size_t len, char **err); + + int ngx_http_lua_ffi_ssl_clear_certs(void *r, char **err); + ]] + + local errmsg = ffi.new("char *[1]") + + local r = getfenv(0).__ngx_req + if not r then + ngx.log(ngx.ERR, "no request found") + return + end + + ffi.C.ngx_http_lua_ffi_ssl_clear_certs(r, errmsg) + + local f = assert(io.open("t/cert/test_ecdsa.crt", "rb")) + local cert = f:read("*all") + f:close() + + local out = ffi.new("char [?]", #cert) + + local rc = ffi.C.ngx_http_lua_ffi_cert_pem_to_der(cert, #cert, out, errmsg) + if rc < 1 then + ngx.log(ngx.ERR, "failed to parse PEM cert: ", + ffi.string(errmsg[0])) + return + end + + local cert_der = ffi.string(out, rc) + + local rc = ffi.C.ngx_http_lua_ffi_ssl_set_der_certificate(r, cert_der, #cert_der, errmsg) + if rc ~= 0 then + ngx.log(ngx.ERR, "failed to set DER cert: ", + ffi.string(errmsg[0])) + return + end + + f = assert(io.open("t/cert/test_ecdsa.key", "rb")) + local pkey = f:read("*all") + f:close() + + out = ffi.new("char [?]", #pkey) + + local rc = ffi.C.ngx_http_lua_ffi_priv_key_pem_to_der(pkey, #pkey, out, errmsg) + if rc < 1 then + ngx.log(ngx.ERR, "failed to parse PEM priv key: ", + ffi.string(errmsg[0])) + return + end + + local pkey_der = ffi.string(out, rc) + + local rc = ffi.C.ngx_http_lua_ffi_ssl_set_der_private_key(r, pkey_der, #pkey_der, errmsg) + if rc ~= 0 then + ngx.log(ngx.ERR, "failed to set DER priv key: ", + ffi.string(errmsg[0])) + return + end + } + + ssl_certificate ../../cert/test2.crt; + ssl_certificate_key ../../cert/test2.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test_ecdsa.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to recieve response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- error_log +lua ssl server name: "test.com" + +--- no_error_log +[error] +[alert] diff --git a/debian/modules/nginx-lua/t/cert/test2.crt b/debian/modules/nginx-lua/t/cert/test2.crt new file mode 100644 index 0000000..edc3b0d --- /dev/null +++ b/debian/modules/nginx-lua/t/cert/test2.crt @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIIChzCCAfACCQDjCkJpJUtZmjANBgkqhkiG9w0BAQUFADCBhjELMAkGA1UEBhMC +VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28x +EjAQBgNVBAoMCU9wZW5SZXN0eTESMBAGA1UEAwwJdGVzdDIuY29tMSIwIAYJKoZI +hvcNAQkBFhNvcGVucmVzdHlAZ21haWwuY29tMCAXDTE0MDkxMzAwMTgxMFoYDzIx +MTQwODIwMDAxODEwWjCBhjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3Ju +aWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xEjAQBgNVBAoMCU9wZW5SZXN0eTES +MBAGA1UEAwwJdGVzdDIuY29tMSIwIAYJKoZIhvcNAQkBFhNvcGVucmVzdHlAZ21h +aWwuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDy+OVI2u5NBOeB2Cyz +Gnwy9b7Ao4CSi05XtUxh2IoVdzYZz6c4PFb9C1ad52LDdRStiQT5A7+RKLj6Kr7f +JrKFziJxMy4g4Kdn9G659vE7CWu/UAVjRUtc+mTBAEfjdbumizmHLG7DmnNhGl3R +NGiVNLsUInSMGfUlJRzZJXhI4QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAEMmRvyN +N7uE24Tc6TR19JadNHK8g3YGktRoXWiqd/y0HY4NRPgvnK/nX7CY/wXa1j+uDO8K +e6/Ldm5RZrjtvfHJmTSAu8zkqTJz8bqRDH7kzL5Ni2Ky2x8r9dtB0ImpOiSlwvZN +snMvbrxEdwBiqlC9prV2f9aG+ACo1KnPL0j6 +-----END CERTIFICATE----- diff --git a/debian/modules/nginx-lua/t/cert/test2.key b/debian/modules/nginx-lua/t/cert/test2.key new file mode 100644 index 0000000..82ce6ce --- /dev/null +++ b/debian/modules/nginx-lua/t/cert/test2.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDy+OVI2u5NBOeB2CyzGnwy9b7Ao4CSi05XtUxh2IoVdzYZz6c4 +PFb9C1ad52LDdRStiQT5A7+RKLj6Kr7fJrKFziJxMy4g4Kdn9G659vE7CWu/UAVj +RUtc+mTBAEfjdbumizmHLG7DmnNhGl3RNGiVNLsUInSMGfUlJRzZJXhI4QIDAQAB +AoGAEqBB83PVENJvbOTFiHVfUAjGtr3R/Wnwd4jOcjHHZB3fZ9sjVoxJntxfp3s1 +dwZir2rxlqVS6i3VAFiGiVTOGo2Vvzhw2J7f58twCECmnLb2f863AkGEYe4dAndD +GHGD0WI0CBMD1sT18YCj561o0Wol5deWH0gM9pr2N3HkeIECQQD6hUKFlFhrpaHP +WNJsl6BxgE6pB5kxLcMcpIQ7P+kHUvtyvCJl5QZJqPrpPGjRsAI5Ph92rpsp/zDp +/IZNWGVjAkEA+Ele31Rt+XbV32MrLKZgBDBk+Pzss5LTn9fZ5v1k/7hrMk2VVWvk +AD6n5QiGe/g59woANpPb1T9l956SBf0d6wJABTXOS17pc9uvANP1FGMW6CVl/Wf2 +DKrJ+weE5IKQwyE7r4gwIvRfbBrClSU3fNzvPueG2f4JphbzmnoxBNzIxwJAYivY +mGNwzHehXx99/byXMHDWK+EN0n8WsBgP75Z3rekEcbJdfpYXY8Via1vwmOnwOW65 +4NqbzHix37PSNw37GwJBALxaGNpREO2Tk+oWOvsD2QyviMVae3mXAJHc6nLVdKDM +q0YvDT6VdeNYYFTkAuzJacsVXOpn6AnUMFj0OBedMhc= +-----END RSA PRIVATE KEY----- diff --git a/debian/modules/nginx-lua/t/cert/test_ecdsa.crt b/debian/modules/nginx-lua/t/cert/test_ecdsa.crt new file mode 100644 index 0000000..b3e1e9f --- /dev/null +++ b/debian/modules/nginx-lua/t/cert/test_ecdsa.crt @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBtDCCAVoCCQD0QJnL8zpA0jAKBggqhkjOPQQDAjBhMQswCQYDVQQGEwJVUzET +MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzESMBAG +A1UECgwJT3BlblJlc3R5MREwDwYDVQQDDAh0ZXN0LmNvbTAgFw0xNTA3MTcyMTUx +NDFaGA8yMTE1MDYyMzIxNTE0MVowYTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh +bGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xEjAQBgNVBAoMCU9wZW5S +ZXN0eTERMA8GA1UEAwwIdGVzdC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC +AAT/OtGmlIlbtvvJ3OP0dm5lyEMCrMnpDTDjwBPnUZ2f+16LCmNsdtEJ0r0Sd4GM +o4Lss2JpwzPy2SLGEj3KwGKSMAoGCCqGSM49BAMCA0gAMEUCIQDbNwDkq1FiqcRD +XdbP1MPAc33N2IK9EDIfMgJ0nTL82wIgNZiL4xvCQe9UA0zC+JqHLnVCQHYAM9kI +BbvzNrt0hEM= +-----END CERTIFICATE----- diff --git a/debian/modules/nginx-lua/t/cert/test_ecdsa.key b/debian/modules/nginx-lua/t/cert/test_ecdsa.key new file mode 100644 index 0000000..46eb72c --- /dev/null +++ b/debian/modules/nginx-lua/t/cert/test_ecdsa.key @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg0vwBPGgv1hE6RnQo +3imyoceR+5dLsKegodOlBwnWtbuhRANCAAT/OtGmlIlbtvvJ3OP0dm5lyEMCrMnp +DTDjwBPnUZ2f+16LCmNsdtEJ0r0Sd4GMo4Lss2JpwzPy2SLGEj3KwGKS +-----END PRIVATE KEY----- diff --git a/debian/modules/nginx-lua/util/build2.sh b/debian/modules/nginx-lua/util/build.sh similarity index 100% rename from debian/modules/nginx-lua/util/build2.sh rename to debian/modules/nginx-lua/util/build.sh From fd1a40a6f89e94a118ed1fe550d330c6ccce9606 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 12 Feb 2016 14:47:59 +0200 Subject: [PATCH 081/651] Update Vcs field with secure links Fixes vcs-field-uses-insecure-uri https://lintian.debian.org/tags/vcs-field-uses-insecure-uri.html --- debian/control | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/control b/debian/control index 7c60e5f..d96788e 100644 --- a/debian/control +++ b/debian/control @@ -26,8 +26,8 @@ Build-Depends: autotools-dev, zlib1g-dev Standards-Version: 3.9.6.0 Homepage: http://nginx.net -Vcs-Git: git://anonscm.debian.org/collab-maint/nginx.git -Vcs-Browser: http://anonscm.debian.org/gitweb/?p=collab-maint/nginx.git;a=summary +Vcs-Git: https://anonscm.debian.org/cgit/collab-maint/nginx.git +Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/nginx.git Package: nginx Architecture: all From 7b00376f31ef3b908921f594ef14fa4d61864012 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 29 Mar 2016 13:20:16 +0300 Subject: [PATCH 082/651] Bump Standards-Version to 3.9.7.0 (no changes needed) --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index d96788e..f43fe4f 100644 --- a/debian/control +++ b/debian/control @@ -24,7 +24,7 @@ Build-Depends: autotools-dev, libxslt1-dev, po-debconf, zlib1g-dev -Standards-Version: 3.9.6.0 +Standards-Version: 3.9.7.0 Homepage: http://nginx.net Vcs-Git: https://anonscm.debian.org/cgit/collab-maint/nginx.git Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/nginx.git From a50cd439eb4f8d5ad8c2519e0914d00b49a5ee23 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Mar 2016 13:38:53 +0300 Subject: [PATCH 083/651] Add documentation option to systemd unit Fixes systemd-service-file-missing-documentation-key lintian check. --- debian/nginx-common.nginx.service | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/nginx-common.nginx.service b/debian/nginx-common.nginx.service index 0da034d..a909641 100644 --- a/debian/nginx-common.nginx.service +++ b/debian/nginx-common.nginx.service @@ -12,6 +12,7 @@ # [Unit] Description=A high performance web server and a reverse proxy server +Documentation=man:nginx(8) After=network.target [Service] From 44b30c100a3bcf9b4b6a89910aa4d989a5e1c46b Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 12 Feb 2016 14:27:46 +0200 Subject: [PATCH 084/651] Disable PIE hardening flags for now, it breaks dynamic libraries --- debian/rules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/rules b/debian/rules index 1cdef59..c18af76 100755 --- a/debian/rules +++ b/debian/rules @@ -1,7 +1,7 @@ #!/usr/bin/make -f export DH_VERBOSE=1 -export DEB_BUILD_MAINT_OPTIONS=hardening=+all +export DEB_BUILD_MAINT_OPTIONS=hardening=+all,-pie debian_cflags:=$(shell dpkg-buildflags --get CFLAGS) $(shell dpkg-buildflags --get CPPFLAGS) debian_ldflags:=$(shell dpkg-buildflags --get LDFLAGS) From 7a5fa94b9d190bedabcdada1cdd6ca91fb5e0ef3 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 23 Mar 2016 16:36:44 +0200 Subject: [PATCH 085/651] Setup modules-{enabled,available} directories Modules have to be declared with top-level includes --- debian/conf/nginx.conf | 1 + debian/nginx-common.dirs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/debian/conf/nginx.conf b/debian/conf/nginx.conf index 01a4a21..6e57ea9 100644 --- a/debian/conf/nginx.conf +++ b/debian/conf/nginx.conf @@ -1,6 +1,7 @@ user www-data; worker_processes auto; pid /run/nginx.pid; +include /etc/nginx/modules-enabled/*.conf; events { worker_connections 768; diff --git a/debian/nginx-common.dirs b/debian/nginx-common.dirs index d75dabf..8ee01f5 100644 --- a/debian/nginx-common.dirs +++ b/debian/nginx-common.dirs @@ -1,6 +1,8 @@ etc/nginx etc/nginx/sites-available etc/nginx/sites-enabled +etc/nginx/modules-available +etc/nginx/modules-enabled etc/nginx/conf.d etc/ufw/applications.d usr/share/nginx From 916384bde3a24d93cf2434687520429ea6855d27 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 23 Mar 2016 16:43:07 +0200 Subject: [PATCH 086/651] Setup libnginx-mod packaging flow We introduce a dh_nginx helper script. For now dh_nginx will only be used in the nginx source but when are confident about it will ship it in a nginx-dev package. --- debian/autoscripts/postinst-nginx | 11 ++ debian/autoscripts/postrm-nginx | 11 ++ debian/autoscripts/prerm-nginx | 11 ++ debian/dh_nginx | 278 +++++++++++++++++++++++++++++ debian/libnginx-mod.nginx.skeleton | 13 ++ debian/nginx-common.links | 1 + debian/rules | 10 +- 7 files changed, 334 insertions(+), 1 deletion(-) create mode 100644 debian/autoscripts/postinst-nginx create mode 100644 debian/autoscripts/postrm-nginx create mode 100644 debian/autoscripts/prerm-nginx create mode 100755 debian/dh_nginx create mode 100755 debian/libnginx-mod.nginx.skeleton create mode 100644 debian/nginx-common.links diff --git a/debian/autoscripts/postinst-nginx b/debian/autoscripts/postinst-nginx new file mode 100644 index 0000000..565015b --- /dev/null +++ b/debian/autoscripts/postinst-nginx @@ -0,0 +1,11 @@ +for conf in #NAMES# ; do + # Symlink on fresh installations + if [ -z "$2" ]; then + ln -sf /usr/share/nginx/modules-available/$conf \ + /etc/nginx/modules-enabled/$conf + fi +done + +if [ -s /run/nginx.pid ]; then + nginx -s reload +fi diff --git a/debian/autoscripts/postrm-nginx b/debian/autoscripts/postrm-nginx new file mode 100644 index 0000000..60b0493 --- /dev/null +++ b/debian/autoscripts/postrm-nginx @@ -0,0 +1,11 @@ +if [ "$1" = "purge" ] ; then + for conf in #NAMES# ; do + if [ -e /etc/nginx/etc/nginx/modules-enabled/$conf ]; then + rm /etc/nginx/etc/nginx/modules-enabled/$conf + fi + done + + if [ -s /run/nginx.pid ]; then + nginx -s reload + fi +fi diff --git a/debian/autoscripts/prerm-nginx b/debian/autoscripts/prerm-nginx new file mode 100644 index 0000000..efeaae8 --- /dev/null +++ b/debian/autoscripts/prerm-nginx @@ -0,0 +1,11 @@ +if [ "$1" = "remove" ] || [ "$1" = "deconfigure" ] ; then + for conf in #NAMES# ; do + if [ -e /etc/nginx/etc/nginx/modules-enabled/$conf ]; then + rm /etc/nginx/etc/nginx/modules-enabled/$conf + fi + done + + if [ -s /run/nginx.pid ]; then + nginx -s reload + fi +fi diff --git a/debian/dh_nginx b/debian/dh_nginx new file mode 100755 index 0000000..26dedb2 --- /dev/null +++ b/debian/dh_nginx @@ -0,0 +1,278 @@ +#! /usr/bin/perl + +# dh_nginx - Nginx configuration helper +# Copyright (C) 2016 Christos Trochalakis +# +# This program is licensed under the terms of the GNU General +# Public License veserion 2+ +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +use strict; +use File::Find; +use Debian::Debhelper::Dh_Lib; + + +=head1 NAME + +dh_nginx - register configuration snippets to the nginx web server + +=cut + +sub nginx_depends +{ + return 'nginx-light (= ${binary:Version}) |nginx-full (= ${binary:Version}) | nginx-extras (= ${binary:Version})' +} + +sub nginx_api_installdir +{ + return "/usr/lib/nginx/modules/"; +} + +sub nginx_modules_conf_installdir +{ + return "usr/share/nginx/modules-available/" +} + +=head1 SYNOPSIS + +B [S>] [B<-n>|B<--noscripts>] + +=head1 DESCRIPTION + +B is a debhelper program that is responsible for correctly installing +Nginx configuration snippets and setting postinst, prerm and dependencies in +Nginx web server modules and web applications. + +It supports the following configuration types + +=over 4 + +=item * +Nginx modules + +=head1 INVOCATION + + %: + dh $@ --with nginx + +=head1 FILES + +=over 4 + +=item debian/I.nginx + +=item debian/nginx + +=back + +Lists files to be registered with the Nginx HTTP server. The file is +interpreted as line separated list of installation stanzas, where each entry +consists of whitespace separated values conforming to the file semantics below. + +=head2 FILE SEMANTICS + +Each line consists of a triple + +I I [I] + +where the values are interpreted as follows: + + +=head3 I + +Denotes the type of file to be installed. Recognized values are B for +Nginx modules. + +=head3 I + +Is interpreted as existing file name within the source package. No path +expansion is effectuated. Just like L, B can not +rename files. + +=head3 I + +Is inrerpreted as optional arguments if any, currently not used. + +=head2 MODULES + +Modules are handled specially and are determined by the B type. Modules must +have a I<.conf> suffix. In that case the file is interpreted as module load +file and is installed to I. If the file is ending +with a I<.so> suffix it is interpreted as actual module shared object and is +installed to the Nginx module directory. Moreover, if a I<.load> file is +installed the configuration is activated in the maintainer script at +installation time. + +=head1 OPTIONS + +=over 4 + +=item B<-e>, B<--noenable> + +Install maintainer scripts accordingly, but do not enable the scripts or +configuration by default. + +=item B<-n>, B<--noscripts> + +Do not modify F/F/F maintainer scripts. + + +=back + +=head1 NOTES + +Note that this command is not idempotent. L should be called +between invocations of this command. Otherwise, it may cause multiple +instances of the same text to be added to maintainer scripts. + +=head1 AUTHOR + +This manual and L was written by Christos Trochalakis. +dh_nginx is heavily influnced by dh_apache2 written by Arno Toell +. + +=cut + + +## +## main code starts here +## + +init(options => { + "e|noenable" => \$dh{NOENABLE}, +}); + +foreach my $package ((@{$dh{DOPACKAGES}})) +{ + my %PACKAGE_TYPE = ( + has_a_module => [], + ); + + my $file = pkgfile($package, "nginx"); + my $tmp = tmpdir($package); + + my @files_to_register = filedoublearray($file, ".") if $file; + foreach my $line (@files_to_register) + { + my $type = lc(shift @{$line}) if $line->[0]; + my $source = shift @{$line} if $line->[0]; + my @arguments = map {"$_ "} @{$line}; + + $type = "modules" if $type eq "mod"; + my $installdir = $tmp . "/" . nginx_modules_conf_installdir(); + + verbose_print("$type -- $source -- @arguments\n\n"); + + if ($type eq "modules") + { + my $basesource = basename($source); + + if ($type eq "modules") + { + if ($basesource =~ m/\.conf$/) + { + my $enablename = $basesource; + push @{$PACKAGE_TYPE{'has_a_module'}}, $enablename; + verbose_print("Installing module configuration $enablename into $installdir\n"); + } + elsif ($basesource =~ m/\.so$/) + { + my $modinstalldir = $tmp . "/" . nginx_api_installdir(); + verbose_print("Installing module binary $source into $modinstalldir\n"); + if (! -d $modinstalldir) + { + complex_doit("mkdir","-p", $modinstalldir); + complex_doit("chmod","755","$modinstalldir"); + } + complex_doit("cp", $source, $modinstalldir); + next; + } + + # TODO + error("module: \"$basesource\" needs .conf, .so or .load suffix") if $basesource !~ m/\.(conf|so)/; + } + + if (! -d $installdir) + { + complex_doit("mkdir","-p",$installdir); + complex_doit("chmod","755","$installdir"); + } + complex_doit("cp",$source,$installdir); + complex_doit("chmod","644","$installdir/$basesource"); + + } + else + { + error("Unknown parameter: $type\n"); + } + + } + + my @postinst_autoscripts; + + if ($#{$PACKAGE_TYPE{'has_a_module'}} >= 0) + { + if ($package !~ m/libnginx-mod-\w+?/) + { + warning("Package $package appears to be an Nginx module. It should comply to the package naming scheme libnginx-mod-\n"); + } + addsubstvar($package, "misc:Depends", nginx_depends()); + + my $modules = ""; + foreach my $module (@{$PACKAGE_TYPE{'has_a_module'}}) + { + $modules .= "$module "; + } + + push @postinst_autoscripts, ["module", $modules]; + } + + if (! $dh{NOSCRIPTS}) + { + foreach my $ref (@postinst_autoscripts) + { + for my $script_type (qw/postinst prerm postrm/) + { + if ($script_type eq "postinst" && $dh{NOENABLE}) + { + next + } + + my %replacements = ( + NAMES => $ref->[1], + ); + + my $sed_command = ""; + foreach my $key (sort keys %replacements) + { + my $val = $replacements{$key}; + # Use a control char as separator for sed, to + # reduce escaping issues. Everything else is + # passed verbatim, i.e. it must not contain any + # shell or sed special characters. + my $sep = "\x17"; + $sed_command .= "s" . $sep . "#$key#" . + $sep . $val . + $sep . "g; "; + } + + autoscript($package, "$script_type", "$script_type-nginx", $sed_command); + } + } + } +} + +# vim: syntax=perl sw=8 sts=8 sr noet diff --git a/debian/libnginx-mod.nginx.skeleton b/debian/libnginx-mod.nginx.skeleton new file mode 100755 index 0000000..bf7936c --- /dev/null +++ b/debian/libnginx-mod.nginx.skeleton @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use File::Basename; + +# Guess module name +$module = basename($0, '.nginx'); +$module =~ s/^libnginx-mod-//; + +$modulepath = $module; +$modulepath =~ s/-/_/; + +print "mod debian/build-full/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/nginx-common.links b/debian/nginx-common.links new file mode 100644 index 0000000..ca651a5 --- /dev/null +++ b/debian/nginx-common.links @@ -0,0 +1 @@ +usr/lib/nginx/modules usr/share/nginx/modules diff --git a/debian/rules b/debian/rules index c18af76..8dd6eca 100755 --- a/debian/rules +++ b/debian/rules @@ -36,6 +36,7 @@ common_configure_flags := \ --error-log-path=/var/log/nginx/error.log \ --lock-path=/var/lock/nginx.lock \ --pid-path=/run/nginx.pid \ + --modules-path=/usr/lib/nginx/modules \ --http-client-body-temp-path=/var/lib/nginx/body \ --http-fastcgi-temp-path=/var/lib/nginx/fastcgi \ --http-proxy-temp-path=/var/lib/nginx/proxy \ @@ -126,10 +127,14 @@ extras_configure_flags := \ override_dh_auto_configure: $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) override_dh_auto_build: $(foreach flavour,$(FLAVOURS),build.arch.$(flavour)) -override_dh_strip: $(foreach flavour,$(FLAVOURS),strip.arch.$(flavour)) +override_dh_strip: $(foreach flavour,$(FLAVOURS),strip.arch.$(flavour)) $(foreach mod,$(DYN_MODS),strip.mods.$(mod)) override_dh_clean: $(foreach flavour,$(FLAVOURS),clean.$(flavour)) dh_clean +override_dh_install: + dh_install + DH_AUTOSCRIPTDIR=$(CURDIR)/debian/autoscripts debian/dh_nginx + override_dh_installinit: dh_installinit --no-restart-on-upgrade --no-start --name=nginx @@ -145,6 +150,9 @@ build.arch.%: strip.arch.%: dh_strip --package=nginx-$(*) --dbg-package=nginx-$(*)-dbg +strip.mods.%: + dh_strip --package=libnginx-mod-$(*) --automatic-dbgsym + config.arch.%: dh_testdir mkdir -p $(BUILDDIR_$*) From b231ba8f39ea52a6277f029bf1c8a9f75eb61796 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Mar 2016 16:22:08 +0300 Subject: [PATCH 087/651] dh_nginx: Modules depend on nginx-common for now We will change that to nginx-binary when it's available. --- debian/dh_nginx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/dh_nginx b/debian/dh_nginx index 26dedb2..2d7b942 100755 --- a/debian/dh_nginx +++ b/debian/dh_nginx @@ -33,7 +33,7 @@ dh_nginx - register configuration snippets to the nginx web server sub nginx_depends { - return 'nginx-light (= ${binary:Version}) |nginx-full (= ${binary:Version}) | nginx-extras (= ${binary:Version})' + return 'nginx-common (= ${source:Version})' } sub nginx_api_installdir From d19e7548ee639c07ee534164d1be02d88ceba8d0 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 23 Mar 2016 16:44:39 +0200 Subject: [PATCH 088/651] Build libnginx-mod-* packages --- debian/control | 63 ++++++++++++++++++- debian/libnginx-mod-http-geoip.nginx | 13 ++++ debian/libnginx-mod-http-image-filter.nginx | 13 ++++ debian/libnginx-mod-http-xslt-filter.nginx | 13 ++++ debian/libnginx-mod-mail.nginx | 13 ++++ debian/libnginx-mod-stream.nginx | 13 ++++ debian/libnginx-mod.conf/mod-http-geoip.conf | 1 + .../mod-http-image-filter.conf | 1 + .../mod-http-xslt-filter.conf | 1 + debian/libnginx-mod.conf/mod-mail.conf | 1 + debian/libnginx-mod.conf/mod-stream.conf | 1 + debian/libnginx-mod.nginx.skeleton | 2 +- debian/rules | 21 ++++--- 13 files changed, 144 insertions(+), 12 deletions(-) create mode 100755 debian/libnginx-mod-http-geoip.nginx create mode 100755 debian/libnginx-mod-http-image-filter.nginx create mode 100755 debian/libnginx-mod-http-xslt-filter.nginx create mode 100755 debian/libnginx-mod-mail.nginx create mode 100755 debian/libnginx-mod-stream.nginx create mode 100644 debian/libnginx-mod.conf/mod-http-geoip.conf create mode 100644 debian/libnginx-mod.conf/mod-http-image-filter.conf create mode 100644 debian/libnginx-mod.conf/mod-http-xslt-filter.conf create mode 100644 debian/libnginx-mod.conf/mod-mail.conf create mode 100644 debian/libnginx-mod.conf/mod-stream.conf diff --git a/debian/control b/debian/control index f43fe4f..49aacde 100644 --- a/debian/control +++ b/debian/control @@ -79,7 +79,14 @@ Description: small, powerful, scalable web/proxy server - common files Package: nginx-full Architecture: any -Depends: nginx-common (= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} +Depends: nginx-common (= ${source:Version}), + libnginx-mod-http-geoip (= ${binary:Version}), + libnginx-mod-http-image-filter (= ${binary:Version}), + libnginx-mod-http-xslt-filter (= ${binary:Version}), + libnginx-mod-mail (= ${binary:Version}), + libnginx-mod-stream (= ${binary:Version}), + ${misc:Depends}, + ${shlibs:Depends} Breaks: nginx (<< 1.4.5-1) Provides: httpd, httpd-cgi, nginx Conflicts: nginx-extras, nginx-light @@ -164,6 +171,11 @@ Package: nginx-extras Architecture: any Priority: extra Depends: nginx-common (= ${source:Version}), + libnginx-mod-http-geoip (= ${binary:Version}), + libnginx-mod-http-image-filter (= ${binary:Version}), + libnginx-mod-http-xslt-filter (= ${binary:Version}), + libnginx-mod-mail (= ${binary:Version}), + libnginx-mod-stream (= ${binary:Version}), ${misc:Depends}, ${perl:Depends}, ${shlibs:Depends} @@ -209,3 +221,52 @@ Description: nginx web/proxy server (extended version) - debugging symbols This package provides debugging symbols for nginx-extras, to assist in debugging issues that you may find. It should not be required for normal operation. + +Package: libnginx-mod-http-geoip +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: GeoIP HTTP module for Nginx + The ngx_http_geoip module creates variables with values depending on the + client IP address, using the precompiled MaxMind databases. + . + Those variables include country, region, city, latitude, longitude, postal + code, etc. + +Package: libnginx-mod-http-image-filter +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: HTTP image filter module for Nginx + The ngx_http_image_filter module is a filter that transforms images in JPEG, + GIF, and PNG formats. + . + The module supports filters such as rotate, resize, crop, quality, sharpening, + interlacing and more. + +Package: libnginx-mod-http-xslt-filter +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: XSLT Transformation module for Nginx + The ngx_http_xslt_filter module is a filter that transforms XML responses + using one or more XSLT stylesheets. + . + The transformation can be adjusted by setting the relevant configuration + parameters. + +Package: libnginx-mod-mail +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: Mail module for Nginx + The nginx_mail module adds mail proxy support to nginx. + . + The module supports proxying all the standard mail protocols such as IMAP, + POP3 & SMTP. + +Package: libnginx-mod-stream +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: Stream module for Nginx + The nginx_stream module adds stream proxy support to nginx. + . + Stream module supports loadbalancing & proxying to TCP servers. The module + also supports ACLs/connection limiting and configuring multiple operational + parameters. diff --git a/debian/libnginx-mod-http-geoip.nginx b/debian/libnginx-mod-http-geoip.nginx new file mode 100755 index 0000000..02c5edc --- /dev/null +++ b/debian/libnginx-mod-http-geoip.nginx @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use File::Basename; + +# Guess module name +$module = basename($0, '.nginx'); +$module =~ s/^libnginx-mod-//; + +$modulepath = $module; +$modulepath =~ s/-/_/g; + +print "mod debian/build-full/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-http-image-filter.nginx b/debian/libnginx-mod-http-image-filter.nginx new file mode 100755 index 0000000..02c5edc --- /dev/null +++ b/debian/libnginx-mod-http-image-filter.nginx @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use File::Basename; + +# Guess module name +$module = basename($0, '.nginx'); +$module =~ s/^libnginx-mod-//; + +$modulepath = $module; +$modulepath =~ s/-/_/g; + +print "mod debian/build-full/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-http-xslt-filter.nginx b/debian/libnginx-mod-http-xslt-filter.nginx new file mode 100755 index 0000000..02c5edc --- /dev/null +++ b/debian/libnginx-mod-http-xslt-filter.nginx @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use File::Basename; + +# Guess module name +$module = basename($0, '.nginx'); +$module =~ s/^libnginx-mod-//; + +$modulepath = $module; +$modulepath =~ s/-/_/g; + +print "mod debian/build-full/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-mail.nginx b/debian/libnginx-mod-mail.nginx new file mode 100755 index 0000000..02c5edc --- /dev/null +++ b/debian/libnginx-mod-mail.nginx @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use File::Basename; + +# Guess module name +$module = basename($0, '.nginx'); +$module =~ s/^libnginx-mod-//; + +$modulepath = $module; +$modulepath =~ s/-/_/g; + +print "mod debian/build-full/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-stream.nginx b/debian/libnginx-mod-stream.nginx new file mode 100755 index 0000000..02c5edc --- /dev/null +++ b/debian/libnginx-mod-stream.nginx @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use File::Basename; + +# Guess module name +$module = basename($0, '.nginx'); +$module =~ s/^libnginx-mod-//; + +$modulepath = $module; +$modulepath =~ s/-/_/g; + +print "mod debian/build-full/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod.conf/mod-http-geoip.conf b/debian/libnginx-mod.conf/mod-http-geoip.conf new file mode 100644 index 0000000..9721986 --- /dev/null +++ b/debian/libnginx-mod.conf/mod-http-geoip.conf @@ -0,0 +1 @@ +load_module modules/ngx_http_geoip_module.so; diff --git a/debian/libnginx-mod.conf/mod-http-image-filter.conf b/debian/libnginx-mod.conf/mod-http-image-filter.conf new file mode 100644 index 0000000..dfa2939 --- /dev/null +++ b/debian/libnginx-mod.conf/mod-http-image-filter.conf @@ -0,0 +1 @@ +load_module modules/ngx_http_image_filter_module.so; diff --git a/debian/libnginx-mod.conf/mod-http-xslt-filter.conf b/debian/libnginx-mod.conf/mod-http-xslt-filter.conf new file mode 100644 index 0000000..a4f87ac --- /dev/null +++ b/debian/libnginx-mod.conf/mod-http-xslt-filter.conf @@ -0,0 +1 @@ +load_module modules/ngx_http_xslt_filter_module.so; diff --git a/debian/libnginx-mod.conf/mod-mail.conf b/debian/libnginx-mod.conf/mod-mail.conf new file mode 100644 index 0000000..cfd4a4d --- /dev/null +++ b/debian/libnginx-mod.conf/mod-mail.conf @@ -0,0 +1 @@ +load_module modules/ngx_mail_module.so; diff --git a/debian/libnginx-mod.conf/mod-stream.conf b/debian/libnginx-mod.conf/mod-stream.conf new file mode 100644 index 0000000..f2b2657 --- /dev/null +++ b/debian/libnginx-mod.conf/mod-stream.conf @@ -0,0 +1 @@ +load_module modules/ngx_stream_module.so; diff --git a/debian/libnginx-mod.nginx.skeleton b/debian/libnginx-mod.nginx.skeleton index bf7936c..02c5edc 100755 --- a/debian/libnginx-mod.nginx.skeleton +++ b/debian/libnginx-mod.nginx.skeleton @@ -7,7 +7,7 @@ $module = basename($0, '.nginx'); $module =~ s/^libnginx-mod-//; $modulepath = $module; -$modulepath =~ s/-/_/; +$modulepath =~ s/-/_/g; print "mod debian/build-full/objs/ngx_${modulepath}_module.so\n"; print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/rules b/debian/rules index 8dd6eca..6f88edc 100755 --- a/debian/rules +++ b/debian/rules @@ -11,6 +11,7 @@ DEBIAN_NGINX_PERL_LDFLAGS:= $(shell DEB_BUILD_MAINT_OPTIONS=hardening=+all,-pie export DEBIAN_NGINX_PERL_LDFLAGS FLAVOURS := full light extras +DYN_MODS := http-geoip http-image-filter http-xslt-filter mail stream MODULESDIR = $(CURDIR)/debian/modules BASEDIR = $(CURDIR) @@ -70,16 +71,16 @@ full_configure_flags := \ $(common_configure_flags) \ --with-http_addition_module \ --with-http_dav_module \ - --with-http_geoip_module \ + --with-http_geoip_module=dynamic \ --with-http_gunzip_module \ --with-http_gzip_static_module \ - --with-http_image_filter_module \ + --with-http_image_filter_module=dynamic \ --with-http_v2_module \ --with-http_sub_module \ - --with-http_xslt_module \ - --with-stream \ + --with-http_xslt_module=dynamic \ + --with-stream=dynamic \ --with-stream_ssl_module \ - --with-mail \ + --with-mail=dynamic \ --with-mail_ssl_module \ --with-threads \ --add-module=$(MODULESDIR)/nginx-auth-pam \ @@ -93,20 +94,20 @@ extras_configure_flags := \ --with-http_addition_module \ --with-http_dav_module \ --with-http_flv_module \ - --with-http_geoip_module \ + --with-http_geoip_module=dynamic \ --with-http_gunzip_module \ --with-http_gzip_static_module \ - --with-http_image_filter_module \ + --with-http_image_filter_module=dynamic \ --with-http_mp4_module \ --with-http_perl_module \ --with-http_random_index_module \ --with-http_secure_link_module \ --with-http_v2_module \ --with-http_sub_module \ - --with-http_xslt_module \ - --with-mail \ + --with-http_xslt_module=dynamic \ + --with-mail=dynamic \ --with-mail_ssl_module \ - --with-stream \ + --with-stream=dynamic \ --with-stream_ssl_module \ --with-threads \ --add-module=$(MODULESDIR)/headers-more-nginx-module \ From 24ba8b51ef2d27d90ec3b0739ef099fb9cef8212 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 30 Mar 2016 09:53:48 +0300 Subject: [PATCH 089/651] Make sure signature stays the same in all nginx builds When a dyn module is loaded the signature of the module is compared to the one of the nginx binary. dyn modules are build from nginx-full, so in order to make them loadable in other flavors we need to make sure all the binaries share the same signature. The signature is a vector computed from 33+3 parameters (src/core/ngx_module.h) With this commit we align all nginx flavors to same signature vector. --- debian/control | 3 +- ...ure-stays-the-same-in-all-nginx-buil.patch | 30 +++++++++++++++++++ debian/patches/series | 1 + debian/rules | 11 +++---- 4 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch diff --git a/debian/control b/debian/control index 49aacde..2076f5c 100644 --- a/debian/control +++ b/debian/control @@ -148,7 +148,8 @@ Description: nginx web/proxy server (basic version) FastCGI, Map, Proxy, Rewrite. . OPTIONAL HTTP MODULES: Auth Request, Charset, Gzip, Gzip Precompression, - Headers, Index, Log, Real IP, SSL, Stub Status, Upstream. + Headers, HTTP/2, Index, Log, Real IP, SSL, Stub Status, Thread Pool, WebDAV, + Upstream. . THIRD PARTY MODULES: Echo. diff --git a/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch b/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch new file mode 100644 index 0000000..1bea8b2 --- /dev/null +++ b/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch @@ -0,0 +1,30 @@ +From: Christos Trochalakis +Date: Wed, 30 Mar 2016 09:47:11 +0300 +Subject: Make sure signature stays the same in all nginx builds + +NGX_HTTP_HEADERS is part of nginx signature. When a dyn +modules is loaded the signature of the module is compared +to the one of the nginx binary. + +dyn modules are build from nginx-full, so in order to make +them loadable in other flavors we need to make sure all the +binaries share the same signature. +--- + configure | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/configure b/configure +index ceff15e..3816fa1 100755 +--- a/configure ++++ b/configure +@@ -58,6 +58,10 @@ if [ "$NGX_PLATFORM" != win32 ]; then + . auto/unix + fi + ++# Debian ++# Make sure signature stays the same on all nginx flavors ++have=NGX_HTTP_HEADERS . auto/have ++ + . auto/threads + . auto/modules + . auto/lib/conf diff --git a/debian/patches/series b/debian/patches/series index 73f535e..04b971f 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1 +1,2 @@ perl-use-dpkg-buildflags.patch +0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch diff --git a/debian/rules b/debian/rules index 6f88edc..f9db327 100755 --- a/debian/rules +++ b/debian/rules @@ -49,7 +49,10 @@ common_configure_flags := \ --with-http_ssl_module \ --with-http_stub_status_module \ --with-http_realip_module \ - --with-http_auth_request_module + --with-http_auth_request_module \ + --with-http_v2_module \ + --with-http_dav_module \ + --with-threads light_configure_flags := \ $(common_configure_flags) \ @@ -70,19 +73,16 @@ light_configure_flags := \ full_configure_flags := \ $(common_configure_flags) \ --with-http_addition_module \ - --with-http_dav_module \ --with-http_geoip_module=dynamic \ --with-http_gunzip_module \ --with-http_gzip_static_module \ --with-http_image_filter_module=dynamic \ - --with-http_v2_module \ --with-http_sub_module \ --with-http_xslt_module=dynamic \ --with-stream=dynamic \ --with-stream_ssl_module \ --with-mail=dynamic \ --with-mail_ssl_module \ - --with-threads \ --add-module=$(MODULESDIR)/nginx-auth-pam \ --add-module=$(MODULESDIR)/nginx-dav-ext-module \ --add-module=$(MODULESDIR)/nginx-echo \ @@ -92,7 +92,6 @@ full_configure_flags := \ extras_configure_flags := \ $(common_configure_flags) \ --with-http_addition_module \ - --with-http_dav_module \ --with-http_flv_module \ --with-http_geoip_module=dynamic \ --with-http_gunzip_module \ @@ -102,14 +101,12 @@ extras_configure_flags := \ --with-http_perl_module \ --with-http_random_index_module \ --with-http_secure_link_module \ - --with-http_v2_module \ --with-http_sub_module \ --with-http_xslt_module=dynamic \ --with-mail=dynamic \ --with-mail_ssl_module \ --with-stream=dynamic \ --with-stream_ssl_module \ - --with-threads \ --add-module=$(MODULESDIR)/headers-more-nginx-module \ --add-module=$(MODULESDIR)/nginx-auth-pam \ --add-module=$(MODULESDIR)/nginx-cache-purge \ From bba86a8f896aeecb716dde79ef3f2ba9fc86a092 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 30 Mar 2016 10:00:33 +0300 Subject: [PATCH 090/651] tests: Test if nginx-light can successfully load dynamic modules --- debian/tests/control | 3 +++ 1 file changed, 3 insertions(+) diff --git a/debian/tests/control b/debian/tests/control index 8d0e384..881cc56 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -10,3 +10,6 @@ Test-Command: curl --silent --fail -o /dev/null -w "response_code: %{http_code}\ Restrictions: allow-stderr isolation-container Depends: nginx-extras, curl +Test-Command: curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ +Restrictions: allow-stderr isolation-container +Depends: nginx-light, libnginx-mod-stream, curl From 830a8fbc342545e228baefbbb9f4f540d6fdd3f6 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 30 Mar 2016 11:17:18 +0300 Subject: [PATCH 091/651] Sum up changes --- debian/changelog | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/debian/changelog b/debian/changelog index 0f8009f..226b72b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,23 @@ nginx (1.9.11-1) UNRELEASED; urgency=medium [ Christos Trochalakis ] * New upstream release (1.9.11) (Closes: #812806) + * debian: + + Setup dynamic module flow, and implement a simple dh_nginx helper for + internal use. + + Split modules in libnginx-mod-* packages. + Not all modules are ready for dynamic building. + * debian/control: + + Enable http/2, thread pool & WebDAV on nginx-light. + In order for dynamic modules to be loadable in all nginx flavors we need + to ensure the share the same build signature. + + Use secure VCS uri (lintian). + + Bump Standards to 3.9.7. + * debian/rules: + + Disable PIE for now so we can build dynamic modules. + * debian/tests/control: + + Test if modules are loadable in nginx-light. + * debian/nginx-common.nginx.service: + + Documentation points to nginx man page. * debian/modules/nginx-lua: + Update nginx-lua to v0.10.1rc0-5-g01727a3. Fixes buiding failures with nginx 1.9.11. From 95448c85f548c75efe77f4433c6bb1f5a30e36b2 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 30 Mar 2016 11:23:20 +0300 Subject: [PATCH 092/651] Imported Upstream version 1.9.12 --- CHANGES | 30 +++ CHANGES.ru | 29 +++ auto/cc/conf | 10 + auto/cc/msvc | 31 ++- auto/cc/name | 27 +- auto/install | 5 +- auto/lib/md5/conf | 4 +- auto/lib/md5/make | 4 +- auto/lib/openssl/conf | 15 +- auto/lib/openssl/make | 2 +- auto/lib/pcre/conf | 4 +- auto/lib/pcre/make | 4 +- auto/lib/sha1/conf | 4 +- auto/lib/sha1/make | 4 +- auto/lib/zlib/conf | 4 +- auto/lib/zlib/make | 4 +- auto/make | 4 + auto/modules | 3 +- auto/unix | 1 + src/core/nginx.c | 79 ++++-- src/core/nginx.h | 4 +- src/core/ngx_cycle.h | 4 +- src/core/ngx_module.c | 2 +- src/core/ngx_module.h | 2 +- src/event/ngx_event_openssl.c | 15 +- .../modules/ngx_http_headers_filter_module.c | 16 +- src/http/ngx_http_request.c | 19 +- src/http/v2/ngx_http_v2.c | 237 ++++++++++++----- src/http/v2/ngx_http_v2.h | 5 + src/http/v2/ngx_http_v2_filter_module.c | 224 +++++++++++----- src/http/v2/ngx_http_v2_huff_encode.c | 244 ++++++++++++++++++ src/os/unix/ngx_process_cycle.c | 2 +- src/os/unix/ngx_setaffinity.c | 44 +--- src/os/unix/ngx_setaffinity.h | 16 +- src/stream/ngx_stream_proxy_module.c | 7 +- 35 files changed, 820 insertions(+), 289 deletions(-) diff --git a/CHANGES b/CHANGES index da1fa00..e94e14f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,34 @@ +Changes with nginx 1.9.12 24 Feb 2016 + + *) Feature: Huffman encoding of response headers in HTTP/2. + Thanks to Vlad Krasnov. + + *) Feature: the "worker_cpu_affinity" directive now supports more than + 64 CPUs. + + *) Bugfix: compatibility with 3rd party C++ modules; the bug had + appeared in 1.9.11. + Thanks to Piotr Sikora. + + *) Bugfix: nginx could not be built statically with OpenSSL on Linux; + the bug had appeared in 1.9.11. + + *) Bugfix: the "add_header ... always" directive with an empty value did + not delete "Last-Modified" and "ETag" header lines from error + responses. + + *) Workaround: "called a function you should not call" and "shutdown + while in init" messages might appear in logs when using OpenSSL + 1.0.2f. + + *) Bugfix: invalid headers might be logged incorrectly. + + *) Bugfix: socket leak when using HTTP/2. + + *) Bugfix: in the ngx_http_v2_module. + + Changes with nginx 1.9.11 09 Feb 2016 *) Feature: TCP support in resolver. diff --git a/CHANGES.ru b/CHANGES.ru index 33302e2..c11c477 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,33 @@ +Изменения в nginx 1.9.12 24.02.2016 + + *) Добавление: кодирование Хаффмана заголовков ответов в HTTP/2. + Спасибо Владу Краснову. + + *) Добавление: директива worker_cpu_affinity теперь поддерживает более + 64 процессоров. + + *) Исправление: совместимость со сторонними модулями на C++; ошибка + появилась в 1.9.11. + Спасибо Piotr Sikora. + + *) Исправление: nginx не собирался статически с OpenSSL на Linux; ошибка + появилась в 1.9.11. + + *) Исправление: директива "add_header ... always" с пустым значением не + удаляла из заголовков ошибочных ответов строки Last-Modified и ETag. + + *) Изменение: при использовании OpenSSL 1.0.2f в логах могли появляться + сообщения "called a function you should not call" и "shutdown while + in init". + + *) Исправление: ошибочные заголовки могли логгироваться некорректно. + + *) Исправление: утечки сокетов при использовании HTTP/2. + + *) Исправление: в модуле ngx_http_v2_module. + + Изменения в nginx 1.9.11 09.02.2016 *) Добавление: теперь resolver поддерживает TCP. diff --git a/auto/cc/conf b/auto/cc/conf index 35fd39c..f2c25ed 100644 --- a/auto/cc/conf +++ b/auto/cc/conf @@ -225,6 +225,16 @@ if [ "$NGX_PLATFORM" != win32 ]; then . auto/feature + ngx_feature="gcc builtin 64 bit byteswap" + ngx_feature_name="NGX_HAVE_GCC_BSWAP64" + ngx_feature_run=no + ngx_feature_incs= + ngx_feature_path= + ngx_feature_libs= + ngx_feature_test="__builtin_bswap64(0)" + . auto/feature + + # ngx_feature="inline" # ngx_feature_name= # ngx_feature_run=no diff --git a/auto/cc/msvc b/auto/cc/msvc index e588c48..4eef101 100644 --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -3,9 +3,24 @@ # Copyright (C) Nginx, Inc. -# MSVC 6.0 SP2 -# MSVC Toolkit 2003 (7.1) -# MSVC 2005 Express Edition SP1 (8.0) +# MSVC 6.0 SP2 cl 12.00 +# MSVC Toolkit 2003 (7.1) cl 13.10 +# MSVC 2005 Express Edition SP1 (8.0) cl 14.00 +# MSVC 2008 Express Edition (9.0) cl 15.00 +# MSVC 2010 (10.0) cl 16.00 +# MSVC 2015 (14.0) cl 19.00 + + +NGX_MSVC_VER=`$NGX_WINE $CC 2>&1 | grep 'Compiler Version' 2>&1 \ + | sed -e 's/^.* Version \(.*\)/\1/'` + +echo " + cl version: $NGX_MSVC_VER" + +have=NGX_COMPILER value="\"cl $NGX_MSVC_VER\"" . auto/define + + +ngx_msvc_ver=`echo $NGX_MSVC_VER | sed -e 's/^\([0-9]*\).*/\1/'` + # optimizations @@ -90,17 +105,17 @@ CORE_LIBS="$CORE_LIBS kernel32.lib user32.lib" #CORE_LINK="$CORE_LINK -subsystem:windows -entry:mainCRTStartup" # debug -# msvc8 under Wine issues -# Program database manager mismatch; please check your installation -if [ $NGX_CC_NAME != msvc8 ]; then +# msvc under Wine issues +# C1902: Program database manager mismatch; please check your installation +if [ -z "$NGX_WINE" ]; then CFLAGS="$CFLAGS -Zi" CORE_LINK="$CORE_LINK -debug" fi # MSVC 2005 supports C99 variadic macros -if [ $NGX_CC_NAME = msvc8 ]; then - have=NGX_HAVE_C99_VARIADIC_MACROS . auto/have +if [ "$ngx_msvc_ver" -ge 14 ]; then + have=NGX_HAVE_C99_VARIADIC_MACROS . auto/have fi diff --git a/auto/cc/name b/auto/cc/name index 51a7ed9..35d319e 100644 --- a/auto/cc/name +++ b/auto/cc/name @@ -25,31 +25,8 @@ fi if [ "$CC" = cl ]; then - if `$NGX_WINE $CC -v 2>&1 \ - | grep '^Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16' \ - >/dev/null 2>&1`; then - - NGX_CC_NAME=msvc10 - echo " + using Microsoft Visual C++ 10 compiler" - - elif `$NGX_WINE $CC -v 2>&1 \ - | grep '^Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14' \ - >/dev/null 2>&1`; then - - NGX_CC_NAME=msvc8 - echo " + using Microsoft Visual C++ 8 compiler" - - elif `$NGX_WINE $CC -v 2>&1 \ - | grep '^Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13' \ - >/dev/null 2>&1`; then - - NGX_CC_NAME=msvc7 - echo " + using Microsoft Visual C++ 7 compiler" - - else - NGX_CC_NAME=msvc - echo " + using Microsoft Visual C++ compiler" - fi + NGX_CC_NAME=msvc + echo " + using Microsoft Visual C++ compiler" elif [ "$CC" = wcl386 ]; then NGX_CC_NAME=owc diff --git a/auto/install b/auto/install index 4dcc743..9469a49 100644 --- a/auto/install +++ b/auto/install @@ -104,8 +104,7 @@ $NGX_OBJS/nginx.8: $NGX_MAN $NGX_AUTO_CONFIG_H -e "s|%%ERROR_LOG_PATH%%|${NGX_ERROR_LOG_PATH:-stderr}|" \\ < $NGX_MAN > \$@ -install: $NGX_OBJS${ngx_dirsep}nginx${ngx_binext} \ - $NGX_INSTALL_PERL_MODULES +install: build $NGX_INSTALL_PERL_MODULES test -d '\$(DESTDIR)$NGX_PREFIX' || mkdir -p '\$(DESTDIR)$NGX_PREFIX' test -d '\$(DESTDIR)`dirname "$NGX_SBIN_PATH"`' \ @@ -187,8 +186,6 @@ cat << END >> Makefile build: \$(MAKE) -f $NGX_MAKEFILE - \$(MAKE) -f $NGX_MAKEFILE modules - \$(MAKE) -f $NGX_MAKEFILE manpage install: \$(MAKE) -f $NGX_MAKEFILE install diff --git a/auto/lib/md5/conf b/auto/lib/md5/conf index eb5dfd1..49c0ddf 100644 --- a/auto/lib/md5/conf +++ b/auto/lib/md5/conf @@ -20,12 +20,12 @@ if [ $MD5 != NONE ]; then case "$NGX_CC_NAME" in - msvc* | owc* | bcc) + msvc | owc | bcc) LINK_DEPS="$LINK_DEPS $MD5/md5.lib" CORE_LIBS="$CORE_LIBS $MD5/md5.lib" ;; - icc*) + icc) LINK_DEPS="$LINK_DEPS $MD5/libmd5.a" # to allow -ipo optimization we link with the *.o but not library diff --git a/auto/lib/md5/make b/auto/lib/md5/make index 81f138a..7000b20 100644 --- a/auto/lib/md5/make +++ b/auto/lib/md5/make @@ -5,13 +5,13 @@ case "$NGX_CC_NAME" in - msvc*) + msvc) ngx_makefile=makefile.msvc ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC MD5_ASM=$MD5_ASM" ngx_md5="MD5=\"$MD5\"" ;; - owc*) + owc) ngx_makefile=makefile.owc ngx_opt="CPU_OPT=\"$CPU_OPT\"" ngx_md5=`echo MD5=\"$MD5\" | sed -e "s/\//$ngx_regex_dirsep/g"` diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf index 2187e5c..e438050 100644 --- a/auto/lib/openssl/conf +++ b/auto/lib/openssl/conf @@ -32,6 +32,7 @@ if [ $OPENSSL != NONE ]; then CORE_DEPS="$CORE_DEPS $OPENSSL/.openssl/include/openssl/ssl.h" CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libssl.a" CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libcrypto.a" + CORE_LIBS="$CORE_LIBS $NGX_LIBDL" if [ "$NGX_PLATFORM" = win32 ]; then CORE_LIBS="$CORE_LIBS -lgdi32 -lcrypt32 -lws2_32" @@ -50,7 +51,7 @@ else ngx_feature_run=no ngx_feature_incs="#include " ngx_feature_path= - ngx_feature_libs="-lssl -lcrypto" + ngx_feature_libs="-lssl -lcrypto $NGX_LIBDL" ngx_feature_test="SSL_library_init()" . auto/feature @@ -62,9 +63,9 @@ else ngx_feature_path="/usr/local/include" if [ $NGX_RPATH = YES ]; then - ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lssl -lcrypto" + ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lssl -lcrypto $NGX_LIBDL" else - ngx_feature_libs="-L/usr/local/lib -lssl -lcrypto" + ngx_feature_libs="-L/usr/local/lib -lssl -lcrypto $NGX_LIBDL" fi . auto/feature @@ -78,9 +79,9 @@ else ngx_feature_path="/usr/pkg/include" if [ $NGX_RPATH = YES ]; then - ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lssl -lcrypto" + ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lssl -lcrypto $NGX_LIBDL" else - ngx_feature_libs="-L/usr/pkg/lib -lssl -lcrypto" + ngx_feature_libs="-L/usr/pkg/lib -lssl -lcrypto $NGX_LIBDL" fi . auto/feature @@ -94,9 +95,9 @@ else ngx_feature_path="/opt/local/include" if [ $NGX_RPATH = YES ]; then - ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lssl -lcrypto" + ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lssl -lcrypto $NGX_LIBDL" else - ngx_feature_libs="-L/opt/local/lib -lssl -lcrypto" + ngx_feature_libs="-L/opt/local/lib -lssl -lcrypto $NGX_LIBDL" fi . auto/feature diff --git a/auto/lib/openssl/make b/auto/lib/openssl/make index 765cd06..a6090c6 100644 --- a/auto/lib/openssl/make +++ b/auto/lib/openssl/make @@ -53,7 +53,7 @@ $OPENSSL/.openssl/include/openssl/ssl.h: $NGX_MAKEFILE && if [ -f Makefile ]; then \$(MAKE) clean; fi \\ && ./config --prefix=$ngx_prefix no-shared $OPENSSL_OPT \\ && \$(MAKE) \\ - && \$(MAKE) install LIBDIR=lib + && \$(MAKE) install_sw LIBDIR=lib END diff --git a/auto/lib/pcre/conf b/auto/lib/pcre/conf index 939f01b..5e3960f 100644 --- a/auto/lib/pcre/conf +++ b/auto/lib/pcre/conf @@ -8,7 +8,7 @@ if [ $PCRE != NONE ]; then case "$NGX_CC_NAME" in - msvc* | owc* | bcc) + msvc | owc | bcc) have=NGX_PCRE . auto/have have=PCRE_STATIC . auto/have CORE_DEPS="$CORE_DEPS $PCRE/pcre.h" @@ -16,7 +16,7 @@ if [ $PCRE != NONE ]; then CORE_LIBS="$CORE_LIBS $PCRE/pcre.lib" ;; - icc* ) + icc) have=NGX_PCRE . auto/have CORE_DEPS="$CORE_DEPS $PCRE/pcre.h" diff --git a/auto/lib/pcre/make b/auto/lib/pcre/make index 0a27a11..97c9f3b 100644 --- a/auto/lib/pcre/make +++ b/auto/lib/pcre/make @@ -5,13 +5,13 @@ case "$NGX_CC_NAME" in - msvc*) + msvc) ngx_makefile=makefile.msvc ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC" ngx_pcre="PCRE=\"$PCRE\"" ;; - owc*) + owc) ngx_makefile=makefile.owc ngx_opt="CPU_OPT=\"$CPU_OPT\"" ngx_pcre=`echo PCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"` diff --git a/auto/lib/sha1/conf b/auto/lib/sha1/conf index fd69afd..78f9efd 100644 --- a/auto/lib/sha1/conf +++ b/auto/lib/sha1/conf @@ -10,12 +10,12 @@ if [ $SHA1 != NONE ]; then case "$NGX_CC_NAME" in - msvc* | owc* | bcc) + msvc | owc | bcc) LINK_DEPS="$LINK_DEPS $SHA1/sha1.lib" CORE_LIBS="$CORE_LIBS $SHA1/sha1.lib" ;; - icc*) + icc) LINK_DEPS="$LINK_DEPS $SHA1/libsha.a" # to allow -ipo optimization we link with the *.o but not library diff --git a/auto/lib/sha1/make b/auto/lib/sha1/make index fc10aae..fc3b340 100644 --- a/auto/lib/sha1/make +++ b/auto/lib/sha1/make @@ -5,13 +5,13 @@ case "$NGX_CC_NAME" in - msvc*) + msvc) ngx_makefile=makefile.msvc ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC SHA1_ASM=$SHA1_ASM" ngx_sha1="SHA1=\"$SHA1\"" ;; - owc*) + owc) ngx_makefile=makefile.owc ngx_opt="CPU_OPT=\"$CPU_OPT\"" ngx_sha1=`echo SHA1=\"$SHA1\" | sed -e "s/\//$ngx_regex_dirsep/g"` diff --git a/auto/lib/zlib/conf b/auto/lib/zlib/conf index 26db642..239592e 100644 --- a/auto/lib/zlib/conf +++ b/auto/lib/zlib/conf @@ -8,13 +8,13 @@ if [ $ZLIB != NONE ]; then case "$NGX_CC_NAME" in - msvc* | owc* | bcc) + msvc | owc | bcc) have=NGX_ZLIB . auto/have LINK_DEPS="$LINK_DEPS $ZLIB/zlib.lib" CORE_LIBS="$CORE_LIBS $ZLIB/zlib.lib" ;; - icc*) + icc) have=NGX_ZLIB . auto/have LINK_DEPS="$LINK_DEPS $ZLIB/libz.a" diff --git a/auto/lib/zlib/make b/auto/lib/zlib/make index 7875ef6..0082ad5 100644 --- a/auto/lib/zlib/make +++ b/auto/lib/zlib/make @@ -5,14 +5,14 @@ case "$NGX_CC_NAME" in - msvc*) + msvc) ngx_makefile=makefile.msvc ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC" ngx_zlib="ZLIB=\"$ZLIB\"" ;; - owc*) + owc) ngx_makefile=makefile.owc ngx_opt="CPU_OPT=\"$CPU_OPT\"" ngx_zlib=`echo ZLIB=\"$ZLIB\" | sed -e "s/\//$ngx_regex_dirsep/g"` diff --git a/auto/make b/auto/make index 039a70f..560924b 100644 --- a/auto/make +++ b/auto/make @@ -223,6 +223,10 @@ ngx_main_link=${MAIN_LINK:+`echo $MAIN_LINK \ cat << END >> $NGX_MAKEFILE +build: binary modules manpage + +binary: $NGX_OBJS${ngx_dirsep}nginx${ngx_binext} + $NGX_OBJS${ngx_dirsep}nginx${ngx_binext}: $ngx_deps$ngx_spacer \$(LINK) ${ngx_long_start}${ngx_binout}$NGX_OBJS${ngx_dirsep}nginx$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link $ngx_rcc diff --git a/auto/modules b/auto/modules index 2074778..ebfc91d 100644 --- a/auto/modules +++ b/auto/modules @@ -530,11 +530,10 @@ if [ $HTTP_AUTH_BASIC = YES ]; then ngx_module_incs= ngx_module_deps= ngx_module_srcs=src/http/modules/ngx_http_auth_basic_module.c - ngx_module_libs= + ngx_module_libs=$CRYPT_LIB ngx_module_link=$HTTP_AUTH_BASIC . auto/module - CORE_LIBS="$CORE_LIBS $CRYPT_LIB" fi if [ $HTTP_ACCESS = YES ]; then diff --git a/auto/unix b/auto/unix index e07df08..ce01791 100755 --- a/auto/unix +++ b/auto/unix @@ -272,6 +272,7 @@ if [ $ngx_found != yes ]; then if [ $ngx_found = yes ]; then CORE_LIBS="$CORE_LIBS -ldl" + NGX_LIBDL="-ldl" fi fi diff --git a/src/core/nginx.c b/src/core/nginx.c index 6ce030c..cdc067e 100644 --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -481,6 +481,12 @@ ngx_add_inherited_sockets(ngx_cycle_t *cycle) } } + if (v != p) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "invalid socket number \"%s\" in " NGINX_VAR + " environment variable, ignoring", v); + } + ngx_inherited = 1; return ngx_set_inherited_sockets(cycle); @@ -1264,16 +1270,16 @@ ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #if (NGX_HAVE_CPU_AFFINITY) ngx_core_conf_t *ccf = conf; - u_char ch; - uint64_t *mask; + u_char ch, *p; ngx_str_t *value; ngx_uint_t i, n; + ngx_cpuset_t *mask; if (ccf->cpu_affinity) { return "is duplicate"; } - mask = ngx_palloc(cf->pool, (cf->args->nelts - 1) * sizeof(uint64_t)); + mask = ngx_palloc(cf->pool, (cf->args->nelts - 1) * sizeof(ngx_cpuset_t)); if (mask == NULL) { return NGX_CONF_ERROR; } @@ -1293,7 +1299,12 @@ ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } ccf->cpu_affinity_auto = 1; - mask[0] = (uint64_t) -1 >> (64 - ngx_min(64, ngx_ncpu)); + + CPU_ZERO(&mask[0]); + for (i = 0; i < (ngx_uint_t) ngx_min(ngx_ncpu, CPU_SETSIZE); i++) { + CPU_SET(i, &mask[0]); + } + n = 2; } else { @@ -1302,30 +1313,34 @@ ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) for ( /* void */ ; n < cf->args->nelts; n++) { - if (value[n].len > 64) { + if (value[n].len > CPU_SETSIZE) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"worker_cpu_affinity\" supports up to 64 CPUs only"); + "\"worker_cpu_affinity\" supports up to %d CPUs only", + CPU_SETSIZE); return NGX_CONF_ERROR; } - mask[n - 1] = 0; + i = 0; + CPU_ZERO(&mask[n - 1]); - for (i = 0; i < value[n].len; i++) { - - ch = value[n].data[i]; + for (p = value[n].data + value[n].len - 1; + p >= value[n].data; + p--) + { + ch = *p; if (ch == ' ') { continue; } - mask[n - 1] <<= 1; + i++; if (ch == '0') { continue; } if (ch == '1') { - mask[n - 1] |= 1; + CPU_SET(i - 1, &mask[n - 1]); continue; } @@ -1347,43 +1362,57 @@ ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } -uint64_t +ngx_cpuset_t * ngx_get_cpu_affinity(ngx_uint_t n) { - uint64_t mask; - ngx_uint_t i; +#if (NGX_HAVE_CPU_AFFINITY) + ngx_uint_t i, j; + ngx_cpuset_t *mask; ngx_core_conf_t *ccf; + static ngx_cpuset_t result; + ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, ngx_core_module); if (ccf->cpu_affinity == NULL) { - return 0; + return NULL; } if (ccf->cpu_affinity_auto) { - mask = ccf->cpu_affinity[ccf->cpu_affinity_n - 1]; + mask = &ccf->cpu_affinity[ccf->cpu_affinity_n - 1]; - if (mask == 0) { - return 0; - } + for (i = 0, j = n; /* void */ ; i++) { - for (i = 0; /* void */ ; i++) { - if ((mask & ((uint64_t) 1 << (i % 64))) && n-- == 0) { + if (CPU_ISSET(i % CPU_SETSIZE, mask) && j-- == 0) { break; } + if (i == CPU_SETSIZE && j == n) { + /* empty mask */ + return NULL; + } + /* void */ } - return (uint64_t) 1 << (i % 64); + CPU_ZERO(&result); + CPU_SET(i % CPU_SETSIZE, &result); + + return &result; } if (ccf->cpu_affinity_n > n) { - return ccf->cpu_affinity[n]; + return &ccf->cpu_affinity[n]; } - return ccf->cpu_affinity[ccf->cpu_affinity_n - 1]; + return &ccf->cpu_affinity[ccf->cpu_affinity_n - 1]; + +#else + + return NULL; + +#endif } diff --git a/src/core/nginx.h b/src/core/nginx.h index e416e90..dec7b88 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1009011 -#define NGINX_VERSION "1.9.11" +#define nginx_version 1009012 +#define NGINX_VERSION "1.9.12" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h index 27401d0..cfdbb55 100644 --- a/src/core/ngx_cycle.h +++ b/src/core/ngx_cycle.h @@ -94,7 +94,7 @@ typedef struct { ngx_uint_t cpu_affinity_auto; ngx_uint_t cpu_affinity_n; - uint64_t *cpu_affinity; + ngx_cpuset_t *cpu_affinity; char *username; ngx_uid_t user; @@ -121,7 +121,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); -uint64_t ngx_get_cpu_affinity(ngx_uint_t n); +ngx_cpuset_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/src/core/ngx_module.c b/src/core/ngx_module.c index 1e947c9..f5ec86a 100644 --- a/src/core/ngx_module.c +++ b/src/core/ngx_module.c @@ -171,7 +171,7 @@ ngx_add_module(ngx_conf_t *cf, ngx_str_t *file, ngx_module_t *module, if (module->version != nginx_version) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "module \"%V\" version %ui instead of %ui", - file, module->version, nginx_version); + file, module->version, (ngx_uint_t) nginx_version); return NGX_ERROR; } diff --git a/src/core/ngx_module.h b/src/core/ngx_module.h index cd28c49..3e74def 100644 --- a/src/core/ngx_module.h +++ b/src/core/ngx_module.h @@ -253,7 +253,7 @@ struct ngx_module_s { ngx_uint_t spare1; ngx_uint_t version; - char *signature; + const char *signature; void *ctx; ngx_command_t *commands; diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 57dfc6c..de10d48 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -1767,6 +1767,19 @@ ngx_ssl_shutdown(ngx_connection_t *c) int n, sslerr, mode; ngx_err_t err; + if (SSL_in_init(c->ssl->connection)) { + /* + * OpenSSL 1.0.2f complains if SSL_shutdown() is called during + * an SSL handshake, while previous versions always return 0. + * Avoid calling SSL_shutdown() if handshake wasn't completed. + */ + + SSL_free(c->ssl->connection); + c->ssl = NULL; + + return NGX_OK; + } + if (c->timedout) { mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN; SSL_set_quiet_shutdown(c->ssl->connection, 1); @@ -1797,7 +1810,7 @@ ngx_ssl_shutdown(ngx_connection_t *c) sslerr = 0; - /* SSL_shutdown() never returns -1, on error it returns 0 */ + /* before 0.9.8m SSL_shutdown() returned 0 instead of -1 on errors */ if (n != 1 && ERR_peek_error()) { sslerr = SSL_get_error(c->ssl->connection, n); diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c index 985e5b3..6738afe 100644 --- a/src/http/modules/ngx_http_headers_filter_module.c +++ b/src/http/modules/ngx_http_headers_filter_module.c @@ -712,17 +712,17 @@ ngx_http_headers_add(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (value[2].len == 0) { ngx_memzero(&hv->value, sizeof(ngx_http_complex_value_t)); - return NGX_CONF_OK; - } - ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + } else { + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); - ccv.cf = cf; - ccv.value = &value[2]; - ccv.complex_value = &hv->value; + ccv.cf = cf; + ccv.value = &value[2]; + ccv.complex_value = &hv->value; - if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { - return NGX_CONF_ERROR; + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } } if (cf->args->nelts == 3) { diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 99e9325..fd790e1 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1351,12 +1351,11 @@ ngx_http_process_request_headers(ngx_event_t *rev) continue; } - /* rc == NGX_HTTP_PARSE_INVALID_HEADER: "\r" is not followed by "\n" */ + /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent invalid header line: \"%*s\\r...\"", - r->header_end - r->header_name_start, - r->header_name_start); + "client sent invalid header line"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); return; } @@ -2574,12 +2573,6 @@ ngx_http_set_write_handler(ngx_http_request_t *r) ngx_http_test_reading; r->write_event_handler = ngx_http_writer; -#if (NGX_HTTP_V2) - if (r->stream) { - return NGX_OK; - } -#endif - wev = r->connection->write; if (wev->ready && wev->delayed) { @@ -2665,12 +2658,6 @@ ngx_http_writer(ngx_http_request_t *r) if (r->buffered || r->postponed || (r == r->main && c->buffered)) { -#if (NGX_HTTP_V2) - if (r->stream) { - return; - } -#endif - if (!wev->delayed) { ngx_add_timer(wev, clcf->send_timeout); } diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 4e378c9..4c4a4e7 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -112,10 +112,10 @@ static u_char *ngx_http_v2_state_skip_padded(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end); static u_char *ngx_http_v2_state_skip(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end); -static u_char *ngx_http_v2_state_skip_headers(ngx_http_v2_connection_t *h2c, - u_char *pos, u_char *end); static u_char *ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end, ngx_http_v2_handler_pt handler); +static u_char *ngx_http_v2_state_headers_save(ngx_http_v2_connection_t *h2c, + u_char *pos, u_char *end, ngx_http_v2_handler_pt handler); static u_char *ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c, ngx_uint_t err); @@ -164,6 +164,7 @@ static ngx_int_t ngx_http_v2_cookie(ngx_http_request_t *r, static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r); static void ngx_http_v2_run_request(ngx_http_request_t *r); static ngx_int_t ngx_http_v2_init_request_body(ngx_http_request_t *r); +static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r); static ngx_int_t ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, ngx_http_v2_stream_t *stream, ngx_uint_t status); @@ -432,6 +433,10 @@ ngx_http_v2_write_handler(ngx_event_t *wev) "run http2 stream %ui", stream->node->id); wev = stream->request->connection->write; + + wev->active = 0; + wev->ready = 1; + wev->handler(wev); } @@ -885,6 +890,7 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, ngx_buf_t *buf; ngx_int_t rc; ngx_temp_file_t *tf; + ngx_connection_t *fc; ngx_http_request_t *r; ngx_http_v2_stream_t *stream; ngx_http_request_body_t *rb; @@ -921,6 +927,7 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, return ngx_http_v2_state_skip_padded(h2c, pos, end); } + fc = r->connection; rb = r->request_body; tf = rb->temp_file; buf = rb->buf; @@ -931,7 +938,7 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, if (r->headers_in.content_length_n != -1 && r->headers_in.content_length_n < rb->rest) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + ngx_log_error(NGX_LOG_INFO, fc->log, 0, "client intended to send body data " "larger than declared"); @@ -944,7 +951,7 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, if (clcf->client_max_body_size && clcf->client_max_body_size < rb->rest) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + ngx_log_error(NGX_LOG_ERR, fc->log, 0, "client intended to send " "too large chunked body: %O bytes", rb->rest); @@ -984,6 +991,11 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, } if (h2c->state.length) { + if (rb->post_handler) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + ngx_add_timer(fc->read, clcf->client_body_timeout); + } + return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_read_data); } @@ -995,7 +1007,7 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, r->headers_in.content_length_n = rb->rest; } else if (r->headers_in.content_length_n != rb->rest) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + ngx_log_error(NGX_LOG_INFO, fc->log, 0, "client prematurely closed stream: " "only %O out of %O bytes of request body received", rb->rest, r->headers_in.content_length_n); @@ -1015,9 +1027,17 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, } if (rb->post_handler) { + if (fc->read->timer_set) { + ngx_del_timer(fc->read); + } + r->read_event_handler = ngx_http_block_reading; rb->post_handler(r); } + + } else if (rb->post_handler) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + ngx_add_timer(fc->read, clcf->client_body_timeout); } if (h2c->state.padding) { @@ -1029,6 +1049,9 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, error: if (rb->post_handler) { + if (fc->read->timer_set) { + ngx_del_timer(fc->read); + } if (stream->skip_data == NGX_HTTP_V2_DATA_ERROR) { rc = (r->headers_in.content_length_n == -1) @@ -1133,6 +1156,11 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, h2c->last_sid = h2c->state.sid; + h2c->state.pool = ngx_create_pool(1024, h2c->connection->log); + if (h2c->state.pool == NULL) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + } + if (depend == h2c->state.sid) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, "client sent HEADERS frame for stream %ui " @@ -1146,7 +1174,7 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, NGX_HTTP_V2_INTERNAL_ERROR); } - return ngx_http_v2_state_skip_headers(h2c, pos, end); + return ngx_http_v2_state_header_block(h2c, pos, end); } h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, @@ -1166,7 +1194,7 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, NGX_HTTP_V2_INTERNAL_ERROR); } - return ngx_http_v2_state_skip_headers(h2c, pos, end); + return ngx_http_v2_state_header_block(h2c, pos, end); } node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 1); @@ -1185,6 +1213,11 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); } + h2c->state.stream = stream; + + stream->pool = h2c->state.pool; + h2c->state.keep_pool = 1; + stream->request->request_length = h2c->state.length; stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; @@ -1192,9 +1225,6 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, node->stream = stream; - h2c->state.stream = stream; - h2c->state.pool = stream->request->pool; - if (priority || node->parent == NULL) { node->weight = weight; ngx_http_v2_set_dependency(h2c, node, depend, excl); @@ -1213,8 +1243,8 @@ ngx_http_v2_state_header_block(ngx_http_v2_connection_t *h2c, u_char *pos, ngx_uint_t indexed, size_update, prefix; if (end - pos < 1) { - return ngx_http_v2_state_save(h2c, pos, end, - ngx_http_v2_state_header_block); + return ngx_http_v2_state_headers_save(h2c, pos, end, + ngx_http_v2_state_header_block); } if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) @@ -1257,8 +1287,8 @@ ngx_http_v2_state_header_block(ngx_http_v2_connection_t *h2c, u_char *pos, if (value < 0) { if (value == NGX_AGAIN) { - return ngx_http_v2_state_save(h2c, pos, end, - ngx_http_v2_state_header_block); + return ngx_http_v2_state_headers_save(h2c, pos, end, + ngx_http_v2_state_header_block); } if (value == NGX_DECLINED) { @@ -1328,8 +1358,8 @@ ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c, u_char *pos, } if (end - pos < 1) { - return ngx_http_v2_state_save(h2c, pos, end, - ngx_http_v2_state_field_len); + return ngx_http_v2_state_headers_save(h2c, pos, end, + ngx_http_v2_state_field_len); } huff = *pos >> 7; @@ -1337,8 +1367,8 @@ ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c, u_char *pos, if (len < 0) { if (len == NGX_AGAIN) { - return ngx_http_v2_state_save(h2c, pos, end, - ngx_http_v2_state_field_len); + return ngx_http_v2_state_headers_save(h2c, pos, end, + ngx_http_v2_state_field_len); } if (len == NGX_DECLINED) { @@ -1430,8 +1460,8 @@ ngx_http_v2_state_field_huff(ngx_http_v2_connection_t *h2c, u_char *pos, } if (h2c->state.length) { - return ngx_http_v2_state_save(h2c, pos, end, - ngx_http_v2_state_field_huff); + return ngx_http_v2_state_headers_save(h2c, pos, end, + ngx_http_v2_state_field_huff); } if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) { @@ -1475,8 +1505,8 @@ ngx_http_v2_state_field_raw(ngx_http_v2_connection_t *h2c, u_char *pos, } if (h2c->state.length) { - return ngx_http_v2_state_save(h2c, pos, end, - ngx_http_v2_state_field_raw); + return ngx_http_v2_state_headers_save(h2c, pos, end, + ngx_http_v2_state_field_raw); } if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) { @@ -1686,7 +1716,6 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, error: h2c->state.stream = NULL; - h2c->state.pool = NULL; return ngx_http_v2_state_header_complete(h2c, pos, end); } @@ -1699,8 +1728,7 @@ ngx_http_v2_state_header_complete(ngx_http_v2_connection_t *h2c, u_char *pos, ngx_http_v2_stream_t *stream; if (h2c->state.length) { - h2c->state.handler = h2c->state.pool ? ngx_http_v2_state_header_block - : ngx_http_v2_state_skip_headers; + h2c->state.handler = ngx_http_v2_state_header_block; return pos; } @@ -1713,12 +1741,14 @@ ngx_http_v2_state_header_complete(ngx_http_v2_connection_t *h2c, u_char *pos, if (stream) { ngx_http_v2_run_request(stream->request); + } - } else if (h2c->state.pool) { + if (!h2c->state.keep_pool) { ngx_destroy_pool(h2c->state.pool); } h2c->state.pool = NULL; + h2c->state.keep_pool = 0; if (h2c->state.padding) { return ngx_http_v2_state_skip_padded(h2c, pos, end); @@ -1749,7 +1779,7 @@ ngx_http_v2_handle_continuation(ngx_http_v2_connection_t *h2c, u_char *pos, } if ((size_t) (end - pos) < len + NGX_HTTP_V2_FRAME_HEADER_SIZE) { - return ngx_http_v2_state_save(h2c, pos, end, handler); + return ngx_http_v2_state_headers_save(h2c, pos, end, handler); } p = pos + len; @@ -2224,8 +2254,10 @@ ngx_http_v2_state_window_update(ngx_http_v2_connection_t *h2c, u_char *pos, wev = stream->request->connection->write; - if (!wev->timer_set) { - wev->delayed = 0; + wev->active = 0; + wev->ready = 1; + + if (!wev->delayed) { wev->handler(wev); } } @@ -2257,8 +2289,10 @@ ngx_http_v2_state_window_update(ngx_http_v2_connection_t *h2c, u_char *pos, wev = stream->request->connection->write; - if (!wev->timer_set) { - wev->delayed = 0; + wev->active = 0; + wev->ready = 1; + + if (!wev->delayed) { wev->handler(wev); if (h2c->send_window == 0) { @@ -2336,19 +2370,6 @@ ngx_http_v2_state_skip(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) } -static u_char * -ngx_http_v2_state_skip_headers(ngx_http_v2_connection_t *h2c, u_char *pos, - u_char *end) -{ - h2c->state.pool = ngx_create_pool(1024, h2c->connection->log); - if (h2c->state.pool == NULL) { - return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); - } - - return ngx_http_v2_state_header_block(h2c, pos, end); -} - - static u_char * ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end, ngx_http_v2_handler_pt handler) @@ -2378,6 +2399,28 @@ ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end, } +static u_char * +ngx_http_v2_state_headers_save(ngx_http_v2_connection_t *h2c, u_char *pos, + u_char *end, ngx_http_v2_handler_pt handler) +{ + ngx_event_t *rev; + ngx_http_request_t *r; + ngx_http_core_srv_conf_t *cscf; + + if (h2c->state.stream) { + r = h2c->state.stream->request; + rev = r->connection->read; + + if (!rev->timer_set) { + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + ngx_add_timer(rev, cscf->client_header_timeout); + } + } + + return ngx_http_v2_state_save(h2c, pos, end, handler); +} + + static u_char * ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c, ngx_uint_t err) @@ -2756,6 +2799,7 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c) ngx_memcpy(log, h2c->connection->log, sizeof(ngx_log_t)); log->data = ctx; + log->action = "reading client request headers"; ngx_memzero(rev, sizeof(ngx_event_t)); @@ -3562,7 +3606,8 @@ ngx_int_t ngx_http_v2_read_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler) { - ngx_http_v2_stream_t *stream; + ngx_http_v2_stream_t *stream; + ngx_http_core_loc_conf_t *clcf; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http2 read request body"); @@ -3598,13 +3643,48 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r, r->request_body->post_handler = post_handler; - r->read_event_handler = ngx_http_test_reading; + r->read_event_handler = ngx_http_v2_read_client_request_body_handler; r->write_event_handler = ngx_http_request_empty_handler; + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + ngx_add_timer(r->connection->read, clcf->client_body_timeout); + return NGX_AGAIN; } +static void +ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r) +{ + ngx_connection_t *fc; + + fc = r->connection; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 read client request body handler"); + + if (fc->read->timedout) { + ngx_log_error(NGX_LOG_INFO, fc->log, NGX_ETIMEDOUT, "client timed out"); + + fc->timedout = 1; + r->stream->skip_data = NGX_HTTP_V2_DATA_DISCARD; + + ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT); + return; + } + + if (fc->error) { + ngx_log_error(NGX_LOG_INFO, fc->log, 0, + "client prematurely closed stream"); + + r->stream->skip_data = NGX_HTTP_V2_DATA_DISCARD; + + ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); + return; + } +} + + static ngx_int_t ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, ngx_http_v2_stream_t *stream, ngx_uint_t status) @@ -3633,6 +3713,7 @@ ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, void ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) { + ngx_pool_t *pool; ngx_event_t *ev; ngx_connection_t *fc; ngx_http_v2_node_t *node; @@ -3654,27 +3735,44 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) if (!stream->out_closed) { if (ngx_http_v2_send_rst_stream(h2c, node->id, - NGX_HTTP_V2_INTERNAL_ERROR) + fc->timedout ? NGX_HTTP_V2_PROTOCOL_ERROR + : NGX_HTTP_V2_INTERNAL_ERROR) != NGX_OK) { h2c->connection->error = 1; } } + if (h2c->state.stream == stream) { + h2c->state.stream = NULL; + } + node->stream = NULL; ngx_queue_insert_tail(&h2c->closed, &node->reuse); h2c->closed_nodes++; + /* + * This pool keeps decoded request headers which can be used by log phase + * handlers in ngx_http_free_request(). + * + * The pointer is stored into local variable because the stream object + * will be destroyed after a call to ngx_http_free_request(). + */ + pool = stream->pool; + ngx_http_free_request(stream->request, rc); - ev = fc->read; + if (pool != h2c->state.pool) { + ngx_destroy_pool(pool); - if (ev->active || ev->disabled) { - ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, - "fake read event was activated"); + } else { + /* pool will be destroyed when the complete header is parsed */ + h2c->state.keep_pool = 0; } + ev = fc->read; + if (ev->timer_set) { ngx_del_timer(ev); } @@ -3685,11 +3783,6 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) ev = fc->write; - if (ev->active || ev->disabled) { - ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, - "fake write event was activated"); - } - if (ev->timer_set) { ngx_del_timer(ev); } @@ -3723,9 +3816,18 @@ ngx_http_v2_close_stream_handler(ngx_event_t *ev) fc = ev->data; r = fc->data; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, "http2 close stream handler"); + if (ev->timedout) { + ngx_log_error(NGX_LOG_INFO, fc->log, NGX_ETIMEDOUT, "client timed out"); + + fc->timedout = 1; + + ngx_http_v2_close_stream(r->stream, NGX_HTTP_REQUEST_TIME_OUT); + return; + } + ngx_http_v2_close_stream(r->stream, 0); } @@ -3733,7 +3835,11 @@ ngx_http_v2_close_stream_handler(ngx_event_t *ev) static void ngx_http_v2_handle_connection_handler(ngx_event_t *rev) { - ngx_connection_t *c; + ngx_connection_t *c; + ngx_http_v2_connection_t *h2c; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "http2 handle connection handler"); rev->handler = ngx_http_v2_read_handler; @@ -3743,6 +3849,12 @@ ngx_http_v2_handle_connection_handler(ngx_event_t *rev) } c = rev->data; + h2c = c->data; + + if (h2c->last_out && ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) { + ngx_http_v2_finalize_connection(h2c, 0); + return; + } ngx_http_v2_handle_connection(c->data); } @@ -3821,7 +3933,6 @@ ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c, if (h2c->state.stream) { h2c->state.stream->out_closed = 1; - h2c->state.pool = NULL; ngx_http_v2_close_stream(h2c->state.stream, NGX_HTTP_BAD_REQUEST); } @@ -3865,9 +3976,7 @@ ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c, if (stream->queued) { stream->queued = 0; - ev = fc->write; - ev->delayed = 0; } else { ev = fc->read; @@ -3936,8 +4045,10 @@ ngx_http_v2_adjust_windows(ngx_http_v2_connection_t *h2c, ssize_t delta) wev = stream->request->connection->write; - if (!wev->timer_set) { - wev->delayed = 0; + wev->active = 0; + wev->ready = 1; + + if (!wev->delayed) { wev->handler(wev); } } diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 0f03922..5a791e6 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -73,6 +73,7 @@ typedef struct { unsigned flags:8; unsigned incomplete:1; + unsigned keep_pool:1; /* HPACK */ unsigned parse_name:1; @@ -186,6 +187,8 @@ struct ngx_http_v2_stream_s { size_t header_limit; + ngx_pool_t *pool; + unsigned handled:1; unsigned blocked:1; unsigned exhausted:1; @@ -274,6 +277,8 @@ ngx_int_t ngx_http_v2_table_size(ngx_http_v2_connection_t *h2c, size_t size); ngx_int_t ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, ngx_uint_t last, ngx_log_t *log); +size_t ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst, + ngx_uint_t lower); #define ngx_http_v2_prefix(bits) ((1 << (bits)) - 1) diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index ea58979..caa835d 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -25,6 +25,11 @@ #define ngx_http_v2_indexed(i) (128 + (i)) #define ngx_http_v2_inc_indexed(i) (64 + (i)) +#define ngx_http_v2_write_name(dst, src, len, tmp) \ + ngx_http_v2_string_encode(dst, src, len, tmp, 1) +#define ngx_http_v2_write_value(dst, src, len, tmp) \ + ngx_http_v2_string_encode(dst, src, len, tmp, 0) + #define NGX_HTTP_V2_ENCODE_RAW 0 #define NGX_HTTP_V2_ENCODE_HUFF 0x80 @@ -46,6 +51,8 @@ #define NGX_HTTP_V2_VARY_INDEX 59 +static u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, + u_char *tmp, ngx_uint_t lower); static u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, ngx_uint_t value); static ngx_http_v2_out_frame_t *ngx_http_v2_create_headers_frame( @@ -119,8 +126,8 @@ static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static ngx_int_t ngx_http_v2_header_filter(ngx_http_request_t *r) { - u_char status, *pos, *start, *p; - size_t len; + u_char status, *pos, *start, *p, *tmp; + size_t len, tmp_len; ngx_str_t host, location; ngx_uint_t i, port; ngx_list_part_t *part; @@ -136,6 +143,14 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) #endif u_char addr[NGX_SOCKADDR_STRLEN]; + static const u_char nginx[5] = "\x84\xaa\x63\x55\xe7"; +#if (NGX_HTTP_GZIP) + static const u_char accept_encoding[12] = + "\x8b\x84\x84\x2d\x69\x5b\x05\x44\x3c\x86\xaa\x6f"; +#endif + + static size_t nginx_ver_len = ngx_http_v2_literal_size(NGINX_VER); + static u_char nginx_ver[ngx_http_v2_literal_size(NGINX_VER)]; if (!r->stream) { return ngx_http_next_header_filter(r); @@ -215,8 +230,7 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->headers_out.server == NULL) { - len += 1 + (clcf->server_tokens ? ngx_http_v2_literal_size(NGINX_VER) - : ngx_http_v2_literal_size("nginx")); + len += 1 + (clcf->server_tokens ? nginx_ver_len : sizeof(nginx)); } if (r->headers_out.date == NULL) { @@ -340,10 +354,12 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) len += 1 + NGX_HTTP_V2_INT_OCTETS + r->headers_out.location->value.len; } + tmp_len = len; + #if (NGX_HTTP_GZIP) if (r->gzip_vary) { if (clcf->gzip_vary) { - len += 1 + ngx_http_v2_literal_size("Accept-Encoding"); + len += 1 + sizeof(accept_encoding); } else { r->gzip_vary = 0; @@ -371,14 +387,14 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) } if (header[i].key.len > NGX_HTTP_V2_MAX_FIELD) { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + ngx_log_error(NGX_LOG_CRIT, fc->log, 0, "too long response header name: \"%V\"", &header[i].key); return NGX_ERROR; } if (header[i].value.len > NGX_HTTP_V2_MAX_FIELD) { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + ngx_log_error(NGX_LOG_CRIT, fc->log, 0, "too long response header value: \"%V: %V\"", &header[i].key, &header[i].value); return NGX_ERROR; @@ -386,15 +402,29 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) len += 1 + NGX_HTTP_V2_INT_OCTETS + header[i].key.len + NGX_HTTP_V2_INT_OCTETS + header[i].value.len; + + if (header[i].key.len > tmp_len) { + tmp_len = header[i].key.len; + } + + if (header[i].value.len > tmp_len) { + tmp_len = header[i].value.len; + } } - pos = ngx_palloc(r->pool, len); - if (pos == NULL) { + tmp = ngx_palloc(r->pool, tmp_len); + pos = ngx_pnalloc(r->pool, len); + + if (pos == NULL || tmp == NULL) { return NGX_ERROR; } start = pos; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 output header: \":status: %03ui\"", + r->headers_out.status); + if (status) { *pos++ = status; @@ -405,24 +435,34 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) } if (r->headers_out.server == NULL) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 output header: \"server: %s\"", + clcf->server_tokens ? NGINX_VER : "nginx"); + *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_SERVER_INDEX); if (clcf->server_tokens) { - *pos++ = NGX_HTTP_V2_ENCODE_RAW | (sizeof(NGINX_VER) - 1); - pos = ngx_cpymem(pos, NGINX_VER, sizeof(NGINX_VER) - 1); + if (nginx_ver[0] == '\0') { + p = ngx_http_v2_write_value(nginx_ver, (u_char *) NGINX_VER, + sizeof(NGINX_VER) - 1, tmp); + nginx_ver_len = p - nginx_ver; + } + + pos = ngx_cpymem(pos, nginx_ver, nginx_ver_len); } else { - *pos++ = NGX_HTTP_V2_ENCODE_RAW | (sizeof("nginx") - 1); - pos = ngx_cpymem(pos, "nginx", sizeof("nginx") - 1); + pos = ngx_cpymem(pos, nginx, sizeof(nginx)); } } if (r->headers_out.date == NULL) { - *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_DATE_INDEX); - *pos++ = (u_char) ngx_cached_http_time.len; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 output header: \"date: %V\"", + &ngx_cached_http_time); - pos = ngx_cpymem(pos, ngx_cached_http_time.data, - ngx_cached_http_time.len); + *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_DATE_INDEX); + pos = ngx_http_v2_write_value(pos, ngx_cached_http_time.data, + ngx_cached_http_time.len, tmp); } if (r->headers_out.content_type.len) { @@ -431,39 +471,43 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) if (r->headers_out.content_type_len == r->headers_out.content_type.len && r->headers_out.charset.len) { - *pos = NGX_HTTP_V2_ENCODE_RAW; - pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(7), - r->headers_out.content_type.len - + sizeof("; charset=") - 1 - + r->headers_out.charset.len); + len = r->headers_out.content_type.len + sizeof("; charset=") - 1 + + r->headers_out.charset.len; - p = pos; + p = ngx_pnalloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } - pos = ngx_cpymem(pos, r->headers_out.content_type.data, - r->headers_out.content_type.len); + p = ngx_cpymem(p, r->headers_out.content_type.data, + r->headers_out.content_type.len); - pos = ngx_cpymem(pos, "; charset=", sizeof("; charset=") - 1); + p = ngx_cpymem(p, "; charset=", sizeof("; charset=") - 1); - pos = ngx_cpymem(pos, r->headers_out.charset.data, - r->headers_out.charset.len); + p = ngx_cpymem(p, r->headers_out.charset.data, + r->headers_out.charset.len); - /* update r->headers_out.content_type for possible logging */ + /* updated r->headers_out.content_type is also needed for logging */ - r->headers_out.content_type.len = pos - p; - r->headers_out.content_type.data = p; - - } else { - *pos = NGX_HTTP_V2_ENCODE_RAW; - pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(7), - r->headers_out.content_type.len); - pos = ngx_cpymem(pos, r->headers_out.content_type.data, - r->headers_out.content_type.len); + r->headers_out.content_type.len = len; + r->headers_out.content_type.data = p - len; } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 output header: \"content-type: %V\"", + &r->headers_out.content_type); + + pos = ngx_http_v2_write_value(pos, r->headers_out.content_type.data, + r->headers_out.content_type.len, tmp); } if (r->headers_out.content_length == NULL && r->headers_out.content_length_n >= 0) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 output header: \"content-length: %O\"", + r->headers_out.content_length_n); + *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_CONTENT_LENGTH_INDEX); p = pos; @@ -476,26 +520,37 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) { *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_LAST_MODIFIED_INDEX); - *pos++ = NGX_HTTP_V2_ENCODE_RAW - | (sizeof("Wed, 31 Dec 1986 18:00:00 GMT") - 1); - pos = ngx_http_time(pos, r->headers_out.last_modified_time); + ngx_http_time(pos, r->headers_out.last_modified_time); + len = sizeof("Wed, 31 Dec 1986 18:00:00 GMT") - 1; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 output header: \"last-modified: %*s\"", + len, pos); + + /* + * Date will always be encoded using huffman in the temporary buffer, + * so it's safe here to use src and dst pointing to the same address. + */ + pos = ngx_http_v2_write_value(pos, pos, len, tmp); } if (r->headers_out.location && r->headers_out.location->value.len) { - *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_LOCATION_INDEX); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 output header: \"location: %V\"", + &r->headers_out.location->value); - *pos = NGX_HTTP_V2_ENCODE_RAW; - pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(7), - r->headers_out.location->value.len); - pos = ngx_cpymem(pos, r->headers_out.location->value.data, - r->headers_out.location->value.len); + *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_LOCATION_INDEX); + pos = ngx_http_v2_write_value(pos, r->headers_out.location->value.data, + r->headers_out.location->value.len, tmp); } #if (NGX_HTTP_GZIP) if (r->gzip_vary) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 output header: \"vary: Accept-Encoding\""); + *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_VARY_INDEX); - *pos++ = NGX_HTTP_V2_ENCODE_RAW | (sizeof("Accept-Encoding") - 1); - pos = ngx_cpymem(pos, "Accept-Encoding", sizeof("Accept-Encoding") - 1); + pos = ngx_cpymem(pos, accept_encoding, sizeof(accept_encoding)); } #endif @@ -518,18 +573,23 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) continue; } +#if (NGX_DEBUG) + if (fc->log->log_level & NGX_LOG_DEBUG_HTTP) { + ngx_strlow(tmp, header[i].key.data, header[i].key.len); + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 output header: \"%*s: %V\"", + header[i].key.len, tmp, &header[i].value); + } +#endif + *pos++ = 0; - *pos = NGX_HTTP_V2_ENCODE_RAW; - pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(7), - header[i].key.len); - ngx_strlow(pos, header[i].key.data, header[i].key.len); - pos += header[i].key.len; + pos = ngx_http_v2_write_name(pos, header[i].key.data, + header[i].key.len, tmp); - *pos = NGX_HTTP_V2_ENCODE_RAW; - pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(7), - header[i].value.len); - pos = ngx_cpymem(pos, header[i].value.data, header[i].value.len); + pos = ngx_http_v2_write_value(pos, header[i].value.data, + header[i].value.len, tmp); } frame = ngx_http_v2_create_headers_frame(r, start, pos); @@ -556,6 +616,32 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) } +static u_char * +ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp, + ngx_uint_t lower) +{ + size_t hlen; + + hlen = ngx_http_v2_huff_encode(src, len, tmp, lower); + + if (hlen > 0) { + *dst = NGX_HTTP_V2_ENCODE_HUFF; + dst = ngx_http_v2_write_int(dst, ngx_http_v2_prefix(7), hlen); + return ngx_cpymem(dst, tmp, hlen); + } + + *dst = NGX_HTTP_V2_ENCODE_RAW; + dst = ngx_http_v2_write_int(dst, ngx_http_v2_prefix(7), len); + + if (lower) { + ngx_strlow(dst, src, len); + return dst + len; + } + + return ngx_cpymem(dst, src, len); +} + + static u_char * ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, ngx_uint_t value) { @@ -713,7 +799,9 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) if (in == NULL) { if (stream->queued) { - fc->write->delayed = 1; + fc->write->active = 1; + fc->write->ready = 0; + } else { fc->buffered &= ~NGX_HTTP_V2_BUFFERED; } @@ -724,7 +812,8 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) h2c = stream->connection; if (size && ngx_http_v2_flow_control(h2c, stream) == NGX_DECLINED) { - fc->write->delayed = 1; + fc->write->active = 1; + fc->write->ready = 0; return in; } @@ -861,7 +950,8 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) } if (in && ngx_http_v2_flow_control(h2c, stream) == NGX_DECLINED) { - fc->write->delayed = 1; + fc->write->active = 1; + fc->write->ready = 0; } return in; @@ -992,7 +1082,8 @@ ngx_http_v2_filter_send(ngx_connection_t *fc, ngx_http_v2_stream_t *stream) if (stream->queued) { fc->buffered |= NGX_HTTP_V2_BUFFERED; - fc->write->delayed = 1; + fc->write->active = 1; + fc->write->ready = 0; return NGX_AGAIN; } @@ -1230,14 +1321,7 @@ ngx_http_v2_handle_stream(ngx_http_v2_connection_t *h2c, wev = stream->request->connection->write; - /* - * This timer can only be set if the stream was delayed because of rate - * limit. In that case the event should be triggered by the timer. - */ - - if (!wev->timer_set) { - wev->delayed = 0; - + if (!wev->delayed) { stream->handled = 1; ngx_queue_insert_tail(&h2c->posted, &stream->queue); } diff --git a/src/http/v2/ngx_http_v2_huff_encode.c b/src/http/v2/ngx_http_v2_huff_encode.c index 6c412cf..3f822cd 100644 --- a/src/http/v2/ngx_http_v2_huff_encode.c +++ b/src/http/v2/ngx_http_v2_huff_encode.c @@ -2,9 +2,253 @@ /* * Copyright (C) Nginx, Inc. * Copyright (C) Valentin V. Bartenev + * Copyright (C) 2015 Vlad Krasnov */ #include #include #include + + +typedef struct { + uint32_t code; + uint32_t len; +} ngx_http_v2_huff_encode_code_t; + + +static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table[256] = +{ + {0x00001ff8, 13}, {0x007fffd8, 23}, {0x0fffffe2, 28}, {0x0fffffe3, 28}, + {0x0fffffe4, 28}, {0x0fffffe5, 28}, {0x0fffffe6, 28}, {0x0fffffe7, 28}, + {0x0fffffe8, 28}, {0x00ffffea, 24}, {0x3ffffffc, 30}, {0x0fffffe9, 28}, + {0x0fffffea, 28}, {0x3ffffffd, 30}, {0x0fffffeb, 28}, {0x0fffffec, 28}, + {0x0fffffed, 28}, {0x0fffffee, 28}, {0x0fffffef, 28}, {0x0ffffff0, 28}, + {0x0ffffff1, 28}, {0x0ffffff2, 28}, {0x3ffffffe, 30}, {0x0ffffff3, 28}, + {0x0ffffff4, 28}, {0x0ffffff5, 28}, {0x0ffffff6, 28}, {0x0ffffff7, 28}, + {0x0ffffff8, 28}, {0x0ffffff9, 28}, {0x0ffffffa, 28}, {0x0ffffffb, 28}, + {0x00000014, 6}, {0x000003f8, 10}, {0x000003f9, 10}, {0x00000ffa, 12}, + {0x00001ff9, 13}, {0x00000015, 6}, {0x000000f8, 8}, {0x000007fa, 11}, + {0x000003fa, 10}, {0x000003fb, 10}, {0x000000f9, 8}, {0x000007fb, 11}, + {0x000000fa, 8}, {0x00000016, 6}, {0x00000017, 6}, {0x00000018, 6}, + {0x00000000, 5}, {0x00000001, 5}, {0x00000002, 5}, {0x00000019, 6}, + {0x0000001a, 6}, {0x0000001b, 6}, {0x0000001c, 6}, {0x0000001d, 6}, + {0x0000001e, 6}, {0x0000001f, 6}, {0x0000005c, 7}, {0x000000fb, 8}, + {0x00007ffc, 15}, {0x00000020, 6}, {0x00000ffb, 12}, {0x000003fc, 10}, + {0x00001ffa, 13}, {0x00000021, 6}, {0x0000005d, 7}, {0x0000005e, 7}, + {0x0000005f, 7}, {0x00000060, 7}, {0x00000061, 7}, {0x00000062, 7}, + {0x00000063, 7}, {0x00000064, 7}, {0x00000065, 7}, {0x00000066, 7}, + {0x00000067, 7}, {0x00000068, 7}, {0x00000069, 7}, {0x0000006a, 7}, + {0x0000006b, 7}, {0x0000006c, 7}, {0x0000006d, 7}, {0x0000006e, 7}, + {0x0000006f, 7}, {0x00000070, 7}, {0x00000071, 7}, {0x00000072, 7}, + {0x000000fc, 8}, {0x00000073, 7}, {0x000000fd, 8}, {0x00001ffb, 13}, + {0x0007fff0, 19}, {0x00001ffc, 13}, {0x00003ffc, 14}, {0x00000022, 6}, + {0x00007ffd, 15}, {0x00000003, 5}, {0x00000023, 6}, {0x00000004, 5}, + {0x00000024, 6}, {0x00000005, 5}, {0x00000025, 6}, {0x00000026, 6}, + {0x00000027, 6}, {0x00000006, 5}, {0x00000074, 7}, {0x00000075, 7}, + {0x00000028, 6}, {0x00000029, 6}, {0x0000002a, 6}, {0x00000007, 5}, + {0x0000002b, 6}, {0x00000076, 7}, {0x0000002c, 6}, {0x00000008, 5}, + {0x00000009, 5}, {0x0000002d, 6}, {0x00000077, 7}, {0x00000078, 7}, + {0x00000079, 7}, {0x0000007a, 7}, {0x0000007b, 7}, {0x00007ffe, 15}, + {0x000007fc, 11}, {0x00003ffd, 14}, {0x00001ffd, 13}, {0x0ffffffc, 28}, + {0x000fffe6, 20}, {0x003fffd2, 22}, {0x000fffe7, 20}, {0x000fffe8, 20}, + {0x003fffd3, 22}, {0x003fffd4, 22}, {0x003fffd5, 22}, {0x007fffd9, 23}, + {0x003fffd6, 22}, {0x007fffda, 23}, {0x007fffdb, 23}, {0x007fffdc, 23}, + {0x007fffdd, 23}, {0x007fffde, 23}, {0x00ffffeb, 24}, {0x007fffdf, 23}, + {0x00ffffec, 24}, {0x00ffffed, 24}, {0x003fffd7, 22}, {0x007fffe0, 23}, + {0x00ffffee, 24}, {0x007fffe1, 23}, {0x007fffe2, 23}, {0x007fffe3, 23}, + {0x007fffe4, 23}, {0x001fffdc, 21}, {0x003fffd8, 22}, {0x007fffe5, 23}, + {0x003fffd9, 22}, {0x007fffe6, 23}, {0x007fffe7, 23}, {0x00ffffef, 24}, + {0x003fffda, 22}, {0x001fffdd, 21}, {0x000fffe9, 20}, {0x003fffdb, 22}, + {0x003fffdc, 22}, {0x007fffe8, 23}, {0x007fffe9, 23}, {0x001fffde, 21}, + {0x007fffea, 23}, {0x003fffdd, 22}, {0x003fffde, 22}, {0x00fffff0, 24}, + {0x001fffdf, 21}, {0x003fffdf, 22}, {0x007fffeb, 23}, {0x007fffec, 23}, + {0x001fffe0, 21}, {0x001fffe1, 21}, {0x003fffe0, 22}, {0x001fffe2, 21}, + {0x007fffed, 23}, {0x003fffe1, 22}, {0x007fffee, 23}, {0x007fffef, 23}, + {0x000fffea, 20}, {0x003fffe2, 22}, {0x003fffe3, 22}, {0x003fffe4, 22}, + {0x007ffff0, 23}, {0x003fffe5, 22}, {0x003fffe6, 22}, {0x007ffff1, 23}, + {0x03ffffe0, 26}, {0x03ffffe1, 26}, {0x000fffeb, 20}, {0x0007fff1, 19}, + {0x003fffe7, 22}, {0x007ffff2, 23}, {0x003fffe8, 22}, {0x01ffffec, 25}, + {0x03ffffe2, 26}, {0x03ffffe3, 26}, {0x03ffffe4, 26}, {0x07ffffde, 27}, + {0x07ffffdf, 27}, {0x03ffffe5, 26}, {0x00fffff1, 24}, {0x01ffffed, 25}, + {0x0007fff2, 19}, {0x001fffe3, 21}, {0x03ffffe6, 26}, {0x07ffffe0, 27}, + {0x07ffffe1, 27}, {0x03ffffe7, 26}, {0x07ffffe2, 27}, {0x00fffff2, 24}, + {0x001fffe4, 21}, {0x001fffe5, 21}, {0x03ffffe8, 26}, {0x03ffffe9, 26}, + {0x0ffffffd, 28}, {0x07ffffe3, 27}, {0x07ffffe4, 27}, {0x07ffffe5, 27}, + {0x000fffec, 20}, {0x00fffff3, 24}, {0x000fffed, 20}, {0x001fffe6, 21}, + {0x003fffe9, 22}, {0x001fffe7, 21}, {0x001fffe8, 21}, {0x007ffff3, 23}, + {0x003fffea, 22}, {0x003fffeb, 22}, {0x01ffffee, 25}, {0x01ffffef, 25}, + {0x00fffff4, 24}, {0x00fffff5, 24}, {0x03ffffea, 26}, {0x007ffff4, 23}, + {0x03ffffeb, 26}, {0x07ffffe6, 27}, {0x03ffffec, 26}, {0x03ffffed, 26}, + {0x07ffffe7, 27}, {0x07ffffe8, 27}, {0x07ffffe9, 27}, {0x07ffffea, 27}, + {0x07ffffeb, 27}, {0x0ffffffe, 28}, {0x07ffffec, 27}, {0x07ffffed, 27}, + {0x07ffffee, 27}, {0x07ffffef, 27}, {0x07fffff0, 27}, {0x03ffffee, 26} +}; + + +/* same as above, but embeds lowercase transformation */ +static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table_lc[256] = +{ + {0x00001ff8, 13}, {0x007fffd8, 23}, {0x0fffffe2, 28}, {0x0fffffe3, 28}, + {0x0fffffe4, 28}, {0x0fffffe5, 28}, {0x0fffffe6, 28}, {0x0fffffe7, 28}, + {0x0fffffe8, 28}, {0x00ffffea, 24}, {0x3ffffffc, 30}, {0x0fffffe9, 28}, + {0x0fffffea, 28}, {0x3ffffffd, 30}, {0x0fffffeb, 28}, {0x0fffffec, 28}, + {0x0fffffed, 28}, {0x0fffffee, 28}, {0x0fffffef, 28}, {0x0ffffff0, 28}, + {0x0ffffff1, 28}, {0x0ffffff2, 28}, {0x3ffffffe, 30}, {0x0ffffff3, 28}, + {0x0ffffff4, 28}, {0x0ffffff5, 28}, {0x0ffffff6, 28}, {0x0ffffff7, 28}, + {0x0ffffff8, 28}, {0x0ffffff9, 28}, {0x0ffffffa, 28}, {0x0ffffffb, 28}, + {0x00000014, 6}, {0x000003f8, 10}, {0x000003f9, 10}, {0x00000ffa, 12}, + {0x00001ff9, 13}, {0x00000015, 6}, {0x000000f8, 8}, {0x000007fa, 11}, + {0x000003fa, 10}, {0x000003fb, 10}, {0x000000f9, 8}, {0x000007fb, 11}, + {0x000000fa, 8}, {0x00000016, 6}, {0x00000017, 6}, {0x00000018, 6}, + {0x00000000, 5}, {0x00000001, 5}, {0x00000002, 5}, {0x00000019, 6}, + {0x0000001a, 6}, {0x0000001b, 6}, {0x0000001c, 6}, {0x0000001d, 6}, + {0x0000001e, 6}, {0x0000001f, 6}, {0x0000005c, 7}, {0x000000fb, 8}, + {0x00007ffc, 15}, {0x00000020, 6}, {0x00000ffb, 12}, {0x000003fc, 10}, + {0x00001ffa, 13}, {0x00000003, 5}, {0x00000023, 6}, {0x00000004, 5}, + {0x00000024, 6}, {0x00000005, 5}, {0x00000025, 6}, {0x00000026, 6}, + {0x00000027, 6}, {0x00000006, 5}, {0x00000074, 7}, {0x00000075, 7}, + {0x00000028, 6}, {0x00000029, 6}, {0x0000002a, 6}, {0x00000007, 5}, + {0x0000002b, 6}, {0x00000076, 7}, {0x0000002c, 6}, {0x00000008, 5}, + {0x00000009, 5}, {0x0000002d, 6}, {0x00000077, 7}, {0x00000078, 7}, + {0x00000079, 7}, {0x0000007a, 7}, {0x0000007b, 7}, {0x00001ffb, 13}, + {0x0007fff0, 19}, {0x00001ffc, 13}, {0x00003ffc, 14}, {0x00000022, 6}, + {0x00007ffd, 15}, {0x00000003, 5}, {0x00000023, 6}, {0x00000004, 5}, + {0x00000024, 6}, {0x00000005, 5}, {0x00000025, 6}, {0x00000026, 6}, + {0x00000027, 6}, {0x00000006, 5}, {0x00000074, 7}, {0x00000075, 7}, + {0x00000028, 6}, {0x00000029, 6}, {0x0000002a, 6}, {0x00000007, 5}, + {0x0000002b, 6}, {0x00000076, 7}, {0x0000002c, 6}, {0x00000008, 5}, + {0x00000009, 5}, {0x0000002d, 6}, {0x00000077, 7}, {0x00000078, 7}, + {0x00000079, 7}, {0x0000007a, 7}, {0x0000007b, 7}, {0x00007ffe, 15}, + {0x000007fc, 11}, {0x00003ffd, 14}, {0x00001ffd, 13}, {0x0ffffffc, 28}, + {0x000fffe6, 20}, {0x003fffd2, 22}, {0x000fffe7, 20}, {0x000fffe8, 20}, + {0x003fffd3, 22}, {0x003fffd4, 22}, {0x003fffd5, 22}, {0x007fffd9, 23}, + {0x003fffd6, 22}, {0x007fffda, 23}, {0x007fffdb, 23}, {0x007fffdc, 23}, + {0x007fffdd, 23}, {0x007fffde, 23}, {0x00ffffeb, 24}, {0x007fffdf, 23}, + {0x00ffffec, 24}, {0x00ffffed, 24}, {0x003fffd7, 22}, {0x007fffe0, 23}, + {0x00ffffee, 24}, {0x007fffe1, 23}, {0x007fffe2, 23}, {0x007fffe3, 23}, + {0x007fffe4, 23}, {0x001fffdc, 21}, {0x003fffd8, 22}, {0x007fffe5, 23}, + {0x003fffd9, 22}, {0x007fffe6, 23}, {0x007fffe7, 23}, {0x00ffffef, 24}, + {0x003fffda, 22}, {0x001fffdd, 21}, {0x000fffe9, 20}, {0x003fffdb, 22}, + {0x003fffdc, 22}, {0x007fffe8, 23}, {0x007fffe9, 23}, {0x001fffde, 21}, + {0x007fffea, 23}, {0x003fffdd, 22}, {0x003fffde, 22}, {0x00fffff0, 24}, + {0x001fffdf, 21}, {0x003fffdf, 22}, {0x007fffeb, 23}, {0x007fffec, 23}, + {0x001fffe0, 21}, {0x001fffe1, 21}, {0x003fffe0, 22}, {0x001fffe2, 21}, + {0x007fffed, 23}, {0x003fffe1, 22}, {0x007fffee, 23}, {0x007fffef, 23}, + {0x000fffea, 20}, {0x003fffe2, 22}, {0x003fffe3, 22}, {0x003fffe4, 22}, + {0x007ffff0, 23}, {0x003fffe5, 22}, {0x003fffe6, 22}, {0x007ffff1, 23}, + {0x03ffffe0, 26}, {0x03ffffe1, 26}, {0x000fffeb, 20}, {0x0007fff1, 19}, + {0x003fffe7, 22}, {0x007ffff2, 23}, {0x003fffe8, 22}, {0x01ffffec, 25}, + {0x03ffffe2, 26}, {0x03ffffe3, 26}, {0x03ffffe4, 26}, {0x07ffffde, 27}, + {0x07ffffdf, 27}, {0x03ffffe5, 26}, {0x00fffff1, 24}, {0x01ffffed, 25}, + {0x0007fff2, 19}, {0x001fffe3, 21}, {0x03ffffe6, 26}, {0x07ffffe0, 27}, + {0x07ffffe1, 27}, {0x03ffffe7, 26}, {0x07ffffe2, 27}, {0x00fffff2, 24}, + {0x001fffe4, 21}, {0x001fffe5, 21}, {0x03ffffe8, 26}, {0x03ffffe9, 26}, + {0x0ffffffd, 28}, {0x07ffffe3, 27}, {0x07ffffe4, 27}, {0x07ffffe5, 27}, + {0x000fffec, 20}, {0x00fffff3, 24}, {0x000fffed, 20}, {0x001fffe6, 21}, + {0x003fffe9, 22}, {0x001fffe7, 21}, {0x001fffe8, 21}, {0x007ffff3, 23}, + {0x003fffea, 22}, {0x003fffeb, 22}, {0x01ffffee, 25}, {0x01ffffef, 25}, + {0x00fffff4, 24}, {0x00fffff5, 24}, {0x03ffffea, 26}, {0x007ffff4, 23}, + {0x03ffffeb, 26}, {0x07ffffe6, 27}, {0x03ffffec, 26}, {0x03ffffed, 26}, + {0x07ffffe7, 27}, {0x07ffffe8, 27}, {0x07ffffe9, 27}, {0x07ffffea, 27}, + {0x07ffffeb, 27}, {0x0ffffffe, 28}, {0x07ffffec, 27}, {0x07ffffed, 27}, + {0x07ffffee, 27}, {0x07ffffef, 27}, {0x07fffff0, 27}, {0x03ffffee, 26} +}; + + +#if (NGX_PTR_SIZE == 8) + +#if (NGX_HAVE_LITTLE_ENDIAN) + +#if (NGX_HAVE_GCC_BSWAP64) +#define ngx_http_v2_huff_encode_buf(dst, buf) \ + (*(uint64_t *) (dst) = __builtin_bswap64(buf)) +#else +#define ngx_http_v2_huff_encode_buf(dst, buf) \ + ((dst)[0] = (u_char) ((buf) >> 56), \ + (dst)[1] = (u_char) ((buf) >> 48), \ + (dst)[2] = (u_char) ((buf) >> 40), \ + (dst)[3] = (u_char) ((buf) >> 32), \ + (dst)[4] = (u_char) ((buf) >> 24), \ + (dst)[5] = (u_char) ((buf) >> 16), \ + (dst)[6] = (u_char) ((buf) >> 8), \ + (dst)[7] = (u_char) (buf)) +#endif + +#else /* !NGX_HAVE_LITTLE_ENDIAN */ +#define ngx_http_v2_huff_encode_buf(dst, buf) \ + (*(uint64_t *) (dst) = (buf)) +#endif + +#else /* NGX_PTR_SIZE == 4 */ + +#define ngx_http_v2_huff_encode_buf(dst, buf) \ + (*(uint32_t *) (dst) = htonl(buf)) + +#endif + + +size_t +ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst, ngx_uint_t lower) +{ + u_char *end; + size_t hlen; + ngx_uint_t buf, pending, code; + ngx_http_v2_huff_encode_code_t *table, *next; + + table = lower ? ngx_http_v2_huff_encode_table_lc + : ngx_http_v2_huff_encode_table; + hlen = 0; + buf = 0; + pending = 0; + + end = src + len; + + while (src != end) { + next = &table[*src++]; + + code = next->code; + pending += next->len; + + /* accumulate bits */ + if (pending < sizeof(buf) * 8) { + buf |= code << (sizeof(buf) * 8 - pending); + continue; + } + + if (hlen + sizeof(buf) >= len) { + return 0; + } + + pending -= sizeof(buf) * 8; + + buf |= code >> pending; + + ngx_http_v2_huff_encode_buf(&dst[hlen], buf); + + hlen += sizeof(buf); + + buf = pending ? code << (sizeof(buf) * 8 - pending) : 0; + } + + if (pending == 0) { + return hlen; + } + + buf |= (ngx_uint_t) -1 >> pending; + + pending = ngx_align(pending, 8); + + if (hlen + pending / 8 >= len) { + return 0; + } + + buf >>= sizeof(buf) * 8 - pending; + + do { + pending -= 8; + dst[hlen++] = (u_char) (buf >> pending); + } while (pending); + + return hlen; +} diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c index 7c6bf7a..9be6376 100644 --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -784,9 +784,9 @@ static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker) { sigset_t set; - uint64_t cpu_affinity; ngx_int_t n; ngx_uint_t i; + ngx_cpuset_t *cpu_affinity; struct rlimit rlmt; ngx_core_conf_t *ccf; ngx_listening_t *ls; diff --git a/src/os/unix/ngx_setaffinity.c b/src/os/unix/ngx_setaffinity.c index 8f6cf35..34ec390 100644 --- a/src/os/unix/ngx_setaffinity.c +++ b/src/os/unix/ngx_setaffinity.c @@ -10,29 +10,20 @@ #if (NGX_HAVE_CPUSET_SETAFFINITY) -#include - void -ngx_setaffinity(uint64_t cpu_affinity, ngx_log_t *log) +ngx_setaffinity(ngx_cpuset_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); + for (i = 0; i < CPU_SETSIZE; i++) { + if (CPU_ISSET(i, cpu_affinity)) { + ngx_log_error(NGX_LOG_NOTICE, log, 0, + "cpuset_setaffinity(): using cpu #%ui", i); } - i++; - cpu_affinity >>= 1; - } while (cpu_affinity); + } if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, - sizeof(cpuset_t), &mask) == -1) + sizeof(cpuset_t), cpu_affinity) == -1) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "cpuset_setaffinity() failed"); @@ -42,25 +33,18 @@ ngx_setaffinity(uint64_t cpu_affinity, ngx_log_t *log) #elif (NGX_HAVE_SCHED_SETAFFINITY) void -ngx_setaffinity(uint64_t cpu_affinity, ngx_log_t *log) +ngx_setaffinity(ngx_cpuset_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); + for (i = 0; i < CPU_SETSIZE; i++) { + if (CPU_ISSET(i, cpu_affinity)) { + ngx_log_error(NGX_LOG_NOTICE, log, 0, + "sched_setaffinity(): using cpu #%ui", i); } - i++; - cpu_affinity >>= 1; - } while (cpu_affinity); + } - if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) == -1) { + if (sched_setaffinity(0, sizeof(cpu_set_t), cpu_affinity) == -1) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "sched_setaffinity() failed"); } diff --git a/src/os/unix/ngx_setaffinity.h b/src/os/unix/ngx_setaffinity.h index 33f5835..a4139ed 100644 --- a/src/os/unix/ngx_setaffinity.h +++ b/src/os/unix/ngx_setaffinity.h @@ -11,12 +11,26 @@ #define NGX_HAVE_CPU_AFFINITY 1 -void ngx_setaffinity(uint64_t cpu_affinity, ngx_log_t *log); +#if (NGX_HAVE_SCHED_SETAFFINITY) + +typedef cpu_set_t ngx_cpuset_t; + +#elif (NGX_HAVE_CPUSET_SETAFFINITY) + +#include + +typedef cpuset_t ngx_cpuset_t; + +#endif + +void ngx_setaffinity(ngx_cpuset_t *cpu_affinity, ngx_log_t *log); #else #define ngx_setaffinity(cpu_affinity, log) +typedef uint64_t ngx_cpuset_t; + #endif diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 6800500..b969fea 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -10,9 +10,6 @@ #include -typedef void (*ngx_stream_proxy_handler_pt)(ngx_stream_session_t *s); - - typedef struct { ngx_msec_t connect_timeout; ngx_msec_t timeout; @@ -435,8 +432,6 @@ ngx_stream_proxy_connect(ngx_stream_session_t *s) ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "proxy connect: %i", rc); - pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); - if (rc == NGX_ERROR) { ngx_stream_proxy_finalize(s, NGX_ERROR); return; @@ -471,6 +466,8 @@ ngx_stream_proxy_connect(ngx_stream_session_t *s) pc->read->handler = ngx_stream_proxy_connect_handler; pc->write->handler = ngx_stream_proxy_connect_handler; + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + ngx_add_timer(pc->write, pscf->connect_timeout); } From 3072f74f2dc5a1dc18dc5f7f288f9613800f3780 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 30 Mar 2016 11:27:04 +0300 Subject: [PATCH 093/651] Imported Upstream version 1.9.13 --- CHANGES | 47 + CHANGES.ru | 50 + auto/init | 1 - auto/install | 63 +- auto/lib/conf | 2 +- auto/lib/make | 2 +- auto/lib/perl/conf | 7 +- auto/lib/perl/make | 5 +- auto/make | 45 +- auto/module | 4 +- auto/modules | 6 +- auto/options | 6 +- auto/sources | 1 + auto/unix | 39 + src/core/nginx.c | 4 +- src/core/nginx.h | 4 +- src/core/ngx_connection.c | 108 +- src/core/ngx_connection.h | 4 + src/core/ngx_cycle.c | 4 + src/core/ngx_file.c | 13 +- src/core/ngx_file.h | 2 + src/core/ngx_inet.c | 6 +- src/core/ngx_module.c | 3 +- src/core/ngx_module.h | 2 +- src/core/ngx_output_chain.c | 12 +- src/core/ngx_palloc.c | 88 +- src/core/ngx_resolver.c | 1024 ++++++++++++++++- src/core/ngx_resolver.h | 48 +- src/event/modules/ngx_devpoll_module.c | 4 +- src/event/modules/ngx_epoll_module.c | 3 + src/event/modules/ngx_eventport_module.c | 2 +- src/event/ngx_event.c | 6 +- src/event/ngx_event.h | 9 +- src/event/ngx_event_accept.c | 443 ++++++- src/event/ngx_event_connect.c | 41 +- src/event/ngx_event_connect.h | 1 + src/event/ngx_event_pipe.c | 98 +- src/event/ngx_event_pipe.h | 10 + src/http/modules/ngx_http_fastcgi_module.c | 1 + src/http/modules/ngx_http_proxy_module.c | 1 + src/http/modules/ngx_http_scgi_module.c | 1 + src/http/modules/ngx_http_sub_filter_module.c | 8 +- src/http/modules/ngx_http_uwsgi_module.c | 1 + src/http/ngx_http_cache.h | 4 + src/http/ngx_http_copy_filter_module.c | 16 +- src/http/ngx_http_core_module.c | 9 + src/http/ngx_http_core_module.h | 1 + src/http/ngx_http_file_cache.c | 48 +- src/http/ngx_http_request_body.c | 109 +- src/http/ngx_http_upstream.c | 230 +++- src/http/ngx_http_upstream.h | 3 +- src/http/v2/ngx_http_v2.c | 15 +- src/os/unix/ngx_darwin_init.c | 1 + src/os/unix/ngx_errno.h | 1 + src/os/unix/ngx_files.c | 284 +++-- src/os/unix/ngx_files.h | 6 +- src/os/unix/ngx_freebsd_init.c | 1 + src/os/unix/ngx_freebsd_sendfile_chain.c | 13 + src/os/unix/ngx_linux_init.c | 1 + src/os/unix/ngx_linux_sendfile_chain.c | 65 +- src/os/unix/ngx_os.h | 2 + src/os/unix/ngx_posix_config.h | 2 +- src/os/unix/ngx_posix_init.c | 1 + src/os/unix/ngx_solaris_init.c | 1 + src/os/unix/ngx_solaris_sendfilev_chain.c | 23 + src/os/unix/ngx_udp_send.c | 56 + src/stream/ngx_stream.c | 9 +- src/stream/ngx_stream.h | 2 + src/stream/ngx_stream_core_module.c | 30 +- src/stream/ngx_stream_handler.c | 15 +- src/stream/ngx_stream_proxy_module.c | 167 ++- src/stream/ngx_stream_upstream.c | 2 +- src/stream/ngx_stream_upstream.h | 1 + 73 files changed, 2809 insertions(+), 538 deletions(-) create mode 100644 src/os/unix/ngx_udp_send.c diff --git a/CHANGES b/CHANGES index e94e14f..0ac9c61 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,51 @@ +Changes with nginx 1.9.13 29 Mar 2016 + + *) Change: non-idempotent requests (POST, LOCK, PATCH) are no longer + passed to the next server by default if a request has been sent to a + backend; the "non_idempotent" parameter of the "proxy_next_upstream" + directive explicitly allows retrying such requests. + + *) Feature: the ngx_http_perl_module can be built dynamically. + + *) Feature: UDP support in the stream module. + + *) Feature: the "aio_write" directive. + + *) Feature: now cache manager monitors number of elements in caches and + tries to avoid cache keys zone overflows. + + *) Bugfix: "task already active" and "second aio post" alerts might + appear in logs when using the "sendfile" and "aio" directives with + subrequests. + + *) Bugfix: "zero size buf in output" alerts might appear in logs if + caching was used and a client closed a connection prematurely. + + *) Bugfix: connections with clients might be closed needlessly if + caching was used. + Thanks to Justin Li. + + *) Bugfix: nginx might hog CPU if the "sendfile" directive was used on + Linux or Solaris and a file being sent was changed during sending. + + *) Bugfix: connections might hang when using the "sendfile" and "aio + threads" directives. + + *) Bugfix: in the "proxy_pass", "fastcgi_pass", "scgi_pass", and + "uwsgi_pass" directives when using variables. + Thanks to Piotr Sikora. + + *) Bugfix: in the ngx_http_sub_filter_module. + + *) Bugfix: if an error occurred in a cached backend connection, the + request was passed to the next server regardless of the + proxy_next_upstream directive. + + *) Bugfix: "CreateFile() failed" errors when creating temporary files on + Windows. + + Changes with nginx 1.9.12 24 Feb 2016 *) Feature: Huffman encoding of response headers in HTTP/2. diff --git a/CHANGES.ru b/CHANGES.ru index c11c477..7c92f7b 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,54 @@ +Изменения в nginx 1.9.13 29.03.2016 + + *) Изменение: неидемпотентные запросы (POST, LOCK, PATCH) теперь по + умолчанию не передаются на другой сервер, если запрос уже был + отправлен на бэкенд; параметр non_idempotent директивы + proxy_next_upstream явно разрешает повторять такие запросы. + + *) Добавление: модуль ngx_http_perl_module теперь можно собрать + динамически. + + *) Добавление: поддержка UDP в модуле stream. + + *) Добавление: директива aio_write. + + *) Добавление: теперь cache manager следит за количеством элементов в + кэше и старается не допускать переполнений зоны разделяемой памяти. + + *) Исправление: при использовании директив sendfile и aio с подзапросами + в логах могли появляться сообщения "task already active" и "second + aio post". + + *) Исправление: при использовании кэширования в логах могли появляться + сообщения "zero size buf in output", если клиент закрывал соединение + преждевременно. + + *) Исправление: при использовании кэширования соединения с клиентами + могли закрываться без необходимости. + Спасибо Justin Li. + + *) Исправление: nginx мог нагружать процессор при использовании + директивы sendfile на Linux и Solaris, если отправляемый файл был + изменён в процессе отправки. + + *) Исправление: при использовании директив sendfile и "aio threads" + соединения могли зависать. + + *) Исправление: в директивах proxy_pass, fastcgi_pass, scgi_pass и + uwsgi_pass при использовании переменных. + Спасибо Piotr Sikora. + + *) Исправление: в модуле ngx_http_sub_filter_module. + + *) Исправление: если в закэшированном соединении к бэкенду происходила + ошибка, запрос передавался на другой сервер без учёта директивы + proxy_next_upstream. + + *) Исправление: ошибки "CreateFile() failed" при создании временных + файлов на Windows. + + Изменения в nginx 1.9.12 24.02.2016 *) Добавление: кодирование Хаффмана заголовков ответов в HTTP/2. diff --git a/auto/init b/auto/init index c593eda..910f529 100644 --- a/auto/init +++ b/auto/init @@ -5,7 +5,6 @@ NGX_MAKEFILE=$NGX_OBJS/Makefile NGX_MODULES_C=$NGX_OBJS/ngx_modules.c -NGX_MODULES= NGX_AUTO_HEADERS_H=$NGX_OBJS/ngx_auto_headers.h NGX_AUTO_CONFIG_H=$NGX_OBJS/ngx_auto_config.h diff --git a/auto/install b/auto/install index 9469a49..d884487 100644 --- a/auto/install +++ b/auto/install @@ -3,7 +3,7 @@ # Copyright (C) Nginx, Inc. -if [ $USE_PERL = YES ]; then +if [ $USE_PERL != NO ]; then cat << END >> $NGX_MAKEFILE @@ -107,54 +107,54 @@ $NGX_OBJS/nginx.8: $NGX_MAN $NGX_AUTO_CONFIG_H install: build $NGX_INSTALL_PERL_MODULES test -d '\$(DESTDIR)$NGX_PREFIX' || mkdir -p '\$(DESTDIR)$NGX_PREFIX' - test -d '\$(DESTDIR)`dirname "$NGX_SBIN_PATH"`' \ + test -d '\$(DESTDIR)`dirname "$NGX_SBIN_PATH"`' \\ || mkdir -p '\$(DESTDIR)`dirname "$NGX_SBIN_PATH"`' - test ! -f '\$(DESTDIR)$NGX_SBIN_PATH' \ - || mv '\$(DESTDIR)$NGX_SBIN_PATH' \ + test ! -f '\$(DESTDIR)$NGX_SBIN_PATH' \\ + || mv '\$(DESTDIR)$NGX_SBIN_PATH' \\ '\$(DESTDIR)$NGX_SBIN_PATH.old' cp $NGX_OBJS/nginx '\$(DESTDIR)$NGX_SBIN_PATH' - test -d '\$(DESTDIR)$NGX_CONF_PREFIX' \ + test -d '\$(DESTDIR)$NGX_CONF_PREFIX' \\ || mkdir -p '\$(DESTDIR)$NGX_CONF_PREFIX' cp conf/koi-win '\$(DESTDIR)$NGX_CONF_PREFIX' cp conf/koi-utf '\$(DESTDIR)$NGX_CONF_PREFIX' cp conf/win-utf '\$(DESTDIR)$NGX_CONF_PREFIX' - test -f '\$(DESTDIR)$NGX_CONF_PREFIX/mime.types' \ + test -f '\$(DESTDIR)$NGX_CONF_PREFIX/mime.types' \\ || cp conf/mime.types '\$(DESTDIR)$NGX_CONF_PREFIX' cp conf/mime.types '\$(DESTDIR)$NGX_CONF_PREFIX/mime.types.default' - test -f '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi_params' \ + test -f '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi_params' \\ || cp conf/fastcgi_params '\$(DESTDIR)$NGX_CONF_PREFIX' - cp conf/fastcgi_params \ + cp conf/fastcgi_params \\ '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi_params.default' - test -f '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi.conf' \ + test -f '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi.conf' \\ || cp conf/fastcgi.conf '\$(DESTDIR)$NGX_CONF_PREFIX' cp conf/fastcgi.conf '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi.conf.default' - test -f '\$(DESTDIR)$NGX_CONF_PREFIX/uwsgi_params' \ + test -f '\$(DESTDIR)$NGX_CONF_PREFIX/uwsgi_params' \\ || cp conf/uwsgi_params '\$(DESTDIR)$NGX_CONF_PREFIX' - cp conf/uwsgi_params \ + cp conf/uwsgi_params \\ '\$(DESTDIR)$NGX_CONF_PREFIX/uwsgi_params.default' - test -f '\$(DESTDIR)$NGX_CONF_PREFIX/scgi_params' \ + test -f '\$(DESTDIR)$NGX_CONF_PREFIX/scgi_params' \\ || cp conf/scgi_params '\$(DESTDIR)$NGX_CONF_PREFIX' - cp conf/scgi_params \ + cp conf/scgi_params \\ '\$(DESTDIR)$NGX_CONF_PREFIX/scgi_params.default' - test -f '\$(DESTDIR)$NGX_CONF_PATH' \ + test -f '\$(DESTDIR)$NGX_CONF_PATH' \\ || cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PATH' cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PREFIX/nginx.conf.default' - test -d '\$(DESTDIR)`dirname "$NGX_PID_PATH"`' \ + test -d '\$(DESTDIR)`dirname "$NGX_PID_PATH"`' \\ || mkdir -p '\$(DESTDIR)`dirname "$NGX_PID_PATH"`' - test -d '\$(DESTDIR)`dirname "$NGX_HTTP_LOG_PATH"`' || \ - mkdir -p '\$(DESTDIR)`dirname "$NGX_HTTP_LOG_PATH"`' + test -d '\$(DESTDIR)`dirname "$NGX_HTTP_LOG_PATH"`' \\ + || mkdir -p '\$(DESTDIR)`dirname "$NGX_HTTP_LOG_PATH"`' - test -d '\$(DESTDIR)$NGX_PREFIX/html' \ + test -d '\$(DESTDIR)$NGX_PREFIX/html' \\ || cp -R $NGX_HTML '\$(DESTDIR)$NGX_PREFIX' END @@ -162,24 +162,38 @@ END if test -n "$NGX_ERROR_LOG_PATH"; then cat << END >> $NGX_MAKEFILE - test -d '\$(DESTDIR)`dirname "$NGX_ERROR_LOG_PATH"`' || \ - mkdir -p '\$(DESTDIR)`dirname "$NGX_ERROR_LOG_PATH"`' + test -d '\$(DESTDIR)`dirname "$NGX_ERROR_LOG_PATH"`' \\ + || mkdir -p '\$(DESTDIR)`dirname "$NGX_ERROR_LOG_PATH"`' END fi -if test -n "$NGX_MODULES"; then +if test -n "$DYNAMIC_MODULES"; then cat << END >> $NGX_MAKEFILE - test -d '\$(DESTDIR)$NGX_MODULES_PATH' \ + test -d '\$(DESTDIR)$NGX_MODULES_PATH' \\ || mkdir -p '\$(DESTDIR)$NGX_MODULES_PATH' - cp $NGX_MODULES '\$(DESTDIR)$NGX_MODULES_PATH' END fi +for ngx_module in $DYNAMIC_MODULES +do + ngx_module=$ngx_module$ngx_modext + + cat << END >> $NGX_MAKEFILE + + test ! -f '\$(DESTDIR)$NGX_MODULES_PATH/$ngx_module' \\ + || mv '\$(DESTDIR)$NGX_MODULES_PATH/$ngx_module' \\ + '\$(DESTDIR)$NGX_MODULES_PATH/$ngx_module.old' + cp $NGX_OBJS/$ngx_module '\$(DESTDIR)$NGX_MODULES_PATH/$ngx_module' +END + +done + + # create Makefile cat << END >> Makefile @@ -190,6 +204,9 @@ build: install: \$(MAKE) -f $NGX_MAKEFILE install +modules: + \$(MAKE) -f $NGX_MAKEFILE modules + upgrade: $NGX_SBIN_PATH -t diff --git a/auto/lib/conf b/auto/lib/conf index 6aaa43a..a6242e7 100644 --- a/auto/lib/conf +++ b/auto/lib/conf @@ -66,7 +66,7 @@ if [ $USE_LIBGD != NO ]; then . auto/lib/libgd/conf fi -if [ $USE_PERL = YES ]; then +if [ $USE_PERL != NO ]; then . auto/lib/perl/conf fi diff --git a/auto/lib/make b/auto/lib/make index 58a84a3..6298b94 100644 --- a/auto/lib/make +++ b/auto/lib/make @@ -27,6 +27,6 @@ if [ $NGX_LIBATOMIC != NO -a $NGX_LIBATOMIC != YES ]; then . auto/lib/libatomic/make fi -if [ $USE_PERL = YES ]; then +if [ $USE_PERL != NO ]; then . auto/lib/perl/make fi diff --git a/auto/lib/perl/conf b/auto/lib/perl/conf index 4d1bcf1..f5f5d3e 100644 --- a/auto/lib/perl/conf +++ b/auto/lib/perl/conf @@ -60,8 +60,11 @@ if test -n "$NGX_PERL_VER"; then | sed -e 's/-arch i386//' -e 's/-arch x86_64//'` fi - CORE_LINK="$CORE_LINK $ngx_perl_ldopts" - LINK_DEPS="$LINK_DEPS $NGX_OBJS/$ngx_perl_module" + if [ $USE_PERL = YES ]; then + CORE_LINK="$CORE_LINK $ngx_perl_ldopts" + fi + + NGX_LIB_PERL="$ngx_perl_ldopts" if test -n "$NGX_PERL_MODULES"; then have=NGX_PERL_MODULES value="(u_char *) \"$NGX_PERL_MODULES\"" diff --git a/auto/lib/perl/make b/auto/lib/perl/make index d1c1b9e..8af8902 100644 --- a/auto/lib/perl/make +++ b/auto/lib/perl/make @@ -8,7 +8,10 @@ v=`grep 'define NGINX_VERSION' src/core/nginx.h | sed -e 's/^.*"\(.*\)".*/\1/'` cat << END >> $NGX_MAKEFILE -$NGX_OBJS/src/http/modules/perl/blib/arch/auto/nginx/nginx.$ngx_perl_dlext: \\ +$NGX_OBJS/src/http/modules/perl/ngx_http_perl_module.o: \\ + $NGX_OBJS/$ngx_perl_module + +$NGX_OBJS/$ngx_perl_module: \\ \$(CORE_DEPS) \$(HTTP_DEPS) \\ src/http/modules/perl/ngx_http_perl_module.h \\ $NGX_OBJS/src/http/modules/perl/Makefile diff --git a/auto/make b/auto/make index 560924b..5589bee 100644 --- a/auto/make +++ b/auto/make @@ -225,12 +225,12 @@ cat << END >> $NGX_MAKEFILE build: binary modules manpage -binary: $NGX_OBJS${ngx_dirsep}nginx${ngx_binext} +binary: $NGX_OBJS${ngx_dirsep}nginx$ngx_binext -$NGX_OBJS${ngx_dirsep}nginx${ngx_binext}: $ngx_deps$ngx_spacer - \$(LINK) ${ngx_long_start}${ngx_binout}$NGX_OBJS${ngx_dirsep}nginx$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link +$NGX_OBJS${ngx_dirsep}nginx$ngx_binext: $ngx_deps$ngx_spacer + \$(LINK) $ngx_long_start$ngx_binout$NGX_OBJS${ngx_dirsep}nginx$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link $ngx_rcc -${ngx_long_end} +$ngx_long_end modules: END @@ -281,7 +281,7 @@ if [ $HTTP = YES ]; then ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)" else ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) \$(CORE_INCS) \$(HTTP_INCS)" - ngx_perl_cc="\$(CC) $ngx_compile_opt \$(NGX_PERL_CFLAGS) " + ngx_perl_cc="\$(CC) $ngx_compile_opt \$(NGX_PERL_CFLAGS)" ngx_perl_cc="$ngx_perl_cc \$(CORE_INCS) \$(HTTP_INCS)" fi @@ -437,9 +437,9 @@ fi # the addons config.make -if test -n "$NGX_ADDONS"; then +if test -n "$NGX_ADDONS$DYNAMIC_ADDONS"; then - for ngx_addon_dir in $NGX_ADDONS + for ngx_addon_dir in $NGX_ADDONS $DYNAMIC_ADDONS do if test -f $ngx_addon_dir/config.make; then . $ngx_addon_dir/config.make @@ -494,6 +494,8 @@ if test -n "$NGX_PCH"; then ngx_cc="\$(CC) $ngx_compile_opt $ngx_pic_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)" else ngx_cc="\$(CC) $ngx_compile_opt $ngx_pic_opt \$(CFLAGS) \$(ALL_INCS)" + ngx_perl_cc="\$(CC) $ngx_compile_opt $ngx_pic_opt \$(NGX_PERL_CFLAGS)" + ngx_perl_cc="$ngx_perl_cc \$(ALL_INCS)" fi ngx_obj_deps="\$(CORE_DEPS)" @@ -605,9 +607,7 @@ END | sed -e "s/ *\([^ ][^ ]*\)/$ngx_long_regex_cont\1/g" \ -e "s/\//$ngx_regex_dirsep/g"` - ngx_obj=$NGX_OBJS${ngx_dirsep}${ngx_module}${ngx_modext} - - NGX_MODULES="$NGX_MODULES $ngx_obj" + ngx_obj=$NGX_OBJS$ngx_dirsep$ngx_module$ngx_modext if [ "$NGX_PLATFORM" = win32 ]; then ngx_module_libs="$CORE_LIBS $ngx_module_libs" @@ -639,15 +639,15 @@ $ngx_modules_obj: \$(CORE_DEPS)$ngx_cont$ngx_modules_c END - for ngx_src in $ngx_module_srcs + for ngx_source in $ngx_module_srcs do - case "$ngx_src" in + case "$ngx_source" in src/*) - ngx_obj=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"` + ngx_obj=`echo $ngx_source | sed -e "s/\//$ngx_regex_dirsep/g"` ;; *) - ngx_obj="addon/`basename \`dirname $ngx_src\``" - ngx_obj=`echo $ngx_obj/\`basename $ngx_src\` \ + ngx_obj="addon/`basename \`dirname $ngx_source\``" + ngx_obj=`echo $ngx_obj/\`basename $ngx_source\` \ | sed -e "s/\//$ngx_regex_dirsep/g"` ;; esac @@ -658,14 +658,25 @@ END -e "s#^\(.*\.\)c\\$#$ngx_objs_dir\1$ngx_objext#g" \ -e "s#^\(.*\.\)S\\$#$ngx_objs_dir\1$ngx_objext#g"` - ngx_src=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"` + ngx_src=`echo $ngx_source | sed -e "s/\//$ngx_regex_dirsep/g"` - cat << END >> $NGX_MAKEFILE + if [ $ngx_source = src/http/modules/perl/ngx_http_perl_module.c ]; then + + cat << END >> $NGX_MAKEFILE + +$ngx_obj: $ngx_obj_deps$ngx_cont$ngx_src + $ngx_perl_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX + +END + else + + cat << END >> $NGX_MAKEFILE $ngx_obj: $ngx_obj_deps$ngx_cont$ngx_src $ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX END + fi done done diff --git a/auto/module b/auto/module index 908f0c6..16a816f 100644 --- a/auto/module +++ b/auto/module @@ -40,7 +40,7 @@ if [ "$ngx_module_link" = DYNAMIC ]; then do case $lib in - LIBXSLT | LIBGD | GEOIP) + LIBXSLT | LIBGD | GEOIP | PERL) libs="$libs \$NGX_LIB_$lib" if eval [ "\$USE_${lib}" = NO ] ; then @@ -48,7 +48,7 @@ if [ "$ngx_module_link" = DYNAMIC ]; then fi ;; - PCRE | OPENSSL | MD5 | SHA1 | ZLIB | PERL) + PCRE | OPENSSL | MD5 | SHA1 | ZLIB) eval USE_${lib}=YES ;; diff --git a/auto/modules b/auto/modules index ebfc91d..22ff6d9 100644 --- a/auto/modules +++ b/auto/modules @@ -727,14 +727,12 @@ if [ $HTTP_SCGI = YES ]; then . auto/module fi -if [ $HTTP_PERL = YES ]; then - USE_PERL=YES - +if [ $HTTP_PERL != NO ]; then ngx_module_name=ngx_http_perl_module ngx_module_incs=src/http/modules/perl ngx_module_deps=src/http/modules/perl/ngx_http_perl_module.h ngx_module_srcs=src/http/modules/perl/ngx_http_perl_module.c - ngx_module_libs= + ngx_module_libs=PERL ngx_module_link=$HTTP_PERL . auto/module diff --git a/auto/options b/auto/options index 36b34bc..ac8beb1 100644 --- a/auto/options +++ b/auto/options @@ -271,6 +271,7 @@ do --without-http_upstream_zone_module) HTTP_UPSTREAM_ZONE=NO ;; --with-http_perl_module) HTTP_PERL=YES ;; + --with-http_perl_module=dynamic) HTTP_PERL=DYNAMIC ;; --with-perl_modules_path=*) NGX_PERL_MODULES="$value" ;; --with-perl=*) NGX_PERL="$value" ;; @@ -452,6 +453,7 @@ cat << END disable ngx_http_upstream_zone_module --with-http_perl_module enable ngx_http_perl_module + --with-http_perl_module=dynamic enable dynamic ngx_http_perl_module --with-perl_modules_path=PATH set Perl modules path --with-perl=PATH set perl binary pathname @@ -477,8 +479,8 @@ cat << END --without-mail_imap_module disable ngx_mail_imap_module --without-mail_smtp_module disable ngx_mail_smtp_module - --with-stream enable TCP proxy module - --with-stream=dynamic enable dynamic TCP proxy module + --with-stream enable TCP/UDP proxy module + --with-stream=dynamic enable dynamic TCP/UDP proxy module --with-stream_ssl_module enable ngx_stream_ssl_module --without-stream_limit_conn_module disable ngx_stream_limit_conn_module --without-stream_access_module disable ngx_stream_access_module diff --git a/auto/sources b/auto/sources index e08e863..27849e6 100644 --- a/auto/sources +++ b/auto/sources @@ -165,6 +165,7 @@ UNIX_SRCS="$CORE_SRCS $EVENT_SRCS \ src/os/unix/ngx_udp_recv.c \ src/os/unix/ngx_send.c \ src/os/unix/ngx_writev_chain.c \ + src/os/unix/ngx_udp_send.c \ src/os/unix/ngx_channel.c \ src/os/unix/ngx_shmem.c \ src/os/unix/ngx_process.c \ diff --git a/auto/unix b/auto/unix index ce01791..16d9523 100755 --- a/auto/unix +++ b/auto/unix @@ -329,6 +329,45 @@ ngx_feature_test="setsockopt(0, SOL_SOCKET, SO_ACCEPTFILTER, NULL, 0)" . auto/feature +# BSD way to get IPv4 datagram destination address + +ngx_feature="IP_RECVDSTADDR" +ngx_feature_name="NGX_HAVE_IP_RECVDSTADDR" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="setsockopt(0, IPPROTO_IP, IP_RECVDSTADDR, NULL, 0)" +. auto/feature + + +# Linux way to get IPv4 datagram destination address + +ngx_feature="IP_PKTINFO" +ngx_feature_name="NGX_HAVE_IP_PKTINFO" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="setsockopt(0, IPPROTO_IP, IP_PKTINFO, NULL, 0)" +. auto/feature + + +# RFC 3542 way to get IPv6 datagram destination address + +ngx_feature="IPV6_RECVPKTINFO" +ngx_feature_name="NGX_HAVE_IPV6_RECVPKTINFO" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="setsockopt(0, IPPROTO_IPV6, IPV6_RECVPKTINFO, NULL, 0)" +. auto/feature + + ngx_feature="TCP_DEFER_ACCEPT" ngx_feature_name="NGX_HAVE_DEFERRED_ACCEPT" ngx_feature_run=no diff --git a/src/core/nginx.c b/src/core/nginx.c index cdc067e..2823169 100644 --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -10,7 +10,7 @@ #include -static void ngx_show_version_info(); +static void ngx_show_version_info(void); static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle); static ngx_int_t ngx_get_options(int argc, char *const *argv); static ngx_int_t ngx_process_options(ngx_cycle_t *cycle); @@ -372,7 +372,7 @@ main(int argc, char *const *argv) static void -ngx_show_version_info() +ngx_show_version_info(void) { ngx_write_stderr("nginx version: " NGINX_VER_BUILD NGX_LINEFEED); diff --git a/src/core/nginx.h b/src/core/nginx.h index dec7b88..238d8b8 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1009012 -#define NGINX_VERSION "1.9.12" +#define nginx_version 1009013 +#define NGINX_VERSION "1.9.13" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 0c19d5d..572def2 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -210,6 +210,18 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) olen = sizeof(int); + if (getsockopt(ls[i].fd, SOL_SOCKET, SO_TYPE, (void *) &ls[i].type, + &olen) + == -1) + { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, + "getsockopt(SO_TYPE) %V failed", &ls[i].addr_text); + ls[i].ignore = 1; + continue; + } + + olen = sizeof(int); + if (getsockopt(ls[i].fd, SOL_SOCKET, SO_RCVBUF, (void *) &ls[i].rcvbuf, &olen) == -1) @@ -274,6 +286,10 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) #endif + if (ls[i].type != SOCK_STREAM) { + continue; + } + #if (NGX_HAVE_TCP_FASTOPEN) olen = sizeof(int); @@ -566,6 +582,11 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) } #endif + if (ls[i].type != SOCK_STREAM) { + ls[i].fd = s; + continue; + } + if (listen(s, ls[i].backlog) == -1) { err = ngx_socket_errno; @@ -865,6 +886,67 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle) #endif #endif /* NGX_HAVE_DEFERRED_ACCEPT */ + +#if (NGX_HAVE_IP_RECVDSTADDR) + + if (ls[i].wildcard + && ls[i].type == SOCK_DGRAM + && ls[i].sockaddr->sa_family == AF_INET) + { + value = 1; + + if (setsockopt(ls[i].fd, IPPROTO_IP, IP_RECVDSTADDR, + (const void *) &value, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(IP_RECVDSTADDR) " + "for %V failed, ignored", + &ls[i].addr_text); + } + } + +#elif (NGX_HAVE_IP_PKTINFO) + + if (ls[i].wildcard + && ls[i].type == SOCK_DGRAM + && ls[i].sockaddr->sa_family == AF_INET) + { + value = 1; + + if (setsockopt(ls[i].fd, IPPROTO_IP, IP_PKTINFO, + (const void *) &value, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(IP_PKTINFO) " + "for %V failed, ignored", + &ls[i].addr_text); + } + } + +#endif + +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + + if (ls[i].wildcard + && ls[i].type == SOCK_DGRAM + && ls[i].sockaddr->sa_family == AF_INET6) + { + value = 1; + + if (setsockopt(ls[i].fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, + (const void *) &value, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(IPV6_RECVPKTINFO) " + "for %V failed, ignored", + &ls[i].addr_text); + } + } + +#endif } return; @@ -978,7 +1060,7 @@ ngx_get_connection(ngx_socket_t s, ngx_log_t *log) ngx_cycle->free_connections = c->data; ngx_cycle->free_connection_n--; - if (ngx_cycle->files) { + if (ngx_cycle->files && ngx_cycle->files[s] == NULL) { ngx_cycle->files[s] = c; } @@ -1019,7 +1101,7 @@ ngx_free_connection(ngx_connection_t *c) ngx_cycle->free_connections = c; ngx_cycle->free_connection_n++; - if (ngx_cycle->files) { + if (ngx_cycle->files && ngx_cycle->files[c->fd] == c) { ngx_cycle->files[c->fd] = NULL; } } @@ -1045,16 +1127,18 @@ ngx_close_connection(ngx_connection_t *c) ngx_del_timer(c->write); } - if (ngx_del_conn) { - ngx_del_conn(c, NGX_CLOSE_EVENT); + if (!c->shared) { + if (ngx_del_conn) { + ngx_del_conn(c, NGX_CLOSE_EVENT); - } else { - if (c->read->active || c->read->disabled) { - ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); - } + } else { + if (c->read->active || c->read->disabled) { + ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); + } - if (c->write->active || c->write->disabled) { - ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); + if (c->write->active || c->write->disabled) { + ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); + } } } @@ -1078,6 +1162,10 @@ ngx_close_connection(ngx_connection_t *c) fd = c->fd; c->fd = (ngx_socket_t) -1; + if (c->shared) { + return; + } + if (ngx_close_socket(fd) == -1) { err = ngx_socket_errno; diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index 977f028..19a2ab7 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -64,6 +64,7 @@ struct ngx_listening_s { unsigned nonblocking:1; unsigned shared:1; /* shared between threads or processes */ unsigned addr_ntop:1; + unsigned wildcard:1; #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) unsigned ipv6only:1; @@ -141,6 +142,8 @@ struct ngx_connection_s { ngx_pool_t *pool; + int type; + struct sockaddr *sockaddr; socklen_t socklen; ngx_str_t addr_text; @@ -174,6 +177,7 @@ struct ngx_connection_s { unsigned idle:1; unsigned reusable:1; unsigned close:1; + unsigned shared:1; unsigned sendfile:1; unsigned sndlowat:1; diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c index f103266..5785eb5 100644 --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -512,6 +512,10 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) continue; } + if (ls[i].type != nls[n].type) { + continue; + } + if (ngx_cmp_sockaddr(nls[n].sockaddr, nls[n].socklen, ls[i].sockaddr, ls[i].socklen, 1) == NGX_OK) diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c index 3ebd73d..d3e2ece 100644 --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -124,6 +124,15 @@ ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain) } } +#if (NGX_THREADS && NGX_HAVE_PWRITEV) + + if (tf->thread_write) { + return ngx_thread_write_chain_to_file(&tf->file, chain, tf->offset, + tf->pool); + } + +#endif + return ngx_write_chain_to_file(&tf->file, chain, tf->offset, tf->pool); } @@ -187,7 +196,7 @@ ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool, err = ngx_errno; - if (err == NGX_EEXIST) { + if (err == NGX_EEXIST_FILE) { n = (uint32_t) ngx_next_temp_number(1); continue; } @@ -683,7 +692,7 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext) #if (NGX_WIN32) - if (err == NGX_EEXIST) { + if (err == NGX_EEXIST || err == NGX_EEXIST_FILE) { err = ngx_win32_rename_file(src, to, ext->log); if (err == 0) { diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h index 301b191..5f8228b 100644 --- a/src/core/ngx_file.h +++ b/src/core/ngx_file.h @@ -27,6 +27,7 @@ struct ngx_file_s { ngx_int_t (*thread_handler)(ngx_thread_task_t *task, ngx_file_t *file); void *thread_ctx; + ngx_thread_task_t *thread_task; #endif #if (NGX_HAVE_FILE_AIO) @@ -77,6 +78,7 @@ typedef struct { unsigned log_level:8; unsigned persistent:1; unsigned clean:1; + unsigned thread_write:1; } ngx_temp_file_t; diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c index 96a04fd..3bbadb8 100644 --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -529,14 +529,16 @@ ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u) { u_char *p; + size_t len; p = u->url.data; + len = u->url.len; - if (ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) { + if (len >= 5 && ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) { return ngx_parse_unix_domain_url(pool, u); } - if (p[0] == '[') { + if (len && p[0] == '[') { return ngx_parse_inet6_url(pool, u); } diff --git a/src/core/ngx_module.c b/src/core/ngx_module.c index f5ec86a..3e3c506 100644 --- a/src/core/ngx_module.c +++ b/src/core/ngx_module.c @@ -23,11 +23,10 @@ static ngx_uint_t ngx_modules_n; ngx_int_t -ngx_preinit_modules() +ngx_preinit_modules(void) { ngx_uint_t i; - ngx_max_module = 0; for (i = 0; ngx_modules[i]; i++) { ngx_modules[i]->index = i; ngx_modules[i]->name = ngx_module_names[i]; diff --git a/src/core/ngx_module.h b/src/core/ngx_module.h index 3e74def..e911cb4 100644 --- a/src/core/ngx_module.h +++ b/src/core/ngx_module.h @@ -288,7 +288,7 @@ typedef struct { } ngx_core_module_t; -ngx_int_t ngx_preinit_modules(); +ngx_int_t ngx_preinit_modules(void); ngx_int_t ngx_cycle_modules(ngx_cycle_t *cycle); ngx_int_t ngx_init_modules(ngx_cycle_t *cycle); ngx_int_t ngx_count_modules(ngx_cycle_t *cycle, ngx_uint_t type); diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c index 252359a..f784578 100644 --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -577,11 +577,15 @@ ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx) } else #endif #if (NGX_THREADS) - if (src->file->thread_handler) { - n = ngx_thread_read(&ctx->thread_task, src->file, dst->pos, - (size_t) size, src->file_pos, ctx->pool); + if (ctx->thread_handler) { + src->file->thread_task = ctx->thread_task; + src->file->thread_handler = ctx->thread_handler; + src->file->thread_ctx = ctx->filter_ctx; + + n = ngx_thread_read(src->file, dst->pos, (size_t) size, + src->file_pos, ctx->pool); if (n == NGX_AGAIN) { - ctx->aio = 1; + ctx->thread_task = src->file->thread_task; return NGX_AGAIN; } diff --git a/src/core/ngx_palloc.c b/src/core/ngx_palloc.c index ef4a647..d3044ac 100644 --- a/src/core/ngx_palloc.c +++ b/src/core/ngx_palloc.c @@ -9,6 +9,8 @@ #include +static ngx_inline void *ngx_palloc_small(ngx_pool_t *pool, size_t size, + ngx_uint_t align); static void *ngx_palloc_block(ngx_pool_t *pool, size_t size); static void *ngx_palloc_large(ngx_pool_t *pool, size_t size); @@ -56,15 +58,6 @@ ngx_destroy_pool(ngx_pool_t *pool) } } - for (l = pool->large; l; l = l->next) { - - ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc); - - if (l->alloc) { - ngx_free(l->alloc); - } - } - #if (NGX_DEBUG) /* @@ -72,6 +65,10 @@ ngx_destroy_pool(ngx_pool_t *pool) * so we cannot use this log while free()ing the pool */ + for (l = pool->large; l; l = l->next) { + ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc); + } + for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) { ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p, unused: %uz", p, p->d.end - p->d.last); @@ -83,6 +80,12 @@ ngx_destroy_pool(ngx_pool_t *pool) #endif + for (l = pool->large; l; l = l->next) { + if (l->alloc) { + ngx_free(l->alloc); + } + } + for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) { ngx_free(p); @@ -119,28 +122,11 @@ ngx_reset_pool(ngx_pool_t *pool) void * ngx_palloc(ngx_pool_t *pool, size_t size) { - u_char *m; - ngx_pool_t *p; - +#if !(NGX_DEBUG_PALLOC) if (size <= pool->max) { - - p = pool->current; - - do { - m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT); - - if ((size_t) (p->d.end - m) >= size) { - p->d.last = m + size; - - return m; - } - - p = p->d.next; - - } while (p); - - return ngx_palloc_block(pool, size); + return ngx_palloc_small(pool, size, 1); } +#endif return ngx_palloc_large(pool, size); } @@ -148,31 +134,43 @@ ngx_palloc(ngx_pool_t *pool, size_t size) void * ngx_pnalloc(ngx_pool_t *pool, size_t size) +{ +#if !(NGX_DEBUG_PALLOC) + if (size <= pool->max) { + return ngx_palloc_small(pool, size, 0); + } +#endif + + return ngx_palloc_large(pool, size); +} + + +static ngx_inline void * +ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align) { u_char *m; ngx_pool_t *p; - if (size <= pool->max) { + p = pool->current; - p = pool->current; + do { + m = p->d.last; - do { - m = p->d.last; + if (align) { + m = ngx_align_ptr(m, NGX_ALIGNMENT); + } - if ((size_t) (p->d.end - m) >= size) { - p->d.last = m + size; + if ((size_t) (p->d.end - m) >= size) { + p->d.last = m + size; - return m; - } + return m; + } - p = p->d.next; + p = p->d.next; - } while (p); + } while (p); - return ngx_palloc_block(pool, size); - } - - return ngx_palloc_large(pool, size); + return ngx_palloc_block(pool, size); } @@ -237,7 +235,7 @@ ngx_palloc_large(ngx_pool_t *pool, size_t size) } } - large = ngx_palloc(pool, sizeof(ngx_pool_large_t)); + large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1); if (large == NULL) { ngx_free(p); return NULL; @@ -262,7 +260,7 @@ ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment) return NULL; } - large = ngx_palloc(pool, sizeof(ngx_pool_large_t)); + large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1); if (large == NULL) { ngx_free(p); return NULL; diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index 7f0d3ad..38bf956 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -74,8 +74,10 @@ static ngx_int_t ngx_resolver_send_tcp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec, u_char *query, u_short qlen); static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, ngx_str_t *name); +static ngx_int_t ngx_resolver_create_srv_query(ngx_resolver_t *r, + ngx_resolver_node_t *rn, ngx_str_t *name); static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r, - ngx_resolver_node_t *rn, ngx_addr_t *addr); + ngx_resolver_node_t *rn, ngx_resolver_addr_t *addr); static void ngx_resolver_resend_handler(ngx_event_t *ev); static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue); @@ -88,10 +90,15 @@ static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype, ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans); +static void ngx_resolver_process_srv(ngx_resolver_t *r, u_char *buf, size_t n, + ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, + ngx_uint_t trunc, ngx_uint_t ans); static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan); static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash); +static ngx_resolver_node_t *ngx_resolver_lookup_srv(ngx_resolver_t *r, + ngx_str_t *name, uint32_t hash); static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr); static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp, @@ -105,9 +112,14 @@ static void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size); static void ngx_resolver_free(ngx_resolver_t *r, void *p); static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p); static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size); -static ngx_addr_t *ngx_resolver_export(ngx_resolver_t *r, +static ngx_resolver_addr_t *ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn, ngx_uint_t rotate); +static void ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx); static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len); +static void ngx_resolver_resolve_srv_names(ngx_resolver_ctx_t *ctx, + ngx_resolver_node_t *rn); +static void ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *ctx); +static ngx_int_t ngx_resolver_cmp_srvs(const void *one, const void *two); #if (NGX_HAVE_INET6) static void ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp, @@ -149,13 +161,18 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) ngx_rbtree_init(&r->name_rbtree, &r->name_sentinel, ngx_resolver_rbtree_insert_value); + ngx_rbtree_init(&r->srv_rbtree, &r->srv_sentinel, + ngx_resolver_rbtree_insert_value); + ngx_rbtree_init(&r->addr_rbtree, &r->addr_sentinel, ngx_rbtree_insert_value); ngx_queue_init(&r->name_resend_queue); + ngx_queue_init(&r->srv_resend_queue); ngx_queue_init(&r->addr_resend_queue); ngx_queue_init(&r->name_expire_queue); + ngx_queue_init(&r->srv_expire_queue); ngx_queue_init(&r->addr_expire_queue); #if (NGX_HAVE_INET6) @@ -274,6 +291,8 @@ ngx_resolver_cleanup(void *data) ngx_resolver_cleanup_tree(r, &r->name_rbtree); + ngx_resolver_cleanup_tree(r, &r->srv_rbtree); + ngx_resolver_cleanup_tree(r, &r->addr_rbtree); #if (NGX_HAVE_INET6) @@ -383,7 +402,9 @@ ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp) ngx_int_t ngx_resolve_name(ngx_resolver_ctx_t *ctx) { + size_t slen; ngx_int_t rc; + ngx_str_t name; ngx_resolver_t *r; r = ctx->resolver; @@ -400,9 +421,41 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx) return NGX_OK; } - /* lock name mutex */ + if (ctx->service.len) { + slen = ctx->service.len; - rc = ngx_resolve_name_locked(r, ctx, &ctx->name); + if (ngx_strlchr(ctx->service.data, + ctx->service.data + ctx->service.len, '.') + == NULL) + { + slen += sizeof("_._tcp") - 1; + } + + name.len = slen + 1 + ctx->name.len; + + name.data = ngx_resolver_alloc(r, name.len); + if (name.data == NULL) { + return NGX_ERROR; + } + + if (slen == ctx->service.len) { + ngx_sprintf(name.data, "%V.%V", &ctx->service, &ctx->name); + + } else { + ngx_sprintf(name.data, "_%V._tcp.%V", &ctx->service, &ctx->name); + } + + /* lock name mutex */ + + rc = ngx_resolve_name_locked(r, ctx, &name); + + ngx_resolver_free(r, name.data); + + } else { + /* lock name mutex */ + + rc = ngx_resolve_name_locked(r, ctx, &ctx->name); + } if (rc == NGX_OK) { return NGX_OK; @@ -429,6 +482,7 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx) void ngx_resolve_name_done(ngx_resolver_ctx_t *ctx) { + ngx_uint_t i; ngx_resolver_t *r; ngx_resolver_ctx_t *w, **p; ngx_resolver_node_t *rn; @@ -448,6 +502,23 @@ ngx_resolve_name_done(ngx_resolver_ctx_t *ctx) /* lock name mutex */ + if (ctx->nsrvs) { + for (i = 0; i < ctx->nsrvs; i++) { + if (ctx->srvs[i].ctx) { + ngx_resolve_name_done(ctx->srvs[i].ctx); + } + + if (ctx->srvs[i].addrs) { + ngx_resolver_free(r, ctx->srvs[i].addrs->sockaddr); + ngx_resolver_free(r, ctx->srvs[i].addrs); + } + + ngx_resolver_free(r, ctx->srvs[i].name.data); + } + + ngx_resolver_free(r, ctx->srvs); + } + if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) { rn = ctx->node; @@ -466,15 +537,20 @@ ngx_resolve_name_done(ngx_resolver_ctx_t *ctx) p = &w->next; w = w->next; } - } - ngx_log_error(NGX_LOG_ALERT, r->log, 0, - "could not cancel %V resolving", &ctx->name); + ngx_log_error(NGX_LOG_ALERT, r->log, 0, + "could not cancel %V resolving", &ctx->name); + } } done: - ngx_resolver_expire(r, &r->name_rbtree, &r->name_expire_queue); + if (ctx->service.len) { + ngx_resolver_expire(r, &r->srv_rbtree, &r->srv_expire_queue); + + } else { + ngx_resolver_expire(r, &r->name_rbtree, &r->name_expire_queue); + } /* unlock name mutex */ @@ -501,16 +577,31 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, uint32_t hash; ngx_int_t rc; ngx_str_t cname; - ngx_uint_t naddrs; - ngx_addr_t *addrs; + ngx_uint_t i, naddrs; + ngx_queue_t *resend_queue, *expire_queue; + ngx_rbtree_t *tree; ngx_resolver_ctx_t *next, *last; + ngx_resolver_addr_t *addrs; ngx_resolver_node_t *rn; ngx_strlow(name->data, name->data, name->len); hash = ngx_crc32_short(name->data, name->len); - rn = ngx_resolver_lookup_name(r, name, hash); + if (ctx->service.len) { + rn = ngx_resolver_lookup_srv(r, name, hash); + + tree = &r->srv_rbtree; + resend_queue = &r->srv_resend_queue; + expire_queue = &r->srv_expire_queue; + + } else { + rn = ngx_resolver_lookup_name(r, name, hash); + + tree = &r->name_rbtree; + resend_queue = &r->name_resend_queue; + expire_queue = &r->name_expire_queue; + } if (rn) { @@ -525,7 +616,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, rn->expire = ngx_time() + r->expire; - ngx_queue_insert_head(&r->name_expire_queue, &rn->queue); + ngx_queue_insert_head(expire_queue, &rn->queue); naddrs = (rn->naddrs == (u_short) -1) ? 0 : rn->naddrs; #if (NGX_HAVE_INET6) @@ -551,6 +642,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, do { ctx->state = NGX_OK; + ctx->valid = rn->valid; ctx->naddrs = naddrs; if (addrs == NULL) { @@ -580,6 +672,23 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, return NGX_OK; } + if (rn->nsrvs) { + last->next = rn->waiting; + rn->waiting = NULL; + + /* unlock name mutex */ + + do { + next = ctx->next; + + ngx_resolver_resolve_srv_names(ctx, rn); + + ctx = next; + } while (ctx); + + return NGX_OK; + } + /* NGX_RESOLVE_CNAME */ if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) { @@ -597,6 +706,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, do { ctx->state = NGX_RESOLVE_NXDOMAIN; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); next = ctx->next; ctx->handler(ctx); @@ -609,7 +719,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, if (rn->waiting) { - if (ctx->event == NULL) { + if (ctx->event == NULL && ctx->timeout) { ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); if (ctx->event == NULL) { return NGX_ERROR; @@ -661,6 +771,16 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, } #endif + if (rn->nsrvs) { + for (i = 0; i < rn->nsrvs; i++) { + if (rn->u.srvs[i].name.data) { + ngx_resolver_free_locked(r, rn->u.srvs[i].name.data); + } + } + + ngx_resolver_free_locked(r, rn->u.srvs); + } + /* unlock alloc mutex */ } else { @@ -683,17 +803,22 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, rn->query6 = NULL; #endif - ngx_rbtree_insert(&r->name_rbtree, &rn->node); + ngx_rbtree_insert(tree, &rn->node); } - rc = ngx_resolver_create_name_query(r, rn, name); + if (ctx->service.len) { + rc = ngx_resolver_create_srv_query(r, rn, name); + + } else { + rc = ngx_resolver_create_name_query(r, rn, name); + } if (rc == NGX_ERROR) { goto failed; } if (rc == NGX_DECLINED) { - ngx_rbtree_delete(&r->name_rbtree, &rn->node); + ngx_rbtree_delete(tree, &rn->node); ngx_resolver_free(r, rn->query); ngx_resolver_free(r, rn->name); @@ -722,12 +847,13 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0; rn->tcp6 = 0; #endif + rn->nsrvs = 0; if (ngx_resolver_send_query(r, rn) != NGX_OK) { goto failed; } - if (ctx->event == NULL) { + if (ctx->event == NULL && ctx->timeout) { ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); if (ctx->event == NULL) { goto failed; @@ -741,13 +867,13 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, ngx_add_timer(ctx->event, ctx->timeout); } - if (ngx_queue_empty(&r->name_resend_queue)) { + if (ngx_queue_empty(resend_queue)) { ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000)); } rn->expire = ngx_time() + r->resend_timeout; - ngx_queue_insert_head(&r->name_resend_queue, &rn->queue); + ngx_queue_insert_head(resend_queue, &rn->queue); rn->code = 0; rn->cnlen = 0; @@ -766,7 +892,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, failed: - ngx_rbtree_delete(&r->name_rbtree, &rn->node); + ngx_rbtree_delete(tree, &rn->node); if (rn->query) { ngx_resolver_free(r, rn->query); @@ -859,6 +985,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) /* unlock addr mutex */ ctx->state = NGX_OK; + ctx->valid = rn->valid; ctx->handler(ctx); @@ -869,18 +996,20 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) if (rn->waiting) { - ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); - if (ctx->event == NULL) { - return NGX_ERROR; + if (ctx->event == NULL && ctx->timeout) { + ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); + if (ctx->event == NULL) { + return NGX_ERROR; + } + + ctx->event->handler = ngx_resolver_timeout_handler; + ctx->event->data = ctx; + ctx->event->log = r->log; + ctx->ident = -1; + + ngx_add_timer(ctx->event, ctx->timeout); } - ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; - ctx->event->log = r->log; - ctx->ident = -1; - - ngx_add_timer(ctx->event, ctx->timeout); - ctx->next = rn->waiting; rn->waiting = ctx; ctx->state = NGX_AGAIN; @@ -941,23 +1070,26 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) rn->naddrs6 = (u_short) -1; rn->tcp6 = 0; #endif + rn->nsrvs = 0; if (ngx_resolver_send_query(r, rn) != NGX_OK) { goto failed; } - ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); - if (ctx->event == NULL) { - goto failed; + if (ctx->event == NULL && ctx->timeout) { + ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); + if (ctx->event == NULL) { + goto failed; + } + + ctx->event->handler = ngx_resolver_timeout_handler; + ctx->event->data = ctx; + ctx->event->log = r->log; + ctx->ident = -1; + + ngx_add_timer(ctx->event, ctx->timeout); } - ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; - ctx->event->log = r->log; - ctx->ident = -1; - - ngx_add_timer(ctx->event, ctx->timeout); - if (ngx_queue_empty(resend_queue)) { ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000)); } @@ -1294,7 +1426,7 @@ ngx_resolver_send_tcp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec, static void ngx_resolver_resend_handler(ngx_event_t *ev) { - time_t timer, atimer, ntimer; + time_t timer, atimer, stimer, ntimer; #if (NGX_HAVE_INET6) time_t a6timer; #endif @@ -1309,6 +1441,8 @@ ngx_resolver_resend_handler(ngx_event_t *ev) ntimer = ngx_resolver_resend(r, &r->name_rbtree, &r->name_resend_queue); + stimer = ngx_resolver_resend(r, &r->srv_rbtree, &r->srv_resend_queue); + /* unlock name mutex */ /* lock addr mutex */ @@ -1336,6 +1470,13 @@ ngx_resolver_resend_handler(ngx_event_t *ev) timer = ngx_min(timer, atimer); } + if (timer == 0) { + timer = stimer; + + } else if (stimer) { + timer = ngx_min(timer, stimer); + } + #if (NGX_HAVE_INET6) if (timer == 0) { @@ -1696,6 +1837,13 @@ found: break; + case NGX_RESOLVE_SRV: + + ngx_resolver_process_srv(r, buf, n, ident, code, nan, trunc, + i + sizeof(ngx_resolver_qs_t)); + + break; + case NGX_RESOLVE_PTR: ngx_resolver_process_ptr(r, buf, n, ident, code, nan); @@ -1749,7 +1897,6 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, uint32_t hash; in_addr_t *addr; ngx_str_t name; - ngx_addr_t *addrs; ngx_uint_t type, class, qident, naddrs, a, i, j, start; #if (NGX_HAVE_INET6) struct in6_addr *addr6; @@ -1757,6 +1904,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, ngx_resolver_an_t *an; ngx_resolver_ctx_t *ctx, *next; ngx_resolver_node_t *rn; + ngx_resolver_addr_t *addrs; ngx_resolver_connection_t *rec; if (ngx_resolver_copy(r, &name, buf, @@ -1948,6 +2096,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, while (next) { ctx = next; ctx->state = code; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); next = ctx->next; ctx->handler(ctx); @@ -2262,6 +2411,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, while (next) { ctx = next; ctx->state = NGX_OK; + ctx->valid = rn->valid; ctx->naddrs = naddrs; if (addrs == NULL) { @@ -2390,6 +2540,536 @@ next: } +static void +ngx_resolver_process_srv(ngx_resolver_t *r, u_char *buf, size_t n, + ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, + ngx_uint_t trunc, ngx_uint_t ans) +{ + char *err; + u_char *cname; + size_t len; + int32_t ttl; + uint32_t hash; + ngx_str_t name; + ngx_uint_t type, qident, class, start, nsrvs, a, i, j; + ngx_resolver_an_t *an; + ngx_resolver_ctx_t *ctx, *next; + ngx_resolver_srv_t *srvs; + ngx_resolver_node_t *rn; + ngx_resolver_connection_t *rec; + + if (ngx_resolver_copy(r, &name, buf, + buf + sizeof(ngx_resolver_hdr_t), buf + n) + != NGX_OK) + { + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name); + + hash = ngx_crc32_short(name.data, name.len); + + rn = ngx_resolver_lookup_srv(r, &name, hash); + + if (rn == NULL || rn->query == NULL) { + ngx_log_error(r->log_level, r->log, 0, + "unexpected response for %V", &name); + ngx_resolver_free(r, name.data); + goto failed; + } + + if (trunc && rn->tcp) { + ngx_resolver_free(r, name.data); + goto failed; + } + + qident = (rn->query[0] << 8) + rn->query[1]; + + if (ident != qident) { + ngx_log_error(r->log_level, r->log, 0, + "wrong ident %ui response for %V, expect %ui", + ident, &name, qident); + ngx_resolver_free(r, name.data); + goto failed; + } + + ngx_resolver_free(r, name.data); + + if (trunc) { + + ngx_queue_remove(&rn->queue); + + if (rn->waiting == NULL) { + ngx_rbtree_delete(&r->srv_rbtree, &rn->node); + ngx_resolver_free_node(r, rn); + return; + } + + rec = r->connections.elts; + rec = &rec[rn->last_connection]; + + rn->tcp = 1; + + (void) ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen); + + rn->expire = ngx_time() + r->resend_timeout; + + ngx_queue_insert_head(&r->srv_resend_queue, &rn->queue); + + return; + } + + if (code == 0 && rn->code) { + code = rn->code; + } + + if (code == 0 && nan == 0) { + code = NGX_RESOLVE_NXDOMAIN; + } + + if (code) { + next = rn->waiting; + rn->waiting = NULL; + + ngx_queue_remove(&rn->queue); + + ngx_rbtree_delete(&r->srv_rbtree, &rn->node); + + while (next) { + ctx = next; + ctx->state = code; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); + next = ctx->next; + + ctx->handler(ctx); + } + + ngx_resolver_free_node(r, rn); + + return; + } + + i = ans; + nsrvs = 0; + cname = NULL; + + for (a = 0; a < nan; a++) { + + start = i; + + while (i < n) { + + if (buf[i] & 0xc0) { + i += 2; + goto found; + } + + if (buf[i] == 0) { + i++; + goto test_length; + } + + i += 1 + buf[i]; + } + + goto short_response; + + test_length: + + if (i - start < 2) { + err = "invalid name DNS response"; + goto invalid; + } + + found: + + if (i + sizeof(ngx_resolver_an_t) >= n) { + goto short_response; + } + + an = (ngx_resolver_an_t *) &buf[i]; + + type = (an->type_hi << 8) + an->type_lo; + class = (an->class_hi << 8) + an->class_lo; + len = (an->len_hi << 8) + an->len_lo; + ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16) + + (an->ttl[2] << 8) + (an->ttl[3]); + + if (class != 1) { + ngx_log_error(r->log_level, r->log, 0, + "unexpected RR class %ui", class); + goto failed; + } + + if (ttl < 0) { + ttl = 0; + } + + rn->ttl = ngx_min(rn->ttl, (uint32_t) ttl); + + i += sizeof(ngx_resolver_an_t); + + switch (type) { + + case NGX_RESOLVE_SRV: + + if (i + 6 > n) { + goto short_response; + } + + if (ngx_resolver_copy(r, NULL, buf, &buf[i + 6], buf + n) + != NGX_OK) + { + goto failed; + } + + nsrvs++; + + break; + + case NGX_RESOLVE_CNAME: + + cname = &buf[i]; + + break; + + case NGX_RESOLVE_DNAME: + + break; + + default: + + ngx_log_error(r->log_level, r->log, 0, + "unexpected RR type %ui", type); + } + + i += len; + } + + ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolver nsrvs:%ui cname:%p ttl:%uD", + nsrvs, cname, rn->ttl); + + if (nsrvs) { + + srvs = ngx_resolver_calloc(r, nsrvs * sizeof(ngx_resolver_srv_t)); + if (srvs == NULL) { + goto failed; + } + + rn->u.srvs = srvs; + rn->nsrvs = (u_short) nsrvs; + + j = 0; + i = ans; + + for (a = 0; a < nan; a++) { + + for ( ;; ) { + + if (buf[i] & 0xc0) { + i += 2; + break; + } + + if (buf[i] == 0) { + i++; + break; + } + + i += 1 + buf[i]; + } + + an = (ngx_resolver_an_t *) &buf[i]; + + type = (an->type_hi << 8) + an->type_lo; + len = (an->len_hi << 8) + an->len_lo; + + i += sizeof(ngx_resolver_an_t); + + if (type == NGX_RESOLVE_SRV) { + + srvs[j].priority = (buf[i] << 8) + buf[i + 1]; + srvs[j].weight = (buf[i + 2] << 8) + buf[i + 3]; + + if (srvs[j].weight == 0) { + srvs[j].weight = 1; + } + + srvs[j].port = (buf[i + 4] << 8) + buf[i + 5]; + + if (ngx_resolver_copy(r, &srvs[j].name, buf, &buf[i + 6], + buf + n) + != NGX_OK) + { + goto failed; + } + + j++; + } + + i += len; + } + + ngx_sort(srvs, nsrvs, sizeof(ngx_resolver_srv_t), + ngx_resolver_cmp_srvs); + + ngx_resolver_free(r, rn->query); + rn->query = NULL; + + ngx_queue_remove(&rn->queue); + + rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl); + rn->expire = ngx_time() + r->expire; + + ngx_queue_insert_head(&r->srv_expire_queue, &rn->queue); + + next = rn->waiting; + rn->waiting = NULL; + + while (next) { + ctx = next; + next = ctx->next; + + ngx_resolver_resolve_srv_names(ctx, rn); + } + + return; + } + + rn->nsrvs = 0; + + if (cname) { + + /* CNAME only */ + + if (ngx_resolver_copy(r, &name, buf, cname, buf + n) != NGX_OK) { + goto failed; + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolver cname:\"%V\"", &name); + + ngx_queue_remove(&rn->queue); + + rn->cnlen = (u_short) name.len; + rn->u.cname = name.data; + + rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl); + rn->expire = ngx_time() + r->expire; + + ngx_queue_insert_head(&r->srv_expire_queue, &rn->queue); + + ngx_resolver_free(r, rn->query); + rn->query = NULL; +#if (NGX_HAVE_INET6) + rn->query6 = NULL; +#endif + + ctx = rn->waiting; + rn->waiting = NULL; + + if (ctx) { + + if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) { + + /* unlock name mutex */ + + do { + ctx->state = NGX_RESOLVE_NXDOMAIN; + next = ctx->next; + + ctx->handler(ctx); + + ctx = next; + } while (ctx); + + return; + } + + for (next = ctx; next; next = next->next) { + next->node = NULL; + } + + (void) ngx_resolve_name_locked(r, ctx, &name); + } + + /* unlock name mutex */ + + return; + } + + ngx_log_error(r->log_level, r->log, 0, "no SRV type in DNS response"); + + return; + +short_response: + + err = "short DNS response"; + +invalid: + + /* unlock name mutex */ + + ngx_log_error(r->log_level, r->log, 0, err); + + return; + +failed: + + /* unlock name mutex */ + + return; +} + + +static void +ngx_resolver_resolve_srv_names(ngx_resolver_ctx_t *ctx, ngx_resolver_node_t *rn) +{ + ngx_uint_t i; + ngx_resolver_t *r; + ngx_resolver_ctx_t *cctx; + ngx_resolver_srv_name_t *srvs; + + r = ctx->resolver; + + ctx->node = NULL; + ctx->state = NGX_OK; + ctx->valid = rn->valid; + ctx->count = rn->nsrvs; + + srvs = ngx_resolver_calloc(r, rn->nsrvs * sizeof(ngx_resolver_srv_name_t)); + if (srvs == NULL) { + goto failed; + } + + ctx->srvs = srvs; + ctx->nsrvs = rn->nsrvs; + + for (i = 0; i < rn->nsrvs; i++) { + srvs[i].name.data = ngx_resolver_alloc(r, rn->u.srvs[i].name.len); + if (srvs[i].name.data == NULL) { + goto failed; + } + + srvs[i].name.len = rn->u.srvs[i].name.len; + ngx_memcpy(srvs[i].name.data, rn->u.srvs[i].name.data, + srvs[i].name.len); + + cctx = ngx_resolve_start(r, NULL); + if (cctx == NULL) { + goto failed; + } + + cctx->name = srvs[i].name; + cctx->handler = ngx_resolver_srv_names_handler; + cctx->data = ctx; + cctx->srvs = &srvs[i]; + cctx->timeout = 0; + + srvs[i].priority = rn->u.srvs[i].priority; + srvs[i].weight = rn->u.srvs[i].weight; + srvs[i].port = rn->u.srvs[i].port; + srvs[i].ctx = cctx; + + if (ngx_resolve_name(cctx) == NGX_ERROR) { + srvs[i].ctx = NULL; + goto failed; + } + } + + return; + +failed: + + ctx->state = NGX_ERROR; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); + + ctx->handler(ctx); +} + + +static void +ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx) +{ + ngx_uint_t i; + u_char (*sockaddr)[NGX_SOCKADDRLEN]; + ngx_addr_t *addrs; + ngx_resolver_t *r; + struct sockaddr_in *sin; + ngx_resolver_ctx_t *ctx; + ngx_resolver_srv_name_t *srv; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + r = cctx->resolver; + ctx = cctx->data; + srv = cctx->srvs; + + ctx->count--; + + srv->ctx = NULL; + + if (cctx->naddrs) { + + ctx->valid = ngx_min(ctx->valid, cctx->valid); + + addrs = ngx_resolver_calloc(r, cctx->naddrs * sizeof(ngx_addr_t)); + if (addrs == NULL) { + ngx_resolve_name_done(cctx); + + ctx->state = NGX_ERROR; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); + + ctx->handler(ctx); + return; + } + + sockaddr = ngx_resolver_alloc(r, cctx->naddrs * NGX_SOCKADDRLEN); + if (sockaddr == NULL) { + ngx_resolver_free(r, addrs); + ngx_resolve_name_done(cctx); + + ctx->state = NGX_ERROR; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); + + ctx->handler(ctx); + return; + } + + for (i = 0; i < cctx->naddrs; i++) { + addrs[i].sockaddr = (struct sockaddr *) sockaddr[i]; + addrs[i].socklen = cctx->addrs[i].socklen; + + ngx_memcpy(sockaddr[i], cctx->addrs[i].sockaddr, + addrs[i].socklen); + + switch (addrs[i].sockaddr->sa_family) { +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) addrs[i].sockaddr; + sin6->sin6_port = htons(srv->port); + break; +#endif + default: /* AF_INET */ + sin = (struct sockaddr_in *) addrs[i].sockaddr; + sin->sin_port = htons(srv->port); + } + } + + srv->addrs = addrs; + srv->naddrs = cctx->naddrs; + } + + ngx_resolve_name_done(cctx); + + if (ctx->count == 0) { + ngx_resolver_report_srv(r, ctx); + } +} + + static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan) @@ -2541,6 +3221,7 @@ valid: while (next) { ctx = next; ctx->state = code; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); next = ctx->next; ctx->handler(ctx); @@ -2675,6 +3356,7 @@ ptr: while (next) { ctx = next; ctx->state = NGX_OK; + ctx->valid = rn->valid; ctx->name = name; next = ctx->next; @@ -2746,6 +3428,47 @@ ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash) } +static ngx_resolver_node_t * +ngx_resolver_lookup_srv(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash) +{ + ngx_int_t rc; + ngx_rbtree_node_t *node, *sentinel; + ngx_resolver_node_t *rn; + + node = r->srv_rbtree.root; + sentinel = r->srv_rbtree.sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + rn = ngx_resolver_node(node); + + rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen); + + if (rc == 0) { + return rn; + } + + node = (rc < 0) ? node->left : node->right; + } + + /* not found */ + + return NULL; +} + + static ngx_resolver_node_t * ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr) { @@ -3033,9 +3756,97 @@ ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, } +static ngx_int_t +ngx_resolver_create_srv_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, + ngx_str_t *name) +{ + u_char *p, *s; + size_t len, nlen; + ngx_uint_t ident; + ngx_resolver_qs_t *qs; + ngx_resolver_hdr_t *query; + + nlen = name->len ? (1 + name->len + 1) : 1; + + len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t); + + p = ngx_resolver_alloc(r, len); + if (p == NULL) { + return NGX_ERROR; + } + + rn->qlen = (u_short) len; + rn->query = p; + + query = (ngx_resolver_hdr_t *) p; + + ident = ngx_random(); + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolve: \"%V\" SRV %i", name, ident & 0xffff); + + query->ident_hi = (u_char) ((ident >> 8) & 0xff); + query->ident_lo = (u_char) (ident & 0xff); + + /* recursion query */ + query->flags_hi = 1; query->flags_lo = 0; + + /* one question */ + query->nqs_hi = 0; query->nqs_lo = 1; + query->nan_hi = 0; query->nan_lo = 0; + query->nns_hi = 0; query->nns_lo = 0; + query->nar_hi = 0; query->nar_lo = 0; + + p += sizeof(ngx_resolver_hdr_t) + nlen; + + qs = (ngx_resolver_qs_t *) p; + + /* query type */ + qs->type_hi = 0; qs->type_lo = NGX_RESOLVE_SRV; + + /* IN query class */ + qs->class_hi = 0; qs->class_lo = 1; + + /* converts "www.example.com" to "\3www\7example\3com\0" */ + + len = 0; + p--; + *p-- = '\0'; + + if (name->len == 0) { + return NGX_DECLINED; + } + + for (s = name->data + name->len - 1; s >= name->data; s--) { + if (*s != '.') { + *p = *s; + len++; + + } else { + if (len == 0 || len > 255) { + return NGX_DECLINED; + } + + *p = (u_char) len; + len = 0; + } + + p--; + } + + if (len == 0 || len > 255) { + return NGX_DECLINED; + } + + *p = (u_char) len; + + return NGX_OK; +} + + static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, - ngx_addr_t *addr) + ngx_resolver_addr_t *addr) { u_char *p, *d; size_t len; @@ -3239,6 +4050,8 @@ ngx_resolver_timeout_handler(ngx_event_t *ev) static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn) { + ngx_uint_t i; + /* lock alloc mutex */ if (rn->query) { @@ -3263,6 +4076,16 @@ ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn) } #endif + if (rn->nsrvs) { + for (i = 0; i < rn->nsrvs; i++) { + if (rn->u.srvs[i].name.data) { + ngx_resolver_free_locked(r, rn->u.srvs[i].name.data); + } + } + + ngx_resolver_free_locked(r, rn->u.srvs); + } + ngx_resolver_free_locked(r, rn); /* unlock alloc mutex */ @@ -3334,15 +4157,15 @@ ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size) } -static ngx_addr_t * +static ngx_resolver_addr_t * ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn, ngx_uint_t rotate) { - ngx_addr_t *dst; ngx_uint_t d, i, j, n; u_char (*sockaddr)[NGX_SOCKADDRLEN]; in_addr_t *addr; struct sockaddr_in *sin; + ngx_resolver_addr_t *dst; #if (NGX_HAVE_INET6) struct in6_addr *addr6; struct sockaddr_in6 *sin6; @@ -3353,7 +4176,7 @@ ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn, n += rn->naddrs6; #endif - dst = ngx_resolver_calloc(r, n * sizeof(ngx_addr_t)); + dst = ngx_resolver_calloc(r, n * sizeof(ngx_resolver_addr_t)); if (dst == NULL) { return NULL; } @@ -3417,6 +4240,99 @@ ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn, } +static void +ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) +{ + ngx_uint_t naddrs, nsrvs, nw, i, j, k, l, m, n, w; + ngx_resolver_addr_t *addrs; + ngx_resolver_srv_name_t *srvs; + + naddrs = 0; + + for (i = 0; i < ctx->nsrvs; i++) { + naddrs += ctx->srvs[i].naddrs; + } + + if (naddrs == 0) { + ctx->state = NGX_RESOLVE_NXDOMAIN; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); + + ctx->handler(ctx); + return; + } + + addrs = ngx_resolver_calloc(r, naddrs * sizeof(ngx_resolver_addr_t)); + if (addrs == NULL) { + ctx->state = NGX_ERROR; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); + + ctx->handler(ctx); + return; + } + + srvs = ctx->srvs; + nsrvs = ctx->nsrvs; + + i = 0; + n = 0; + + do { + nw = 0; + + for (j = i; j < nsrvs; j++) { + if (srvs[j].priority != srvs[i].priority) { + break; + } + + nw += srvs[j].naddrs * srvs[j].weight; + } + + if (nw == 0) { + goto next_srv; + } + + w = ngx_random() % nw; + + for (k = i; k < j; k++) { + if (w < srvs[k].naddrs * srvs[k].weight) { + break; + } + + w -= srvs[k].naddrs * srvs[k].weight; + } + + for (l = i; l < j; l++) { + + for (m = 0; m < srvs[k].naddrs; m++) { + addrs[n].socklen = srvs[k].addrs[m].socklen; + addrs[n].sockaddr = srvs[k].addrs[m].sockaddr; + addrs[n].name = srvs[k].name; + addrs[n].priority = srvs[k].priority; + addrs[n].weight = srvs[k].weight; + n++; + } + + if (++k == j) { + k = i; + } + } + +next_srv: + + i = j; + + } while (i < ctx->nsrvs); + + ctx->state = NGX_OK; + ctx->addrs = addrs; + ctx->naddrs = naddrs; + + ctx->handler(ctx); + + ngx_resolver_free(r, addrs); +} + + char * ngx_resolver_strerror(ngx_int_t err) { @@ -3728,3 +4644,19 @@ failed: return NGX_ERROR; } + + +static ngx_int_t +ngx_resolver_cmp_srvs(const void *one, const void *two) +{ + ngx_int_t p1, p2; + ngx_resolver_srv_t *first, *second; + + first = (ngx_resolver_srv_t *) one; + second = (ngx_resolver_srv_t *) two; + + p1 = first->priority; + p2 = second->priority; + + return p1 - p2; +} diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h index 3165abd..e36cfdc 100644 --- a/src/core/ngx_resolver.h +++ b/src/core/ngx_resolver.h @@ -21,6 +21,7 @@ #if (NGX_HAVE_INET6) #define NGX_RESOLVE_AAAA 28 #endif +#define NGX_RESOLVE_SRV 33 #define NGX_RESOLVE_DNAME 39 #define NGX_RESOLVE_FORMERR 1 @@ -57,6 +58,36 @@ typedef struct ngx_resolver_ctx_s ngx_resolver_ctx_t; typedef void (*ngx_resolver_handler_pt)(ngx_resolver_ctx_t *ctx); +typedef struct { + struct sockaddr *sockaddr; + socklen_t socklen; + ngx_str_t name; + u_short priority; + u_short weight; +} ngx_resolver_addr_t; + + +typedef struct { + ngx_str_t name; + u_short priority; + u_short weight; + u_short port; +} ngx_resolver_srv_t; + + +typedef struct { + ngx_str_t name; + u_short priority; + u_short weight; + u_short port; + + ngx_resolver_ctx_t *ctx; + + ngx_uint_t naddrs; + ngx_addr_t *addrs; +} ngx_resolver_srv_name_t; + + typedef struct { ngx_rbtree_node_t node; ngx_queue_t queue; @@ -81,10 +112,12 @@ typedef struct { in_addr_t addr; in_addr_t *addrs; u_char *cname; + ngx_resolver_srv_t *srvs; } u; u_char code; u_short naddrs; + u_short nsrvs; u_short cnlen; #if (NGX_HAVE_INET6) @@ -127,13 +160,18 @@ struct ngx_resolver_s { ngx_rbtree_t name_rbtree; ngx_rbtree_node_t name_sentinel; + ngx_rbtree_t srv_rbtree; + ngx_rbtree_node_t srv_sentinel; + ngx_rbtree_t addr_rbtree; ngx_rbtree_node_t addr_sentinel; ngx_queue_t name_resend_queue; + ngx_queue_t srv_resend_queue; ngx_queue_t addr_resend_queue; ngx_queue_t name_expire_queue; + ngx_queue_t srv_expire_queue; ngx_queue_t addr_expire_queue; #if (NGX_HAVE_INET6) @@ -163,12 +201,18 @@ struct ngx_resolver_ctx_s { ngx_int_t state; ngx_str_t name; + ngx_str_t service; + time_t valid; ngx_uint_t naddrs; - ngx_addr_t *addrs; - ngx_addr_t addr; + ngx_resolver_addr_t *addrs; + ngx_resolver_addr_t addr; struct sockaddr_in sin; + ngx_uint_t count; + ngx_uint_t nsrvs; + ngx_resolver_srv_name_t *srvs; + ngx_resolver_handler_pt handler; void *data; ngx_msec_t timeout; diff --git a/src/event/modules/ngx_devpoll_module.c b/src/event/modules/ngx_devpoll_module.c index fa8aebd..f985fbd 100644 --- a/src/event/modules/ngx_devpoll_module.c +++ b/src/event/modules/ngx_devpoll_module.c @@ -14,7 +14,9 @@ /* Solaris declarations */ +#ifndef POLLREMOVE #define POLLREMOVE 0x0800 +#endif #define DP_POLL 0xD001 #define DP_ISPOLLED 0xD002 @@ -436,7 +438,7 @@ ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, default: ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - "unexpected event %04Xd for closed and removed socket %d, ", + "unexpected event %04Xd for closed and removed socket %d, " "ioctl(DP_ISPOLLED) returned rc:%d, fd:%d, event %04Xd", revents, fd, rc, pfd.fd, pfd.revents); diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c index d7f915d..081b0e5 100644 --- a/src/event/modules/ngx_epoll_module.c +++ b/src/event/modules/ngx_epoll_module.c @@ -840,6 +840,9 @@ ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) } wev->ready = 1; +#if (NGX_THREADS) + wev->complete = 1; +#endif if (flags & NGX_POST_EVENTS) { ngx_post_event(wev, &ngx_posted_events); diff --git a/src/event/modules/ngx_eventport_module.c b/src/event/modules/ngx_eventport_module.c index bacbb05..9184547 100644 --- a/src/event/modules/ngx_eventport_module.c +++ b/src/event/modules/ngx_eventport_module.c @@ -49,7 +49,7 @@ typedef struct port_notify { void *portnfy_user; /* user defined */ } port_notify_t; -#if (__FreeBSD_version < 700005) +#if (__FreeBSD__) && (__FreeBSD_version < 700005) typedef struct itimerspec { /* definition per POSIX.4 */ struct timespec it_interval;/* timer period */ diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index 955622b..38f9b38 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -746,6 +746,7 @@ ngx_event_process_init(ngx_cycle_t *cycle) return NGX_ERROR; } + c->type = ls[i].type; c->log = &ls[i].log; c->listening = &ls[i]; @@ -818,7 +819,8 @@ ngx_event_process_init(ngx_cycle_t *cycle) #else - rev->handler = ngx_event_accept; + rev->handler = (c->type == SOCK_STREAM) ? ngx_event_accept + : ngx_event_recvmsg; if (ngx_use_accept_mutex #if (NGX_HAVE_REUSEPORT) @@ -1206,7 +1208,7 @@ ngx_event_core_init_conf(ngx_cycle_t *cycle, void *conf) #endif -#if (NGX_HAVE_DEVPOLL) +#if (NGX_HAVE_DEVPOLL) && !(NGX_TEST_BUILD_DEVPOLL) module = &ngx_devpoll_module; diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index 855c58d..591005a 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -343,7 +343,8 @@ extern ngx_event_actions_t ngx_event_actions; #define NGX_DISABLE_EVENT EV_DISABLE -#elif (NGX_HAVE_DEVPOLL || NGX_HAVE_EVENTPORT) +#elif (NGX_HAVE_DEVPOLL && !(NGX_TEST_BUILD_DEVPOLL)) \ + || (NGX_HAVE_EVENTPORT && !(NGX_TEST_BUILD_EVENTPORT)) #define NGX_READ_EVENT POLLIN #define NGX_WRITE_EVENT POLLOUT @@ -352,7 +353,7 @@ extern ngx_event_actions_t ngx_event_actions; #define NGX_ONESHOT_EVENT 1 -#elif (NGX_HAVE_EPOLL) +#elif (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL) #define NGX_READ_EVENT (EPOLLIN|EPOLLRDHUP) #define NGX_WRITE_EVENT EPOLLOUT @@ -418,6 +419,7 @@ extern ngx_os_io_t ngx_io; #define ngx_udp_recv ngx_io.udp_recv #define ngx_send ngx_io.send #define ngx_send_chain ngx_io.send_chain +#define ngx_udp_send ngx_io.udp_send #define NGX_EVENT_MODULE 0x544E5645 /* "EVNT" */ @@ -491,6 +493,9 @@ extern ngx_module_t ngx_event_core_module; void ngx_event_accept(ngx_event_t *ev); +#if !(NGX_WIN32) +void ngx_event_recvmsg(ngx_event_t *ev); +#endif ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle); u_char *ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len); diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index 8888f5a..1c87a34 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -13,6 +13,10 @@ static ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle); static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all); static void ngx_close_accepted_connection(ngx_connection_t *c); +#if (NGX_DEBUG) +static void ngx_debug_accepted_connection(ngx_event_conf_t *ecf, + ngx_connection_t *c); +#endif void @@ -149,6 +153,8 @@ ngx_event_accept(ngx_event_t *ev) return; } + c->type = SOCK_STREAM; + #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, 1); #endif @@ -276,60 +282,10 @@ ngx_event_accept(ngx_event_t *ev) #if (NGX_DEBUG) { + ngx_str_t addr; + u_char text[NGX_SOCKADDR_STRLEN]; - ngx_str_t addr; - struct sockaddr_in *sin; - ngx_cidr_t *cidr; - ngx_uint_t i; - u_char text[NGX_SOCKADDR_STRLEN]; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; - ngx_uint_t n; -#endif - - cidr = ecf->debug_connection.elts; - for (i = 0; i < ecf->debug_connection.nelts; i++) { - if (cidr[i].family != (ngx_uint_t) c->sockaddr->sa_family) { - goto next; - } - - switch (cidr[i].family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) c->sockaddr; - for (n = 0; n < 16; n++) { - if ((sin6->sin6_addr.s6_addr[n] - & cidr[i].u.in6.mask.s6_addr[n]) - != cidr[i].u.in6.addr.s6_addr[n]) - { - goto next; - } - } - break; -#endif - -#if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - break; -#endif - - default: /* AF_INET */ - sin = (struct sockaddr_in *) c->sockaddr; - if ((sin->sin_addr.s_addr & cidr[i].u.in.mask) - != cidr[i].u.in.addr) - { - goto next; - } - break; - } - - log->log_level = NGX_LOG_DEBUG_CONNECTION|NGX_LOG_DEBUG_ALL; - break; - - next: - continue; - } + ngx_debug_accepted_connection(ecf, c); if (log->log_level & NGX_LOG_DEBUG_EVENT) { addr.data = text; @@ -363,6 +319,324 @@ ngx_event_accept(ngx_event_t *ev) } +#if !(NGX_WIN32) + +void +ngx_event_recvmsg(ngx_event_t *ev) +{ + ssize_t n; + ngx_log_t *log; + ngx_err_t err; + ngx_event_t *rev, *wev; + struct iovec iov[1]; + struct msghdr msg; + ngx_listening_t *ls; + ngx_event_conf_t *ecf; + ngx_connection_t *c, *lc; + u_char sa[NGX_SOCKADDRLEN]; + static u_char buffer[65535]; + +#if (NGX_HAVE_MSGHDR_MSG_CONTROL) + +#if (NGX_HAVE_IP_RECVDSTADDR) + u_char msg_control[CMSG_SPACE(sizeof(struct in_addr))]; +#elif (NGX_HAVE_IP_PKTINFO) + u_char msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))]; +#endif + +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + u_char msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; +#endif + +#endif + + if (ev->timedout) { + if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) { + return; + } + + ev->timedout = 0; + } + + ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module); + + if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) { + ev->available = ecf->multi_accept; + } + + lc = ev->data; + ls = lc->listening; + ev->ready = 0; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "recvmsg on %V, ready: %d", &ls->addr_text, ev->available); + + do { + ngx_memzero(&msg, sizeof(struct msghdr)); + + iov[0].iov_base = (void *) buffer; + iov[0].iov_len = sizeof(buffer); + + msg.msg_name = &sa; + msg.msg_namelen = sizeof(sa); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + +#if (NGX_HAVE_MSGHDR_MSG_CONTROL) + + if (ls->wildcard) { + +#if (NGX_HAVE_IP_RECVDSTADDR || NGX_HAVE_IP_PKTINFO) + if (ls->sockaddr->sa_family == AF_INET) { + msg.msg_control = &msg_control; + msg.msg_controllen = sizeof(msg_control); + } +#endif + +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + if (ls->sockaddr->sa_family == AF_INET6) { + msg.msg_control = &msg_control6; + msg.msg_controllen = sizeof(msg_control6); + } +#endif + } + +#endif + + n = recvmsg(lc->fd, &msg, 0); + + if (n == -1) { + err = ngx_socket_errno; + + if (err == NGX_EAGAIN) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err, + "recvmsg() not ready"); + return; + } + + ngx_log_error(NGX_LOG_ALERT, ev->log, err, "recvmsg() failed"); + + return; + } + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1); +#endif + +#if (NGX_HAVE_MSGHDR_MSG_CONTROL) + if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "recvmsg() truncated data"); + continue; + } +#endif + + ngx_accept_disabled = ngx_cycle->connection_n / 8 + - ngx_cycle->free_connection_n; + + c = ngx_get_connection(lc->fd, ev->log); + if (c == NULL) { + return; + } + + c->shared = 1; + c->type = SOCK_DGRAM; + c->socklen = msg.msg_namelen; + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_active, 1); +#endif + + c->pool = ngx_create_pool(ls->pool_size, ev->log); + if (c->pool == NULL) { + ngx_close_accepted_connection(c); + return; + } + + c->sockaddr = ngx_palloc(c->pool, c->socklen); + if (c->sockaddr == NULL) { + ngx_close_accepted_connection(c); + return; + } + + ngx_memcpy(c->sockaddr, msg.msg_name, c->socklen); + + log = ngx_palloc(c->pool, sizeof(ngx_log_t)); + if (log == NULL) { + ngx_close_accepted_connection(c); + return; + } + + *log = ls->log; + + c->send = ngx_udp_send; + + c->log = log; + c->pool->log = log; + + c->listening = ls; + c->local_sockaddr = ls->sockaddr; + c->local_socklen = ls->socklen; + +#if (NGX_HAVE_MSGHDR_MSG_CONTROL) + + if (ls->wildcard) { + struct cmsghdr *cmsg; + struct sockaddr *sockaddr; + + sockaddr = ngx_palloc(c->pool, c->local_socklen); + if (sockaddr == NULL) { + ngx_close_accepted_connection(c); + return; + } + + ngx_memcpy(sockaddr, c->local_sockaddr, c->local_socklen); + c->local_sockaddr = sockaddr; + + for (cmsg = CMSG_FIRSTHDR(&msg); + cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) + { + +#if (NGX_HAVE_IP_RECVDSTADDR) + + if (cmsg->cmsg_level == IPPROTO_IP + && cmsg->cmsg_type == IP_RECVDSTADDR + && sockaddr->sa_family == AF_INET) + { + struct in_addr *addr; + struct sockaddr_in *sin; + + addr = (struct in_addr *) CMSG_DATA(cmsg); + sin = (struct sockaddr_in *) sockaddr; + sin->sin_addr = *addr; + + break; + } + +#elif (NGX_HAVE_IP_PKTINFO) + + if (cmsg->cmsg_level == IPPROTO_IP + && cmsg->cmsg_type == IP_PKTINFO + && sockaddr->sa_family == AF_INET) + { + struct in_pktinfo *pkt; + struct sockaddr_in *sin; + + pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); + sin = (struct sockaddr_in *) sockaddr; + sin->sin_addr = pkt->ipi_addr; + + break; + } + +#endif + +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + + if (cmsg->cmsg_level == IPPROTO_IPV6 + && cmsg->cmsg_type == IPV6_PKTINFO + && sockaddr->sa_family == AF_INET6) + { + struct in6_pktinfo *pkt6; + struct sockaddr_in6 *sin6; + + pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); + sin6 = (struct sockaddr_in6 *) sockaddr; + sin6->sin6_addr = pkt6->ipi6_addr; + + break; + } + +#endif + + } + } + +#endif + + c->buffer = ngx_create_temp_buf(c->pool, n); + if (c->buffer == NULL) { + ngx_close_accepted_connection(c); + return; + } + + c->buffer->last = ngx_cpymem(c->buffer->last, buffer, n); + + rev = c->read; + wev = c->write; + + wev->ready = 1; + + rev->log = log; + wev->log = log; + + /* + * TODO: MT: - ngx_atomic_fetch_add() + * or protection by critical section or light mutex + * + * TODO: MP: - allocated in a shared memory + * - ngx_atomic_fetch_add() + * or protection by critical section or light mutex + */ + + c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_handled, 1); +#endif + + if (ls->addr_ntop) { + c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len); + if (c->addr_text.data == NULL) { + ngx_close_accepted_connection(c); + return; + } + + c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen, + c->addr_text.data, + ls->addr_text_max_len, 0); + if (c->addr_text.len == 0) { + ngx_close_accepted_connection(c); + return; + } + } + +#if (NGX_DEBUG) + { + ngx_str_t addr; + u_char text[NGX_SOCKADDR_STRLEN]; + + ngx_debug_accepted_connection(ecf, c); + + if (log->log_level & NGX_LOG_DEBUG_EVENT) { + addr.data = text; + addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text, + NGX_SOCKADDR_STRLEN, 1); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0, + "*%uA recvmsg: %V fd:%d n:%z", + c->number, &addr, c->fd, n); + } + + } +#endif + + log->data = NULL; + log->handler = NULL; + + ls->handler(c); + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + ev->available -= n; + } + + } while (ev->available); +} + +#endif + + ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle) { @@ -476,7 +750,7 @@ ngx_close_accepted_connection(ngx_connection_t *c) fd = c->fd; c->fd = (ngx_socket_t) -1; - if (ngx_close_socket(fd) == -1) { + if (!c->shared && ngx_close_socket(fd) == -1) { ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, ngx_close_socket_n " failed"); } @@ -497,3 +771,64 @@ ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len) return ngx_snprintf(buf, len, " while accepting new connection on %V", log->data); } + + +#if (NGX_DEBUG) + +static void +ngx_debug_accepted_connection(ngx_event_conf_t *ecf, ngx_connection_t *c) +{ + struct sockaddr_in *sin; + ngx_cidr_t *cidr; + ngx_uint_t i; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; + ngx_uint_t n; +#endif + + cidr = ecf->debug_connection.elts; + for (i = 0; i < ecf->debug_connection.nelts; i++) { + if (cidr[i].family != (ngx_uint_t) c->sockaddr->sa_family) { + goto next; + } + + switch (cidr[i].family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) c->sockaddr; + for (n = 0; n < 16; n++) { + if ((sin6->sin6_addr.s6_addr[n] + & cidr[i].u.in6.mask.s6_addr[n]) + != cidr[i].u.in6.addr.s6_addr[n]) + { + goto next; + } + } + break; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) c->sockaddr; + if ((sin->sin_addr.s_addr & cidr[i].u.in.mask) + != cidr[i].u.in.addr) + { + goto next; + } + break; + } + + c->log->log_level = NGX_LOG_DEBUG_CONNECTION|NGX_LOG_DEBUG_ALL; + break; + + next: + continue; + } +} + +#endif diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c index 1186958..8aca862 100644 --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -14,7 +14,7 @@ ngx_int_t ngx_event_connect_peer(ngx_peer_connection_t *pc) { - int rc; + int rc, type; ngx_int_t event; ngx_err_t err; ngx_uint_t level; @@ -27,9 +27,12 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc) return rc; } - s = ngx_socket(pc->sockaddr->sa_family, SOCK_STREAM, 0); + type = (pc->type ? pc->type : SOCK_STREAM); - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, "socket %d", s); + s = ngx_socket(pc->sockaddr->sa_family, type, 0); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, "%s socket %d", + (type == SOCK_STREAM) ? "stream" : "dgram", s); if (s == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, @@ -49,6 +52,8 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc) return NGX_ERROR; } + c->type = type; + if (pc->rcvbuf) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (const void *) &pc->rcvbuf, sizeof(int)) == -1) @@ -75,25 +80,31 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc) } } - c->recv = ngx_recv; - c->send = ngx_send; - c->recv_chain = ngx_recv_chain; - c->send_chain = ngx_send_chain; + if (type == SOCK_STREAM) { + c->recv = ngx_recv; + c->send = ngx_send; + c->recv_chain = ngx_recv_chain; + c->send_chain = ngx_send_chain; - c->sendfile = 1; + c->sendfile = 1; - c->log_error = pc->log_error; - - if (pc->sockaddr->sa_family == AF_UNIX) { - c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; - c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; + if (pc->sockaddr->sa_family == AF_UNIX) { + c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; + c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; #if (NGX_SOLARIS) - /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */ - c->sendfile = 0; + /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */ + c->sendfile = 0; #endif + } + + } else { /* type == SOCK_DGRAM */ + c->recv = ngx_udp_recv; + c->send = ngx_send; } + c->log_error = pc->log_error; + rev = c->read; wev = c->write; diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h index ed18db7..1bacf82 100644 --- a/src/event/ngx_event_connect.h +++ b/src/event/ngx_event_connect.h @@ -55,6 +55,7 @@ struct ngx_peer_connection_s { ngx_addr_t *local; + int type; int rcvbuf; ngx_log_t *log; diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c index 2d0e7d3..ee86c7e 100644 --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -112,6 +112,14 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) return NGX_OK; } +#if (NGX_THREADS) + if (p->aio) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, + "pipe read upstream: aio"); + return NGX_AGAIN; + } +#endif + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe read upstream: %d", p->upstream->read->ready); @@ -258,19 +266,6 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) break; } - if (rc == NGX_AGAIN) { - if (ngx_event_flags & NGX_USE_LEVEL_EVENT - && p->upstream->read->active - && p->upstream->read->ready) - { - if (ngx_del_event(p->upstream->read, NGX_READ_EVENT, 0) - == NGX_ERROR) - { - return NGX_ABORT; - } - } - } - if (rc != NGX_OK) { return rc; } @@ -475,8 +470,10 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write chain"); - if (ngx_event_pipe_write_chain_to_temp_file(p) == NGX_ABORT) { - return NGX_ABORT; + rc = ngx_event_pipe_write_chain_to_temp_file(p); + + if (rc != NGX_OK) { + return rc; } } @@ -499,6 +496,18 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p) ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write downstream: %d", downstream->write->ready); +#if (NGX_THREADS) + + if (p->writing) { + rc = ngx_event_pipe_write_chain_to_temp_file(p); + + if (rc == NGX_ABORT) { + return NGX_ABORT; + } + } + +#endif + flushed = 0; for ( ;; ) { @@ -532,6 +541,10 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p) p->out = NULL; } + if (p->writing) { + break; + } + if (p->in) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write downstream flush in"); @@ -608,7 +621,7 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p) p->out = p->out->next; - } else if (!p->cacheable && p->in) { + } else if (!p->cacheable && !p->writing && p->in) { cl = p->in; ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0, @@ -710,12 +723,38 @@ ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p) ssize_t size, bsize, n; ngx_buf_t *b; ngx_uint_t prev_last_shadow; - ngx_chain_t *cl, *tl, *next, *out, **ll, **last_out, **last_free, fl; + ngx_chain_t *cl, *tl, *next, *out, **ll, **last_out, **last_free; + +#if (NGX_THREADS) + + if (p->writing) { + + if (p->aio) { + return NGX_AGAIN; + } + + out = p->writing; + p->writing = NULL; + + n = ngx_write_chain_to_temp_file(p->temp_file, NULL); + + if (n == NGX_ERROR) { + return NGX_ABORT; + } + + goto done; + } + +#endif if (p->buf_to_file) { - fl.buf = p->buf_to_file; - fl.next = p->in; - out = &fl; + out = ngx_alloc_chain_link(p->pool); + if (out == NULL) { + return NGX_ABORT; + } + + out->buf = p->buf_to_file; + out->next = p->in; } else { out = p->in; @@ -775,12 +814,31 @@ ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p) p->last_in = &p->in; } +#if (NGX_THREADS) + p->temp_file->thread_write = p->thread_handler ? 1 : 0; + p->temp_file->file.thread_task = p->thread_task; + p->temp_file->file.thread_handler = p->thread_handler; + p->temp_file->file.thread_ctx = p->thread_ctx; +#endif + n = ngx_write_chain_to_temp_file(p->temp_file, out); if (n == NGX_ERROR) { return NGX_ABORT; } +#if (NGX_THREADS) + + if (n == NGX_AGAIN) { + p->writing = out; + p->thread_task = p->temp_file->file.thread_task; + return NGX_AGAIN; + } + +done: + +#endif + 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; diff --git a/src/event/ngx_event_pipe.h b/src/event/ngx_event_pipe.h index 451fc4c..ef2e7a0 100644 --- a/src/event/ngx_event_pipe.h +++ b/src/event/ngx_event_pipe.h @@ -30,6 +30,8 @@ struct ngx_event_pipe_s { ngx_chain_t *in; ngx_chain_t **last_in; + ngx_chain_t *writing; + ngx_chain_t *out; ngx_chain_t *free; ngx_chain_t *busy; @@ -45,6 +47,13 @@ struct ngx_event_pipe_s { ngx_event_pipe_output_filter_pt output_filter; void *output_ctx; +#if (NGX_THREADS) + ngx_int_t (*thread_handler)(ngx_thread_task_t *task, + ngx_file_t *file); + void *thread_ctx; + ngx_thread_task_t *thread_task; +#endif + unsigned read:1; unsigned cacheable:1; unsigned single_buf:1; @@ -56,6 +65,7 @@ struct ngx_event_pipe_s { unsigned downstream_done:1; unsigned downstream_error:1; unsigned cyclic_temp_file:1; + unsigned aio:1; ngx_int_t allocated; ngx_bufs_t bufs; diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index dbd7767..e3024b3 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -206,6 +206,7 @@ static ngx_conf_bitmask_t ngx_http_fastcgi_next_upstream_masks[] = { { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, + { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT }, { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 }, diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index a869e74..5005b6b 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -213,6 +213,7 @@ static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = { { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, + { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT }, { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 }, { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index 76c7786..b468eb7 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -77,6 +77,7 @@ static ngx_conf_bitmask_t ngx_http_scgi_next_upstream_masks[] = { { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, + { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT }, { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 }, diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c index 8ba75ed..7bf6e19 100644 --- a/src/http/modules/ngx_http_sub_filter_module.c +++ b/src/http/modules/ngx_http_sub_filter_module.c @@ -229,7 +229,7 @@ ngx_http_sub_header_filter(ngx_http_request_t *r) return ngx_http_next_header_filter(r); } - ctx->matches = ngx_pnalloc(r->pool, sizeof(ngx_array_t)); + ctx->matches = ngx_palloc(r->pool, sizeof(ngx_array_t)); if (ctx->matches == NULL) { return NGX_ERROR; } @@ -237,7 +237,7 @@ ngx_http_sub_header_filter(ngx_http_request_t *r) ctx->matches->elts = matches; ctx->matches->nelts = j; - ctx->tables = ngx_pnalloc(r->pool, sizeof(ngx_http_sub_tables_t)); + ctx->tables = ngx_palloc(r->pool, sizeof(ngx_http_sub_tables_t)); if (ctx->tables == NULL) { return NGX_ERROR; } @@ -859,7 +859,7 @@ ngx_http_sub_merge_conf(ngx_conf_t *cf, void *parent, void *child) pairs = conf->pairs->elts; n = conf->pairs->nelts; - matches = ngx_pnalloc(cf->pool, sizeof(ngx_http_sub_match_t) * n); + matches = ngx_palloc(cf->pool, sizeof(ngx_http_sub_match_t) * n); if (matches == NULL) { return NGX_CONF_ERROR; } @@ -869,7 +869,7 @@ ngx_http_sub_merge_conf(ngx_conf_t *cf, void *parent, void *child) matches[i].value = &pairs[i].value; } - conf->matches = ngx_pnalloc(cf->pool, sizeof(ngx_array_t)); + conf->matches = ngx_palloc(cf->pool, sizeof(ngx_array_t)); if (conf->matches == NULL) { return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index 0313dfa..fef2c46 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -109,6 +109,7 @@ static ngx_conf_bitmask_t ngx_http_uwsgi_next_upstream_masks[] = { { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, + { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT }, { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 }, diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h index d36fa77..2667cbb 100644 --- a/src/http/ngx_http_cache.h +++ b/src/http/ngx_http_cache.h @@ -138,6 +138,8 @@ typedef struct { ngx_atomic_t cold; ngx_atomic_t loading; off_t size; + ngx_uint_t count; + ngx_uint_t watermark; } ngx_http_file_cache_sh_t; @@ -153,6 +155,8 @@ struct ngx_http_file_cache_s { time_t inactive; + time_t fail_time; + ngx_uint_t files; ngx_uint_t loader_files; ngx_msec_t last; diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c index c6d03ee..c696fb6 100644 --- a/src/http/ngx_http_copy_filter_module.c +++ b/src/http/ngx_http_copy_filter_module.c @@ -204,10 +204,11 @@ ngx_http_copy_aio_event_handler(ngx_event_t *ev) static ssize_t ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file) { - ssize_t n; - static u_char buf[1]; - ngx_event_aio_t *aio; - ngx_http_request_t *r; + ssize_t n; + static u_char buf[1]; + ngx_event_aio_t *aio; + ngx_http_request_t *r; + ngx_output_chain_ctx_t *ctx; n = ngx_file_aio_read(file->file, buf, 1, file->file_pos, NULL); @@ -218,6 +219,9 @@ ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file) r = aio->data; r->main->blocked++; r->aio = 1; + + ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); + ctx->aio = 1; } return n; @@ -252,6 +256,7 @@ ngx_http_copy_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) ngx_str_t name; ngx_thread_pool_t *tp; ngx_http_request_t *r; + ngx_output_chain_ctx_t *ctx; ngx_http_core_loc_conf_t *clcf; r = file->thread_ctx; @@ -285,6 +290,9 @@ ngx_http_copy_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) r->main->blocked++; r->aio = 1; + ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); + ctx->aio = 1; + return NGX_OK; } diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index df7e8d4..b88e869 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -400,6 +400,13 @@ static ngx_command_t ngx_http_core_commands[] = { 0, NULL }, + { ngx_string("aio_write"), + 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_core_loc_conf_t, aio_write), + NULL }, + { ngx_string("read_ahead"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, @@ -3606,6 +3613,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf) clcf->sendfile = NGX_CONF_UNSET; clcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE; clcf->aio = NGX_CONF_UNSET; + clcf->aio_write = NGX_CONF_UNSET; #if (NGX_THREADS) clcf->thread_pool = NGX_CONF_UNSET_PTR; clcf->thread_pool_value = NGX_CONF_UNSET_PTR; @@ -3827,6 +3835,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->sendfile_max_chunk, 0); #if (NGX_HAVE_FILE_AIO || NGX_THREADS) ngx_conf_merge_value(conf->aio, prev->aio, NGX_HTTP_AIO_OFF); + ngx_conf_merge_value(conf->aio_write, prev->aio_write, 0); #endif #if (NGX_THREADS) ngx_conf_merge_ptr_value(conf->thread_pool, prev->thread_pool, NULL); diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 7dec9e1..231c507 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -404,6 +404,7 @@ struct ngx_http_core_loc_conf_s { ngx_flag_t internal; /* internal */ ngx_flag_t sendfile; /* sendfile */ ngx_flag_t aio; /* aio */ + ngx_flag_t aio_write; /* aio_write */ ngx_flag_t tcp_nopush; /* tcp_nopush */ ngx_flag_t tcp_nodelay; /* tcp_nodelay */ ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */ diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index 6633918..3561028 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -62,6 +62,7 @@ static ngx_int_t ngx_http_file_cache_add(ngx_http_file_cache_t *cache, ngx_http_cache_t *c); static ngx_int_t ngx_http_file_cache_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path); +static void ngx_http_file_cache_set_watermark(ngx_http_file_cache_t *cache); ngx_str_t ngx_http_cache_status[] = { @@ -147,6 +148,8 @@ ngx_http_file_cache_init(ngx_shm_zone_t *shm_zone, void *data) cache->sh->cold = 1; cache->sh->loading = 0; cache->sh->size = 0; + cache->sh->count = 0; + cache->sh->watermark = (ngx_uint_t) -1; cache->bsize = ngx_fs_bsize(cache->path->name.data); @@ -691,12 +694,13 @@ ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c) #if (NGX_THREADS) if (clcf->aio == NGX_HTTP_AIO_THREADS) { + c->file.thread_task = c->thread_task; c->file.thread_handler = ngx_http_cache_thread_handler; c->file.thread_ctx = r; - n = ngx_thread_read(&c->thread_task, &c->file, c->buf->pos, - c->body_start, 0, r->pool); + n = ngx_thread_read(&c->file, c->buf->pos, c->body_start, 0, r->pool); + c->thread_task = c->file.thread_task; c->reading = (n == NGX_AGAIN); return n; @@ -860,6 +864,8 @@ ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) fcn = ngx_slab_calloc_locked(cache->shpool, sizeof(ngx_http_file_cache_node_t)); if (fcn == NULL) { + ngx_http_file_cache_set_watermark(cache); + ngx_shmtx_unlock(&cache->shpool->mutex); (void) ngx_http_file_cache_forced_expire(cache); @@ -876,6 +882,8 @@ ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) } } + cache->sh->count++; + ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t)); ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)], @@ -1630,6 +1638,7 @@ ngx_http_file_cache_free(ngx_http_cache_t *c, ngx_temp_file_t *tf) ngx_queue_remove(&fcn->queue); ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node); ngx_slab_free_locked(cache->shpool, fcn); + cache->sh->count--; c->node = NULL; } @@ -1882,6 +1891,7 @@ ngx_http_file_cache_delete(ngx_http_file_cache_t *cache, ngx_queue_t *q, ngx_queue_remove(q); ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node); ngx_slab_free_locked(cache->shpool, fcn); + cache->sh->count--; } } @@ -1891,8 +1901,9 @@ ngx_http_file_cache_manager(void *data) { ngx_http_file_cache_t *cache = data; - off_t size; - time_t next, wait; + off_t size; + time_t next, wait; + ngx_uint_t count, watermark; next = ngx_http_file_cache_expire(cache); @@ -1903,13 +1914,16 @@ ngx_http_file_cache_manager(void *data) ngx_shmtx_lock(&cache->shpool->mutex); size = cache->sh->size; + count = cache->sh->count; + watermark = cache->sh->watermark; ngx_shmtx_unlock(&cache->shpool->mutex); - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "http file cache size: %O", size); + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache size: %O c:%ui w:%i", + size, count, (ngx_int_t) watermark); - if (size < cache->max_size) { + if (size < cache->max_size && count < watermark) { return next; } @@ -2093,10 +2107,20 @@ ngx_http_file_cache_add(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) fcn = ngx_slab_calloc_locked(cache->shpool, sizeof(ngx_http_file_cache_node_t)); if (fcn == NULL) { + ngx_http_file_cache_set_watermark(cache); + + if (cache->fail_time != ngx_time()) { + cache->fail_time = ngx_time(); + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "could not allocate node%s", cache->shpool->log_ctx); + } + ngx_shmtx_unlock(&cache->shpool->mutex); return NGX_ERROR; } + cache->sh->count++; + ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t)); ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)], @@ -2139,6 +2163,16 @@ ngx_http_file_cache_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) } +static void +ngx_http_file_cache_set_watermark(ngx_http_file_cache_t *cache) +{ + cache->sh->watermark = cache->sh->count - cache->sh->count / 8; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache watermark: %ui", cache->sh->watermark); +} + + time_t ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status) { diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c index e9562c0..b5803d5 100644 --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -34,7 +34,7 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, ssize_t size; ngx_int_t rc; ngx_buf_t *b; - ngx_chain_t out, *cl; + ngx_chain_t out; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; @@ -59,10 +59,6 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, goto done; } - if (r->request_body_no_buffering) { - r->request_body_in_file_only = 0; - } - rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -148,37 +144,8 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, if (rb->rest == 0) { /* the whole request body was pre-read */ - - if (r->request_body_in_file_only) { - if (ngx_http_write_request_body(r) != NGX_OK) { - rc = NGX_HTTP_INTERNAL_SERVER_ERROR; - goto done; - } - - if (rb->temp_file->file.offset != 0) { - - cl = ngx_chain_get_free_buf(r->pool, &rb->free); - if (cl == NULL) { - rc = NGX_HTTP_INTERNAL_SERVER_ERROR; - goto done; - } - - b = cl->buf; - - ngx_memzero(b, sizeof(ngx_buf_t)); - - b->in_file = 1; - b->file_last = rb->temp_file->file.offset; - b->file = &rb->temp_file->file; - - rb->bufs = cl; - } - } - r->request_body_no_buffering = 0; - post_handler(r); - return NGX_OK; } @@ -289,8 +256,7 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) size_t size; ssize_t n; ngx_int_t rc; - ngx_buf_t *b; - ngx_chain_t *cl, out; + ngx_chain_t out; ngx_connection_t *c; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; @@ -439,33 +405,6 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) ngx_del_timer(c->read); } - if (rb->temp_file || r->request_body_in_file_only) { - - /* save the last part */ - - if (ngx_http_write_request_body(r) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (rb->temp_file->file.offset != 0) { - - cl = ngx_chain_get_free_buf(r->pool, &rb->free); - if (cl == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - b = cl->buf; - - ngx_memzero(b, sizeof(ngx_buf_t)); - - b->in_file = 1; - b->file_last = rb->temp_file->file.offset; - b->file = &rb->temp_file->file; - - rb->bufs = cl; - } - } - if (!r->request_body_no_buffering) { r->read_event_handler = ngx_http_block_reading; rb->post_handler(r); @@ -1127,9 +1066,8 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_int_t ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) { -#if (NGX_DEBUG) + ngx_buf_t *b; ngx_chain_t *cl; -#endif ngx_http_request_body_t *rb; rb = r->request_body; @@ -1166,13 +1104,46 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (rb->rest > 0 - && rb->buf && rb->buf->last == rb->buf->end - && !r->request_body_no_buffering) - { + if (r->request_body_no_buffering) { + return NGX_OK; + } + + if (rb->rest > 0) { + + if (rb->buf && rb->buf->last == rb->buf->end + && ngx_http_write_request_body(r) != NGX_OK) + { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + return NGX_OK; + } + + /* rb->rest == 0 */ + + if (rb->temp_file || r->request_body_in_file_only) { + if (ngx_http_write_request_body(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } + + if (rb->temp_file->file.offset != 0) { + + cl = ngx_chain_get_free_buf(r->pool, &rb->free); + if (cl == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + b = cl->buf; + + ngx_memzero(b, sizeof(ngx_buf_t)); + + b->in_file = 1; + b->file_last = rb->temp_file->file.offset; + b->file = &rb->temp_file->file; + + rb->bufs = cl; + } } return NGX_OK; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index dbaa956..911049f 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -76,6 +76,13 @@ static void static ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data); static ngx_int_t ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes); +#if (NGX_THREADS) +static ngx_int_t ngx_http_upstream_thread_handler(ngx_thread_task_t *task, + ngx_file_t *file); +static void ngx_http_upstream_thread_event_handler(ngx_event_t *ev); +#endif +static ngx_int_t ngx_http_upstream_output_filter(void *data, + ngx_chain_t *chain); static void ngx_http_upstream_process_downstream(ngx_http_request_t *r); static void ngx_http_upstream_process_upstream(ngx_http_request_t *r, ngx_http_upstream_t *u); @@ -416,10 +423,10 @@ static ngx_http_upstream_next_t ngx_http_upstream_next_errors[] = { ngx_conf_bitmask_t ngx_http_upstream_cache_method_mask[] = { - { ngx_string("GET"), NGX_HTTP_GET}, - { ngx_string("HEAD"), NGX_HTTP_HEAD }, - { ngx_string("POST"), NGX_HTTP_POST }, - { ngx_null_string, 0 } + { ngx_string("GET"), NGX_HTTP_GET }, + { ngx_string("HEAD"), NGX_HTTP_HEAD }, + { ngx_string("POST"), NGX_HTTP_POST }, + { ngx_null_string, 0 } }; @@ -2861,11 +2868,16 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) ngx_http_file_cache_free(r->cache, u->pipe->temp_file); } + if (r->header_only && !u->cacheable && !u->store) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + #endif p = u->pipe; - p->output_filter = (ngx_event_pipe_output_filter_pt) ngx_http_output_filter; + p->output_filter = ngx_http_upstream_output_filter; p->output_ctx = r; p->tag = u->output.tag; p->bufs = u->conf->bufs; @@ -2908,6 +2920,13 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) p->max_temp_file_size = u->conf->max_temp_file_size; p->temp_file_write_size = u->conf->temp_file_write_size; +#if (NGX_THREADS) + if (clcf->aio == NGX_HTTP_AIO_THREADS && clcf->aio_write) { + p->thread_handler = ngx_http_upstream_thread_handler; + p->thread_ctx = r; + } +#endif + p->preread_bufs = ngx_alloc_chain_link(r->pool); if (p->preread_bufs == NULL) { ngx_http_upstream_finalize_request(r, u, NGX_ERROR); @@ -3482,6 +3501,97 @@ ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes) } +#if (NGX_THREADS) + +static ngx_int_t +ngx_http_upstream_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) +{ + ngx_str_t name; + ngx_event_pipe_t *p; + ngx_thread_pool_t *tp; + ngx_http_request_t *r; + ngx_http_core_loc_conf_t *clcf; + + r = file->thread_ctx; + p = r->upstream->pipe; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + tp = clcf->thread_pool; + + if (tp == NULL) { + if (ngx_http_complex_value(r, clcf->thread_pool_value, &name) + != NGX_OK) + { + return NGX_ERROR; + } + + tp = ngx_thread_pool_get((ngx_cycle_t *) ngx_cycle, &name); + + if (tp == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "thread pool \"%V\" not found", &name); + return NGX_ERROR; + } + } + + task->event.data = r; + task->event.handler = ngx_http_upstream_thread_event_handler; + + if (ngx_thread_task_post(tp, task) != NGX_OK) { + return NGX_ERROR; + } + + r->main->blocked++; + r->aio = 1; + p->aio = 1; + + return NGX_OK; +} + + +static void +ngx_http_upstream_thread_event_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + ngx_http_request_t *r; + + r = ev->data; + c = r->connection; + + ngx_http_set_log_request(c->log, r); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream thread: \"%V?%V\"", &r->uri, &r->args); + + r->main->blocked--; + r->aio = 0; + + r->write_event_handler(r); + + ngx_http_run_posted_requests(c); +} + +#endif + + +static ngx_int_t +ngx_http_upstream_output_filter(void *data, ngx_chain_t *chain) +{ + ngx_int_t rc; + ngx_event_pipe_t *p; + ngx_http_request_t *r; + + r = data; + p = r->upstream->pipe; + + rc = ngx_http_output_filter(r, chain); + + p->aio = r->aio; + + return rc; +} + + static void ngx_http_upstream_process_downstream(ngx_http_request_t *r) { @@ -3500,6 +3610,10 @@ ngx_http_upstream_process_downstream(ngx_http_request_t *r) c->log->action = "sending to client"; +#if (NGX_THREADS) + p->aio = r->aio; +#endif + if (wev->timedout) { if (wev->delayed) { @@ -3629,6 +3743,12 @@ ngx_http_upstream_process_request(ngx_http_request_t *r, p = u->pipe; +#if (NGX_THREADS) + if (p->writing) { + return; + } +#endif + if (u->peer.connection) { if (u->store) { @@ -3827,42 +3947,36 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, "upstream timed out"); } - if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR - && (!u->request_sent || !r->request_body_no_buffering)) - { - status = 0; - + if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) { /* TODO: inform balancer instead */ - u->peer.tries++; + } - } else { - switch (ft_type) { + switch (ft_type) { - case NGX_HTTP_UPSTREAM_FT_TIMEOUT: - status = NGX_HTTP_GATEWAY_TIME_OUT; - break; + case NGX_HTTP_UPSTREAM_FT_TIMEOUT: + status = NGX_HTTP_GATEWAY_TIME_OUT; + break; - case NGX_HTTP_UPSTREAM_FT_HTTP_500: - status = NGX_HTTP_INTERNAL_SERVER_ERROR; - break; + case NGX_HTTP_UPSTREAM_FT_HTTP_500: + status = NGX_HTTP_INTERNAL_SERVER_ERROR; + break; - case NGX_HTTP_UPSTREAM_FT_HTTP_403: - status = NGX_HTTP_FORBIDDEN; - break; + case NGX_HTTP_UPSTREAM_FT_HTTP_403: + status = NGX_HTTP_FORBIDDEN; + break; - case NGX_HTTP_UPSTREAM_FT_HTTP_404: - status = NGX_HTTP_NOT_FOUND; - break; + case NGX_HTTP_UPSTREAM_FT_HTTP_404: + status = NGX_HTTP_NOT_FOUND; + break; - /* - * NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING - * never reach here - */ + /* + * NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING + * never reach here + */ - default: - status = NGX_HTTP_BAD_GATEWAY; - } + default: + status = NGX_HTTP_BAD_GATEWAY; } if (r->connection->error) { @@ -3871,37 +3985,42 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, return; } - if (status) { - u->state->status = status; - timeout = u->conf->next_upstream_timeout; + u->state->status = status; - if (u->peer.tries == 0 - || !(u->conf->next_upstream & ft_type) - || (u->request_sent && r->request_body_no_buffering) - || (timeout && ngx_current_msec - u->peer.start_time >= timeout)) - { + timeout = u->conf->next_upstream_timeout; + + if (u->request_sent + && (r->method & (NGX_HTTP_POST|NGX_HTTP_LOCK|NGX_HTTP_PATCH))) + { + ft_type |= NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT; + } + + if (u->peer.tries == 0 + || ((u->conf->next_upstream & ft_type) != ft_type) + || (u->request_sent && r->request_body_no_buffering) + || (timeout && ngx_current_msec - u->peer.start_time >= timeout)) + { #if (NGX_HTTP_CACHE) - if (u->cache_status == NGX_HTTP_CACHE_EXPIRED - && (u->conf->cache_use_stale & ft_type)) - { - ngx_int_t rc; + if (u->cache_status == NGX_HTTP_CACHE_EXPIRED + && (u->conf->cache_use_stale & ft_type)) + { + ngx_int_t rc; - rc = u->reinit_request(r); + rc = u->reinit_request(r); - if (rc == NGX_OK) { - u->cache_status = NGX_HTTP_CACHE_STALE; - rc = ngx_http_upstream_cache_send(r, u); - } - - ngx_http_upstream_finalize_request(r, u, rc); - return; + if (rc == NGX_OK) { + u->cache_status = NGX_HTTP_CACHE_STALE; + rc = ngx_http_upstream_cache_send(r, u); } -#endif - ngx_http_upstream_finalize_request(r, u, status); + ngx_http_upstream_finalize_request(r, u, rc); return; } +#endif + + ngx_http_upstream_finalize_request(r, u, status); + return; } if (u->peer.connection) { @@ -4068,7 +4187,8 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r, if (!u->header_sent || rc == NGX_HTTP_REQUEST_TIME_OUT - || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST) + || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST + || (u->pipe && u->pipe->downstream_error)) { ngx_http_finalize_request(r, rc); return; diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index 4246c8a..7595dcf 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -29,6 +29,7 @@ #define NGX_HTTP_UPSTREAM_FT_UPDATING 0x00000400 #define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK 0x00000800 #define NGX_HTTP_UPSTREAM_FT_MAX_WAITING 0x00001000 +#define NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT 0x00002000 #define NGX_HTTP_UPSTREAM_FT_NOLIVE 0x40000000 #define NGX_HTTP_UPSTREAM_FT_OFF 0x80000000 @@ -281,7 +282,7 @@ typedef struct { ngx_uint_t no_port; /* unsigned no_port:1 */ ngx_uint_t naddrs; - ngx_addr_t *addrs; + ngx_resolver_addr_t *addrs; struct sockaddr *sockaddr; socklen_t socklen; diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 4c4a4e7..ababd4b 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -2503,8 +2503,8 @@ ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, ngx_uint_t ack) ngx_http_v2_srv_conf_t *h2scf; ngx_http_v2_out_frame_t *frame; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2 send SETTINGS frame"); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 send SETTINGS frame ack:%ui", ack); frame = ngx_palloc(h2c->pool, sizeof(ngx_http_v2_out_frame_t)); if (frame == NULL) { @@ -2595,6 +2595,10 @@ ngx_http_v2_send_window_update(ngx_http_v2_connection_t *h2c, ngx_uint_t sid, ngx_buf_t *buf; ngx_http_v2_out_frame_t *frame; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 send WINDOW_UPDATE frame sid:%ui, window:%uz", + sid, window); + frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_WINDOW_UPDATE_SIZE, NGX_HTTP_V2_WINDOW_UPDATE_FRAME, NGX_HTTP_V2_NO_FLAG, sid); @@ -2619,6 +2623,10 @@ ngx_http_v2_send_rst_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t sid, ngx_buf_t *buf; ngx_http_v2_out_frame_t *frame; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 send RST_STREAM frame sid:%ui, status:%uz", + sid, status); + frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_RST_STREAM_SIZE, NGX_HTTP_V2_RST_STREAM_FRAME, NGX_HTTP_V2_NO_FLAG, sid); @@ -2642,6 +2650,9 @@ ngx_http_v2_send_goaway(ngx_http_v2_connection_t *h2c, ngx_uint_t status) ngx_buf_t *buf; ngx_http_v2_out_frame_t *frame; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 send GOAWAY frame, status:%uz", status); + frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_GOAWAY_SIZE, NGX_HTTP_V2_GOAWAY_FRAME, NGX_HTTP_V2_NO_FLAG, 0); diff --git a/src/os/unix/ngx_darwin_init.c b/src/os/unix/ngx_darwin_init.c index 1bc7520..a9d12a8 100644 --- a/src/os/unix/ngx_darwin_init.c +++ b/src/os/unix/ngx_darwin_init.c @@ -23,6 +23,7 @@ static ngx_os_io_t ngx_darwin_io = { ngx_readv_chain, ngx_udp_unix_recv, ngx_unix_send, + ngx_udp_unix_send, #if (NGX_HAVE_SENDFILE) ngx_darwin_sendfile_chain, NGX_IO_SENDFILE diff --git a/src/os/unix/ngx_errno.h b/src/os/unix/ngx_errno.h index 16cafda..7d6ca76 100644 --- a/src/os/unix/ngx_errno.h +++ b/src/os/unix/ngx_errno.h @@ -25,6 +25,7 @@ typedef int ngx_err_t; #define NGX_EACCES EACCES #define NGX_EBUSY EBUSY #define NGX_EEXIST EEXIST +#define NGX_EEXIST_FILE EEXIST #define NGX_EXDEV EXDEV #define NGX_ENOTDIR ENOTDIR #define NGX_EISDIR EISDIR diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c index 00a6a49..bcef7ec 100644 --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -12,9 +12,11 @@ #if (NGX_THREADS) #include static void ngx_thread_read_handler(void *data, ngx_log_t *log); +static void ngx_thread_write_chain_to_file_handler(void *data, ngx_log_t *log); #endif -static ssize_t ngx_writev_file(ngx_file_t *file, ngx_array_t *vec, size_t size, +static ngx_chain_t *ngx_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *cl); +static ssize_t ngx_writev_file(ngx_file_t *file, ngx_iovec_t *vec, off_t offset); @@ -76,38 +78,39 @@ ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) #if (NGX_THREADS) typedef struct { - ngx_fd_t fd; - u_char *buf; - size_t size; - off_t offset; + ngx_fd_t fd; + ngx_uint_t write; /* unsigned write:1; */ - size_t read; - ngx_err_t err; -} ngx_thread_read_ctx_t; + u_char *buf; + size_t size; + ngx_chain_t *chain; + off_t offset; + + size_t nbytes; + ngx_err_t err; +} ngx_thread_file_ctx_t; ssize_t -ngx_thread_read(ngx_thread_task_t **taskp, ngx_file_t *file, u_char *buf, - size_t size, off_t offset, ngx_pool_t *pool) +ngx_thread_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, + ngx_pool_t *pool) { ngx_thread_task_t *task; - ngx_thread_read_ctx_t *ctx; + ngx_thread_file_ctx_t *ctx; ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, "thread read: %d, %p, %uz, %O", file->fd, buf, size, offset); - task = *taskp; + task = file->thread_task; if (task == NULL) { - task = ngx_thread_task_alloc(pool, sizeof(ngx_thread_read_ctx_t)); + task = ngx_thread_task_alloc(pool, sizeof(ngx_thread_file_ctx_t)); if (task == NULL) { return NGX_ERROR; } - task->handler = ngx_thread_read_handler; - - *taskp = task; + file->thread_task = task; } ctx = task->ctx; @@ -115,15 +118,25 @@ ngx_thread_read(ngx_thread_task_t **taskp, ngx_file_t *file, u_char *buf, if (task->event.complete) { task->event.complete = 0; + if (ctx->write) { + ngx_log_error(NGX_LOG_ALERT, file->log, 0, + "invalid thread call, read instead of write"); + return NGX_ERROR; + } + if (ctx->err) { ngx_log_error(NGX_LOG_CRIT, file->log, ctx->err, "pread() \"%s\" failed", file->name.data); return NGX_ERROR; } - return ctx->read; + return ctx->nbytes; } + task->handler = ngx_thread_read_handler; + + ctx->write = 0; + ctx->fd = file->fd; ctx->buf = buf; ctx->size = size; @@ -142,7 +155,7 @@ ngx_thread_read(ngx_thread_task_t **taskp, ngx_file_t *file, u_char *buf, static void ngx_thread_read_handler(void *data, ngx_log_t *log) { - ngx_thread_read_ctx_t *ctx = data; + ngx_thread_file_ctx_t *ctx = data; ssize_t n; @@ -154,7 +167,7 @@ ngx_thread_read_handler(void *data, ngx_log_t *log) ctx->err = ngx_errno; } else { - ctx->read = n; + ctx->nbytes = n; ctx->err = 0; } @@ -276,17 +289,13 @@ ngx_open_tempfile(u_char *name, ngx_uint_t persistent, ngx_uint_t access) } -#define NGX_IOVS 8 - ssize_t ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, ngx_pool_t *pool) { - u_char *prev; - size_t size; ssize_t total, n; - ngx_array_t vec; - struct iovec *iov, iovs[NGX_IOVS]; + ngx_iovec_t vec; + struct iovec iovs[NGX_IOVS_PREALLOCATE]; /* use pwrite() if there is the only buf in a chain */ @@ -298,46 +307,18 @@ ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, total = 0; - vec.elts = iovs; - vec.size = sizeof(struct iovec); - vec.nalloc = NGX_IOVS; - vec.pool = pool; + vec.iovs = iovs; + vec.nalloc = NGX_IOVS_PREALLOCATE; do { - prev = NULL; - iov = NULL; - size = 0; - - vec.nelts = 0; - /* create the iovec and coalesce the neighbouring bufs */ - - while (cl && vec.nelts < IOV_MAX) { - if (prev == cl->buf->pos) { - iov->iov_len += cl->buf->last - cl->buf->pos; - - } else { - iov = ngx_array_push(&vec); - if (iov == NULL) { - return NGX_ERROR; - } - - iov->iov_base = (void *) cl->buf->pos; - iov->iov_len = cl->buf->last - cl->buf->pos; - } - - size += cl->buf->last - cl->buf->pos; - prev = cl->buf->last; - cl = cl->next; - } + cl = ngx_chain_to_iovec(&vec, cl); /* use pwrite() if there is the only iovec buffer */ - if (vec.nelts == 1) { - iov = vec.elts; - - n = ngx_write_file(file, (u_char *) iov[0].iov_base, - iov[0].iov_len, offset); + if (vec.count == 1) { + n = ngx_write_file(file, (u_char *) iovs[0].iov_base, + iovs[0].iov_len, offset); if (n == NGX_ERROR) { return n; @@ -346,7 +327,7 @@ ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, return total + n; } - n = ngx_writev_file(file, &vec, size, offset); + n = ngx_writev_file(file, &vec, offset); if (n == NGX_ERROR) { return n; @@ -361,20 +342,61 @@ ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, } +static ngx_chain_t * +ngx_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *cl) +{ + size_t total, size; + u_char *prev; + ngx_uint_t n; + struct iovec *iov; + + iov = NULL; + prev = NULL; + total = 0; + n = 0; + + for ( /* void */ ; cl; cl = cl->next) { + size = cl->buf->last - cl->buf->pos; + + if (prev == cl->buf->pos) { + iov->iov_len += size; + + } else { + if (n == vec->nalloc) { + break; + } + + iov = &vec->iovs[n++]; + + iov->iov_base = (void *) cl->buf->pos; + iov->iov_len = size; + } + + prev = cl->buf->pos + size; + total += size; + } + + vec->count = n; + vec->size = total; + + return cl; +} + + static ssize_t -ngx_writev_file(ngx_file_t *file, ngx_array_t *vec, size_t size, off_t offset) +ngx_writev_file(ngx_file_t *file, ngx_iovec_t *vec, off_t offset) { ssize_t n; ngx_err_t err; ngx_log_debug3(NGX_LOG_DEBUG_CORE, file->log, 0, - "writev: %d, %uz, %O", file->fd, size, offset); + "writev: %d, %uz, %O", file->fd, vec->size, offset); #if (NGX_HAVE_PWRITEV) eintr: - n = pwritev(file->fd, vec->elts, vec->nelts, offset); + n = pwritev(file->fd, vec->iovs, vec->count, offset); if (n == -1) { err = ngx_errno; @@ -390,10 +412,10 @@ eintr: return NGX_ERROR; } - if ((size_t) n != size) { + if ((size_t) n != vec->size) { ngx_log_error(NGX_LOG_CRIT, file->log, 0, "pwritev() \"%s\" has written only %z of %uz", - file->name.data, n, size); + file->name.data, n, vec->size); return NGX_ERROR; } @@ -411,7 +433,7 @@ eintr: eintr: - n = writev(file->fd, vec->elts, vec->nelts); + n = writev(file->fd, vec->iovs, vec->count); if (n == -1) { err = ngx_errno; @@ -427,10 +449,10 @@ eintr: return NGX_ERROR; } - if ((size_t) n != size) { + if ((size_t) n != vec->size) { ngx_log_error(NGX_LOG_CRIT, file->log, 0, "writev() \"%s\" has written only %z of %uz", - file->name.data, n, size); + file->name.data, n, vec->size); return NGX_ERROR; } @@ -444,6 +466,132 @@ eintr: } +#if (NGX_THREADS) + +ssize_t +ngx_thread_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, + ngx_pool_t *pool) +{ + ngx_thread_task_t *task; + ngx_thread_file_ctx_t *ctx; + + ngx_log_debug3(NGX_LOG_DEBUG_CORE, file->log, 0, + "thread write chain: %d, %p, %O", + file->fd, cl, offset); + + task = file->thread_task; + + if (task == NULL) { + task = ngx_thread_task_alloc(pool, + sizeof(ngx_thread_file_ctx_t)); + if (task == NULL) { + return NGX_ERROR; + } + + file->thread_task = task; + } + + ctx = task->ctx; + + if (task->event.complete) { + task->event.complete = 0; + + if (!ctx->write) { + ngx_log_error(NGX_LOG_ALERT, file->log, 0, + "invalid thread call, write instead of read"); + return NGX_ERROR; + } + + if (ctx->err || ctx->nbytes == 0) { + ngx_log_error(NGX_LOG_CRIT, file->log, ctx->err, + "pwritev() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + file->offset += ctx->nbytes; + return ctx->nbytes; + } + + task->handler = ngx_thread_write_chain_to_file_handler; + + ctx->write = 1; + + ctx->fd = file->fd; + ctx->chain = cl; + ctx->offset = offset; + + if (file->thread_handler(task, file) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_AGAIN; +} + + +static void +ngx_thread_write_chain_to_file_handler(void *data, ngx_log_t *log) +{ + ngx_thread_file_ctx_t *ctx = data; + +#if (NGX_HAVE_PWRITEV) + + off_t offset; + ssize_t n; + ngx_err_t err; + ngx_chain_t *cl; + ngx_iovec_t vec; + struct iovec iovs[NGX_IOVS_PREALLOCATE]; + + vec.iovs = iovs; + vec.nalloc = NGX_IOVS_PREALLOCATE; + + cl = ctx->chain; + offset = ctx->offset; + + ctx->nbytes = 0; + ctx->err = 0; + + do { + /* create the iovec and coalesce the neighbouring bufs */ + cl = ngx_chain_to_iovec(&vec, cl); + +eintr: + + n = pwritev(ctx->fd, iovs, vec.count, offset); + + if (n == -1) { + err = ngx_errno; + + if (err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, err, + "pwritev() was interrupted"); + goto eintr; + } + + ctx->err = err; + return; + } + + if ((size_t) n != vec.size) { + ctx->nbytes = 0; + return; + } + + ctx->nbytes += n; + offset += n; + } while (cl); + +#else + + ctx->err = NGX_ENOSYS; + return; + +#endif +} + +#endif /* NGX_THREADS */ + + ngx_int_t ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s) { diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h index 6081b00..07872b1 100644 --- a/src/os/unix/ngx_files.h +++ b/src/os/unix/ngx_files.h @@ -385,8 +385,10 @@ extern ngx_uint_t ngx_file_aio; #endif #if (NGX_THREADS) -ssize_t ngx_thread_read(ngx_thread_task_t **taskp, ngx_file_t *file, - u_char *buf, size_t size, off_t offset, ngx_pool_t *pool); +ssize_t ngx_thread_read(ngx_file_t *file, u_char *buf, size_t size, + off_t offset, ngx_pool_t *pool); +ssize_t ngx_thread_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, + off_t offset, ngx_pool_t *pool); #endif diff --git a/src/os/unix/ngx_freebsd_init.c b/src/os/unix/ngx_freebsd_init.c index c4c12dd..71672c7 100644 --- a/src/os/unix/ngx_freebsd_init.c +++ b/src/os/unix/ngx_freebsd_init.c @@ -32,6 +32,7 @@ static ngx_os_io_t ngx_freebsd_io = { ngx_readv_chain, ngx_udp_unix_recv, ngx_unix_send, + ngx_udp_unix_send, #if (NGX_HAVE_SENDFILE) ngx_freebsd_sendfile_chain, NGX_IO_SENDFILE diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c index 3f17dc6..d0299f5 100644 --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -247,6 +247,19 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) #if (NGX_HAVE_AIO_SENDFILE) if (ebusy) { + if (aio->event.active) { + /* + * tolerate duplicate calls; they can happen due to subrequests + * or multiple calls of the next body filter from a filter + */ + + if (sent) { + c->busy_count = 0; + } + + return in; + } + if (sent == 0) { c->busy_count++; diff --git a/src/os/unix/ngx_linux_init.c b/src/os/unix/ngx_linux_init.c index b306cda..a1372e9 100644 --- a/src/os/unix/ngx_linux_init.c +++ b/src/os/unix/ngx_linux_init.c @@ -18,6 +18,7 @@ static ngx_os_io_t ngx_linux_io = { ngx_readv_chain, ngx_udp_unix_recv, ngx_unix_send, + ngx_udp_unix_send, #if (NGX_HAVE_SENDFILE) ngx_linux_sendfile_chain, NGX_IO_SENDFILE diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c index 97f741d..50a9cea 100644 --- a/src/os/unix/ngx_linux_sendfile_chain.c +++ b/src/os/unix/ngx_linux_sendfile_chain.c @@ -292,6 +292,19 @@ eintr: } } + if (n == 0) { + /* + * if sendfile returns zero, then someone has truncated the file, + * so the offset became beyond the end of the file + */ + + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "sendfile() reported that \"%s\" was truncated at %O", + file->file->name.data, file->file_pos); + + return NGX_ERROR; + } + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfile: %z of %uz @%O", n, size, file->file_pos); @@ -315,7 +328,6 @@ static ngx_int_t ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size, size_t *sent) { - ngx_uint_t flags; ngx_event_t *wev; ngx_thread_task_t *task; ngx_linux_sendfile_ctx_t *ctx; @@ -343,29 +355,60 @@ ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size, if (task->event.complete) { task->event.complete = 0; - if (ctx->err && ctx->err != NGX_EAGAIN) { + if (ctx->err == NGX_EAGAIN) { + *sent = 0; + + if (wev->complete) { + return NGX_DONE; + } + + return NGX_AGAIN; + } + + if (ctx->err) { wev->error = 1; ngx_connection_error(c, ctx->err, "sendfile() failed"); return NGX_ERROR; } + if (ctx->sent == 0) { + /* + * if sendfile returns zero, then someone has truncated the file, + * so the offset became beyond the end of the file + */ + + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "sendfile() reported that \"%s\" was truncated at %O", + file->file->name.data, file->file_pos); + + return NGX_ERROR; + } + *sent = ctx->sent; - return (ctx->sent == ctx->size) ? NGX_DONE : NGX_AGAIN; + if (ctx->sent == ctx->size || wev->complete) { + return NGX_DONE; + } + + return NGX_AGAIN; + } + + if (task->event.active && ctx->file == file) { + /* + * tolerate duplicate calls; they can happen due to subrequests + * or multiple calls of the next body filter from a filter + */ + + *sent = 0; + + return NGX_OK; } ctx->file = file; ctx->socket = c->fd; ctx->size = size; - if (wev->active) { - flags = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ? NGX_CLEAR_EVENT - : NGX_LEVEL_EVENT; - - if (ngx_del_event(wev, NGX_WRITE_EVENT, flags) == NGX_ERROR) { - return NGX_ERROR; - } - } + wev->complete = 0; if (file->file->thread_handler(task, file->file) != NGX_OK) { return NGX_ERROR; diff --git a/src/os/unix/ngx_os.h b/src/os/unix/ngx_os.h index d8bcb01..c0d59ef 100644 --- a/src/os/unix/ngx_os.h +++ b/src/os/unix/ngx_os.h @@ -28,6 +28,7 @@ typedef struct { ngx_recv_chain_pt recv_chain; ngx_recv_pt udp_recv; ngx_send_pt send; + ngx_send_pt udp_send; ngx_send_chain_pt send_chain; ngx_uint_t flags; } ngx_os_io_t; @@ -47,6 +48,7 @@ ssize_t ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size); ssize_t ngx_unix_send(ngx_connection_t *c, u_char *buf, size_t size); ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); +ssize_t ngx_udp_unix_send(ngx_connection_t *c, u_char *buf, size_t size); #if (IOV_MAX > 64) diff --git a/src/os/unix/ngx_posix_config.h b/src/os/unix/ngx_posix_config.h index bf75997..5d1358e 100644 --- a/src/os/unix/ngx_posix_config.h +++ b/src/os/unix/ngx_posix_config.h @@ -128,7 +128,7 @@ #endif -#if (NGX_HAVE_DEVPOLL) +#if (NGX_HAVE_DEVPOLL) && !(NGX_TEST_BUILD_DEVPOLL) #include #include #endif diff --git a/src/os/unix/ngx_posix_init.c b/src/os/unix/ngx_posix_init.c index 61cc8ca..76ed94e 100644 --- a/src/os/unix/ngx_posix_init.c +++ b/src/os/unix/ngx_posix_init.c @@ -24,6 +24,7 @@ ngx_os_io_t ngx_os_io = { ngx_readv_chain, ngx_udp_unix_recv, ngx_unix_send, + ngx_udp_unix_send, ngx_writev_chain, 0 }; diff --git a/src/os/unix/ngx_solaris_init.c b/src/os/unix/ngx_solaris_init.c index f2f3600..83acae1 100644 --- a/src/os/unix/ngx_solaris_init.c +++ b/src/os/unix/ngx_solaris_init.c @@ -19,6 +19,7 @@ static ngx_os_io_t ngx_solaris_io = { ngx_readv_chain, ngx_udp_unix_recv, ngx_unix_send, + ngx_udp_unix_send, #if (NGX_HAVE_SENDFILE) ngx_solaris_sendfilev_chain, NGX_IO_SENDFILE diff --git a/src/os/unix/ngx_solaris_sendfilev_chain.c b/src/os/unix/ngx_solaris_sendfilev_chain.c index 7504239..39bcafa 100644 --- a/src/os/unix/ngx_solaris_sendfilev_chain.c +++ b/src/os/unix/ngx_solaris_sendfilev_chain.c @@ -48,6 +48,7 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) ssize_t n; ngx_int_t eintr; ngx_err_t err; + ngx_buf_t *file; ngx_uint_t nsfv; sendfilevec_t *sfv, sfvs[NGX_SENDFILEVECS]; ngx_event_t *wev; @@ -77,6 +78,7 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) fd = SFV_FD_SELF; prev = NULL; fprev = 0; + file = NULL; sfv = NULL; eintr = 0; sent = 0; @@ -153,6 +155,7 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) sfv->sfv_len = (size_t) size; } + file = cl->buf; fprev = cl->buf->file_pos + size; send += size; } @@ -179,6 +182,26 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err, "sendfilev() sent only %uz bytes", sent); + + } else if (n == 0 && sent == 0) { + + /* + * sendfilev() is documented to return -1 with errno + * set to EINVAL if svf_len is greater than the file size, + * but at least Solaris 11 returns 0 instead + */ + + if (file) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "sendfilev() reported that \"%s\" was truncated at %O", + file->file->name.data, file->file_pos); + + } else { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "sendfilev() returned 0 with memory buffers"); + } + + return NGX_CHAIN_ERROR; } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, diff --git a/src/os/unix/ngx_udp_send.c b/src/os/unix/ngx_udp_send.c new file mode 100644 index 0000000..aabbc8e --- /dev/null +++ b/src/os/unix/ngx_udp_send.c @@ -0,0 +1,56 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +ssize_t +ngx_udp_unix_send(ngx_connection_t *c, u_char *buf, size_t size) +{ + ssize_t n; + ngx_err_t err; + ngx_event_t *wev; + + wev = c->write; + + for ( ;; ) { + n = sendto(c->fd, buf, size, 0, c->sockaddr, c->socklen); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendto: fd:%d %z of %uz to \"%V\"", + c->fd, n, size, &c->addr_text); + + if (n >= 0) { + if ((size_t) n != size) { + wev->error = 1; + (void) ngx_connection_error(c, 0, "sendto() incomplete"); + return NGX_ERROR; + } + + c->sent += n; + + return n; + } + + err = ngx_socket_errno; + + if (err == NGX_EAGAIN) { + wev->ready = 0; + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, NGX_EAGAIN, + "sendto() not ready"); + return NGX_AGAIN; + } + + if (err != NGX_EINTR) { + wev->error = 1; + (void) ngx_connection_error(c, err, "sendto() failed"); + return NGX_ERROR; + } + } +} diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c index caaf38a..3bd8f6d 100644 --- a/src/stream/ngx_stream.c +++ b/src/stream/ngx_stream.c @@ -275,8 +275,11 @@ ngx_stream_add_ports(ngx_conf_t *cf, ngx_array_t *ports, port = ports->elts; for (i = 0; i < ports->nelts; i++) { - if (p == port[i].port && sa->sa_family == port[i].family) { + if (p == port[i].port + && listen->type == port[i].type + && sa->sa_family == port[i].family) + { /* a port is already in the port list */ port = &port[i]; @@ -292,6 +295,7 @@ ngx_stream_add_ports(ngx_conf_t *cf, ngx_array_t *ports, } port->family = sa->sa_family; + port->type = listen->type; port->port = p; if (ngx_array_init(&port->addrs, cf->temp_pool, 2, @@ -364,6 +368,7 @@ ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) ls->addr_ntop = 1; ls->handler = ngx_stream_init_connection; ls->pool_size = 256; + ls->type = addr[i].opt.type; cscf = addr->opt.ctx->srv_conf[ngx_stream_core_module.ctx_index]; @@ -373,6 +378,8 @@ ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) ls->backlog = addr[i].opt.backlog; + ls->wildcard = addr[i].opt.wildcard; + ls->keepalive = addr[i].opt.so_keepalive; #if (NGX_HAVE_KEEPALIVE_TUNABLE) ls->keepidle = addr[i].opt.tcp_keepidle; diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h index 21953e9..49efa45 100644 --- a/src/stream/ngx_stream.h +++ b/src/stream/ngx_stream.h @@ -66,6 +66,7 @@ typedef struct { int tcp_keepcnt; #endif int backlog; + int type; } ngx_stream_listen_t; @@ -102,6 +103,7 @@ typedef struct { typedef struct { int family; + int type; in_port_t port; ngx_array_t addrs; /* array of ngx_stream_conf_addr_t */ } ngx_stream_conf_port_t; diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c index 0ecc448..ebc2b1c 100644 --- a/src/stream/ngx_stream_core_module.c +++ b/src/stream/ngx_stream_core_module.c @@ -252,7 +252,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) in_port_t port; ngx_str_t *value; ngx_url_t u; - ngx_uint_t i; + ngx_uint_t i, backlog; struct sockaddr *sa; struct sockaddr_in *sin; ngx_stream_listen_t *ls; @@ -343,6 +343,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ls->socklen = u.socklen; ls->backlog = NGX_LISTEN_BACKLOG; + ls->type = SOCK_STREAM; ls->wildcard = u.wildcard; ls->ctx = cf->ctx; @@ -350,8 +351,17 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ls->ipv6only = 1; #endif + backlog = 0; + for (i = 2; i < cf->args->nelts; i++) { +#if !(NGX_WIN32) + if (ngx_strcmp(value[i].data, "udp") == 0) { + ls->type = SOCK_DGRAM; + continue; + } +#endif + if (ngx_strcmp(value[i].data, "bind") == 0) { ls->bind = 1; continue; @@ -367,6 +377,8 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } + backlog = 1; + continue; } @@ -530,5 +542,21 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } + if (ls->type == SOCK_DGRAM) { + if (backlog) { + return "\"backlog\" parameter is incompatible with \"udp\""; + } + +#if (NGX_STREAM_SSL) + if (ls->ssl) { + return "\"ssl\" parameter is incompatible with \"udp\""; + } +#endif + + if (ls->so_keepalive) { + return "\"so_keepalive\" parameter is incompatible with \"udp\""; + } + } + return NGX_CONF_OK; } diff --git a/src/stream/ngx_stream_handler.c b/src/stream/ngx_stream_handler.c index b3edb68..aa69e44 100644 --- a/src/stream/ngx_stream_handler.c +++ b/src/stream/ngx_stream_handler.c @@ -52,7 +52,7 @@ ngx_stream_init_connection(ngx_connection_t *c) * is the "*:port" wildcard so getsockname() is needed to determine * the server address. * - * AcceptEx() already gave this address. + * AcceptEx() and recvmsg() already gave this address. */ if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { @@ -137,8 +137,9 @@ ngx_stream_init_connection(ngx_connection_t *c) len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1); - ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %*s connected to %V", - c->number, len, text, &addr_conf->addr_text); + ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA %sclient %*s connected to %V", + c->number, c->type == SOCK_DGRAM ? "udp " : "", + len, text, &addr_conf->addr_text); c->log->connection = c->number; c->log->handler = ngx_stream_log_error; @@ -166,7 +167,10 @@ ngx_stream_init_connection(ngx_connection_t *c) } } - if (cscf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { + if (c->type == SOCK_STREAM + && cscf->tcp_nodelay + && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) + { ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "tcp_nodelay"); tcp_nodelay = 1; @@ -325,7 +329,8 @@ ngx_stream_log_error(ngx_log_t *log, u_char *buf, size_t len) s = log->data; - p = ngx_snprintf(buf, len, ", client: %V, server: %V", + p = ngx_snprintf(buf, len, ", %sclient: %V, server: %V", + s->connection->type == SOCK_DGRAM ? "udp " : "", &s->connection->addr_text, &s->connection->listening->addr_text); len -= p - buf; diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index b969fea..6c535fd 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -17,6 +17,7 @@ typedef struct { size_t buffer_size; size_t upload_rate; size_t download_rate; + ngx_uint_t responses; ngx_uint_t next_upstream_tries; ngx_flag_t next_upstream; ngx_flag_t proxy_protocol; @@ -54,7 +55,7 @@ static void ngx_stream_proxy_process_connection(ngx_event_t *ev, ngx_uint_t from_upstream); static void ngx_stream_proxy_connect_handler(ngx_event_t *ev); static ngx_int_t ngx_stream_proxy_test_connect(ngx_connection_t *c); -static ngx_int_t ngx_stream_proxy_process(ngx_stream_session_t *s, +static void ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, ngx_uint_t do_write); static void ngx_stream_proxy_next_upstream(ngx_stream_session_t *s); static void ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_int_t rc); @@ -167,6 +168,13 @@ static ngx_command_t ngx_stream_proxy_commands[] = { offsetof(ngx_stream_proxy_srv_conf_t, download_rate), NULL }, + { ngx_string("proxy_responses"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, responses), + NULL }, + { ngx_string("proxy_next_upstream"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -351,6 +359,7 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) u->peer.log_error = NGX_ERROR_ERR; u->peer.local = pscf->local; + u->peer.type = c->type; uscf = pscf->upstream; @@ -370,6 +379,14 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) u->proxy_protocol = pscf->proxy_protocol; u->start_sec = ngx_time(); + c->write->handler = ngx_stream_proxy_downstream_handler; + c->read->handler = ngx_stream_proxy_downstream_handler; + + if (c->type == SOCK_DGRAM) { + ngx_stream_proxy_connect(s); + return; + } + p = ngx_pnalloc(c->pool, pscf->buffer_size); if (p == NULL) { ngx_stream_proxy_finalize(s, NGX_ERROR); @@ -381,9 +398,6 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) u->downstream_buf.pos = p; u->downstream_buf.last = p; - c->write->handler = ngx_stream_proxy_downstream_handler; - c->read->handler = ngx_stream_proxy_downstream_handler; - if (u->proxy_protocol #if (NGX_STREAM_SSL) && pscf->ssl == NULL @@ -406,8 +420,8 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) u->proxy_protocol = 0; } - if (ngx_stream_proxy_process(s, 0, 0) != NGX_OK) { - return; + if (c->read->ready) { + ngx_post_event(c->read, &ngx_posted_events); } ngx_stream_proxy_connect(s); @@ -488,7 +502,10 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); - if (cscf->tcp_nodelay && pc->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { + if (pc->type == SOCK_STREAM + && cscf->tcp_nodelay + && pc->tcp_nodelay == NGX_TCP_NODELAY_UNSET) + { ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, "tcp_nodelay"); tcp_nodelay = 1; @@ -516,7 +533,7 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); #if (NGX_STREAM_SSL) - if (pscf->ssl && pc->ssl == NULL) { + if (pc->type == SOCK_STREAM && pscf->ssl && pc->ssl == NULL) { ngx_stream_proxy_ssl_init_connection(s); return; } @@ -535,7 +552,9 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) handler = c->log->handler; c->log->handler = NULL; - ngx_log_error(NGX_LOG_INFO, c->log, 0, "proxy %V connected to %V", + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "%sproxy %V connected to %V", + pc->type == SOCK_DGRAM ? "udp " : "", &str, u->peer.name); c->log->handler = handler; @@ -544,24 +563,36 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) c->log->action = "proxying connection"; - p = ngx_pnalloc(c->pool, pscf->buffer_size); - if (p == NULL) { - ngx_stream_proxy_finalize(s, NGX_ERROR); - return; + if (u->upstream_buf.start == NULL) { + p = ngx_pnalloc(c->pool, pscf->buffer_size); + if (p == NULL) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + u->upstream_buf.start = p; + u->upstream_buf.end = p + pscf->buffer_size; + u->upstream_buf.pos = p; + u->upstream_buf.last = p; } - u->upstream_buf.start = p; - u->upstream_buf.end = p + pscf->buffer_size; - u->upstream_buf.pos = p; - u->upstream_buf.last = p; + if (c->type == SOCK_DGRAM) { + s->received = c->buffer->last - c->buffer->pos; + u->downstream_buf = *c->buffer; + + if (pscf->responses == 0) { + pc->read->ready = 0; + pc->read->eof = 1; + } + } u->connected = 1; pc->read->handler = ngx_stream_proxy_upstream_handler; pc->write->handler = ngx_stream_proxy_upstream_handler; - if (ngx_stream_proxy_process(s, 1, 0) != NGX_OK) { - return; + if (pc->read->ready || pc->read->eof) { + ngx_post_event(pc->read, &ngx_posted_events); } ngx_stream_proxy_process(s, 0, 1); @@ -894,11 +925,15 @@ ngx_stream_proxy_process_connection(ngx_event_t *ev, ngx_uint_t from_upstream) s = c->data; u = s->upstream; + c = s->connection; + pc = u->peer.connection; + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + if (ev->timedout) { + ev->timedout = 0; if (ev->delayed) { - - ev->timedout = 0; ev->delayed = 0; if (!ev->ready) { @@ -907,20 +942,35 @@ ngx_stream_proxy_process_connection(ngx_event_t *ev, ngx_uint_t from_upstream) return; } - if (u->connected) { - pc = u->peer.connection; - - if (!c->read->delayed && !pc->read->delayed) { - pscf = ngx_stream_get_module_srv_conf(s, - ngx_stream_proxy_module); - ngx_add_timer(c->write, pscf->timeout); - } + if (u->connected && !c->read->delayed && !pc->read->delayed) { + ngx_add_timer(c->write, pscf->timeout); } return; } } else { + if (s->connection->type == SOCK_DGRAM) { + if (pscf->responses == NGX_MAX_INT32_VALUE) { + + /* + * successfully terminate timed out UDP session + * with unspecified number of responses + */ + + pc->read->ready = 0; + pc->read->eof = 1; + + ngx_stream_proxy_process(s, 1, 0); + return; + } + + if (u->received == 0) { + ngx_stream_proxy_next_upstream(s); + return; + } + } + ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); ngx_stream_proxy_finalize(s, NGX_DECLINED); return; @@ -1019,7 +1069,7 @@ ngx_stream_proxy_test_connect(ngx_connection_t *c) } -static ngx_int_t +static void ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, ngx_uint_t do_write) { @@ -1039,6 +1089,21 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, c = s->connection; pc = u->connected ? u->peer.connection : NULL; + if (c->type == SOCK_DGRAM && (ngx_terminate || ngx_exiting)) { + + /* socket is already closed on worker shutdown */ + + handler = c->log->handler; + c->log->handler = NULL; + + ngx_log_error(NGX_LOG_INFO, c->log, 0, "disconnected on shutdown"); + + c->log->handler = handler; + + ngx_stream_proxy_finalize(s, NGX_OK); + return; + } + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); if (from_upstream) { @@ -1066,9 +1131,19 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, n = dst->send(dst, b->pos, size); + if (n == NGX_AGAIN && dst->shared) { + /* cannot wait on a shared socket */ + n = NGX_ERROR; + } + if (n == NGX_ERROR) { + if (c->type == SOCK_DGRAM && !from_upstream) { + ngx_stream_proxy_next_upstream(s); + return; + } + ngx_stream_proxy_finalize(s, NGX_DECLINED); - return NGX_ERROR; + return; } if (n > 0) { @@ -1118,6 +1193,12 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, } } + if (c->type == SOCK_DGRAM && ++u->responses == pscf->responses) + { + src->read->ready = 0; + src->read->eof = 1; + } + *received += n; b->last += n; do_write = 1; @@ -1126,6 +1207,11 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, } if (n == NGX_ERROR) { + if (c->type == SOCK_DGRAM && u->received == 0) { + ngx_stream_proxy_next_upstream(s); + return; + } + src->read->eof = 1; } } @@ -1138,29 +1224,30 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, c->log->handler = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, - "%s disconnected" + "%s%s disconnected" ", bytes from/to client:%O/%O" ", bytes from/to upstream:%O/%O", + src->type == SOCK_DGRAM ? "udp " : "", from_upstream ? "upstream" : "client", s->received, c->sent, u->received, pc ? pc->sent : 0); c->log->handler = handler; ngx_stream_proxy_finalize(s, NGX_OK); - return NGX_DONE; + return; } flags = src->read->eof ? NGX_CLOSE_EVENT : 0; - if (ngx_handle_read_event(src->read, flags) != NGX_OK) { + if (!src->shared && ngx_handle_read_event(src->read, flags) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_ERROR); - return NGX_ERROR; + return; } if (dst) { - if (ngx_handle_write_event(dst->write, 0) != NGX_OK) { + if (!dst->shared && ngx_handle_write_event(dst->write, 0) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_ERROR); - return NGX_ERROR; + return; } if (!c->read->delayed && !pc->read->delayed) { @@ -1170,8 +1257,6 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, ngx_del_timer(c->write); } } - - return NGX_OK; } @@ -1333,6 +1418,7 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) conf->buffer_size = NGX_CONF_UNSET_SIZE; conf->upload_rate = NGX_CONF_UNSET_SIZE; conf->download_rate = NGX_CONF_UNSET_SIZE; + conf->responses = NGX_CONF_UNSET_UINT; conf->next_upstream_tries = NGX_CONF_UNSET_UINT; conf->next_upstream = NGX_CONF_UNSET; conf->proxy_protocol = NGX_CONF_UNSET; @@ -1375,6 +1461,9 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_size_value(conf->download_rate, prev->download_rate, 0); + ngx_conf_merge_uint_value(conf->responses, + prev->responses, NGX_MAX_INT32_VALUE); + ngx_conf_merge_uint_value(conf->next_upstream_tries, prev->next_upstream_tries, 0); diff --git a/src/stream/ngx_stream_upstream.c b/src/stream/ngx_stream_upstream.c index 805ee70..69dddc5 100644 --- a/src/stream/ngx_stream_upstream.c +++ b/src/stream/ngx_stream_upstream.c @@ -388,7 +388,7 @@ ngx_stream_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags) uscf->port = u->port; uscf->no_port = u->no_port; - if (u->naddrs == 1) { + if (u->naddrs == 1 && (u->port || u->family == AF_UNIX)) { uscf->servers = ngx_array_create(cf->pool, 1, sizeof(ngx_stream_upstream_server_t)); if (uscf->servers == NULL) { diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h index 80520c2..1f4810c 100644 --- a/src/stream/ngx_stream_upstream.h +++ b/src/stream/ngx_stream_upstream.h @@ -84,6 +84,7 @@ typedef struct { ngx_buf_t upstream_buf; off_t received; time_t start_sec; + ngx_uint_t responses; #if (NGX_STREAM_SSL) ngx_str_t ssl_name; #endif From dfa3b2f2df7c50a06253dd9e4ecb22abae3be065 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 30 Mar 2016 11:28:10 +0300 Subject: [PATCH 094/651] New upstream release (1.9.13) --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 226b72b..ab5e082 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,7 +1,7 @@ -nginx (1.9.11-1) UNRELEASED; urgency=medium +nginx (1.9.13-1) UNRELEASED; urgency=medium [ Christos Trochalakis ] - * New upstream release (1.9.11) (Closes: #812806) + * New upstream release (1.9.13) (Closes: #812806) * debian: + Setup dynamic module flow, and implement a simple dh_nginx helper for internal use. From 5d3e5e8fcb4d6746aa28bc1513ed544cba29c69d Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 30 Mar 2016 12:05:52 +0300 Subject: [PATCH 095/651] Update auth-pam module and introduce libnginx-mod-http-auth-pam --- debian/changelog | 3 ++ debian/control | 11 +++++ debian/libnginx-mod-http-auth-pam.nginx | 13 ++++++ .../libnginx-mod.conf/mod-http-auth-pam.conf | 1 + debian/modules/README.Modules-versions | 2 +- debian/modules/nginx-auth-pam/ChangeLog | 8 ++++ debian/modules/nginx-auth-pam/LICENSE | 2 +- debian/modules/nginx-auth-pam/README.md | 14 +++--- debian/modules/nginx-auth-pam/VERSION | 1 + debian/modules/nginx-auth-pam/config | 18 ++++++-- .../nginx-auth-pam/ngx_http_auth_pam_module.c | 45 ++++++++++++------- debian/rules | 6 +-- 12 files changed, 93 insertions(+), 31 deletions(-) create mode 100755 debian/libnginx-mod-http-auth-pam.nginx create mode 100644 debian/libnginx-mod.conf/mod-http-auth-pam.conf create mode 100644 debian/modules/nginx-auth-pam/VERSION diff --git a/debian/changelog b/debian/changelog index ab5e082..63ae632 100644 --- a/debian/changelog +++ b/debian/changelog @@ -22,6 +22,9 @@ nginx (1.9.13-1) UNRELEASED; urgency=medium * debian/modules/nginx-lua: + Update nginx-lua to v0.10.1rc0-5-g01727a3. Fixes buiding failures with nginx 1.9.11. + * debian/modules/nginx-auth-pam: + + Update http-auth-pam module to 1.5 and convert it to a dyn module. + (Closes: #819062) -- Christos Trochalakis Thu, 11 Feb 2016 15:06:38 +0200 diff --git a/debian/control b/debian/control index 2076f5c..96def42 100644 --- a/debian/control +++ b/debian/control @@ -85,6 +85,7 @@ Depends: nginx-common (= ${source:Version}), libnginx-mod-http-xslt-filter (= ${binary:Version}), libnginx-mod-mail (= ${binary:Version}), libnginx-mod-stream (= ${binary:Version}), + libnginx-mod-http-auth-pam (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} Breaks: nginx (<< 1.4.5-1) @@ -177,6 +178,7 @@ Depends: nginx-common (= ${source:Version}), libnginx-mod-http-xslt-filter (= ${binary:Version}), libnginx-mod-mail (= ${binary:Version}), libnginx-mod-stream (= ${binary:Version}), + libnginx-mod-http-auth-pam (= ${binary:Version}), ${misc:Depends}, ${perl:Depends}, ${shlibs:Depends} @@ -271,3 +273,12 @@ Description: Stream module for Nginx Stream module supports loadbalancing & proxying to TCP servers. The module also supports ACLs/connection limiting and configuring multiple operational parameters. + +Package: libnginx-mod-http-auth-pam +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: PAM authentication module for Nginx + The nginx_http_auth_pam module enables authentication using PAM. + . + The module uses PAM as a backend for simple http authentication. It + also allows setting the pam service name to allow more fine grained control. diff --git a/debian/libnginx-mod-http-auth-pam.nginx b/debian/libnginx-mod-http-auth-pam.nginx new file mode 100755 index 0000000..02c5edc --- /dev/null +++ b/debian/libnginx-mod-http-auth-pam.nginx @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use File::Basename; + +# Guess module name +$module = basename($0, '.nginx'); +$module =~ s/^libnginx-mod-//; + +$modulepath = $module; +$modulepath =~ s/-/_/g; + +print "mod debian/build-full/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod.conf/mod-http-auth-pam.conf b/debian/libnginx-mod.conf/mod-http-auth-pam.conf new file mode 100644 index 0000000..2eb6752 --- /dev/null +++ b/debian/libnginx-mod.conf/mod-http-auth-pam.conf @@ -0,0 +1 @@ +load_module modules/ngx_http_auth_pam_module.so; diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index dbff74d..3952163 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -14,7 +14,7 @@ README for Modules versions nginx-auth-pam Homepage: https://github.com/stogh/ngx_http_auth_pam_module - Version: 1.4 + Version: 1.5 nginx-echo Homepage: https://github.com/agentzh/echo-nginx-module diff --git a/debian/modules/nginx-auth-pam/ChangeLog b/debian/modules/nginx-auth-pam/ChangeLog index 466bd9c..8aaf031 100644 --- a/debian/modules/nginx-auth-pam/ChangeLog +++ b/debian/modules/nginx-auth-pam/ChangeLog @@ -1,3 +1,11 @@ +2016-03-23 sto@iti.es + + * Version 1.5. + * Added support to build module dynamically (patch provided by Sjir + Bagmeijer ). + * Log PAM error and info messages to nginx log files (patch provided by + André Caron ). + 2015-02-04 sto@iti.es * Version 1.4. diff --git a/debian/modules/nginx-auth-pam/LICENSE b/debian/modules/nginx-auth-pam/LICENSE index f5be528..b2d9324 100644 --- a/debian/modules/nginx-auth-pam/LICENSE +++ b/debian/modules/nginx-auth-pam/LICENSE @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2015 Sergio Talens Oliag + * Copyright (C) 2008-2016 Sergio Talens Oliag * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/debian/modules/nginx-auth-pam/README.md b/debian/modules/nginx-auth-pam/README.md index c6d58f0..a4eea45 100644 --- a/debian/modules/nginx-auth-pam/README.md +++ b/debian/modules/nginx-auth-pam/README.md @@ -4,15 +4,17 @@ ### Compilation -When compiling from source build as usual adding the -add-module option: +When compiling from source build as usual adding the ``--add-module`` option: ./configure --add-module=$PATH_TO_MODULE -If you are using a Debian GNU/Linux distribution install the nginx-full package; -the module has been included in the nginx debian package since version 1.1.6-1 -and there are newer packages on the stable distribution (wheezy) and the wheezy -version is also available from the oldstable backports repository -(squeeze-backports). +or if you want to build the module as dynamic use the ``--add-dynamic-module`` +option. + +If you are using a Debian GNU/Linux distribution install the ``nginx-full`` +package; the module has been included in the debian package since version +``1.1.6-1``, so it is available on all stable distributions since the *wheezy* +release. ### Configuration diff --git a/debian/modules/nginx-auth-pam/VERSION b/debian/modules/nginx-auth-pam/VERSION new file mode 100644 index 0000000..c239c60 --- /dev/null +++ b/debian/modules/nginx-auth-pam/VERSION @@ -0,0 +1 @@ +1.5 diff --git a/debian/modules/nginx-auth-pam/config b/debian/modules/nginx-auth-pam/config index ef0815e..9c30919 100644 --- a/debian/modules/nginx-auth-pam/config +++ b/debian/modules/nginx-auth-pam/config @@ -1,4 +1,16 @@ ngx_addon_name=ngx_http_auth_pam_module -HTTP_MODULES="$HTTP_MODULES ngx_http_auth_pam_module" -NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_auth_pam_module.c" -CORE_LIBS="$CORE_LIBS -lpam" + +if test -n "$ngx_module_link"; then + ngx_module_type=HTTP + ngx_module_name=ngx_http_auth_pam_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_auth_pam_module.c" + ngx_module_libs="$CORE_LIBS -lpam" + + . auto/module +else + HTTP_MODULES="$HTTP_MODULES ngx_http_auth_pam_module" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_auth_pam_module.c" + CORE_LIBS="$CORE_LIBS -lpam" +fi \ No newline at end of file diff --git a/debian/modules/nginx-auth-pam/ngx_http_auth_pam_module.c b/debian/modules/nginx-auth-pam/ngx_http_auth_pam_module.c index a49d7a6..167a37f 100644 --- a/debian/modules/nginx-auth-pam/ngx_http_auth_pam_module.c +++ b/debian/modules/nginx-auth-pam/ngx_http_auth_pam_module.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2015 Sergio Talens-Oliag + * Copyright (C) 2008-2016 Sergio Talens-Oliag * * Based on nginx's 'ngx_http_auth_basic_module.c' by Igor Sysoev and apache's * 'mod_auth_pam.c' by Ingo Luetkebolhe. @@ -19,11 +19,12 @@ typedef struct { ngx_str_t passwd; } ngx_http_auth_pam_ctx_t; -/* PAM userinfo */ +/* PAM authinfo */ typedef struct { ngx_str_t username; ngx_str_t password; -} ngx_pam_userinfo; + ngx_log_t *log; +} ngx_pam_authinfo; /* Module configuration struct */ typedef struct { @@ -151,14 +152,14 @@ ngx_auth_pam_talker(int num_msg, const struct pam_message ** msg, struct pam_response ** resp, void *appdata_ptr) { int i; - ngx_pam_userinfo *uinfo; + ngx_pam_authinfo *ainfo; struct pam_response *response; - uinfo = (ngx_pam_userinfo *) appdata_ptr; + ainfo = (ngx_pam_authinfo *) appdata_ptr; response = NULL; /* parameter sanity checking */ - if (!resp || !msg || !uinfo) + if (!resp || !msg || !ainfo) return PAM_CONV_ERR; /* allocate memory to store response */ @@ -176,10 +177,18 @@ ngx_auth_pam_talker(int num_msg, const struct pam_message ** msg, switch (msg[i]->msg_style) { case PAM_PROMPT_ECHO_ON: /* on memory allocation failure, auth fails */ - response[i].resp = strdup((const char *)uinfo->username.data); + response[i].resp = strdup((const char *)ainfo->username.data); break; case PAM_PROMPT_ECHO_OFF: - response[i].resp = strdup((const char *)uinfo->password.data); + response[i].resp = strdup((const char *)ainfo->password.data); + break; + case PAM_ERROR_MSG: + ngx_log_error(NGX_LOG_ERR, ainfo->log, 0, + "PAM: \'%s\'.", msg[i]->msg); + break; + case PAM_TEXT_INFO: + ngx_log_error(NGX_LOG_INFO, ainfo->log, 0, + "PAM: \'%s\'.", msg[i]->msg); break; default: free_resp(i, response); @@ -277,7 +286,7 @@ ngx_http_auth_pam_authenticate(ngx_http_request_t *r, ngx_int_t rc; ngx_http_auth_pam_loc_conf_t *alcf; - ngx_pam_userinfo uinfo; + ngx_pam_authinfo ainfo; struct pam_conv conv_info; /* PAM struct */ pam_handle_t *pamh; u_char *service_name; @@ -303,14 +312,16 @@ ngx_http_auth_pam_authenticate(ngx_http_request_t *r, p = ngx_cpymem(uname_buf, r->headers_in.user.data , len); *p ='\0'; - uinfo.username.data = uname_buf; - uinfo.username.len = len; + ainfo.username.data = uname_buf; + ainfo.username.len = len; - uinfo.password.data = r->headers_in.passwd.data; - uinfo.password.len = r->headers_in.passwd.len; + ainfo.password.data = r->headers_in.passwd.data; + ainfo.password.len = r->headers_in.passwd.len; + + ainfo.log = r->connection->log; conv_info.conv = &ngx_auth_pam_talker; - conv_info.appdata_ptr = (void *) &uinfo; + conv_info.appdata_ptr = (void *) &ainfo; pamh = NULL; @@ -321,7 +332,7 @@ ngx_http_auth_pam_authenticate(ngx_http_request_t *r, service_name = alcf->service_name.data; } if ((rc = pam_start((const char *) service_name, - (const char *) uinfo.username.data, + (const char *) ainfo.username.data, &conv_info, &pamh)) != PAM_SUCCESS) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -339,7 +350,7 @@ ngx_http_auth_pam_authenticate(ngx_http_request_t *r, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "PAM: user '%s' - not authenticated: %s", - uinfo.username.data, pam_strerror(pamh, rc)); + ainfo.username.data, pam_strerror(pamh, rc)); pam_end(pamh, PAM_SUCCESS); return ngx_http_auth_pam_set_realm(r, &alcf->realm); } /* endif authenticate */ @@ -348,7 +359,7 @@ ngx_http_auth_pam_authenticate(ngx_http_request_t *r, if ((rc = pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "PAM: user '%s' - invalid account: %s", - uinfo.username.data, pam_strerror(pamh, rc)); + ainfo.username.data, pam_strerror(pamh, rc)); pam_end(pamh, PAM_SUCCESS); return ngx_http_auth_pam_set_realm(r, &alcf->realm); } diff --git a/debian/rules b/debian/rules index f9db327..4c28a8b 100755 --- a/debian/rules +++ b/debian/rules @@ -11,7 +11,7 @@ DEBIAN_NGINX_PERL_LDFLAGS:= $(shell DEB_BUILD_MAINT_OPTIONS=hardening=+all,-pie export DEBIAN_NGINX_PERL_LDFLAGS FLAVOURS := full light extras -DYN_MODS := http-geoip http-image-filter http-xslt-filter mail stream +DYN_MODS := http-geoip http-image-filter http-xslt-filter mail stream http-auth-pam MODULESDIR = $(CURDIR)/debian/modules BASEDIR = $(CURDIR) @@ -83,7 +83,7 @@ full_configure_flags := \ --with-stream_ssl_module \ --with-mail=dynamic \ --with-mail_ssl_module \ - --add-module=$(MODULESDIR)/nginx-auth-pam \ + --add-dynamic-module=$(MODULESDIR)/nginx-auth-pam \ --add-module=$(MODULESDIR)/nginx-dav-ext-module \ --add-module=$(MODULESDIR)/nginx-echo \ --add-module=$(MODULESDIR)/nginx-upstream-fair \ @@ -108,7 +108,7 @@ extras_configure_flags := \ --with-stream=dynamic \ --with-stream_ssl_module \ --add-module=$(MODULESDIR)/headers-more-nginx-module \ - --add-module=$(MODULESDIR)/nginx-auth-pam \ + --add-dynamic-module=$(MODULESDIR)/nginx-auth-pam \ --add-module=$(MODULESDIR)/nginx-cache-purge \ --add-module=$(MODULESDIR)/nginx-dav-ext-module \ --add-module=$(MODULESDIR)/nginx-development-kit \ From e7ea50abbd00e4172ee7d28f94c94c71047a32f0 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 30 Mar 2016 12:27:13 +0300 Subject: [PATCH 096/651] Update LUA module and introduce libnginx-mod-http-lua --- debian/changelog | 2 +- debian/control | 12 ++++ debian/libnginx-mod-http-lua.nginx | 13 ++++ debian/libnginx-mod.conf/mod-http-lua.conf | 1 + debian/modules/README.Modules-versions | 2 +- debian/modules/nginx-lua/README.markdown | 35 +++++------ .../modules/nginx-lua/doc/HttpLuaModule.wiki | 30 +++++----- .../modules/nginx-lua/src/ngx_http_lua_args.c | 13 ++-- .../nginx-lua/src/ngx_http_lua_balancer.c | 59 +++++++++++++++++-- .../nginx-lua/src/ngx_http_lua_module.c | 16 ++++- .../nginx-lua/src/ngx_http_lua_ssl_certby.c | 28 +++++++-- debian/modules/nginx-lua/t/031-post-args.t | 35 ++++++++++- debian/modules/nginx-lua/t/129-ssl-socket.t | 2 +- debian/modules/nginx-lua/t/133-worker-count.t | 20 +++++++ .../modules/nginx-lua/t/134-worker-count-5.t | 46 +++++++++++++++ debian/rules | 4 +- 16 files changed, 260 insertions(+), 58 deletions(-) create mode 100755 debian/libnginx-mod-http-lua.nginx create mode 100644 debian/libnginx-mod.conf/mod-http-lua.conf diff --git a/debian/changelog b/debian/changelog index 63ae632..24f9b02 100644 --- a/debian/changelog +++ b/debian/changelog @@ -20,7 +20,7 @@ nginx (1.9.13-1) UNRELEASED; urgency=medium * debian/nginx-common.nginx.service: + Documentation points to nginx man page. * debian/modules/nginx-lua: - + Update nginx-lua to v0.10.1rc0-5-g01727a3. + + Update nginx-lua to v0.12 and convert it to a dyn module. Fixes buiding failures with nginx 1.9.11. * debian/modules/nginx-auth-pam: + Update http-auth-pam module to 1.5 and convert it to a dyn module. diff --git a/debian/control b/debian/control index 96def42..96fa475 100644 --- a/debian/control +++ b/debian/control @@ -179,6 +179,7 @@ Depends: nginx-common (= ${source:Version}), libnginx-mod-mail (= ${binary:Version}), libnginx-mod-stream (= ${binary:Version}), libnginx-mod-http-auth-pam (= ${binary:Version}), + libnginx-mod-http-lua (= ${binary:Version}), ${misc:Depends}, ${perl:Depends}, ${shlibs:Depends} @@ -282,3 +283,14 @@ Description: PAM authentication module for Nginx . The module uses PAM as a backend for simple http authentication. It also allows setting the pam service name to allow more fine grained control. + +Package: libnginx-mod-http-lua +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: LUA module for Nginx + Embed LUA runtime into nginx. + . + This module embeds Lua, via the standard Lua 5.1 interpreter or LuaJIT + 2.0/2.1, into Nginx and by leveraging Nginx's subrequests, allows the + integration of the powerful Lua threads (Lua coroutines) into the Nginx event + model. diff --git a/debian/libnginx-mod-http-lua.nginx b/debian/libnginx-mod-http-lua.nginx new file mode 100755 index 0000000..02c5edc --- /dev/null +++ b/debian/libnginx-mod-http-lua.nginx @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use File::Basename; + +# Guess module name +$module = basename($0, '.nginx'); +$module =~ s/^libnginx-mod-//; + +$modulepath = $module; +$modulepath =~ s/-/_/g; + +print "mod debian/build-full/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod.conf/mod-http-lua.conf b/debian/libnginx-mod.conf/mod-http-lua.conf new file mode 100644 index 0000000..f6311f4 --- /dev/null +++ b/debian/libnginx-mod.conf/mod-http-lua.conf @@ -0,0 +1 @@ +load_module modules/ngx_http_lua_module.so; diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index 3952163..53cbc2c 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -22,7 +22,7 @@ README for Modules versions nginx-lua Homepage: https://github.com/openresty/lua-nginx-module - Version: v0.10.1rc0-5-g01727a3 + Version: v0.10.2 nginx-upstream-fair Homepage: https://github.com/gnosek/nginx-upstream-fair diff --git a/debian/modules/nginx-lua/README.markdown b/debian/modules/nginx-lua/README.markdown index 94e67ad..4e8f9bd 100644 --- a/debian/modules/nginx-lua/README.markdown +++ b/debian/modules/nginx-lua/README.markdown @@ -21,6 +21,7 @@ Table of Contents * [Typical Uses](#typical-uses) * [Nginx Compatibility](#nginx-compatibility) * [Installation](#installation) + * [Building as a dynamic module](#building-as-a-dynamic-module) * [C Macro Configurations](#c-macro-configurations) * [Installation on Ubuntu 11.10](#installation-on-ubuntu-1110) * [Community](#community) @@ -61,7 +62,7 @@ Production ready. Version ======= -This document describes ngx_lua [v0.10.0](https://github.com/openresty/lua-nginx-module/tags) released on 11 January 2016. +This document describes ngx_lua [v0.10.2](https://github.com/openresty/lua-nginx-module/tags) released on 8 March 2016. Synopsis ======== @@ -128,7 +129,7 @@ Synopsis ngx.say("status: ", res.status) ngx.say("body:") ngx.print(res.body) - end'; + end } } @@ -264,7 +265,7 @@ It is highly recommended to use the [OpenResty bundle](http://openresty.org) tha Alternatively, ngx_lua can be manually compiled into Nginx: -1. Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuaJIT can be downloaded from the [the LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuaJIT and/or Lua. +1. Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuaJIT can be downloaded from the [LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuaJIT and/or Lua. 1. Download the latest version of the ngx_devel_kit (NDK) module [HERE](https://github.com/simpl/ngx_devel_kit/tags). 1. Download the latest version of ngx_lua [HERE](https://github.com/openresty/lua-nginx-module/tags). 1. Download the latest version of Nginx [HERE](http://nginx.org/) (See [Nginx Compatibility](#nginx-compatibility)) @@ -299,11 +300,17 @@ Build the source with this module: make install ``` +[Back to TOC](#table-of-contents) + +Building as a dynamic module +---------------------------- + Starting from NGINX 1.9.11, you can also compile this module as a dynamic module, by using the `--add-dynamic-module=PATH` option instead of `--add-module=PATH` on the `./configure` command line above. And then you can explicitly load the module in your `nginx.conf` via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module) directive, for example, ```nginx +load_module /path/to/modules/ndk_http_module.so; # assuming NDK is built as a dynamic module too load_module /path/to/modules/ngx_http_lua_module.so; ``` @@ -843,22 +850,11 @@ TODO ==== * cosocket: implement LuaSocket's unconnected UDP API. -* add support for implementing general TCP servers instead of HTTP servers in Lua. For example, +* port this module to the "datagram" subsystem of NGINX for implementing general UDP servers instead of HTTP +servers in Lua. For example, ```lua - tcp { - server { - listen 11212; - handler_by_lua ' - -- custom Lua code implementing the special TCP server... - '; - } - } -``` -* add support for implementing general UDP servers instead of HTTP servers in Lua. For example, -```lua - - udp { + datagram { server { listen 1953; handler_by_lua ' @@ -881,6 +877,7 @@ TODO * add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) methods, to allow micro performance tuning on the user side. * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add `stat` mode similar to [mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html). +* cosocket: add client SSL certificiate support. [Back to TOC](#table-of-contents) @@ -6845,10 +6842,14 @@ Retrieves the current running phase name. Possible return values are for the context of [init_by_lua](#init_by_lua) or [init_by_lua_file](#init_by_lua_file). * `init_worker` for the context of [init_worker_by_lua](#init_worker_by_lua) or [init_worker_by_lua_file](#init_worker_by_lua_file). +* `ssl_cert` + for the context of [ssl_certificate_by_lua_block](#ssl_certificate_by_lua_block) or [ssl_certificate_by_lua_file](#ssl_certificate_by_lua_file). * `set` for the context of [set_by_lua](#set_by_lua) or [set_by_lua_file](#set_by_lua_file). * `rewrite` for the context of [rewrite_by_lua](#rewrite_by_lua) or [rewrite_by_lua_file](#rewrite_by_lua_file). +* `balancer` + for the context of [balancer_by_lua_block](#balancer_by_lua_block) or [balancer_by_lua_file](#balancer_by_lua_file). * `access` for the context of [access_by_lua](#access_by_lua) or [access_by_lua_file](#access_by_lua_file). * `content` diff --git a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki index 3a39ef8..f6824ef 100644 --- a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.0] released on 11 January 2016. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.2] released on 8 March 2016. = Synopsis = @@ -75,7 +75,7 @@ This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/t ngx.say("status: ", res.status) ngx.say("body:") ngx.print(res.body) - end'; + end } } @@ -199,7 +199,7 @@ It is highly recommended to use the [http://openresty.org OpenResty bundle] that Alternatively, ngx_lua can be manually compiled into Nginx: -# Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is ''not'' supported yet). LuaJIT can be downloaded from the [http://luajit.org/download.html the LuaJIT project website] and Lua 5.1, from the [http://www.lua.org/ Lua project website]. Some distribution package managers also distribute LuaJIT and/or Lua. +# Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is ''not'' supported yet). LuaJIT can be downloaded from the [http://luajit.org/download.html LuaJIT project website] and Lua 5.1, from the [http://www.lua.org/ Lua project website]. Some distribution package managers also distribute LuaJIT and/or Lua. # Download the latest version of the ngx_devel_kit (NDK) module [https://github.com/simpl/ngx_devel_kit/tags HERE]. # Download the latest version of ngx_lua [https://github.com/openresty/lua-nginx-module/tags HERE]. # Download the latest version of Nginx [http://nginx.org/ HERE] (See [[#Nginx Compatibility|Nginx Compatibility]]) @@ -233,11 +233,14 @@ Build the source with this module: make install +== Building as a dynamic module == + Starting from NGINX 1.9.11, you can also compile this module as a dynamic module, by using the `--add-dynamic-module=PATH` option instead of `--add-module=PATH` on the `./configure` command line above. And then you can explicitly load the module in your `nginx.conf` via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module) directive, for example, ```nginx +load_module /path/to/modules/ndk_http_module.so; # assuming NDK is built as a dynamic module too load_module /path/to/modules/ngx_http_lua_module.so; ``` @@ -682,20 +685,10 @@ phases. = TODO = * cosocket: implement LuaSocket's unconnected UDP API. -* add support for implementing general TCP servers instead of HTTP servers in Lua. For example, +* port this module to the "datagram" subsystem of NGINX for implementing general UDP servers instead of HTTP +servers in Lua. For example, - tcp { - server { - listen 11212; - handler_by_lua ' - -- custom Lua code implementing the special TCP server... - '; - } - } - -* add support for implementing general UDP servers instead of HTTP servers in Lua. For example, - - udp { + datagram { server { listen 1953; handler_by_lua ' @@ -718,6 +711,7 @@ phases. * add ignore_resp_headers, ignore_resp_body, and ignore_resp options to [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] methods, to allow micro performance tuning on the user side. * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add stat mode similar to [https://httpd.apache.org/docs/trunk/mod/mod_lua.html mod_lua]. +* cosocket: add client SSL certificiate support. = Changes = @@ -5765,10 +5759,14 @@ Retrieves the current running phase name. Possible return values are : for the context of [[#init_by_lua|init_by_lua]] or [[#init_by_lua_file|init_by_lua_file]]. * init_worker : for the context of [[#init_worker_by_lua|init_worker_by_lua]] or [[#init_worker_by_lua_file|init_worker_by_lua_file]]. +* ssl_cert +: for the context of [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua_block]] or [[#ssl_certificate_by_lua_file|ssl_certificate_by_lua_file]]. * set : for the context of [[#set_by_lua|set_by_lua]] or [[#set_by_lua_file|set_by_lua_file]]. * rewrite : for the context of [[#rewrite_by_lua|rewrite_by_lua]] or [[#rewrite_by_lua_file|rewrite_by_lua_file]]. +* balancer +: for the context of [[#balancer_by_lua_block|balancer_by_lua_block]] or [[#balancer_by_lua_file|balancer_by_lua_file]]. * access : for the context of [[#access_by_lua|access_by_lua]] or [[#access_by_lua_file|access_by_lua_file]]. * content diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_args.c b/debian/modules/nginx-lua/src/ngx_http_lua_args.c index dbc2ac6..0c307d6 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_args.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_args.c @@ -111,8 +111,6 @@ ngx_http_lua_ngx_req_get_uri_args(lua_State *L) ngx_http_lua_check_fake_request(L, r); - lua_createtable(L, 0, 4); - if (r->args.len == 0) { lua_createtable(L, 0, 0); return 1; @@ -126,6 +124,8 @@ ngx_http_lua_ngx_req_get_uri_args(lua_State *L) return luaL_error(L, "no memory"); } + lua_createtable(L, 0, 4); + ngx_memcpy(buf, r->args.data, r->args.len); last = buf + r->args.len; @@ -183,12 +183,13 @@ ngx_http_lua_ngx_req_get_post_args(lua_State *L) } if (r->request_body->temp_file) { - return luaL_error(L, "requesty body in temp file not supported"); + lua_pushnil(L); + lua_pushliteral(L, "requesty body in temp file not supported"); + return 2; } - lua_createtable(L, 0, 4); - if (r->request_body->bufs == NULL) { + lua_createtable(L, 0, 0); return 1; } @@ -212,6 +213,8 @@ ngx_http_lua_ngx_req_get_post_args(lua_State *L) return luaL_error(L, "no memory"); } + lua_createtable(L, 0, 4); + p = buf; for (cl = r->request_body->bufs; cl; cl = cl->next) { p = ngx_copy(p, cl->buf->pos, cl->buf->last - cl->buf->pos); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c b/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c index 1201d26..a2c66be 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c @@ -23,8 +23,6 @@ struct ngx_http_lua_balancer_peer_data_s { ngx_http_lua_srv_conf_t *conf; ngx_http_request_t *request; - ngx_event_get_peer_pt get_rr_peer; - ngx_uint_t more_tries; ngx_uint_t total_tries; @@ -38,6 +36,12 @@ struct ngx_http_lua_balancer_peer_data_s { }; +#if (NGX_HTTP_SSL) +static ngx_int_t ngx_http_lua_balancer_set_session(ngx_peer_connection_t *pc, + void *data); +static void ngx_http_lua_balancer_save_session(ngx_peer_connection_t *pc, + void *data); +#endif static ngx_int_t ngx_http_lua_balancer_init(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us); static ngx_int_t ngx_http_lua_balancer_init_peer(ngx_http_request_t *r, @@ -232,10 +236,14 @@ ngx_http_lua_balancer_init_peer(ngx_http_request_t *r, r->upstream->peer.get = ngx_http_lua_balancer_get_peer; r->upstream->peer.free = ngx_http_lua_balancer_free_peer; +#if (NGX_HTTP_SSL) + r->upstream->peer.set_session = ngx_http_lua_balancer_set_session; + r->upstream->peer.save_session = ngx_http_lua_balancer_save_session; +#endif + bcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_lua_module); bp->conf = bcf; - bp->get_rr_peer = ngx_http_upstream_get_round_robin_peer; bp->request = r; return NGX_OK; @@ -254,7 +262,7 @@ ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) ngx_http_lua_balancer_peer_data_t *bp = data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "lua balancer peer, try: %ui", pc->tries); + "lua balancer peer, tries: %ui", pc->tries); lscf = bp->conf; @@ -315,6 +323,9 @@ ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) pc->sockaddr = bp->sockaddr; pc->socklen = bp->socklen; pc->name = &bp->host; + pc->cached = 0; + pc->connection = NULL; + bp->rrp.peers->single = 0; if (bp->more_tries) { @@ -326,7 +337,7 @@ ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) return NGX_OK; } - return bp->get_rr_peer(pc, &bp->rrp); + return ngx_http_upstream_get_round_robin_peer(pc, &bp->rrp); } @@ -388,6 +399,9 @@ ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data, { ngx_http_lua_balancer_peer_data_t *bp = data; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "lua balancer free peer, tries: %ui", pc->tries); + if (bp->sockaddr && bp->socklen) { bp->last_peer_state = (int) state; @@ -404,6 +418,39 @@ ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data, } +#if (NGX_HTTP_SSL) + +static ngx_int_t +ngx_http_lua_balancer_set_session(ngx_peer_connection_t *pc, void *data) +{ + ngx_http_lua_balancer_peer_data_t *bp = data; + + if (bp->sockaddr && bp->socklen) { + /* TODO */ + return NGX_OK; + } + + return ngx_http_upstream_set_round_robin_peer_session(pc, &bp->rrp); +} + + +static void +ngx_http_lua_balancer_save_session(ngx_peer_connection_t *pc, void *data) +{ + ngx_http_lua_balancer_peer_data_t *bp = data; + + if (bp->sockaddr && bp->socklen) { + /* TODO */ + return; + } + + ngx_http_upstream_save_round_robin_peer_session(pc, &bp->rrp); + return; +} + +#endif + + #ifndef NGX_LUA_NO_FFI_API int @@ -493,7 +540,9 @@ int ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r, int count, char **err) { +#if (nginx_version >= 1007005) ngx_uint_t max_tries; +#endif ngx_http_lua_ctx_t *ctx; ngx_http_upstream_t *u; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_module.c b/debian/modules/nginx-lua/src/ngx_http_lua_module.c index 4cfee82..11eb653 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_module.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_module.c @@ -888,14 +888,26 @@ ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } -#if OPENSSL_VERSION_NUMBER >= 0x1000205fL +#ifdef LIBRESSL_VERSION_NUMBER - SSL_CTX_set_cert_cb(sscf->ssl.ctx, ngx_http_lua_ssl_cert_handler, NULL); + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "LibreSSL does not support ssl_ceritificate_by_lua*"); + return NGX_CONF_ERROR; #else +# if OPENSSL_VERSION_NUMBER >= 0x1000205fL + + SSL_CTX_set_cert_cb(sscf->ssl.ctx, ngx_http_lua_ssl_cert_handler, NULL); + +# else + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "OpenSSL too old to support ssl_ceritificate_by_lua*"); return NGX_CONF_ERROR; +# endif + #endif } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c index 32675b2..c4e6a83 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c @@ -530,12 +530,19 @@ ngx_http_lua_ffi_ssl_get_tls1_version(ngx_http_request_t *r, char **err) int ngx_http_lua_ffi_ssl_clear_certs(ngx_http_request_t *r, char **err) { -#if OPENSSL_VERSION_NUMBER < 0x1000205fL +#ifdef LIBRESSL_VERSION_NUMBER + + *err = "LibreSSL not supported"; + return NGX_ERROR; + +#else + +# if OPENSSL_VERSION_NUMBER < 0x1000205fL *err = "at least OpenSSL 1.0.2e required but found " OPENSSL_VERSION_TEXT; return NGX_ERROR; -#else +# else ngx_ssl_conn_t *ssl_conn; @@ -553,7 +560,8 @@ ngx_http_lua_ffi_ssl_clear_certs(ngx_http_request_t *r, char **err) SSL_certs_clear(ssl_conn); return NGX_OK; -#endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */ +# endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */ +#endif } @@ -561,12 +569,19 @@ int ngx_http_lua_ffi_ssl_set_der_certificate(ngx_http_request_t *r, const char *data, size_t len, char **err) { -#if OPENSSL_VERSION_NUMBER < 0x1000205fL +#ifdef LIBRESSL_VERSION_NUMBER + + *err = "LibreSSL not supported"; + return NGX_ERROR; + +#else + +# if OPENSSL_VERSION_NUMBER < 0x1000205fL *err = "at least OpenSSL 1.0.2e required but found " OPENSSL_VERSION_TEXT; return NGX_ERROR; -#else +# else BIO *bio = NULL; X509 *x509 = NULL; @@ -643,7 +658,8 @@ failed: return NGX_ERROR; -#endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */ +# endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */ +#endif } diff --git a/debian/modules/nginx-lua/t/031-post-args.t b/debian/modules/nginx-lua/t/031-post-args.t index 29d6057..4f8b9d7 100644 --- a/debian/modules/nginx-lua/t/031-post-args.t +++ b/debian/modules/nginx-lua/t/031-post-args.t @@ -7,9 +7,8 @@ use Test::Nginx::Socket::Lua; #log_level('warn'); repeat_each(2); -#repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 5); +plan tests => repeat_each() * (blocks() * 2 + 6); #no_diff(); #no_long_string(); @@ -323,3 +322,35 @@ for my $k (@k) { CORE::join("", @k); --- timeout: 4 + + +=== TEST 10: request body in temp file +--- config + location /lua { + lua_need_request_body on; + client_body_in_file_only clean; + content_by_lua_block { + local args, err = ngx.req.get_post_args() + + if not args then + ngx.say(err) + else + local keys = {} + for key, val in pairs(args) do + table.insert(keys, key) + end + + table.sort(keys) + for i, key in ipairs(keys) do + ngx.say(key, " = ", args[key]) + end + end + } + } +--- request +POST /lua +a=3&b=4&c +--- response_body +requesty body in temp file not supported +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/129-ssl-socket.t b/debian/modules/nginx-lua/t/129-ssl-socket.t index 446cfeb..4921099 100644 --- a/debian/modules/nginx-lua/t/129-ssl-socket.t +++ b/debian/modules/nginx-lua/t/129-ssl-socket.t @@ -846,7 +846,7 @@ lua ssl server name: "iscribblet.org" lua ssl certificate verify error SSL reused session [alert] ---- timeout: 5 +--- timeout: 7 diff --git a/debian/modules/nginx-lua/t/133-worker-count.t b/debian/modules/nginx-lua/t/133-worker-count.t index a7bae65..c97f6b4 100644 --- a/debian/modules/nginx-lua/t/133-worker-count.t +++ b/debian/modules/nginx-lua/t/133-worker-count.t @@ -30,3 +30,23 @@ GET /lua workers: 1 --- no_error_log [error] + + + +=== TEST 2: init_by_lua +--- http_config + init_by_lua_block { + package.loaded.count = ngx.worker.count() + } +--- config + location /lua { + content_by_lua_block { + ngx.say("workers: ", package.loaded.count) + } + } +--- request +GET /lua +--- response_body +workers: 1 +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/134-worker-count-5.t b/debian/modules/nginx-lua/t/134-worker-count-5.t index d6f16c2..b257c12 100644 --- a/debian/modules/nginx-lua/t/134-worker-count-5.t +++ b/debian/modules/nginx-lua/t/134-worker-count-5.t @@ -30,3 +30,49 @@ GET /lua worker count: 5 --- no_error_log [error] + + + +=== TEST 2: init_by_lua +--- http_config + init_by_lua_block { + package.loaded.count = ngx.worker.count() + } +--- config + location /lua { + content_by_lua_block { + ngx.say("workers: ", package.loaded.count) + } + } +--- request +GET /lua +--- response_body +workers: 5 +--- no_error_log +[error] + + + +=== TEST 3: init_by_lua + module (github #681) +--- http_config + lua_package_path "t/servroot/html/?.lua;;"; + + init_by_lua_block { + local blah = require "file" + } +--- config + location /lua { + content_by_lua_block { + ngx.say("ok") + } + } +--- user_files +>>> file.lua +local timer_interval = 1 +local time_factor = timer_interval / (ngx.worker.count() * 60) +--- request +GET /lua +--- response_body +ok +--- no_error_log +[error] diff --git a/debian/rules b/debian/rules index 4c28a8b..14d079f 100755 --- a/debian/rules +++ b/debian/rules @@ -11,7 +11,7 @@ DEBIAN_NGINX_PERL_LDFLAGS:= $(shell DEB_BUILD_MAINT_OPTIONS=hardening=+all,-pie export DEBIAN_NGINX_PERL_LDFLAGS FLAVOURS := full light extras -DYN_MODS := http-geoip http-image-filter http-xslt-filter mail stream http-auth-pam +DYN_MODS := http-geoip http-image-filter http-xslt-filter mail stream http-auth-pam http-lua MODULESDIR = $(CURDIR)/debian/modules BASEDIR = $(CURDIR) @@ -115,7 +115,7 @@ extras_configure_flags := \ --add-module=$(MODULESDIR)/nginx-echo \ --add-module=$(MODULESDIR)/ngx-fancyindex \ --add-module=$(MODULESDIR)/nginx-http-push \ - --add-module=$(MODULESDIR)/nginx-lua \ + --add-dynamic-module=$(MODULESDIR)/nginx-lua \ --add-module=$(MODULESDIR)/nginx-upload-progress \ --add-module=$(MODULESDIR)/nginx-upstream-fair \ --add-module=$(MODULESDIR)/ngx_http_substitutions_filter_module From a12faa39a5bce0dc61e596fd08d79fe2469d60f8 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 30 Mar 2016 12:46:10 +0300 Subject: [PATCH 097/651] build modules using nginx-extras --- debian/libnginx-mod-http-auth-pam.nginx | 2 +- debian/libnginx-mod-http-geoip.nginx | 2 +- debian/libnginx-mod-http-image-filter.nginx | 2 +- debian/libnginx-mod-http-lua.nginx | 2 +- debian/libnginx-mod-http-xslt-filter.nginx | 2 +- debian/libnginx-mod-mail.nginx | 2 +- debian/libnginx-mod-stream.nginx | 2 +- debian/libnginx-mod.nginx.skeleton | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/debian/libnginx-mod-http-auth-pam.nginx b/debian/libnginx-mod-http-auth-pam.nginx index 02c5edc..78c206f 100755 --- a/debian/libnginx-mod-http-auth-pam.nginx +++ b/debian/libnginx-mod-http-auth-pam.nginx @@ -9,5 +9,5 @@ $module =~ s/^libnginx-mod-//; $modulepath = $module; $modulepath =~ s/-/_/g; -print "mod debian/build-full/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-http-geoip.nginx b/debian/libnginx-mod-http-geoip.nginx index 02c5edc..78c206f 100755 --- a/debian/libnginx-mod-http-geoip.nginx +++ b/debian/libnginx-mod-http-geoip.nginx @@ -9,5 +9,5 @@ $module =~ s/^libnginx-mod-//; $modulepath = $module; $modulepath =~ s/-/_/g; -print "mod debian/build-full/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-http-image-filter.nginx b/debian/libnginx-mod-http-image-filter.nginx index 02c5edc..78c206f 100755 --- a/debian/libnginx-mod-http-image-filter.nginx +++ b/debian/libnginx-mod-http-image-filter.nginx @@ -9,5 +9,5 @@ $module =~ s/^libnginx-mod-//; $modulepath = $module; $modulepath =~ s/-/_/g; -print "mod debian/build-full/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-http-lua.nginx b/debian/libnginx-mod-http-lua.nginx index 02c5edc..78c206f 100755 --- a/debian/libnginx-mod-http-lua.nginx +++ b/debian/libnginx-mod-http-lua.nginx @@ -9,5 +9,5 @@ $module =~ s/^libnginx-mod-//; $modulepath = $module; $modulepath =~ s/-/_/g; -print "mod debian/build-full/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-http-xslt-filter.nginx b/debian/libnginx-mod-http-xslt-filter.nginx index 02c5edc..78c206f 100755 --- a/debian/libnginx-mod-http-xslt-filter.nginx +++ b/debian/libnginx-mod-http-xslt-filter.nginx @@ -9,5 +9,5 @@ $module =~ s/^libnginx-mod-//; $modulepath = $module; $modulepath =~ s/-/_/g; -print "mod debian/build-full/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-mail.nginx b/debian/libnginx-mod-mail.nginx index 02c5edc..78c206f 100755 --- a/debian/libnginx-mod-mail.nginx +++ b/debian/libnginx-mod-mail.nginx @@ -9,5 +9,5 @@ $module =~ s/^libnginx-mod-//; $modulepath = $module; $modulepath =~ s/-/_/g; -print "mod debian/build-full/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-stream.nginx b/debian/libnginx-mod-stream.nginx index 02c5edc..78c206f 100755 --- a/debian/libnginx-mod-stream.nginx +++ b/debian/libnginx-mod-stream.nginx @@ -9,5 +9,5 @@ $module =~ s/^libnginx-mod-//; $modulepath = $module; $modulepath =~ s/-/_/g; -print "mod debian/build-full/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod.nginx.skeleton b/debian/libnginx-mod.nginx.skeleton index 02c5edc..78c206f 100755 --- a/debian/libnginx-mod.nginx.skeleton +++ b/debian/libnginx-mod.nginx.skeleton @@ -9,5 +9,5 @@ $module =~ s/^libnginx-mod-//; $modulepath = $module; $modulepath =~ s/-/_/g; -print "mod debian/build-full/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; From 6d20e665d31c472845d8c3315b0592ef7df992ee Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 30 Mar 2016 15:07:19 +0300 Subject: [PATCH 098/651] Introduce libnginx-mod-http-perl --- debian/control | 13 ++++++++++++- debian/libnginx-mod-http-perl.install | 7 +++++++ debian/libnginx-mod-http-perl.nginx | 13 +++++++++++++ debian/libnginx-mod.conf/mod-http-perl.conf | 1 + debian/nginx-extras.install | 10 +--------- debian/rules | 4 ++-- 6 files changed, 36 insertions(+), 12 deletions(-) create mode 100755 debian/libnginx-mod-http-perl.install create mode 100755 debian/libnginx-mod-http-perl.nginx create mode 100644 debian/libnginx-mod.conf/mod-http-perl.conf mode change 100755 => 100644 debian/nginx-extras.install diff --git a/debian/control b/debian/control index 96fa475..3d0b6e9 100644 --- a/debian/control +++ b/debian/control @@ -180,8 +180,8 @@ Depends: nginx-common (= ${source:Version}), libnginx-mod-stream (= ${binary:Version}), libnginx-mod-http-auth-pam (= ${binary:Version}), libnginx-mod-http-lua (= ${binary:Version}), + libnginx-mod-http-perl (= ${binary:Version}), ${misc:Depends}, - ${perl:Depends}, ${shlibs:Depends} Breaks: nginx (<< 1.4.5-1) Provides: httpd, httpd-cgi, nginx @@ -275,6 +275,17 @@ Description: Stream module for Nginx also supports ACLs/connection limiting and configuring multiple operational parameters. +Package: libnginx-mod-http-perl +Architecture: any +Depends: ${perl:Depends}, ${misc:Depends}, ${shlibs:Depends} +Description: Perl module for Nginx + Embed Perl runtime into nginx. + . + The ngx_http_perl module is used to implement location and variable handlers + in Perl and insert Perl calls into SSI. + . + Note that this module is marked experimental. + Package: libnginx-mod-http-auth-pam Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends} diff --git a/debian/libnginx-mod-http-perl.install b/debian/libnginx-mod-http-perl.install new file mode 100755 index 0000000..14ca692 --- /dev/null +++ b/debian/libnginx-mod-http-perl.install @@ -0,0 +1,7 @@ +#!/usr/bin/perl -w + +use Config; + +my $vendorarch = substr($Config{vendorarch}, 1); +print "debian/build-extras/objs/src/http/modules/perl/blib/arch/auto/nginx/* $vendorarch/auto/nginx\n"; +print "debian/build-extras/objs/src/http/modules/perl/blib/lib/nginx.pm $vendorarch\n"; diff --git a/debian/libnginx-mod-http-perl.nginx b/debian/libnginx-mod-http-perl.nginx new file mode 100755 index 0000000..78c206f --- /dev/null +++ b/debian/libnginx-mod-http-perl.nginx @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use File::Basename; + +# Guess module name +$module = basename($0, '.nginx'); +$module =~ s/^libnginx-mod-//; + +$modulepath = $module; +$modulepath =~ s/-/_/g; + +print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod.conf/mod-http-perl.conf b/debian/libnginx-mod.conf/mod-http-perl.conf new file mode 100644 index 0000000..ab3d02a --- /dev/null +++ b/debian/libnginx-mod.conf/mod-http-perl.conf @@ -0,0 +1 @@ +load_module modules/ngx_http_perl_module.so; diff --git a/debian/nginx-extras.install b/debian/nginx-extras.install old mode 100755 new mode 100644 index dbcf498..833c24b --- a/debian/nginx-extras.install +++ b/debian/nginx-extras.install @@ -1,9 +1 @@ -#!/usr/bin/perl -w - -use Config; - -my $vendorarch = substr($Config{vendorarch}, 1); -print "debian/build-extras/objs/src/http/modules/perl/blib/arch/auto/nginx/* $vendorarch/auto/nginx\n"; -print "debian/build-extras/objs/src/http/modules/perl/blib/lib/nginx.pm $vendorarch\n"; - -print "debian/build-extras/objs/nginx usr/sbin\n"; +debian/build-extras/objs/nginx usr/sbin diff --git a/debian/rules b/debian/rules index 14d079f..9f6aeaf 100755 --- a/debian/rules +++ b/debian/rules @@ -11,7 +11,7 @@ DEBIAN_NGINX_PERL_LDFLAGS:= $(shell DEB_BUILD_MAINT_OPTIONS=hardening=+all,-pie export DEBIAN_NGINX_PERL_LDFLAGS FLAVOURS := full light extras -DYN_MODS := http-geoip http-image-filter http-xslt-filter mail stream http-auth-pam http-lua +DYN_MODS := http-geoip http-image-filter http-xslt-filter mail stream http-auth-pam http-lua http-perl MODULESDIR = $(CURDIR)/debian/modules BASEDIR = $(CURDIR) @@ -98,7 +98,7 @@ extras_configure_flags := \ --with-http_gzip_static_module \ --with-http_image_filter_module=dynamic \ --with-http_mp4_module \ - --with-http_perl_module \ + --with-http_perl_module=dynamic \ --with-http_random_index_module \ --with-http_secure_link_module \ --with-http_sub_module \ From d5ba950907a7115d16a0e4cd84f6654580fdd57d Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 30 Mar 2016 15:30:59 +0300 Subject: [PATCH 099/651] Perl module ifdefs for SSI so it cannot be loaded across builds. nginx-light is the only flavor that doesn't include SSI so we are including it there. Also, we switch the nginx-light module test to use libnginx-mod-http-perl, that way it's more likely to fail. --- debian/control | 4 ++-- debian/rules | 1 - debian/tests/control | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/debian/control b/debian/control index 3d0b6e9..d83c6cb 100644 --- a/debian/control +++ b/debian/control @@ -149,8 +149,8 @@ Description: nginx web/proxy server (basic version) FastCGI, Map, Proxy, Rewrite. . OPTIONAL HTTP MODULES: Auth Request, Charset, Gzip, Gzip Precompression, - Headers, HTTP/2, Index, Log, Real IP, SSL, Stub Status, Thread Pool, WebDAV, - Upstream. + Headers, HTTP/2, Index, Log, Real IP, SSI, SSL, Stub Status, Thread Pool, + WebDAV, Upstream. . THIRD PARTY MODULES: Echo. diff --git a/debian/rules b/debian/rules index 9f6aeaf..8805781 100755 --- a/debian/rules +++ b/debian/rules @@ -65,7 +65,6 @@ light_configure_flags := \ --without-http_referer_module \ --without-http_scgi_module \ --without-http_split_clients_module \ - --without-http_ssi_module \ --without-http_userid_module \ --without-http_uwsgi_module \ --add-module=$(MODULESDIR)/nginx-echo diff --git a/debian/tests/control b/debian/tests/control index 881cc56..735ce14 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -12,4 +12,4 @@ Depends: nginx-extras, curl Test-Command: curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ Restrictions: allow-stderr isolation-container -Depends: nginx-light, libnginx-mod-stream, curl +Depends: nginx-light, libnginx-mod-http-perl, curl From 166eb741134455e18eaa40f09c1a1d3739f6cc67 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 31 Mar 2016 13:57:49 +0300 Subject: [PATCH 100/651] We accidentally closed a wishlist bug with the nginx-light enhancements --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 24f9b02..a6d6712 100644 --- a/debian/changelog +++ b/debian/changelog @@ -10,7 +10,7 @@ nginx (1.9.13-1) UNRELEASED; urgency=medium * debian/control: + Enable http/2, thread pool & WebDAV on nginx-light. In order for dynamic modules to be loadable in all nginx flavors we need - to ensure the share the same build signature. + to ensure the share the same build signature. (Closes: #816095) + Use secure VCS uri (lintian). + Bump Standards to 3.9.7. * debian/rules: From 832524e25ef79005b55886bc8595e770771846ba Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 31 Mar 2016 13:57:54 +0300 Subject: [PATCH 101/651] Mark nginx-common & nginx-doc as 'Multi-Arch: foreign' (Closes: #812484) --- debian/changelog | 2 ++ debian/control | 2 ++ 2 files changed, 4 insertions(+) diff --git a/debian/changelog b/debian/changelog index a6d6712..7e366f3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,6 +11,8 @@ nginx (1.9.13-1) UNRELEASED; urgency=medium + Enable http/2, thread pool & WebDAV on nginx-light. In order for dynamic modules to be loadable in all nginx flavors we need to ensure the share the same build signature. (Closes: #816095) + + nginx-common & nginx-doc are now 'Multi-Arch: foreign'. (Closes: #812484) + Thanks Elrond for the report and the initial patch. + Use secure VCS uri (lintian). + Bump Standards to 3.9.7. * debian/rules: diff --git a/debian/control b/debian/control index d83c6cb..7c0a636 100644 --- a/debian/control +++ b/debian/control @@ -48,6 +48,7 @@ Description: small, powerful, scalable web/proxy server Package: nginx-doc Architecture: all +Multi-Arch: foreign Section: doc Depends: lsb-base (>= 3.2-14), ${misc:Depends} Description: small, powerful, scalable web/proxy server - documentation @@ -59,6 +60,7 @@ Description: small, powerful, scalable web/proxy server - documentation Package: nginx-common Architecture: all +Multi-Arch: foreign Depends: lsb-base (>= 3.2-14), ${misc:Depends} Replaces: nginx (<< 0.8.54-4), nginx-extras (<< 0.8.54-4), From f6a3b87f152ac63963e729d984677dbcdd4296a4 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 7 Apr 2016 09:06:12 +0300 Subject: [PATCH 102/651] Test all modules in all flavors --- debian/tests/control | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/debian/tests/control b/debian/tests/control index 735ce14..b4f6582 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -12,4 +12,12 @@ Depends: nginx-extras, curl Test-Command: curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ Restrictions: allow-stderr isolation-container -Depends: nginx-light, libnginx-mod-http-perl, curl +Depends: nginx-extras, curl, libnginx-mod-http-auth-pam, libnginx-mod-http-geoip, libnginx-mod-http-image-filter, libnginx-mod-http-lua, libnginx-mod-http-perl, libnginx-mod-http-xslt-filter, libnginx-mod-mail, libnginx-mod-stream + +Test-Command: curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ +Restrictions: allow-stderr isolation-container +Depends: nginx-full, curl, libnginx-mod-http-auth-pam, libnginx-mod-http-geoip, libnginx-mod-http-image-filter, libnginx-mod-http-lua, libnginx-mod-http-perl, libnginx-mod-http-xslt-filter, libnginx-mod-mail, libnginx-mod-stream + +Test-Command: curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ +Restrictions: allow-stderr isolation-container +Depends: nginx-light, curl, libnginx-mod-http-auth-pam, libnginx-mod-http-geoip, libnginx-mod-http-image-filter, libnginx-mod-http-lua, libnginx-mod-http-perl, libnginx-mod-http-xslt-filter, libnginx-mod-mail, libnginx-mod-stream From ddb802850295fc87b9e49d8a0fa0d7f30895f42c Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 7 Apr 2016 09:31:25 +0300 Subject: [PATCH 103/651] Convert tests to scripts --- debian/tests/control | 18 +++++++++--------- debian/tests/extras-module-deps | 3 +++ debian/tests/extras-simple | 3 +++ debian/tests/full-module-deps | 3 +++ debian/tests/full-simple | 3 +++ debian/tests/light-module-deps | 3 +++ debian/tests/light-simple | 3 +++ 7 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 debian/tests/extras-module-deps create mode 100644 debian/tests/extras-simple create mode 100644 debian/tests/full-module-deps create mode 100644 debian/tests/full-simple create mode 100644 debian/tests/light-module-deps create mode 100644 debian/tests/light-simple diff --git a/debian/tests/control b/debian/tests/control index b4f6582..a222b7f 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -1,23 +1,23 @@ -Test-Command: curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ +Tests: light-simple Restrictions: allow-stderr isolation-container Depends: nginx-light, curl -Test-Command: curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ +Tests: full-simple Restrictions: allow-stderr isolation-container Depends: nginx-full, curl -Test-Command: curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ +Tests: extras-simple Restrictions: allow-stderr isolation-container Depends: nginx-extras, curl -Test-Command: curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ -Restrictions: allow-stderr isolation-container -Depends: nginx-extras, curl, libnginx-mod-http-auth-pam, libnginx-mod-http-geoip, libnginx-mod-http-image-filter, libnginx-mod-http-lua, libnginx-mod-http-perl, libnginx-mod-http-xslt-filter, libnginx-mod-mail, libnginx-mod-stream - -Test-Command: curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ +Tests: full-module-deps Restrictions: allow-stderr isolation-container Depends: nginx-full, curl, libnginx-mod-http-auth-pam, libnginx-mod-http-geoip, libnginx-mod-http-image-filter, libnginx-mod-http-lua, libnginx-mod-http-perl, libnginx-mod-http-xslt-filter, libnginx-mod-mail, libnginx-mod-stream -Test-Command: curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ +Tests: light-module-deps Restrictions: allow-stderr isolation-container Depends: nginx-light, curl, libnginx-mod-http-auth-pam, libnginx-mod-http-geoip, libnginx-mod-http-image-filter, libnginx-mod-http-lua, libnginx-mod-http-perl, libnginx-mod-http-xslt-filter, libnginx-mod-mail, libnginx-mod-stream + +Tests: extras-module-deps +Restrictions: allow-stderr isolation-container +Depends: nginx-extras, curl, libnginx-mod-http-auth-pam, libnginx-mod-http-geoip, libnginx-mod-http-image-filter, libnginx-mod-http-lua, libnginx-mod-http-perl, libnginx-mod-http-xslt-filter, libnginx-mod-mail, libnginx-mod-stream diff --git a/debian/tests/extras-module-deps b/debian/tests/extras-module-deps new file mode 100644 index 0000000..cefed50 --- /dev/null +++ b/debian/tests/extras-module-deps @@ -0,0 +1,3 @@ +#!/bin/bash + +curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ diff --git a/debian/tests/extras-simple b/debian/tests/extras-simple new file mode 100644 index 0000000..cefed50 --- /dev/null +++ b/debian/tests/extras-simple @@ -0,0 +1,3 @@ +#!/bin/bash + +curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ diff --git a/debian/tests/full-module-deps b/debian/tests/full-module-deps new file mode 100644 index 0000000..cefed50 --- /dev/null +++ b/debian/tests/full-module-deps @@ -0,0 +1,3 @@ +#!/bin/bash + +curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ diff --git a/debian/tests/full-simple b/debian/tests/full-simple new file mode 100644 index 0000000..cefed50 --- /dev/null +++ b/debian/tests/full-simple @@ -0,0 +1,3 @@ +#!/bin/bash + +curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ diff --git a/debian/tests/light-module-deps b/debian/tests/light-module-deps new file mode 100644 index 0000000..cefed50 --- /dev/null +++ b/debian/tests/light-module-deps @@ -0,0 +1,3 @@ +#!/bin/bash + +curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ diff --git a/debian/tests/light-simple b/debian/tests/light-simple new file mode 100644 index 0000000..cefed50 --- /dev/null +++ b/debian/tests/light-simple @@ -0,0 +1,3 @@ +#!/bin/bash + +curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ From 9551b6324b11f2147cea249184254bbbb387c4f1 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 7 Apr 2016 10:02:52 +0300 Subject: [PATCH 104/651] Update nginx-auth-pam module to 1.5.1 Fixes linking issue with the dynamic module. --- debian/modules/README.Modules-versions | 2 +- debian/modules/nginx-auth-pam/ChangeLog | 6 ++++++ debian/modules/nginx-auth-pam/config | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index 53cbc2c..f6bec49 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -14,7 +14,7 @@ README for Modules versions nginx-auth-pam Homepage: https://github.com/stogh/ngx_http_auth_pam_module - Version: 1.5 + Version: 1.5.1 nginx-echo Homepage: https://github.com/agentzh/echo-nginx-module diff --git a/debian/modules/nginx-auth-pam/ChangeLog b/debian/modules/nginx-auth-pam/ChangeLog index 8aaf031..d45eae4 100644 --- a/debian/modules/nginx-auth-pam/ChangeLog +++ b/debian/modules/nginx-auth-pam/ChangeLog @@ -1,3 +1,9 @@ +2016-04-06 sto@iti.es + + * Version 1.5.1. + * Fix building alongside other modules in nginx 1.9.11+ (patch provided by + Graham Edgecombe ) + 2016-03-23 sto@iti.es * Version 1.5. diff --git a/debian/modules/nginx-auth-pam/config b/debian/modules/nginx-auth-pam/config index 9c30919..2275262 100644 --- a/debian/modules/nginx-auth-pam/config +++ b/debian/modules/nginx-auth-pam/config @@ -5,8 +5,8 @@ if test -n "$ngx_module_link"; then ngx_module_name=ngx_http_auth_pam_module ngx_module_incs= ngx_module_deps= - ngx_module_srcs="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_auth_pam_module.c" - ngx_module_libs="$CORE_LIBS -lpam" + ngx_module_srcs="$ngx_addon_dir/ngx_http_auth_pam_module.c" + ngx_module_libs="-lpam" . auto/module else From 30eb818ca4b5f6cec04d6a455900ec99713f3c07 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 7 Apr 2016 10:23:21 +0300 Subject: [PATCH 105/651] Update nginx-development-kit module to 0.3.0rc1 (dynamic module) --- debian/modules/README.Modules-versions | 2 +- debian/modules/nginx-development-kit/LICENSE | 13 + debian/modules/nginx-development-kit/README | 139 ---------- .../modules/nginx-development-kit/README.md | 238 ++++++++++++++++++ debian/modules/nginx-development-kit/config | 26 +- 5 files changed, 273 insertions(+), 145 deletions(-) create mode 100644 debian/modules/nginx-development-kit/LICENSE delete mode 100644 debian/modules/nginx-development-kit/README create mode 100644 debian/modules/nginx-development-kit/README.md diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index f6bec49..d7f35a4 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -10,7 +10,7 @@ README for Modules versions nginx-development-kit Homepage: https://github.com/simpl/ngx_devel_kit/ - Version: v0.2.19 + Version: v0.3.0rc1 nginx-auth-pam Homepage: https://github.com/stogh/ngx_http_auth_pam_module diff --git a/debian/modules/nginx-development-kit/LICENSE b/debian/modules/nginx-development-kit/LICENSE new file mode 100644 index 0000000..ee54448 --- /dev/null +++ b/debian/modules/nginx-development-kit/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2010-2015, Marcus Clyne + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder 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 HOLDER 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. diff --git a/debian/modules/nginx-development-kit/README b/debian/modules/nginx-development-kit/README deleted file mode 100644 index 50a2d95..0000000 --- a/debian/modules/nginx-development-kit/README +++ /dev/null @@ -1,139 +0,0 @@ - Nginx Development Kit (NDK) - =========================== - -Synopsis - - The NDK is an Nginx module that is designed to extend the core functionality of the - excellent Nginx webserver in a way that can be used as a basis of other Nginx modules. - - It has functions and macros to deal with generic tasks that don't currently have - generic code as part of the core distribution. The NDK itself adds few features - that are seen from a user's point of view - it's just designed to help reduce the - code that Nginx module developers need to write. - - Nginx module developers wishing to use any of the features in the NDK should specify - that the NDK is a dependency of their module, and that users will need to compile - it as well when they compile their own modules. They will also need to declare in - their own modules which features of the NDK they wish to use (explained below). - - If you are not an Nginx module developer, then the only useful part of this project - will be the 'usage for users' section below. - - -Status - - The NDK is now considered to be stable. It is already being used in quite a few third - party modules. - - -Features - - - additional conf_set functions for regexes, complex/script values, paths... - - macros to simplify tasks like checking for NULL values when doing ngx_array_push - - patches to the main source code - - ngx_auto_lib_core generic external library handler is included (see separate readme) - - - -Design - - modular : - - The kit itself is designed in a modular way, so that only the required code is compiled. - It's possible to add just a single NDK module, a few or all of them. - - auto-generated & easily extensible : - - Many of the macros available in the NDK are auto-generated from simple configuration - files. This makes creating similar macros for your own code very simple - it's usually - just the case of adding an extra line to a config file and re-running the build script. - - -Usage for users - - If another Nginx module you wish to use specifies that the NDK is a dependency, you - will need to do the following : - - 1 - download the source (http://github.com/simpl/ngx_devel_kit) - - 2 - unpack the source (tar -xzf $name) - - 3 - compile Nginx with the following extra option - - --add-module=/path/to/src - - e.g. - - ./configure --add-module=/path/to/ndk/base --add-module=/path/to/another/mod - - -Usage for developers - - To use the NDK in your own module, you need to add the following : - - 1 - add this line to your module - - #include - - note : since the NDK includes the following lines - - #include - #include - #include - - you can replace these with the single include above. - - 2 - add the following line in the config file for your module : - - have=NDK_[module_name] . auto/have - - for each NDK module that you wish to use (you need to include auto/have multiple - times if you wish to use multiple NDK modules. - - - Note : the old method of setting - - CFLAGS="$CFLAGS -DNDK_[module_name]" - - is now deprecated. It will still work, but results in unnecessary lines being - displayed when compiling Nginx. - - - Warning : using NDK_ALL - - You can also set NDK_ALL to include all the NDK modules. This is primarily as - a convenience in the early stages of development of another module. However, - - DO NOT LEAVE 'NDK_ALL' IN YOUR CONFIG FILE WHEN PUBLISHING - - Although the NDK is fairly small now, it could in time become a large repository - of code that would, if using NDK_ALL, result in considerably more code being compiled - than is necessary. - - -Todo - - - documentation for modules that don't already have it - - additional phase-handler functions - - generically testing for needing to add a handler - - remove dependency of set_var on OpenSSL being compiled in - - -License - - BSD - - -Contributing / Feedback - - If you are an Nginx module developer, and have developed some functions that are - generic in nature (or would be easily adapted to be so), then please send them to - me at the address below, and I'll add them to the kit. - - -Author - - Marcus Clyne (contact at simpl dot it) - - - diff --git a/debian/modules/nginx-development-kit/README.md b/debian/modules/nginx-development-kit/README.md new file mode 100644 index 0000000..e0ed4eb --- /dev/null +++ b/debian/modules/nginx-development-kit/README.md @@ -0,0 +1,238 @@ +Name +==== + +NDK - Nginx Development Kit + +Table of Contents +================= + +* [Name](#name) +* [Synopsis](#synopsis) +* [Status](#status) +* [Features](#features) +* [Design](#design) + * [modular](#modular) + * [auto-generated & easily extensible](#auto-generated--easily-extensible) +* [Usage for users](#usage-for-users) + * [Building as a dynamic module](#building-as-a-dynamic-module) +* [Usage for developers](#usage-for-developers) + * [Warning: using NDK_ALL](#warning-using-ndk_all) +* [Modules using NDK](#modules-using-ndk) +* [TODO](#todo) +* [License](#license) +* [Contributing / Feedback](#contributing--feedback) +* [Author](#author) + +Synopsis +======== + +The NDK is an Nginx module that is designed to extend the core functionality of the +excellent Nginx webserver in a way that can be used as a basis of other Nginx modules. + +It has functions and macros to deal with generic tasks that don't currently have +generic code as part of the core distribution. The NDK itself adds few features +that are seen from a user's point of view - it's just designed to help reduce the +code that Nginx module developers need to write. + +Nginx module developers wishing to use any of the features in the NDK should specify +that the NDK is a dependency of their module, and that users will need to compile +it as well when they compile their own modules. They will also need to declare in +their own modules which features of the NDK they wish to use (explained below). + +If you are not an Nginx module developer, then the only useful part of this project +will be the 'usage for users' section below. + +Status +====== + +The NDK is now considered to be stable. It is already being used in quite a few third +party modules. + +Features +======== + +* additional conf_set functions for regexes, complex/script values, paths... +* macros to simplify tasks like checking for NULL values when doing ngx_array_push +* patches to the main source code +* ngx_auto_lib_core generic external library handler is included (see separate readme) + +[Back to TOC](#table-of-contents) + +Design +====== + +modular +------- + +The kit itself is designed in a modular way, so that only the required code is compiled. +It's possible to add just a single NDK module, a few or all of them. + +[Back to TOC](#table-of-contents) + +auto-generated & easily extensible +---------------------------------- + +Many of the macros available in the NDK are auto-generated from simple configuration +files. This makes creating similar macros for your own code very simple - it's usually +just the case of adding an extra line to a config file and re-running the build script. + +[Back to TOC](#table-of-contents) + +Usage for users +=============== + +If another Nginx module you wish to use specifies that the NDK is a dependency, you +will need to do the following : + +1. download the source (https://github.com/simpl/ngx_devel_kit) +2. unpack the source (tar -xzf $name) +3. compile Nginx with the following extra option `--add-module=/path/to/ngx_devel_kit`. + +e.g. + +```bash +./configure --add-module=/path/to/ngx_devel_kit \ + --add-module=/path/to/another/module +``` + +[Back to TOC](#table-of-contents) + +Building as a dynamic module +---------------------------- + +Starting from NGINX 1.9.11, you can also compile this module as a dynamic module, by using the `--add-dynamic-module=PATH` option instead of `--add-module=PATH` on the +`./configure` command line above. And then you can explicitly load the module in your `nginx.conf` via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module) +directive, for example, + +```nginx +load_module /path/to/modules/ndk_http_module.so; +load_module /path/to/another/module.so; +``` + +[Back to TOC](#table-of-contents) + +Usage for developers +==================== + +To use the NDK in your own module, you need to add the following: + +1. add this line to your module + +```C +#include +``` + +Note: since the NDK includes the following lines + +```C +#include +#include +#include +``` + +you can replace these with the single include above. +2. add the following line in the config file for your module: + +```bash +have=NDK_[module_name] . auto/have +``` + +for each NDK module that you wish to use (you need to include auto/have multiple +times if you wish to use multiple NDK modules. + +Note: the old method of setting + +```config +CFLAGS="$CFLAGS -DNDK_[module_name]" +``` + +is now deprecated. It will still work, but results in unnecessary lines being +displayed when compiling Nginx. + +[Back to TOC](#table-of-contents) + +Warning: using NDK_ALL +---------------------- + +You can also set `NDK_ALL` to include all the NDK modules. This is primarily as +a convenience in the early stages of development of another module. However, + +DO NOT LEAVE `NDK_ALL` IN YOUR CONFIG FILE WHEN PUBLISHING + +Although the NDK is fairly small now, it could in time become a large repository +of code that would, if using NDK_ALL, result in considerably more code being compiled +than is necessary. + +[Back to TOC](#table-of-contents) + +Modules using NDK +================= + +The following 3rd-party modules make use of NDK. + +* [ngx_http_lua_module](https://github.com/openresty/lua-nginx-module#readme) +* [ngx_http_set_misc_module](https://github.com/openresty/set-misc-nginx-module#readme) +* [ngx_http_encrypted_session_module](https://github.com/openresty/encrypted-session-nginx-module#readme) +* [ngx_http_form_input_module](https://github.com/calio/form-input-nginx-module#readme) +* [ngx_http_iconv_module](https://github.com/calio/iconv-nginx-module#readme) +* [ngx_http_array_var_module](https://github.com/openresty/array-var-nginx-module#readme) + +[Back to TOC](#table-of-contents) + +TODO +==== + +* documentation for modules that don't already have it +* additional phase-handler functions +* generically testing for needing to add a handler +* remove dependency of set_var on OpenSSL being compiled in + +[Back to TOC](#table-of-contents) + +License +======= + +Copyright (c) 2010-2016, Marcus Clyne + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. +2. 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. +3. Neither the name of the copyright holder 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 HOLDER 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. + +[Back to TOC](#table-of-contents) + +Contributing / Feedback +======================= + +If you are an Nginx module developer, and have developed some functions that are +generic in nature (or would be easily adapted to be so), then please send them to +me at the address below, and I'll add them to the kit. + +[Back to TOC](#table-of-contents) + +Author +====== + +Marcus Clyne (contact at simpl dot it) + +[Back to TOC](#table-of-contents) + diff --git a/debian/modules/nginx-development-kit/config b/debian/modules/nginx-development-kit/config index 65563d7..8cb7ad0 100644 --- a/debian/modules/nginx-development-kit/config +++ b/debian/modules/nginx-development-kit/config @@ -18,8 +18,8 @@ ndk_get_nginx_version() { # We get the Nginx version number from the string form rather than # nginx_version because it is available in more (every?) version - cat src/core/nginx.h | - grep '#define NGINX_VERSION' | + cat src/core/nginx.h | + grep '#define NGINX_VERSION' | sed -r \ -e 's/[^0-9.]*([0-9.]+).*/\1/' \ -e 's/([0-9]+\.[0-9]+\.)([0-9]{1})$/\100\2/' \ @@ -35,10 +35,26 @@ ndk_get_nginx_version() { ngx_addon_name=ngx_devel_kit ngx_objs_dirs="$ngx_addon_dir/objs $NGX_OBJS/addon/ndk" +NDK_SRCS="$ngx_addon_dir/src/ndk.c" +NDK_DEPS="$ngx_addon_dir/src/ndk.h" +NDK_INCS="$ngx_addon_dir/src $ngx_objs_dirs" + CORE_INCS="$CORE_INCS $ngx_objs_dirs" HTTP_INCS="$HTTP_INCS $ngx_addon_dir/src $ngx_objs_dir" -HTTP_MODULES="$HTTP_MODULES ndk_http_module" -NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/src/ndk.c" + +if test -n "$ngx_module_link"; then + ngx_module_type=HTTP + ngx_module_name="ndk_http_module" + ngx_module_srcs="$NDK_SRCS" + ngx_module_deps="$NDK_DEPS" + ngx_module_incs="$NDK_INCS" + + . auto/module +else + HTTP_MODULES="$HTTP_MODULES ndk_http_module" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $NDK_SRCS" + NGX_ADDON_DEPS="$NGX_ADDON_SRCS $NDK_DEPS" +fi have=NDK . auto/have @@ -46,4 +62,4 @@ have=NDK . auto/have ## INCLUDES ## ############## -. $ngx_addon_dir/ngx_auto_lib_core \ No newline at end of file +. $ngx_addon_dir/ngx_auto_lib_core From 481751859a332c2881d4df19d4e761be5386f64a Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 7 Apr 2016 10:51:41 +0300 Subject: [PATCH 106/651] Introduce libnginx-mod-http-ndk module --- debian/control | 16 +++++++++++++++- debian/libnginx-mod-http-ndk.nginx | 2 ++ debian/libnginx-mod.conf/mod-http-ndk.conf | 1 + debian/rules | 4 ++-- 4 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 debian/libnginx-mod-http-ndk.nginx create mode 100644 debian/libnginx-mod.conf/mod-http-ndk.conf diff --git a/debian/control b/debian/control index 7c0a636..2398e29 100644 --- a/debian/control +++ b/debian/control @@ -299,7 +299,7 @@ Description: PAM authentication module for Nginx Package: libnginx-mod-http-lua Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: libnginx-mod-http-ndk (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} Description: LUA module for Nginx Embed LUA runtime into nginx. . @@ -307,3 +307,17 @@ Description: LUA module for Nginx 2.0/2.1, into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. + +Package: libnginx-mod-http-ndk +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: Nginx Development Kit module + The NDK is an Nginx module that is designed to extend the core functionality of + the excellent Nginx webserver in a way that can be used as a basis of other + Nginx modules. + . + It has functions and macros to deal with generic tasks that don't currently + have generic code as part of the core distribution. The NDK itself adds few + features that are seen from a user's point of view - it's just designed to help + reduce the code that Nginx module developers need to write. Embed LUA runtime + into nginx. diff --git a/debian/libnginx-mod-http-ndk.nginx b/debian/libnginx-mod-http-ndk.nginx new file mode 100644 index 0000000..1905145 --- /dev/null +++ b/debian/libnginx-mod-http-ndk.nginx @@ -0,0 +1,2 @@ +mod debian/build-extras/objs/ndk_http_module.so +mod debian/libnginx-mod.conf/mod-http-ndk.conf diff --git a/debian/libnginx-mod.conf/mod-http-ndk.conf b/debian/libnginx-mod.conf/mod-http-ndk.conf new file mode 100644 index 0000000..3908af6 --- /dev/null +++ b/debian/libnginx-mod.conf/mod-http-ndk.conf @@ -0,0 +1 @@ +load_module modules/ndk_http_module.so; diff --git a/debian/rules b/debian/rules index 8805781..63abd77 100755 --- a/debian/rules +++ b/debian/rules @@ -11,7 +11,7 @@ DEBIAN_NGINX_PERL_LDFLAGS:= $(shell DEB_BUILD_MAINT_OPTIONS=hardening=+all,-pie export DEBIAN_NGINX_PERL_LDFLAGS FLAVOURS := full light extras -DYN_MODS := http-geoip http-image-filter http-xslt-filter mail stream http-auth-pam http-lua http-perl +DYN_MODS := http-geoip http-image-filter http-xslt-filter mail stream http-auth-pam http-lua http-perl http-ndk MODULESDIR = $(CURDIR)/debian/modules BASEDIR = $(CURDIR) @@ -110,7 +110,7 @@ extras_configure_flags := \ --add-dynamic-module=$(MODULESDIR)/nginx-auth-pam \ --add-module=$(MODULESDIR)/nginx-cache-purge \ --add-module=$(MODULESDIR)/nginx-dav-ext-module \ - --add-module=$(MODULESDIR)/nginx-development-kit \ + --add-dynamic-module=$(MODULESDIR)/nginx-development-kit \ --add-module=$(MODULESDIR)/nginx-echo \ --add-module=$(MODULESDIR)/ngx-fancyindex \ --add-module=$(MODULESDIR)/nginx-http-push \ From 57e63bc6d8f61ca4c8ddeb23957b6f8de01fb46c Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 18 Apr 2016 11:47:04 +0300 Subject: [PATCH 107/651] dh_nginx: Support setting module priorities in .nginx files --- debian/autoscripts/postinst-nginx | 9 ++++++--- debian/autoscripts/postrm-nginx | 9 ++++++--- debian/autoscripts/prerm-nginx | 9 ++++++--- debian/dh_nginx | 9 ++++++--- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/debian/autoscripts/postinst-nginx b/debian/autoscripts/postinst-nginx index 565015b..b2efc7b 100644 --- a/debian/autoscripts/postinst-nginx +++ b/debian/autoscripts/postinst-nginx @@ -1,8 +1,11 @@ -for conf in #NAMES# ; do +for confpair in #NAMES# ; do + from=$(echo $confpair | cut -d: -f1) + to=$(echo $confpair | cut -d: -f2) + # Symlink on fresh installations if [ -z "$2" ]; then - ln -sf /usr/share/nginx/modules-available/$conf \ - /etc/nginx/modules-enabled/$conf + ln -sf /usr/share/nginx/modules-available/$from \ + /etc/nginx/modules-enabled/$to fi done diff --git a/debian/autoscripts/postrm-nginx b/debian/autoscripts/postrm-nginx index 60b0493..bb16a45 100644 --- a/debian/autoscripts/postrm-nginx +++ b/debian/autoscripts/postrm-nginx @@ -1,7 +1,10 @@ if [ "$1" = "purge" ] ; then - for conf in #NAMES# ; do - if [ -e /etc/nginx/etc/nginx/modules-enabled/$conf ]; then - rm /etc/nginx/etc/nginx/modules-enabled/$conf + for confpair in #NAMES# ; do + from=$(echo $confpair | cut -d: -f1) + to=$(echo $confpair | cut -d: -f2) + + if [ -e /etc/nginx/modules-enabled/$to ]; then + rm /etc/nginx/modules-enabled/$to fi done diff --git a/debian/autoscripts/prerm-nginx b/debian/autoscripts/prerm-nginx index efeaae8..8bc2d25 100644 --- a/debian/autoscripts/prerm-nginx +++ b/debian/autoscripts/prerm-nginx @@ -1,7 +1,10 @@ if [ "$1" = "remove" ] || [ "$1" = "deconfigure" ] ; then - for conf in #NAMES# ; do - if [ -e /etc/nginx/etc/nginx/modules-enabled/$conf ]; then - rm /etc/nginx/etc/nginx/modules-enabled/$conf + for confpair in #NAMES# ; do + from=$(echo $confpair | cut -d: -f1) + to=$(echo $confpair | cut -d: -f2) + + if [ -e /etc/nginx/modules-enabled/$to ]; then + rm /etc/nginx/modules-enabled/$to fi done diff --git a/debian/dh_nginx b/debian/dh_nginx index 2d7b942..447ab79 100755 --- a/debian/dh_nginx +++ b/debian/dh_nginx @@ -169,7 +169,8 @@ foreach my $package ((@{$dh{DOPACKAGES}})) { my $type = lc(shift @{$line}) if $line->[0]; my $source = shift @{$line} if $line->[0]; - my @arguments = map {"$_ "} @{$line}; + my @arguments = @{$line}; + my $destination; $type = "modules" if $type eq "mod"; my $installdir = $tmp . "/" . nginx_modules_conf_installdir(); @@ -185,8 +186,10 @@ foreach my $package ((@{$dh{DOPACKAGES}})) if ($basesource =~ m/\.conf$/) { my $enablename = $basesource; - push @{$PACKAGE_TYPE{'has_a_module'}}, $enablename; - verbose_print("Installing module configuration $enablename into $installdir\n"); + my $prio = $#arguments >= 0 ? $arguments[0] : 50; + $destination = "$prio-$basesource"; + push @{$PACKAGE_TYPE{'has_a_module'}}, "$enablename:$destination"; + verbose_print("Installing module configuration $enablename into $installdir prio:$prio\n"); } elsif ($basesource =~ m/\.so$/) { From fef2251ae991b7133991b311268fa39040cdd750 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 7 Apr 2016 12:56:43 +0300 Subject: [PATCH 108/651] NDK is a dependency, load it before nginx-lua --- debian/libnginx-mod-http-ndk.nginx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/libnginx-mod-http-ndk.nginx b/debian/libnginx-mod-http-ndk.nginx index 1905145..562723b 100644 --- a/debian/libnginx-mod-http-ndk.nginx +++ b/debian/libnginx-mod-http-ndk.nginx @@ -1,2 +1,2 @@ mod debian/build-extras/objs/ndk_http_module.so -mod debian/libnginx-mod.conf/mod-http-ndk.conf +mod debian/libnginx-mod.conf/mod-http-ndk.conf 10 From 65f92dd626ecd8eaf809ace9b81406511ce5c7af Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 18 Apr 2016 11:54:13 +0300 Subject: [PATCH 109/651] merge into dh_nginx --- debian/dh_nginx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/debian/dh_nginx b/debian/dh_nginx index 447ab79..3be792d 100755 --- a/debian/dh_nginx +++ b/debian/dh_nginx @@ -112,9 +112,8 @@ Modules are handled specially and are determined by the B type. Modules mus have a I<.conf> suffix. In that case the file is interpreted as module load file and is installed to I. If the file is ending with a I<.so> suffix it is interpreted as actual module shared object and is -installed to the Nginx module directory. Moreover, if a I<.load> file is -installed the configuration is activated in the maintainer script at -installation time. +installed to the Nginx module directory, an optional numeric priority can be +set as the last argument to handle module dependencies. =head1 OPTIONS @@ -205,7 +204,7 @@ foreach my $package ((@{$dh{DOPACKAGES}})) } # TODO - error("module: \"$basesource\" needs .conf, .so or .load suffix") if $basesource !~ m/\.(conf|so)/; + error("module: \"$basesource\" needs .conf, .so or suffix") if $basesource !~ m/\.(conf|so)/; } if (! -d $installdir) From 578f222e929b84dd1cccfb8b7a606fa4d4d5511c Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 18 Apr 2016 12:43:59 +0300 Subject: [PATCH 110/651] README.packaging: Add a note about dynamic module support. --- debian/README.Packaging | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/debian/README.Packaging b/debian/README.Packaging index 66a88c1..61358da 100644 --- a/debian/README.Packaging +++ b/debian/README.Packaging @@ -9,6 +9,22 @@ Workflow for Unstable We use the standard git-buildpackage workflow. +Dynamic Modules +=============== + +Since v1.9.11 Nginx added dynamic module support. This will sanitize the +nginx packaging flow in the long term, but there is a lot work to be done +in order to get there. We will gradually convert all modules to dynamic +as they add support for it. + +Currently nginx modules need to be build together with nginx, but this +will be fixed upstream [0]. Since we already ship 3rd party modules under +debian/modules/ we will start shipping module packages (libnginx-mod) from +the same source. Once upstream implements separated building we will +split each module to a separate source. + +[0] https://www.nginx.com/blog/dynamic-modules-nginx-1-9-11/ + Workflow for Experimental (not-active) ====================================== From 0eb87154ce11613d2ad16e5ff7d0b889ca84fd54 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 18 Apr 2016 12:58:40 +0300 Subject: [PATCH 111/651] Imported Upstream version 1.9.14 --- CHANGES | 19 +- CHANGES.ru | 17 + auto/lib/openssl/conf | 2 +- auto/types/sizeof | 8 +- auto/types/typedef | 13 +- auto/unix | 5 +- contrib/vim/syntax/nginx.vim | 2 +- src/core/nginx.c | 7 +- src/core/nginx.h | 4 +- src/core/ngx_conf_file.c | 6 +- src/core/ngx_config.h | 5 - src/core/ngx_connection.c | 36 +- src/core/ngx_connection.h | 22 +- src/core/ngx_crypt.c | 4 +- src/core/ngx_cycle.c | 10 +- src/core/ngx_cycle.h | 40 +- src/core/ngx_file.c | 6 +- src/core/ngx_inet.c | 22 +- src/core/ngx_log.c | 20 +- src/core/ngx_log.h | 3 +- src/core/ngx_open_file_cache.c | 2 +- src/core/ngx_parse_time.c | 2 +- src/core/ngx_resolver.c | 2 +- src/core/ngx_slab.c | 11 +- src/core/ngx_syslog.c | 6 +- src/core/ngx_times.c | 4 +- src/event/modules/ngx_epoll_module.c | 2 +- src/event/modules/ngx_eventport_module.c | 10 +- src/event/modules/ngx_kqueue_module.c | 23 +- src/event/ngx_event.c | 2 +- src/event/ngx_event.h | 2 +- src/event/ngx_event_openssl.c | 69 +- src/event/ngx_event_openssl.h | 17 + src/event/ngx_event_openssl_stapling.c | 6 +- src/event/ngx_event_pipe.c | 12 +- src/http/modules/ngx_http_auth_basic_module.c | 2 +- .../modules/ngx_http_auth_request_module.c | 4 +- .../modules/ngx_http_chunked_filter_module.c | 2 +- src/http/modules/ngx_http_dav_module.c | 10 +- src/http/modules/ngx_http_fastcgi_module.c | 16 +- .../modules/ngx_http_gzip_filter_module.c | 4 +- .../modules/ngx_http_image_filter_module.c | 4 +- src/http/modules/ngx_http_limit_conn_module.c | 4 +- src/http/modules/ngx_http_map_module.c | 2 +- src/http/modules/ngx_http_memcached_module.c | 2 +- src/http/modules/ngx_http_mp4_module.c | 18 +- src/http/modules/ngx_http_proxy_module.c | 8 +- .../modules/ngx_http_random_index_module.c | 2 +- .../modules/ngx_http_range_filter_module.c | 4 +- src/http/modules/ngx_http_realip_module.c | 4 +- src/http/modules/ngx_http_referer_module.c | 2 +- src/http/modules/ngx_http_rewrite_module.c | 2 +- src/http/modules/ngx_http_scgi_module.c | 2 +- src/http/modules/ngx_http_ssi_filter_module.c | 8 +- src/http/modules/ngx_http_ssl_module.c | 9 +- src/http/modules/ngx_http_sub_filter_module.c | 2 +- .../ngx_http_upstream_ip_hash_module.c | 2 +- .../ngx_http_upstream_least_conn_module.c | 2 +- src/http/ngx_http_core_module.c | 39 +- src/http/ngx_http_core_module.h | 8 +- src/http/ngx_http_file_cache.c | 2 +- src/http/ngx_http_request.c | 12 +- src/http/ngx_http_request.h | 3 + src/http/ngx_http_request_body.c | 41 +- src/http/ngx_http_script.c | 6 +- src/http/ngx_http_upstream.c | 24 +- src/http/ngx_http_upstream_round_robin.c | 2 +- src/http/ngx_http_variables.c | 5 +- src/http/ngx_http_write_filter_module.c | 2 +- src/http/v2/ngx_http_v2.c | 681 ++++++++++-------- src/http/v2/ngx_http_v2.h | 9 +- src/http/v2/ngx_http_v2_module.c | 2 +- src/mail/ngx_mail.h | 2 +- src/mail/ngx_mail_auth_http_module.c | 2 +- src/mail/ngx_mail_proxy_module.c | 2 +- src/mail/ngx_mail_smtp_handler.c | 2 +- src/mail/ngx_mail_ssl_module.c | 8 +- src/os/unix/ngx_atomic.h | 20 +- src/os/unix/ngx_channel.h | 8 +- src/os/unix/ngx_file_aio_read.c | 2 +- src/os/unix/ngx_files.c | 2 +- src/os/unix/ngx_linux_aio_read.c | 2 +- src/os/unix/ngx_linux_sendfile_chain.c | 2 +- src/os/unix/ngx_os.h | 2 +- src/os/unix/ngx_process.c | 2 +- src/os/unix/ngx_process_cycle.c | 10 +- src/os/unix/ngx_readv_chain.c | 2 +- src/os/unix/ngx_recv.c | 4 +- src/os/unix/ngx_send.c | 2 +- src/os/unix/ngx_sunpro_amd64.il | 6 +- src/os/unix/ngx_sunpro_x86.il | 6 +- src/os/unix/ngx_udp_recv.c | 4 +- src/stream/ngx_stream_limit_conn_module.c | 4 +- src/stream/ngx_stream_ssl_module.c | 2 +- .../ngx_stream_upstream_least_conn_module.c | 2 +- src/stream/ngx_stream_upstream_round_robin.c | 2 +- 96 files changed, 844 insertions(+), 628 deletions(-) diff --git a/CHANGES b/CHANGES index 0ac9c61..e1e596e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,21 @@ +Changes with nginx 1.9.14 05 Apr 2016 + + *) Feature: OpenSSL 1.1.0 compatibility. + + *) Feature: the "proxy_request_buffering", "fastcgi_request_buffering", + "scgi_request_buffering", and "uwsgi_request_buffering" directives + now work with HTTP/2. + + *) Bugfix: "zero size buf in output" alerts might appear in logs when + using HTTP/2. + + *) Bugfix: the "client_max_body_size" directive might work incorrectly + when using HTTP/2. + + *) Bugfix: of minor bugs in logging. + + Changes with nginx 1.9.13 29 Mar 2016 *) Change: non-idempotent requests (POST, LOCK, PATCH) are no longer @@ -1875,7 +1892,7 @@ Changes with nginx 1.1.6 17 Oct 2011 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 + *) Change: now the 0x7F-0xFF characters are escaped as \xXX in an access_log. *) Feature: "proxy/fastcgi/scgi/uwsgi_ignore_headers" directives support diff --git a/CHANGES.ru b/CHANGES.ru index 7c92f7b..c6e6e84 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,21 @@ +Изменения в nginx 1.9.14 05.04.2016 + + *) Добавление: совместимость с OpenSSL 1.1.0. + + *) Добавление: директивы proxy_request_buffering, + fastcgi_request_buffering, scgi_request_buffering и + uwsgi_request_buffering теперь работают при использовании HTTP/2. + + *) Исправление: при использовании HTTP/2 в логах могли появляться + сообщения "zero size buf in output". + + *) Исправление: при использовании HTTP/2 директива client_max_body_size + могла работать неверно. + + *) Исправление: незначительных ошибок логгирования. + + Изменения в nginx 1.9.13 29.03.2016 *) Изменение: неидемпотентные запросы (POST, LOCK, PATCH) теперь по diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf index e438050..39d9602 100644 --- a/auto/lib/openssl/conf +++ b/auto/lib/openssl/conf @@ -52,7 +52,7 @@ else ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs="-lssl -lcrypto $NGX_LIBDL" - ngx_feature_test="SSL_library_init()" + ngx_feature_test="SSL_CTX_set_options(NULL, 0)" . auto/feature if [ $ngx_found = no ]; then diff --git a/auto/types/sizeof b/auto/types/sizeof index a5f66bb..b5b71bb 100644 --- a/auto/types/sizeof +++ b/auto/types/sizeof @@ -45,9 +45,6 @@ if [ -x $NGX_AUTOTEST ]; then fi -rm -rf $NGX_AUTOTEST* - - case $ngx_size in 4) ngx_max_value=2147483647 @@ -69,6 +66,11 @@ case $ngx_size in echo $ngx_test >> $NGX_AUTOCONF_ERR echo "----------" >> $NGX_AUTOCONF_ERR + rm -rf $NGX_AUTOTEST* + exit 1 esac + +rm -rf $NGX_AUTOTEST* + diff --git a/auto/types/typedef b/auto/types/typedef index 8b5c368..b55237e 100644 --- a/auto/types/typedef +++ b/auto/types/typedef @@ -49,18 +49,23 @@ END fi fi - rm -rf $NGX_AUTOTEST* - if [ $ngx_found = no ]; then - echo $ngx_n " $ngx_try not found$ngx_c" + if [ $ngx_try = $ngx_type ]; then + echo $ngx_n " $ngx_try not found$ngx_c" + else + echo $ngx_n ", $ngx_try not found$ngx_c" + fi echo "----------" >> $NGX_AUTOCONF_ERR cat $NGX_AUTOTEST.c >> $NGX_AUTOCONF_ERR echo "----------" >> $NGX_AUTOCONF_ERR echo $ngx_test >> $NGX_AUTOCONF_ERR echo "----------" >> $NGX_AUTOCONF_ERR + fi - else + rm -rf $NGX_AUTOTEST* + + if [ $ngx_found != no ]; then break fi done diff --git a/auto/unix b/auto/unix index 16d9523..8c0e813 100755 --- a/auto/unix +++ b/auto/unix @@ -260,7 +260,7 @@ ngx_feature_run=no ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs= -ngx_feature_test="dlopen(NULL, 0); dlsym(NULL, NULL)" +ngx_feature_test="dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); dlsym(NULL, NULL)" . auto/feature @@ -547,6 +547,7 @@ ngx_param=NGX_PTR_SIZE; ngx_value=$ngx_size; . auto/types/value NGX_INCLUDE_AUTO_CONFIG_H="#include \"ngx_auto_config.h\"" +ngx_type="uint32_t"; ngx_types="u_int32_t"; . auto/types/typedef ngx_type="uint64_t"; ngx_types="u_int64_t"; . auto/types/typedef ngx_type="sig_atomic_t"; ngx_types="int"; . auto/types/typedef @@ -555,7 +556,7 @@ ngx_param=NGX_SIG_ATOMIC_T_SIZE; ngx_value=$ngx_size; . auto/types/value ngx_type="socklen_t"; ngx_types="int"; . auto/types/typedef -ngx_type="in_addr_t"; ngx_types="uint32_t"; . auto/types/typedef +ngx_type="in_addr_t"; ngx_types="uint32_t u_int32_t"; . auto/types/typedef ngx_type="in_port_t"; ngx_types="u_short"; . auto/types/typedef diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim index 444d96e..8f13017 100644 --- a/contrib/vim/syntax/nginx.vim +++ b/contrib/vim/syntax/nginx.vim @@ -57,6 +57,7 @@ syn keyword ngxDirectiveError post_action syn keyword ngxDirectiveDeprecated connections syn keyword ngxDirectiveDeprecated imap syn keyword ngxDirectiveDeprecated limit_zone +syn keyword ngxDirectiveDeprecated mysql_test syn keyword ngxDirectiveDeprecated open_file_cache_retest syn keyword ngxDirectiveDeprecated optimize_server_names syn keyword ngxDirectiveDeprecated satisfy_any @@ -246,7 +247,6 @@ syn keyword ngxDirective mp4_max_buffer_size syn keyword ngxDirective msie_padding syn keyword ngxDirective msie_refresh syn keyword ngxDirective multi_accept -syn keyword ngxDirective mysql_test syn keyword ngxDirective open_file_cache syn keyword ngxDirective open_file_cache_errors syn keyword ngxDirective open_file_cache_events diff --git a/src/core/nginx.c b/src/core/nginx.c index 2823169..60f8fe7 100644 --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -413,13 +413,12 @@ ngx_show_version_info(void) #endif #if (NGX_SSL) - if (SSLeay() == SSLEAY_VERSION_NUMBER) { + if (ngx_strcmp(ngx_ssl_version(), OPENSSL_VERSION_TEXT) == 0) { ngx_write_stderr("built with " OPENSSL_VERSION_TEXT NGX_LINEFEED); } else { ngx_write_stderr("built with " OPENSSL_VERSION_TEXT " (running with "); - ngx_write_stderr((char *) (uintptr_t) - SSLeay_version(SSLEAY_VERSION)); + ngx_write_stderr((char *) (uintptr_t) ngx_ssl_version()); ngx_write_stderr(")" NGX_LINEFEED); } #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME @@ -1510,7 +1509,7 @@ ngx_load_module(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - ngx_log_debug2(NGX_LOG_DEBUG_CORE, cf->log, 0, "module: %s i:%i", + ngx_log_debug2(NGX_LOG_DEBUG_CORE, cf->log, 0, "module: %s i:%ui", module->name, module->index); } diff --git a/src/core/nginx.h b/src/core/nginx.h index 238d8b8..d0a6f65 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1009013 -#define NGINX_VERSION "1.9.13" +#define nginx_version 1009014 +#define NGINX_VERSION "1.9.14" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c index fb72656..c60d5fb 100644 --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -613,9 +613,9 @@ ngx_conf_read_token(ngx_conf_t *cf) need_space = 0; } else { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "unexpected \"%c\"", ch); - return NGX_ERROR; + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unexpected \"%c\"", ch); + return NGX_ERROR; } } diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h index 145e43a..a0bfa63 100644 --- a/src/core/ngx_config.h +++ b/src/core/ngx_config.h @@ -125,12 +125,7 @@ typedef intptr_t ngx_flag_t; #endif -#if ((__GNU__ == 2) && (__GNUC_MINOR__ < 8)) -#define NGX_MAX_UINT32_VALUE (uint32_t) 0xffffffffLL -#else #define NGX_MAX_UINT32_VALUE (uint32_t) 0xffffffff -#endif - #define NGX_MAX_INT32_VALUE (uint32_t) 0x7fffffff diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 572def2..5a53bac 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -47,21 +47,21 @@ ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen) switch (ls->sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: - ls->addr_text_max_len = NGX_INET6_ADDRSTRLEN; - break; + ls->addr_text_max_len = NGX_INET6_ADDRSTRLEN; + break; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: - ls->addr_text_max_len = NGX_UNIX_ADDRSTRLEN; - len++; - break; + ls->addr_text_max_len = NGX_UNIX_ADDRSTRLEN; + len++; + break; #endif case AF_INET: - ls->addr_text_max_len = NGX_INET_ADDRSTRLEN; - break; + ls->addr_text_max_len = NGX_INET_ADDRSTRLEN; + break; default: - ls->addr_text_max_len = NGX_SOCKADDR_STRLEN; - break; + ls->addr_text_max_len = NGX_SOCKADDR_STRLEN; + break; } ls->addr_text.data = ngx_pnalloc(cf->pool, len); @@ -168,22 +168,22 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) #if (NGX_HAVE_INET6) case AF_INET6: - ls[i].addr_text_max_len = NGX_INET6_ADDRSTRLEN; - len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1; - break; + ls[i].addr_text_max_len = NGX_INET6_ADDRSTRLEN; + len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1; + break; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: - ls[i].addr_text_max_len = NGX_UNIX_ADDRSTRLEN; - len = NGX_UNIX_ADDRSTRLEN; - break; + ls[i].addr_text_max_len = NGX_UNIX_ADDRSTRLEN; + len = NGX_UNIX_ADDRSTRLEN; + break; #endif case AF_INET: - ls[i].addr_text_max_len = NGX_INET_ADDRSTRLEN; - len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; - break; + ls[i].addr_text_max_len = NGX_INET_ADDRSTRLEN; + len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; + break; default: ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index 19a2ab7..b0d162a 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -95,25 +95,25 @@ struct ngx_listening_s { typedef enum { - NGX_ERROR_ALERT = 0, - NGX_ERROR_ERR, - NGX_ERROR_INFO, - NGX_ERROR_IGNORE_ECONNRESET, - NGX_ERROR_IGNORE_EINVAL + NGX_ERROR_ALERT = 0, + NGX_ERROR_ERR, + NGX_ERROR_INFO, + NGX_ERROR_IGNORE_ECONNRESET, + NGX_ERROR_IGNORE_EINVAL } ngx_connection_log_error_e; typedef enum { - NGX_TCP_NODELAY_UNSET = 0, - NGX_TCP_NODELAY_SET, - NGX_TCP_NODELAY_DISABLED + NGX_TCP_NODELAY_UNSET = 0, + NGX_TCP_NODELAY_SET, + NGX_TCP_NODELAY_DISABLED } ngx_connection_tcp_nodelay_e; typedef enum { - NGX_TCP_NOPUSH_UNSET = 0, - NGX_TCP_NOPUSH_SET, - NGX_TCP_NOPUSH_DISABLED + NGX_TCP_NOPUSH_UNSET = 0, + NGX_TCP_NOPUSH_SET, + NGX_TCP_NOPUSH_DISABLED } ngx_connection_tcp_nopush_e; diff --git a/src/core/ngx_crypt.c b/src/core/ngx_crypt.c index d7d068c..9db74f4 100644 --- a/src/core/ngx_crypt.c +++ b/src/core/ngx_crypt.c @@ -165,8 +165,8 @@ ngx_crypt_to64(u_char *p, uint32_t v, size_t n) "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; while (n--) { - *p++ = itoa64[v & 0x3f]; - v >>= 6; + *p++ = itoa64[v & 0x3f]; + v >>= 6; } return p; diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c index 5785eb5..98599f3 100644 --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -1006,7 +1006,7 @@ ngx_int_t ngx_signal_process(ngx_cycle_t *cycle, char *sig) { ssize_t n; - ngx_int_t pid; + ngx_pid_t pid; ngx_file_t file; ngx_core_conf_t *ccf; u_char buf[NGX_INT64_LEN + 2]; @@ -1044,7 +1044,7 @@ ngx_signal_process(ngx_cycle_t *cycle, char *sig) pid = ngx_atoi(buf, ++n); - if (pid == NGX_ERROR) { + if (pid == (ngx_pid_t) NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, cycle->log, 0, "invalid PID number \"%*s\" in \"%s\"", n, buf, file.name.data); @@ -1313,7 +1313,7 @@ ngx_clean_old_cycles(ngx_event_t *ev) if (cycle[i]->connections[n].fd != (ngx_socket_t) -1) { found = 1; - ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "live fd:%d", n); + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "live fd:%ui", n); break; } @@ -1324,13 +1324,13 @@ ngx_clean_old_cycles(ngx_event_t *ev) continue; } - ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "clean old cycle: %d", i); + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "clean old cycle: %ui", i); ngx_destroy_pool(cycle[i]->pool); cycle[i] = NULL; } - ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "old cycles status: %d", live); + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "old cycles status: %ui", live); if (live) { ngx_add_timer(ev, 30000); diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h index cfdbb55..c51b7ff 100644 --- a/src/core/ngx_cycle.h +++ b/src/core/ngx_cycle.h @@ -79,35 +79,35 @@ struct ngx_cycle_s { typedef struct { - ngx_flag_t daemon; - ngx_flag_t master; + ngx_flag_t daemon; + ngx_flag_t master; - ngx_msec_t timer_resolution; + ngx_msec_t timer_resolution; - ngx_int_t worker_processes; - ngx_int_t debug_points; + ngx_int_t worker_processes; + ngx_int_t debug_points; - ngx_int_t rlimit_nofile; - off_t rlimit_core; + ngx_int_t rlimit_nofile; + off_t rlimit_core; - int priority; + int priority; - ngx_uint_t cpu_affinity_auto; - ngx_uint_t cpu_affinity_n; - ngx_cpuset_t *cpu_affinity; + ngx_uint_t cpu_affinity_auto; + ngx_uint_t cpu_affinity_n; + ngx_cpuset_t *cpu_affinity; - char *username; - ngx_uid_t user; - ngx_gid_t group; + char *username; + ngx_uid_t user; + ngx_gid_t group; - ngx_str_t working_directory; - ngx_str_t lock_file; + ngx_str_t working_directory; + ngx_str_t lock_file; - ngx_str_t pid; - ngx_str_t oldpid; + ngx_str_t pid; + ngx_str_t oldpid; - ngx_array_t env; - char **environment; + ngx_array_t env; + char **environment; } ngx_core_conf_t; diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c index d3e2ece..fc2dfd3 100644 --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -155,7 +155,7 @@ ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool, #if 0 for (i = 0; i < file->name.len; i++) { - file->name.data[i] = 'X'; + file->name.data[i] = 'X'; } #endif @@ -841,7 +841,7 @@ ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf) if ((size_t) n != len) { ngx_log_error(NGX_LOG_ALERT, cf->log, 0, - ngx_read_fd_n " has read only %z of %uz from %s", + ngx_read_fd_n " has read only %z of %O from %s", n, size, from); goto failed; } @@ -856,7 +856,7 @@ ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf) if ((size_t) n != len) { ngx_log_error(NGX_LOG_ALERT, cf->log, 0, - ngx_write_fd_n " has written only %z of %uz to %s", + ngx_write_fd_n " has written only %z of %O to %s", n, size, to); goto failed; } diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c index 3bbadb8..a4e80ed 100644 --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -348,7 +348,7 @@ ngx_inet6_ntop(u_char *p, u_char *text, size_t len) continue; } - dst = ngx_sprintf(dst, "%uxi", p[i] * 256 + p[i + 1]); + dst = ngx_sprintf(dst, "%uxd", p[i] * 256 + p[i + 1]); if (i < 14) { *dst++ = ':'; @@ -1242,19 +1242,19 @@ ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1, #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: - /* TODO length */ + /* TODO length */ - saun1 = (struct sockaddr_un *) sa1; - saun2 = (struct sockaddr_un *) sa2; + saun1 = (struct sockaddr_un *) sa1; + saun2 = (struct sockaddr_un *) sa2; - if (ngx_memcmp(&saun1->sun_path, &saun2->sun_path, - sizeof(saun1->sun_path)) - != 0) - { - return NGX_DECLINED; - } + if (ngx_memcmp(&saun1->sun_path, &saun2->sun_path, + sizeof(saun1->sun_path)) + != 0) + { + return NGX_DECLINED; + } - break; + break; #endif default: /* AF_INET */ diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c index 0893871..8e9408d 100644 --- a/src/core/ngx_log.c +++ b/src/core/ngx_log.c @@ -33,14 +33,14 @@ typedef struct { static ngx_command_t ngx_errlog_commands[] = { - {ngx_string("error_log"), - NGX_MAIN_CONF|NGX_CONF_1MORE, - ngx_error_log, - 0, - 0, - NULL}, + { ngx_string("error_log"), + NGX_MAIN_CONF|NGX_CONF_1MORE, + ngx_error_log, + 0, + 0, + NULL }, - ngx_null_command + ngx_null_command }; @@ -86,7 +86,7 @@ static ngx_str_t err_levels[] = { static const char *debug_levels[] = { "debug_core", "debug_alloc", "debug_mutex", "debug_event", - "debug_http", "debug_mail", "debug_mysql", "debug_stream" + "debug_http", "debug_mail", "debug_stream" }; @@ -585,7 +585,7 @@ ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head) return NGX_CONF_ERROR; } - } else if (ngx_strncmp(value[1].data, "memory:", 7) == 0) { + } else if (ngx_strncmp(value[1].data, "memory:", 7) == 0) { #if (NGX_DEBUG) size_t size, needed; @@ -644,7 +644,7 @@ ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head) return NGX_CONF_ERROR; #endif - } else if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) { + } else if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) { peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t)); if (peer == NULL) { return NGX_CONF_ERROR; diff --git a/src/core/ngx_log.h b/src/core/ngx_log.h index 618d3ad..afb73bf 100644 --- a/src/core/ngx_log.h +++ b/src/core/ngx_log.h @@ -29,8 +29,7 @@ #define NGX_LOG_DEBUG_EVENT 0x080 #define NGX_LOG_DEBUG_HTTP 0x100 #define NGX_LOG_DEBUG_MAIL 0x200 -#define NGX_LOG_DEBUG_MYSQL 0x400 -#define NGX_LOG_DEBUG_STREAM 0x800 +#define NGX_LOG_DEBUG_STREAM 0x400 /* * do not forget to update debug_levels[] in src/core/ngx_log.c diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c index f8bb2e3..b23ee78 100644 --- a/src/core/ngx_open_file_cache.c +++ b/src/core/ngx_open_file_cache.c @@ -544,7 +544,7 @@ 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_close_file_n " \"%s\" failed", name); } ngx_set_errno(err); diff --git a/src/core/ngx_parse_time.c b/src/core/ngx_parse_time.c index 831cc71..13afde3 100644 --- a/src/core/ngx_parse_time.c +++ b/src/core/ngx_parse_time.c @@ -220,7 +220,7 @@ ngx_parse_http_time(u_char *value, size_t len) } if (hour > 23 || min > 59 || sec > 59) { - return NGX_ERROR; + return NGX_ERROR; } if (day == 29 && month == 1) { diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index 38bf956..3c52de8 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -1873,7 +1873,7 @@ dns_error_name: ngx_log_error(r->log_level, r->log, 0, "DNS error (%ui: %s), query id:%ui, name:\"%*s\"", code, ngx_resolver_strerror(code), ident, - rn->nlen, rn->name); + (size_t) rn->nlen, rn->name); return; dns_error: diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c index c112506..56e7765 100644 --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -222,11 +222,11 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) if (bitmap[n] == NGX_SLAB_BUSY) { for (n = n + 1; n < map; n++) { - if (bitmap[n] != NGX_SLAB_BUSY) { - p = (uintptr_t) bitmap + i; + if (bitmap[n] != NGX_SLAB_BUSY) { + p = (uintptr_t) bitmap + i; - goto done; - } + goto done; + } } prev = (ngx_slab_page_t *) @@ -392,7 +392,8 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) done: - ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab alloc: %p", p); + ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, + "slab alloc: %p", (void *) p); return (void *) p; } diff --git a/src/core/ngx_syslog.c b/src/core/ngx_syslog.c index 08f4c04..0a67928 100644 --- a/src/core/ngx_syslog.c +++ b/src/core/ngx_syslog.c @@ -10,9 +10,9 @@ #define NGX_SYSLOG_MAX_STR \ - NGX_MAX_ERROR_STR + sizeof("<255>Jan 01 00:00:00 ") - 1 \ - + (NGX_MAXHOSTNAMELEN - 1) + 1 /* space */ \ - + 32 /* tag */ + 2 /* colon, space */ + NGX_MAX_ERROR_STR + sizeof("<255>Jan 01 00:00:00 ") - 1 \ + + (NGX_MAXHOSTNAMELEN - 1) + 1 /* space */ \ + + 32 /* tag */ + 2 /* colon, space */ static char *ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer); diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c index 595c122..843314a 100644 --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -154,7 +154,7 @@ ngx_time_update(void) p2 = &cached_http_log_time[slot][0]; - (void) ngx_sprintf(p2, "%02d/%s/%d:%02d:%02d:%02d %c%02d%02d", + (void) ngx_sprintf(p2, "%02d/%s/%d:%02d:%02d:%02d %c%02i%02i", tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1], tm.ngx_tm_year, tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec, @@ -163,7 +163,7 @@ ngx_time_update(void) p3 = &cached_http_log_iso8601[slot][0]; - (void) ngx_sprintf(p3, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", + (void) ngx_sprintf(p3, "%4d-%02d-%02dT%02d:%02d:%02d%c%02i:%02i", tm.ngx_tm_year, tm.ngx_tm_mon, tm.ngx_tm_mday, tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec, diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c index 081b0e5..828e4d1 100644 --- a/src/event/modules/ngx_epoll_module.c +++ b/src/event/modules/ngx_epoll_module.c @@ -902,7 +902,7 @@ ngx_epoll_eventfd_handler(ngx_event_t *ev) events = io_getevents(ngx_aio_ctx, 1, 64, event, &ts); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, - "io_getevents: %l", events); + "io_getevents: %d", events); if (events > 0) { ready -= events; diff --git a/src/event/modules/ngx_eventport_module.c b/src/event/modules/ngx_eventport_module.c index 9184547..dafa27f 100644 --- a/src/event/modules/ngx_eventport_module.c +++ b/src/event/modules/ngx_eventport_module.c @@ -49,7 +49,7 @@ typedef struct port_notify { void *portnfy_user; /* user defined */ } port_notify_t; -#if (__FreeBSD__) && (__FreeBSD_version < 700005) +#if (__FreeBSD__ && __FreeBSD_version < 700005) || (NGX_DARWIN) typedef struct itimerspec { /* definition per POSIX.4 */ struct timespec it_interval;/* timer period */ @@ -526,18 +526,18 @@ ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "eventport: fd:%d, ev:%04Xd", - event_list[i].portev_object, revents); + (int) event_list[i].portev_object, revents); if (revents & (POLLERR|POLLHUP|POLLNVAL)) { ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "port_getn() error fd:%d ev:%04Xd", - event_list[i].portev_object, revents); + (int) event_list[i].portev_object, revents); } if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "strange port_getn() events fd:%d ev:%04Xd", - event_list[i].portev_object, revents); + (int) event_list[i].portev_object, revents); } if ((revents & (POLLERR|POLLHUP|POLLNVAL)) @@ -615,7 +615,7 @@ ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, default: ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unexpected eventport object %d", - event_list[i].portev_object); + (int) event_list[i].portev_object); continue; } } diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c index 5573cb2..ca3bfe4 100644 --- a/src/event/modules/ngx_kqueue_module.c +++ b/src/event/modules/ngx_kqueue_module.c @@ -579,7 +579,7 @@ ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, if (event_list[i].flags & EV_ERROR) { ngx_log_error(NGX_LOG_ALERT, cycle->log, event_list[i].data, "kevent() error on %d filter:%d flags:%04Xd", - event_list[i].ident, event_list[i].filter, + (int) event_list[i].ident, event_list[i].filter, event_list[i].flags); continue; } @@ -676,13 +676,20 @@ ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, static ngx_inline void ngx_kqueue_dump_event(ngx_log_t *log, struct kevent *kev) { - ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0, - (kev->ident > 0x8000000 && kev->ident != (unsigned) -1) ? - "kevent: %p: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p": - "kevent: %d: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p", - kev->ident, kev->filter, - kev->flags, kev->fflags, - kev->data, kev->udata); + if (kev->ident > 0x8000000 && kev->ident != (unsigned) -1) { + ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0, + "kevent: %p: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p", + (void *) kev->ident, kev->filter, + kev->flags, kev->fflags, + (int) kev->data, kev->udata); + + } else { + ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0, + "kevent: %d: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p", + (int) kev->ident, kev->filter, + kev->flags, kev->fflags, + (int) kev->data, kev->udata); + } } diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index 38f9b38..c8ae5b2 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -525,7 +525,7 @@ ngx_event_module_init(ngx_cycle_t *cycle) (void) ngx_atomic_cmp_set(ngx_connection_counter, 0, 1); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "counter: %p, %d", + "counter: %p, %uA", ngx_connection_counter, *ngx_connection_counter); ngx_temp_number = (ngx_atomic_t *) (shared + 2 * cl); diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index 591005a..ed0682c 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -188,7 +188,7 @@ typedef struct { ngx_int_t (*notify)(ngx_event_handler_pt handler); ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer, - ngx_uint_t flags); + ngx_uint_t flags); ngx_int_t (*init)(ngx_cycle_t *cycle, ngx_msec_t timer); void (*done)(ngx_cycle_t *cycle); diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index de10d48..de10296 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -39,6 +39,9 @@ ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data); static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess); static ngx_ssl_session_t *ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, +#if OPENSSL_VERSION_NUMBER >= 0x10100003L + const +#endif u_char *id, int len, int *copy); static void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess); static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache, @@ -52,7 +55,7 @@ static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, HMAC_CTX *hctx, int enc); #endif -#if (OPENSSL_VERSION_NUMBER < 0x10002002L || defined LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x10002002L static ngx_int_t ngx_ssl_check_name(ngx_str_t *name, ASN1_STRING *str); #endif @@ -108,6 +111,12 @@ int ngx_ssl_stapling_index; ngx_int_t ngx_ssl_init(ngx_log_t *log) { +#if OPENSSL_VERSION_NUMBER >= 0x10100003L + + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); + +#else + #ifndef OPENSSL_IS_BORINGSSL OPENSSL_config(NULL); #endif @@ -117,6 +126,8 @@ ngx_ssl_init(ngx_log_t *log) OpenSSL_add_all_algorithms(); +#endif + #if OPENSSL_VERSION_NUMBER >= 0x0090800fL #ifndef SSL_OP_NO_COMPRESSION { @@ -747,7 +758,7 @@ ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, return NULL; } -#ifndef OPENSSL_NO_DEPRECATED +#if (OPENSSL_VERSION_NUMBER < 0x10100003L && !defined OPENSSL_NO_DEPRECATED) if (key == NULL) { key = RSA_generate_key(512, RSA_F4, NULL, NULL); @@ -1596,7 +1607,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "SSL buf copy: %d", size); + "SSL buf copy: %z", size); ngx_memcpy(buf->last, in->buf->pos, size); @@ -1668,7 +1679,7 @@ ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size) ngx_ssl_clear_error(c->log); - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %d", size); + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %uz", size); n = SSL_write(c->ssl->connection, data, size); @@ -1956,6 +1967,7 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, || n == SSL_R_INAPPROPRIATE_FALLBACK /* 373 */ #endif || n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */ +#ifdef SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE || n == SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE /* 1010 */ || n == SSL_R_SSLV3_ALERT_BAD_RECORD_MAC /* 1020 */ || n == SSL_R_TLSV1_ALERT_DECRYPTION_FAILED /* 1021 */ @@ -1978,7 +1990,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, || n == SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY /* 1071 */ || n == SSL_R_TLSV1_ALERT_INTERNAL_ERROR /* 1080 */ || n == SSL_R_TLSV1_ALERT_USER_CANCELLED /* 1090 */ - || n == SSL_R_TLSV1_ALERT_NO_RENEGOTIATION) /* 1100 */ + || n == SSL_R_TLSV1_ALERT_NO_RENEGOTIATION /* 1100 */ +#endif + ) { switch (c->log_error) { @@ -2143,7 +2157,7 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx) int n, i; X509 *cert; X509_NAME *name; - EVP_MD_CTX md; + EVP_MD_CTX *md; unsigned int len; STACK_OF(X509_NAME) *list; u_char buf[EVP_MAX_MD_SIZE]; @@ -2153,15 +2167,18 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx) * the server certificate, and the client CA list. */ - EVP_MD_CTX_init(&md); + md = EVP_MD_CTX_create(); + if (md == NULL) { + return NGX_ERROR; + } - if (EVP_DigestInit_ex(&md, EVP_sha1(), NULL) == 0) { + if (EVP_DigestInit_ex(md, EVP_sha1(), NULL) == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "EVP_DigestInit_ex() failed"); goto failed; } - if (EVP_DigestUpdate(&md, sess_ctx->data, sess_ctx->len) == 0) { + if (EVP_DigestUpdate(md, sess_ctx->data, sess_ctx->len) == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "EVP_DigestUpdate() failed"); goto failed; @@ -2175,7 +2192,7 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx) goto failed; } - if (EVP_DigestUpdate(&md, buf, len) == 0) { + if (EVP_DigestUpdate(md, buf, len) == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "EVP_DigestUpdate() failed"); goto failed; @@ -2195,7 +2212,7 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx) goto failed; } - if (EVP_DigestUpdate(&md, buf, len) == 0) { + if (EVP_DigestUpdate(md, buf, len) == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "EVP_DigestUpdate() failed"); goto failed; @@ -2203,13 +2220,13 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx) } } - if (EVP_DigestFinal_ex(&md, buf, &len) == 0) { + if (EVP_DigestFinal_ex(md, buf, &len) == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "EVP_DigestUpdate() failed"); goto failed; } - EVP_MD_CTX_cleanup(&md); + EVP_MD_CTX_destroy(md); if (SSL_CTX_set_session_id_context(ssl->ctx, buf, len) == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, @@ -2221,7 +2238,7 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx) failed: - EVP_MD_CTX_cleanup(&md); + EVP_MD_CTX_destroy(md); return NGX_ERROR; } @@ -2442,8 +2459,11 @@ failed: static ngx_ssl_session_t * -ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, u_char *id, int len, - int *copy) +ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, +#if OPENSSL_VERSION_NUMBER >= 0x10100003L + const +#endif + u_char *id, int len, int *copy) { #if OPENSSL_VERSION_NUMBER >= 0x0090707fL const @@ -2460,7 +2480,7 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, u_char *id, int len, u_char buf[NGX_SSL_MAX_SESSION_SIZE]; ngx_connection_t *c; - hash = ngx_crc32_short(id, (size_t) len); + hash = ngx_crc32_short((u_char *) (uintptr_t) id, (size_t) len); *copy = 0; c = ngx_ssl_get_connection(ssl_conn); @@ -2498,7 +2518,8 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, u_char *id, int len, sess_id = (ngx_ssl_sess_id_t *) node; - rc = ngx_memn2cmp(id, sess_id->id, (size_t) len, (size_t) node->data); + rc = ngx_memn2cmp((u_char *) (uintptr_t) id, sess_id->id, + (size_t) len, (size_t) node->data); if (rc == 0) { @@ -2542,9 +2563,9 @@ done: void ngx_ssl_remove_cached_session(SSL_CTX *ssl, ngx_ssl_session_t *sess) { - SSL_CTX_remove_session(ssl, sess); + SSL_CTX_remove_session(ssl, sess); - ngx_ssl_remove_session(ssl, sess); + ngx_ssl_remove_session(ssl, sess); } @@ -2944,7 +2965,7 @@ ngx_ssl_check_host(ngx_connection_t *c, ngx_str_t *name) return NGX_ERROR; } -#if (OPENSSL_VERSION_NUMBER >= 0x10002002L && !defined LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER >= 0x10002002L /* X509_check_host() is only available in OpenSSL 1.0.2+ */ @@ -3061,7 +3082,7 @@ found: } -#if (OPENSSL_VERSION_NUMBER < 0x10002002L || defined LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x10002002L static ngx_int_t ngx_ssl_check_name(ngx_str_t *name, ASN1_STRING *pattern) @@ -3538,8 +3559,12 @@ ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) static void ngx_openssl_exit(ngx_cycle_t *cycle) { +#if OPENSSL_VERSION_NUMBER < 0x10100003L + EVP_cleanup(); #ifndef OPENSSL_NO_ENGINE ENGINE_cleanup(); #endif + +#endif } diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index c86be2a..09654db 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -33,6 +33,23 @@ #define NGX_SSL_NAME "OpenSSL" +#if (defined LIBRESSL_VERSION_NUMBER && OPENSSL_VERSION_NUMBER == 0x20000000L) +#undef OPENSSL_VERSION_NUMBER +#define OPENSSL_VERSION_NUMBER 0x1000107fL +#endif + + +#if (OPENSSL_VERSION_NUMBER >= 0x10100001L) + +#define ngx_ssl_version() OpenSSL_version(OPENSSL_VERSION) + +#else + +#define ngx_ssl_version() SSLeay_version(SSLEAY_VERSION) + +#endif + + #define ngx_ssl_session_t SSL_SESSION #define ngx_ssl_conn_t SSL diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c index fa77678..5322b1b 100644 --- a/src/event/ngx_event_openssl_stapling.c +++ b/src/event/ngx_event_openssl_stapling.c @@ -285,7 +285,11 @@ ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl) for (i = 0; i < n; i++) { issuer = sk_X509_value(chain, i); if (X509_check_issued(issuer, cert) == X509_V_OK) { +#if OPENSSL_VERSION_NUMBER >= 0x10100001L + X509_up_ref(issuer); +#else CRYPTO_add(&issuer->references, 1, CRYPTO_LOCK_X509); +#endif ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0, "SSL get issuer: found %p in extra certs", issuer); @@ -1219,7 +1223,7 @@ ngx_ssl_ocsp_create_request(ngx_ssl_ocsp_ctx_t *ctx) ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0, "ssl ocsp request length %z, escape %d", - base64.len, escape); + base64.len, (int) escape); len = sizeof("GET ") - 1 + ctx->uri.len + sizeof("/") - 1 + base64.len + 2 * escape + sizeof(" HTTP/1.0" CRLF) - 1 diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c index ee86c7e..5ce59ae 100644 --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -434,7 +434,7 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) /* STUB */ cl->buf->num = p->num++; if (p->input_filter(p, cl->buf) == NGX_ERROR) { - return NGX_ABORT; + return NGX_ABORT; } ngx_free_chain(p->pool, cl); @@ -660,7 +660,7 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p) flush: ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, - "pipe write: out:%p, f:%d", out, flush); + "pipe write: out:%p, f:%ui", out, flush); if (out == NULL) { @@ -801,12 +801,12 @@ ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p) } if (cl) { - p->in = cl; - *ll = NULL; + p->in = cl; + *ll = NULL; } else { - p->in = NULL; - p->last_in = &p->in; + p->in = NULL; + p->last_in = &p->in; } } else { diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c index 8ec5329..1e7a0c2 100644 --- a/src/http/modules/ngx_http_auth_basic_module.c +++ b/src/http/modules/ngx_http_auth_basic_module.c @@ -298,7 +298,7 @@ ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r, &encrypted); ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "rc: %d user: \"%V\" salt: \"%s\"", + "rc: %i user: \"%V\" salt: \"%s\"", rc, &r->headers_in.user, passwd->data); if (rc == NGX_OK) { diff --git a/src/http/modules/ngx_http_auth_request_module.c b/src/http/modules/ngx_http_auth_request_module.c index b4307be..bab79e4 100644 --- a/src/http/modules/ngx_http_auth_request_module.c +++ b/src/http/modules/ngx_http_auth_request_module.c @@ -168,7 +168,7 @@ ngx_http_auth_request_handler(ngx_http_request_t *r) } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "auth request unexpected status: %d", ctx->status); + "auth request unexpected status: %ui", ctx->status); return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -219,7 +219,7 @@ ngx_http_auth_request_done(ngx_http_request_t *r, void *data, ngx_int_t rc) ngx_http_auth_request_ctx_t *ctx = data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "auth request done s:%d", r->headers_out.status); + "auth request done s:%ui", r->headers_out.status); ctx->done = 1; ctx->status = r->headers_out.status; diff --git a/src/http/modules/ngx_http_chunked_filter_module.c b/src/http/modules/ngx_http_chunked_filter_module.c index 0059a98..ac2e3e8 100644 --- a/src/http/modules/ngx_http_chunked_filter_module.c +++ b/src/http/modules/ngx_http_chunked_filter_module.c @@ -121,7 +121,7 @@ ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in) for ( ;; ) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http chunk: %d", ngx_buf_size(cl->buf)); + "http chunk: %O", ngx_buf_size(cl->buf)); size += ngx_buf_size(cl->buf); diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c index b9fadd0..3600265 100644 --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -621,11 +621,11 @@ destination_done: if ((r->uri.data[r->uri.len - 1] == '/' && *(last - 1) != '/') || (r->uri.data[r->uri.len - 1] != '/' && *(last - 1) == '/')) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "both URI \"%V\" and \"Destination\" URI \"%V\" " - "should be either collections or non-collections", - &r->uri, &dest->value); - return NGX_HTTP_CONFLICT; + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "both URI \"%V\" and \"Destination\" URI \"%V\" " + "should be either collections or non-collections", + &r->uri, &dest->value); + return NGX_HTTP_CONFLICT; } depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH); diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index e3024b3..a861203 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -751,7 +751,7 @@ ngx_http_fastcgi_eval(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf) url.no_resolve = 1; if (ngx_parse_url(r->pool, &url) != NGX_OK) { - if (url.err) { + if (url.err) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s in upstream \"%V\"", url.err, &url.url); } @@ -1653,7 +1653,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) && f->type != NGX_HTTP_FASTCGI_STDERR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent unexpected FastCGI record: %d", + "upstream sent unexpected FastCGI record: %ui", f->type); return NGX_HTTP_UPSTREAM_INVALID_HEADER; @@ -1800,7 +1800,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) } else { r->cache->header_start += u->buffer.pos - start - - sizeof(ngx_http_fastcgi_header_t); + - sizeof(ngx_http_fastcgi_header_t); } f->large_stderr = 0; @@ -1834,7 +1834,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) rc = ngx_http_parse_header_line(r, &u->buffer, 1); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http fastcgi parser: %d", rc); + "http fastcgi parser: %i", rc); if (rc == NGX_AGAIN) { break; @@ -2505,7 +2505,7 @@ ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes) for (cl = u->out_bufs; cl; cl = cl->next) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http fastcgi in memory %p-%p %uz", + "http fastcgi in memory %p-%p %O", cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf)); if (buf->last == cl->buf->pos) { @@ -2558,8 +2558,8 @@ ngx_http_fastcgi_process_record(ngx_http_request_t *r, case NGX_HTTP_FASTCGI_STDOUT: case NGX_HTTP_FASTCGI_STDERR: case NGX_HTTP_FASTCGI_END_REQUEST: - f->type = (ngx_uint_t) ch; - break; + f->type = (ngx_uint_t) ch; + break; default: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "upstream sent invalid FastCGI " @@ -2654,7 +2654,7 @@ ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc) static ngx_int_t ngx_http_fastcgi_add_variables(ngx_conf_t *cf) { - ngx_http_variable_t *var, *v; + ngx_http_variable_t *var, *v; for (v = ngx_http_fastcgi_vars; v->name.len; v++) { var = ngx_http_add_variable(cf, &v->name, v->flags); diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index f941e63..536fdf8 100644 --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -1009,14 +1009,14 @@ ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size) ctx->allocated -= alloc; ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0, - "gzip alloc: n:%ud s:%ud a:%ud p:%p", + "gzip alloc: n:%ud s:%ud a:%ui p:%p", items, size, alloc, p); return p; } ngx_log_error(NGX_LOG_ALERT, ctx->request->connection->log, 0, - "gzip filter failed to use preallocated memory: %ud of %ud", + "gzip filter failed to use preallocated memory: %ud of %ui", items * size, ctx->allocated); p = ngx_palloc(ctx->request->pool, items * size); diff --git a/src/http/modules/ngx_http_image_filter_module.c b/src/http/modules/ngx_http_image_filter_module.c index bd7a309..b608de1 100644 --- a/src/http/modules/ngx_http_image_filter_module.c +++ b/src/http/modules/ngx_http_image_filter_module.c @@ -144,7 +144,7 @@ static ngx_command_t ngx_http_image_filter_commands[] = { offsetof(ngx_http_image_filter_conf_t, transparency), NULL }, - { ngx_string("image_filter_interlace"), + { ngx_string("image_filter_interlace"), 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, @@ -737,7 +737,7 @@ ngx_http_image_size(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "image size: %d x %d", width, height); + "image size: %d x %d", (int) width, (int) height); ctx->width = width; ctx->height = height; diff --git a/src/http/modules/ngx_http_limit_conn_module.c b/src/http/modules/ngx_http_limit_conn_module.c index 4379311..913d599 100644 --- a/src/http/modules/ngx_http_limit_conn_module.c +++ b/src/http/modules/ngx_http_limit_conn_module.c @@ -232,7 +232,7 @@ ngx_http_limit_conn_handler(ngx_http_request_t *r) } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "limit conn: %08XD %d", node->key, lc->conn); + "limit conn: %08Xi %d", node->key, lc->conn); ngx_shmtx_unlock(&shpool->mutex); @@ -351,7 +351,7 @@ ngx_http_limit_conn_cleanup(void *data) ngx_shmtx_lock(&shpool->mutex); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lccln->shm_zone->shm.log, 0, - "limit conn cleanup: %08XD %d", node->key, lc->conn); + "limit conn cleanup: %08Xi %d", node->key, lc->conn); lc->conn--; diff --git a/src/http/modules/ngx_http_map_module.c b/src/http/modules/ngx_http_map_module.c index 2b80d0f..091ff09 100644 --- a/src/http/modules/ngx_http_map_module.c +++ b/src/http/modules/ngx_http_map_module.c @@ -141,7 +141,7 @@ ngx_http_map_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, *v = *value; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http map: \"%v\" \"%v\"", &val, v); + "http map: \"%V\" \"%v\"", &val, v); return NGX_OK; } diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c index 8341b92..d31996a 100644 --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -523,7 +523,7 @@ ngx_http_memcached_filter(void *data, ssize_t bytes) cl->buf->tag = u->output.tag; ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0, - "memcached filter bytes:%z size:%z length:%z rest:%z", + "memcached filter bytes:%z size:%z length:%O rest:%z", bytes, b->last - b->pos, u->length, ctx->rest); if (bytes <= (ssize_t) (u->length - NGX_HTTP_MEMCACHED_END)) { diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index 980bf57..6cb3ccf 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -913,7 +913,7 @@ ngx_http_mp4_read_atom(ngx_http_mp4_file_t *mp4, ngx_log_debug4(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 atom: %*s @%O:%uL", - 4, atom_name, mp4->offset, atom_size); + (size_t) 4, atom_name, mp4->offset, atom_size); if (atom_size > (uint64_t) (NGX_MAX_OFF_T_VALUE - mp4->offset) || mp4->offset + (off_t) atom_size > end) @@ -1958,7 +1958,7 @@ ngx_http_mp4_read_stsd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "stsd entries:%uD, media:%*s", ngx_mp4_get_32value(stsd_atom->entries), - 4, stsd_atom->media_name); + (size_t) 4, stsd_atom->media_name); trak = ngx_mp4_last_trak(mp4); @@ -2555,14 +2555,14 @@ ngx_http_mp4_crop_ctts_data(ngx_http_mp4_file_t *mp4, "sample:%uD, count:%uD, offset:%uD", start_sample, count, ngx_mp4_get_32value(entry->offset)); - if (start_sample <= count) { - rest = start_sample - 1; - goto found; - } + if (start_sample <= count) { + rest = start_sample - 1; + goto found; + } - start_sample -= count; - entries--; - entry++; + start_sample -= count; + entries--; + entry++; } if (start) { diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 5005b6b..c24ef17 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -1559,7 +1559,7 @@ ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in) for ( ;; ) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "proxy output chunk: %d", ngx_buf_size(cl->buf)); + "proxy output chunk: %O", ngx_buf_size(cl->buf)); size += ngx_buf_size(cl->buf); @@ -1917,7 +1917,7 @@ ngx_http_proxy_input_filter_init(void *data) } ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http proxy filter init s:%d h:%d c:%d l:%O", + "http proxy filter init s:%ui h:%d c:%d l:%O", u->headers_in.status_n, ctx->head, u->headers_in.chunked, u->headers_in.content_length_n); @@ -2125,7 +2125,7 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http proxy chunked state %d, length %d", + "http proxy chunked state %ui, length %O", ctx->chunked.state, p->length); if (b) { @@ -2299,7 +2299,7 @@ ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes) 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", + "http proxy in memory %p-%p %O", cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf)); if (buf->last == cl->buf->pos) { diff --git a/src/http/modules/ngx_http_random_index_module.c b/src/http/modules/ngx_http_random_index_module.c index b0f0e08..b47ee4f 100644 --- a/src/http/modules/ngx_http_random_index_module.c +++ b/src/http/modules/ngx_http_random_index_module.c @@ -230,7 +230,7 @@ ngx_http_random_index_handler(ngx_http_request_t *r) if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, - ngx_close_dir_n " \"%s\" failed", &path); + ngx_close_dir_n " \"%V\" failed", &path); } n = names.nelts; diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index b07b2e2..57065e1 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -207,7 +207,7 @@ ngx_http_range_header_filter(ngx_http_request_t *r) if_range_time = ngx_parse_http_time(if_range->data, if_range->len); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http ir:%d lm:%d", + "http ir:%T lm:%T", if_range_time, r->headers_out.last_modified_time); if (if_range_time != r->headers_out.last_modified_time) { @@ -665,7 +665,7 @@ ngx_http_range_test_overlapped(ngx_http_request_t *r, range = ctx->ranges.elts; for (i = 0; i < ctx->ranges.nelts; i++) { if (start > range[i].start || last < range[i].end) { - goto overlapped; + goto overlapped; } } } diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c index c3d7ebe..b7befe6 100644 --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -328,8 +328,8 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #if (NGX_HAVE_UNIX_DOMAIN) if (ngx_strcmp(value[1].data, "unix:") == 0) { - cidr->family = AF_UNIX; - return NGX_CONF_OK; + cidr->family = AF_UNIX; + return NGX_CONF_OK; } #endif diff --git a/src/http/modules/ngx_http_referer_module.c b/src/http/modules/ngx_http_referer_module.c index b417eb2..3f0f78e 100644 --- a/src/http/modules/ngx_http_referer_module.c +++ b/src/http/modules/ngx_http_referer_module.c @@ -109,7 +109,7 @@ ngx_module_t ngx_http_referer_module = { static ngx_int_t ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, - uintptr_t data) + uintptr_t data) { u_char *p, *ref, *last; size_t len; diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c index 2ec7f5d..6b2444c 100644 --- a/src/http/modules/ngx_http_rewrite_module.c +++ b/src/http/modules/ngx_http_rewrite_module.c @@ -571,7 +571,7 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) mconf = module->create_loc_conf(cf); if (mconf == NULL) { - return NGX_CONF_ERROR; + return NGX_CONF_ERROR; } ctx->loc_conf[cf->cycle->modules[i]->ctx_index] = mconf; diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index b468eb7..f09617e 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -876,7 +876,7 @@ ngx_http_scgi_create_request(ngx_http_request_t *r) next: continue; - } + } } *b->last++ = (u_char) ','; diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index 8236320..b997aaa 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -468,12 +468,12 @@ ngx_http_ssi_body_filter(ngx_http_request_t *r, ngx_chain_t *in) while (ctx->pos < ctx->buf->last) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "saved: %d state: %d", ctx->saved, ctx->state); + "saved: %uz state: %ui", ctx->saved, ctx->state); rc = ngx_http_ssi_parse(r, ctx); ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "parse: %d, looked: %d %p-%p", + "parse: %i, looked: %uz %p-%p", rc, ctx->looked, ctx->copy_start, ctx->copy_end); if (rc == NGX_ERROR) { @@ -485,7 +485,7 @@ ngx_http_ssi_body_filter(ngx_http_request_t *r, ngx_chain_t *in) if (ctx->output) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "saved: %d", ctx->saved); + "saved: %uz", ctx->saved); if (ctx->saved) { @@ -1911,7 +1911,7 @@ ngx_http_ssi_regex_match(ngx_http_request_t *r, ngx_str_t *pattern, if (rc < NGX_REGEX_NO_MATCHED) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"", + ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"", rc, str, pattern); return NGX_HTTP_SSI_ERROR; } diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 7b051ea..6a4108c 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -337,8 +337,9 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, #if (NGX_DEBUG) for (i = 0; i < inlen; i += in[i] + 1) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "SSL ALPN supported by client: %*s", in[i], &in[i + 1]); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "SSL ALPN supported by client: %*s", + (size_t) in[i], &in[i + 1]); } #endif @@ -365,7 +366,7 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "SSL ALPN selected: %*s", *outlen, *out); + "SSL ALPN selected: %*s", (size_t) *outlen, *out); return SSL_TLSEXT_ERR_OK; } @@ -717,7 +718,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } -#ifndef LIBRESSL_VERSION_NUMBER +#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) /* a temporary 512-bit RSA key is required for export versions of MSIE */ SSL_CTX_set_tmp_rsa_callback(conf->ssl.ctx, ngx_ssl_rsa512_key_callback); #endif diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c index 7bf6e19..bb1c50b 100644 --- a/src/http/modules/ngx_http_sub_filter_module.c +++ b/src/http/modules/ngx_http_sub_filter_module.c @@ -341,7 +341,7 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) rc = ngx_http_sub_parse(r, ctx); ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "parse: %d, looked: \"%V\" %p-%p", + "parse: %i, looked: \"%V\" %p-%p", rc, &ctx->looked, ctx->copy_start, ctx->copy_end); if (rc == NGX_ERROR) { diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c index 401b58e..8a5f0fa 100644 --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c @@ -199,7 +199,7 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "get ip hash peer, hash: %ui %04XA", p, m); + "get ip hash peer, hash: %ui %04XL", p, (uint64_t) m); if (peer->down) { goto next; diff --git a/src/http/modules/ngx_http_upstream_least_conn_module.c b/src/http/modules/ngx_http_upstream_least_conn_module.c index 92951bd..8a300c1 100644 --- a/src/http/modules/ngx_http_upstream_least_conn_module.c +++ b/src/http/modules/ngx_http_upstream_least_conn_module.c @@ -259,7 +259,7 @@ failed: / (8 * sizeof(uintptr_t)); for (i = 0; i < n; i++) { - rrp->tried[i] = 0; + rrp->tried[i] = 0; } ngx_http_upstream_rr_peers_unlock(peers); diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index b88e869..bd36aec 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -1222,7 +1222,7 @@ ngx_http_core_try_files_phase(ngx_http_request_t *r, } name = path.data + root; - } + } if (tf->values == NULL) { @@ -1597,7 +1597,8 @@ ngx_http_core_find_static_location(ngx_http_request_t *r, } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "test location: \"%*s\"", node->len, node->name); + "test location: \"%*s\"", + (size_t) node->len, node->name); n = (len <= (size_t) node->len) ? len : node->len; @@ -3104,7 +3105,7 @@ ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) ctx->loc_conf[cf->cycle->modules[i]->ctx_index] = module->create_loc_conf(cf); if (ctx->loc_conf[cf->cycle->modules[i]->ctx_index] == NULL) { - return NGX_CONF_ERROR; + return NGX_CONF_ERROR; } } } @@ -4540,21 +4541,21 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) static ngx_http_method_name_t ngx_methods_names[] = { - { (u_char *) "GET", (uint32_t) ~NGX_HTTP_GET }, - { (u_char *) "HEAD", (uint32_t) ~NGX_HTTP_HEAD }, - { (u_char *) "POST", (uint32_t) ~NGX_HTTP_POST }, - { (u_char *) "PUT", (uint32_t) ~NGX_HTTP_PUT }, - { (u_char *) "DELETE", (uint32_t) ~NGX_HTTP_DELETE }, - { (u_char *) "MKCOL", (uint32_t) ~NGX_HTTP_MKCOL }, - { (u_char *) "COPY", (uint32_t) ~NGX_HTTP_COPY }, - { (u_char *) "MOVE", (uint32_t) ~NGX_HTTP_MOVE }, - { (u_char *) "OPTIONS", (uint32_t) ~NGX_HTTP_OPTIONS }, - { (u_char *) "PROPFIND", (uint32_t) ~NGX_HTTP_PROPFIND }, - { (u_char *) "PROPPATCH", (uint32_t) ~NGX_HTTP_PROPPATCH }, - { (u_char *) "LOCK", (uint32_t) ~NGX_HTTP_LOCK }, - { (u_char *) "UNLOCK", (uint32_t) ~NGX_HTTP_UNLOCK }, - { (u_char *) "PATCH", (uint32_t) ~NGX_HTTP_PATCH }, - { NULL, 0 } + { (u_char *) "GET", (uint32_t) ~NGX_HTTP_GET }, + { (u_char *) "HEAD", (uint32_t) ~NGX_HTTP_HEAD }, + { (u_char *) "POST", (uint32_t) ~NGX_HTTP_POST }, + { (u_char *) "PUT", (uint32_t) ~NGX_HTTP_PUT }, + { (u_char *) "DELETE", (uint32_t) ~NGX_HTTP_DELETE }, + { (u_char *) "MKCOL", (uint32_t) ~NGX_HTTP_MKCOL }, + { (u_char *) "COPY", (uint32_t) ~NGX_HTTP_COPY }, + { (u_char *) "MOVE", (uint32_t) ~NGX_HTTP_MOVE }, + { (u_char *) "OPTIONS", (uint32_t) ~NGX_HTTP_OPTIONS }, + { (u_char *) "PROPFIND", (uint32_t) ~NGX_HTTP_PROPFIND }, + { (u_char *) "PROPPATCH", (uint32_t) ~NGX_HTTP_PROPPATCH }, + { (u_char *) "LOCK", (uint32_t) ~NGX_HTTP_LOCK }, + { (u_char *) "UNLOCK", (uint32_t) ~NGX_HTTP_UNLOCK }, + { (u_char *) "PATCH", (uint32_t) ~NGX_HTTP_PATCH }, + { NULL, 0 } }; @@ -4627,7 +4628,7 @@ ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) mconf = module->create_loc_conf(cf); if (mconf == NULL) { - return NGX_CONF_ERROR; + return NGX_CONF_ERROR; } ctx->loc_conf[cf->cycle->modules[i]->ctx_index] = mconf; diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 231c507..6c446a0 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -232,10 +232,10 @@ typedef struct { typedef struct { - ngx_hash_combined_t names; + ngx_hash_combined_t names; - ngx_uint_t nregex; - ngx_http_server_name_t *regex; + ngx_uint_t nregex; + ngx_http_server_name_t *regex; } ngx_http_virtual_names_t; @@ -544,7 +544,7 @@ typedef ngx_int_t (*ngx_http_request_body_filter_pt) 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_request_body_save_filter(ngx_http_request_t *r, - ngx_chain_t *chain); + ngx_chain_t *chain); ngx_int_t ngx_http_set_disable_symlinks(ngx_http_request_t *r, diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index 3561028..37cd377 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -1834,7 +1834,7 @@ ngx_http_file_cache_expire(ngx_http_file_cache_t *cache) ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "ignore long locked inactive cache entry %*s, count:%d", - 2 * NGX_HTTP_CACHE_KEY_LEN, key, fcn->count); + (size_t) 2 * NGX_HTTP_CACHE_KEY_LEN, key, fcn->count); } ngx_shmtx_unlock(&cache->shpool->mutex); diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index fd790e1..7d6cada 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -648,7 +648,7 @@ ngx_http_ssl_handshake(ngx_event_t *rev) err = ngx_socket_errno; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http recv(): %d", n); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http recv(): %z", n); if (n == -1) { if (err == NGX_EAGAIN) { @@ -1500,7 +1500,7 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http large header copy: %d", r->header_in->pos - old); + "http large header copy: %uz", r->header_in->pos - old); new = b->start; @@ -2264,7 +2264,7 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc) c = r->connection; ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http finalize request: %d, \"%V?%V\" a:%d, c:%d", + "http finalize request: %i, \"%V?%V\" a:%d, c:%d", rc, &r->uri, &r->args, r == c->data, r->main->count); if (rc == NGX_DONE) { @@ -2956,7 +2956,7 @@ ngx_http_set_keepalive(ngx_http_request_t *r) b->last = b->start; } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "hc free: %p %d", + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "hc free: %p %i", hc->free, hc->nfree); if (hc->free) { @@ -2968,7 +2968,7 @@ ngx_http_set_keepalive(ngx_http_request_t *r) hc->nfree = 0; } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "hc busy: %p %d", + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "hc busy: %p %i", hc->busy, hc->nbusy); if (hc->busy) { @@ -3259,7 +3259,7 @@ ngx_http_lingering_close_handler(ngx_event_t *rev) do { n = c->recv(c, buffer, NGX_HTTP_LINGERING_BUFFER_SIZE); - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lingering read: %d", n); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lingering read: %z", n); if (n == NGX_ERROR || n == 0) { ngx_http_close_request(r, 0); diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 8b88139..cfde7dc 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -284,6 +284,9 @@ typedef struct { ngx_chain_t *bufs; ngx_buf_t *buf; off_t rest; +#if (NGX_HTTP_V2) + off_t received; +#endif ngx_chain_t *free; ngx_chain_t *busy; ngx_http_chunked_t *chunked; diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c index b5803d5..0641329 100644 --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -40,20 +40,19 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, r->main->count++; -#if (NGX_HTTP_V2) - if (r->stream && r == r->main) { - r->request_body_no_buffering = 0; - rc = ngx_http_v2_read_request_body(r, post_handler); - goto done; - } -#endif - if (r != r->main || r->request_body || r->discard_body) { r->request_body_no_buffering = 0; post_handler(r); return NGX_OK; } +#if (NGX_HTTP_V2) + if (r->stream) { + rc = ngx_http_v2_read_request_body(r, post_handler); + goto done; + } +#endif + if (ngx_http_test_expect(r) != NGX_OK) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; @@ -215,6 +214,18 @@ ngx_http_read_unbuffered_request_body(ngx_http_request_t *r) { ngx_int_t rc; +#if (NGX_HTTP_V2) + if (r->stream) { + rc = ngx_http_v2_read_unbuffered_request_body(r); + + if (rc == NGX_OK) { + r->reading_body = 0; + } + + return rc; + } +#endif + if (r->connection->read->timedout) { r->connection->timedout = 1; return NGX_HTTP_REQUEST_TIME_OUT; @@ -503,17 +514,17 @@ ngx_http_discard_request_body(ngx_http_request_t *r) ngx_int_t rc; ngx_event_t *rev; -#if (NGX_HTTP_V2) - if (r->stream && r == r->main) { - r->stream->skip_data = NGX_HTTP_V2_DATA_DISCARD; - return NGX_OK; - } -#endif - if (r != r->main || r->discard_body || r->request_body) { return NGX_OK; } +#if (NGX_HTTP_V2) + if (r->stream) { + r->stream->skip_data = 1; + return NGX_OK; + } +#endif + if (ngx_http_test_expect(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c index 02e2be3..bff9525 100644 --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -19,10 +19,10 @@ static ngx_int_t ngx_http_script_add_var_code(ngx_http_script_compile_t *sc, static ngx_int_t ngx_http_script_add_args_code(ngx_http_script_compile_t *sc); #if (NGX_PCRE) static ngx_int_t ngx_http_script_add_capture_code(ngx_http_script_compile_t *sc, - ngx_uint_t n); + ngx_uint_t n); #endif static ngx_int_t - ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc); + ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc); static size_t ngx_http_script_full_name_len_code(ngx_http_script_engine_t *e); static void ngx_http_script_full_name_code(ngx_http_script_engine_t *e); @@ -1488,7 +1488,7 @@ ngx_http_script_file_code(ngx_http_script_engine_t *e) r = e->request; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http script file op %p \"%V\"", code->op, &path); + "http script file op %p \"%V\"", (void *) code->op, &path); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 911049f..1386bdb 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -1883,17 +1883,17 @@ ngx_http_upstream_send_request_body(ngx_http_request_t *r, if (!r->request_body_no_buffering) { - /* buffered request body */ + /* buffered request body */ - if (!u->request_sent) { - u->request_sent = 1; - out = u->request_bufs; + if (!u->request_sent) { + u->request_sent = 1; + out = u->request_bufs; - } else { - out = NULL; - } + } else { + out = NULL; + } - return ngx_output_chain(&u->output, out); + return ngx_output_chain(&u->output, out); } if (!u->request_sent) { @@ -4327,10 +4327,10 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r, pa = &u->headers_in.cache_control; if (pa->elts == NULL) { - if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK) - { - return NGX_ERROR; - } + if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK) + { + return NGX_ERROR; + } } ph = ngx_array_push(pa); diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c index d6ae33b..8342dc8 100644 --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -480,7 +480,7 @@ failed: / (8 * sizeof(uintptr_t)); for (i = 0; i < n; i++) { - rrp->tried[i] = 0; + rrp->tried[i] = 0; } ngx_http_upstream_rr_peers_unlock(peers); diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index eaf294a..f8271ab 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -2428,9 +2428,8 @@ ngx_http_regex_exec(ngx_http_request_t *r, ngx_http_regex_t *re, ngx_str_t *s) v = cmcf->variables.elts; - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http regex set $%V to \"%*s\"", - &v[index].name, vv->len, vv->data); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http regex set $%V to \"%v\"", &v[index].name, vv); } #endif } diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c index c164440..0036231 100644 --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -174,7 +174,7 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) *ll = NULL; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http write filter: l:%d f:%d s:%O", last, flush, size); + "http write filter: l:%ui f:%ui s:%O", last, flush, size); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index ababd4b..4bd85b8 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -51,6 +51,8 @@ #define NGX_HTTP_V2_MAX_WINDOW ((1U << 31) - 1) #define NGX_HTTP_V2_DEFAULT_WINDOW 65535 +#define NGX_HTTP_V2_INITIAL_WINDOW 0 + #define NGX_HTTP_V2_ROOT (void *) -1 @@ -163,7 +165,9 @@ static ngx_int_t ngx_http_v2_cookie(ngx_http_request_t *r, ngx_http_v2_header_t *header); static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r); static void ngx_http_v2_run_request(ngx_http_request_t *r); -static ngx_int_t ngx_http_v2_init_request_body(ngx_http_request_t *r); +static ngx_int_t ngx_http_v2_process_request_body(ngx_http_request_t *r, + u_char *pos, size_t size, ngx_uint_t last); +static ngx_int_t ngx_http_v2_filter_request_body(ngx_http_request_t *r); static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r); static ngx_int_t ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, @@ -762,8 +766,7 @@ ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) if (h2c->state.length == 0) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, "client sent padded DATA frame " - "with incorrect length: %uz", - h2c->state.length); + "with incorrect length: 0"); return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); } @@ -845,8 +848,9 @@ ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) stream->recv_window -= h2c->state.length; - if (stream->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4) { - + if (stream->no_flow_control + && stream->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4) + { if (ngx_http_v2_send_window_update(h2c, node->id, NGX_HTTP_V2_MAX_WINDOW - stream->recv_window) @@ -875,6 +879,8 @@ ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) return ngx_http_v2_state_skip_padded(h2c, pos, end); } + stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; + h2c->state.stream = stream; return ngx_http_v2_state_read_data(h2c, pos, end); @@ -885,16 +891,10 @@ static u_char * ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) { - size_t size; - ssize_t n; - ngx_buf_t *buf; - ngx_int_t rc; - ngx_temp_file_t *tf; - ngx_connection_t *fc; - ngx_http_request_t *r; - ngx_http_v2_stream_t *stream; - ngx_http_request_body_t *rb; - ngx_http_core_loc_conf_t *clcf; + size_t size; + ngx_int_t rc; + ngx_uint_t last; + ngx_http_v2_stream_t *stream; stream = h2c->state.stream; @@ -903,168 +903,42 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, } if (stream->skip_data) { - stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "skipping http2 DATA frame, reason: %d", - stream->skip_data); + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "skipping http2 DATA frame"); return ngx_http_v2_state_skip_padded(h2c, pos, end); } size = end - pos; - if (size > h2c->state.length) { + if (size >= h2c->state.length) { size = h2c->state.length; + last = stream->in_closed; + + } else { + last = 0; } - r = stream->request; + rc = ngx_http_v2_process_request_body(stream->request, pos, size, last); - if (r->request_body == NULL - && ngx_http_v2_init_request_body(r) != NGX_OK) - { - stream->skip_data = NGX_HTTP_V2_DATA_INTERNAL_ERROR; - return ngx_http_v2_state_skip_padded(h2c, pos, end); + if (rc != NGX_OK) { + stream->skip_data = 1; + ngx_http_finalize_request(stream->request, rc); } - fc = r->connection; - rb = r->request_body; - tf = rb->temp_file; - buf = rb->buf; - - if (size) { - rb->rest += size; - - if (r->headers_in.content_length_n != -1 - && r->headers_in.content_length_n < rb->rest) - { - ngx_log_error(NGX_LOG_INFO, fc->log, 0, - "client intended to send body data " - "larger than declared"); - - stream->skip_data = NGX_HTTP_V2_DATA_ERROR; - goto error; - - } else { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - if (clcf->client_max_body_size - && clcf->client_max_body_size < rb->rest) - { - ngx_log_error(NGX_LOG_ERR, fc->log, 0, - "client intended to send " - "too large chunked body: %O bytes", rb->rest); - - stream->skip_data = NGX_HTTP_V2_DATA_ERROR; - goto error; - } - } - - h2c->state.length -= size; - - if (tf) { - buf->start = pos; - buf->pos = pos; - - pos += size; - - buf->end = pos; - buf->last = pos; - - n = ngx_write_chain_to_temp_file(tf, rb->bufs); - - /* TODO: n == 0 or not complete and level event */ - - if (n == NGX_ERROR) { - stream->skip_data = NGX_HTTP_V2_DATA_INTERNAL_ERROR; - goto error; - } - - tf->offset += n; - - } else { - buf->last = ngx_cpymem(buf->last, pos, size); - pos += size; - } - - r->request_length += size; - } + pos += size; + h2c->state.length -= size; if (h2c->state.length) { - if (rb->post_handler) { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_add_timer(fc->read, clcf->client_body_timeout); - } - return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_read_data); } - if (h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG) { - stream->in_closed = 1; - - if (r->headers_in.content_length_n < 0) { - r->headers_in.content_length_n = rb->rest; - - } else if (r->headers_in.content_length_n != rb->rest) { - ngx_log_error(NGX_LOG_INFO, fc->log, 0, - "client prematurely closed stream: " - "only %O out of %O bytes of request body received", - rb->rest, r->headers_in.content_length_n); - - stream->skip_data = NGX_HTTP_V2_DATA_ERROR; - goto error; - } - - if (tf) { - ngx_memzero(buf, sizeof(ngx_buf_t)); - - buf->in_file = 1; - buf->file_last = tf->file.offset; - buf->file = &tf->file; - - rb->buf = NULL; - } - - if (rb->post_handler) { - if (fc->read->timer_set) { - ngx_del_timer(fc->read); - } - - r->read_event_handler = ngx_http_block_reading; - rb->post_handler(r); - } - - } else if (rb->post_handler) { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_add_timer(fc->read, clcf->client_body_timeout); - } - if (h2c->state.padding) { return ngx_http_v2_state_skip_padded(h2c, pos, end); } return ngx_http_v2_state_complete(h2c, pos, end); - -error: - - if (rb->post_handler) { - if (fc->read->timer_set) { - ngx_del_timer(fc->read); - } - - if (stream->skip_data == NGX_HTTP_V2_DATA_ERROR) { - rc = (r->headers_in.content_length_n == -1) - ? NGX_HTTP_REQUEST_ENTITY_TOO_LARGE : NGX_HTTP_BAD_REQUEST; - - } else { - rc = NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_http_finalize_request(r, rc); - } - - return ngx_http_v2_state_skip_padded(h2c, pos, end); } @@ -2124,7 +1998,7 @@ ngx_http_v2_state_ping(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2 PING frame, flags: %ui", h2c->state.flags); + "http2 PING frame, flags: %ud", h2c->state.flags); if (h2c->state.flags & NGX_HTTP_V2_ACK_FLAG) { return ngx_http_v2_state_skip(h2c, pos, end); @@ -2556,7 +2430,7 @@ ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, ngx_uint_t ack) buf->last = ngx_http_v2_write_uint16(buf->last, NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING); buf->last = ngx_http_v2_write_uint32(buf->last, - NGX_HTTP_V2_MAX_WINDOW); + NGX_HTTP_V2_INITIAL_WINDOW); buf->last = ngx_http_v2_write_uint16(buf->last, NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING); @@ -2878,7 +2752,7 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c) stream->connection = h2c; stream->send_window = h2c->init_window; - stream->recv_window = NGX_HTTP_V2_MAX_WINDOW; + stream->recv_window = NGX_HTTP_V2_INITIAL_WINDOW; h2c->processing++; @@ -3515,155 +3389,299 @@ ngx_http_v2_run_request(ngx_http_request_t *r) ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client prematurely closed stream"); - r->stream->skip_data = NGX_HTTP_V2_DATA_ERROR; + r->stream->skip_data = 1; ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); return; } + r->headers_in.chunked = (r->headers_in.content_length_n == -1); + ngx_http_process_request(r); } -static ngx_int_t -ngx_http_v2_init_request_body(ngx_http_request_t *r) -{ - ngx_buf_t *buf; - ngx_temp_file_t *tf; - ngx_http_request_body_t *rb; - ngx_http_core_loc_conf_t *clcf; - - rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); - if (rb == NULL) { - return NGX_ERROR; - } - - r->request_body = rb; - - if (r->stream->in_closed) { - return NGX_OK; - } - - rb->rest = r->headers_in.content_length_n; - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - if (r->request_body_in_file_only - || rb->rest > (off_t) clcf->client_body_buffer_size - || rb->rest < 0) - { - tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); - if (tf == NULL) { - return NGX_ERROR; - } - - tf->file.fd = NGX_INVALID_FILE; - tf->file.log = r->connection->log; - tf->path = clcf->client_body_temp_path; - tf->pool = r->pool; - tf->warn = "a client request body is buffered to a temporary file"; - tf->log_level = r->request_body_file_log_level; - tf->persistent = r->request_body_in_persistent_file; - tf->clean = r->request_body_in_clean_file; - - if (r->request_body_file_group_access) { - tf->access = 0660; - } - - rb->temp_file = tf; - - if (r->stream->in_closed - && ngx_create_temp_file(&tf->file, tf->path, tf->pool, - tf->persistent, tf->clean, tf->access) - != NGX_OK) - { - return NGX_ERROR; - } - - buf = ngx_calloc_buf(r->pool); - if (buf == NULL) { - return NGX_ERROR; - } - - } else { - - if (rb->rest == 0) { - return NGX_OK; - } - - buf = ngx_create_temp_buf(r->pool, (size_t) rb->rest); - if (buf == NULL) { - return NGX_ERROR; - } - } - - rb->buf = buf; - - rb->bufs = ngx_alloc_chain_link(r->pool); - if (rb->bufs == NULL) { - return NGX_ERROR; - } - - rb->bufs->buf = buf; - rb->bufs->next = NULL; - - rb->rest = 0; - - return NGX_OK; -} - - ngx_int_t ngx_http_v2_read_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler) { + off_t len; ngx_http_v2_stream_t *stream; + ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http2 read request body"); - stream = r->stream; - switch (stream->skip_data) { - - case NGX_HTTP_V2_DATA_DISCARD: + if (stream->skip_data) { + r->request_body_no_buffering = 0; post_handler(r); return NGX_OK; + } - case NGX_HTTP_V2_DATA_ERROR: - if (r->headers_in.content_length_n == -1) { - return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; - } else { - return NGX_HTTP_BAD_REQUEST; - } - - case NGX_HTTP_V2_DATA_INTERNAL_ERROR: + rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); + if (rb == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (!r->request_body && ngx_http_v2_init_request_body(r) != NGX_OK) { - stream->skip_data = NGX_HTTP_V2_DATA_INTERNAL_ERROR; + /* + * set by ngx_pcalloc(): + * + * rb->bufs = NULL; + * rb->buf = NULL; + * rb->received = 0; + * rb->free = NULL; + * rb->busy = NULL; + */ + + rb->rest = 1; + rb->post_handler = post_handler; + + r->request_body = rb; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + len = r->headers_in.content_length_n; + + if (r->request_body_no_buffering && !stream->in_closed) { + r->request_body_in_file_only = 0; + + if (len < 0 || len > (off_t) clcf->client_body_buffer_size) { + len = clcf->client_body_buffer_size; + } + + if (len > NGX_HTTP_V2_MAX_WINDOW) { + len = NGX_HTTP_V2_MAX_WINDOW; + } + } + + if (len >= 0 && len <= (off_t) clcf->client_body_buffer_size + && !r->request_body_in_file_only) + { + rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); + + } else { + rb->buf = ngx_calloc_buf(r->pool); + + if (rb->buf != NULL) { + rb->buf->sync = 1; + } + } + + if (rb->buf == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (stream->in_closed) { - post_handler(r); - return NGX_OK; + r->request_body_no_buffering = 0; + return ngx_http_v2_process_request_body(r, NULL, 0, 1); } - r->request_body->post_handler = post_handler; + if (r->request_body_no_buffering) { + stream->no_flow_control = 0; + stream->recv_window = (size_t) len; + + } else { + stream->no_flow_control = 1; + stream->recv_window = NGX_HTTP_V2_MAX_WINDOW; + } + + if (ngx_http_v2_send_window_update(stream->connection, stream->node->id, + stream->recv_window) + == NGX_ERROR) + { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ngx_add_timer(r->connection->read, clcf->client_body_timeout); r->read_event_handler = ngx_http_v2_read_client_request_body_handler; r->write_event_handler = ngx_http_request_empty_handler; - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_add_timer(r->connection->read, clcf->client_body_timeout); - return NGX_AGAIN; } +static ngx_int_t +ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, + size_t size, ngx_uint_t last) +{ + ngx_buf_t *buf; + ngx_int_t rc; + ngx_connection_t *fc; + ngx_http_request_body_t *rb; + ngx_http_core_loc_conf_t *clcf; + + rb = r->request_body; + + if (rb == NULL) { + return NGX_OK; + } + + fc = r->connection; + buf = rb->buf; + + if (size) { + if (buf->sync) { + buf->pos = buf->start = pos; + buf->last = buf->end = pos + size; + + } else { + if (size > (size_t) (buf->end - buf->last)) { + ngx_log_error(NGX_LOG_INFO, fc->log, 0, + "client intended to send body data " + "larger than declared"); + + return NGX_HTTP_BAD_REQUEST; + } + + buf->last = ngx_cpymem(buf->last, pos, size); + } + } + + if (last) { + rb->rest = 0; + + if (fc->read->timer_set) { + ngx_del_timer(fc->read); + } + + if (r->request_body_no_buffering) { + ngx_post_event(fc->read, &ngx_posted_events); + return NGX_OK; + } + + rc = ngx_http_v2_filter_request_body(r); + + if (rc != NGX_OK) { + return rc; + } + + if (buf->sync) { + /* prevent reusing this buffer in the upstream module */ + rb->buf = NULL; + } + + if (r->headers_in.content_length_n == -1) { + r->headers_in.content_length_n = rb->received; + } + + r->read_event_handler = ngx_http_block_reading; + rb->post_handler(r); + + return NGX_OK; + } + + if (size == 0) { + return NGX_OK; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + ngx_add_timer(fc->read, clcf->client_body_timeout); + + if (r->request_body_no_buffering) { + ngx_post_event(fc->read, &ngx_posted_events); + return NGX_OK; + } + + if (buf->sync) { + return ngx_http_v2_filter_request_body(r); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_v2_filter_request_body(ngx_http_request_t *r) +{ + ngx_buf_t *b, *buf; + ngx_int_t rc; + ngx_chain_t *cl; + ngx_http_request_body_t *rb; + ngx_http_core_loc_conf_t *clcf; + + rb = r->request_body; + buf = rb->buf; + + if (buf->pos == buf->last && rb->rest) { + cl = NULL; + goto update; + } + + cl = ngx_chain_get_free_buf(r->pool, &rb->free); + if (cl == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + b = cl->buf; + + ngx_memzero(b, sizeof(ngx_buf_t)); + + if (buf->pos != buf->last) { + r->request_length += buf->last - buf->pos; + rb->received += buf->last - buf->pos; + + if (r->headers_in.content_length_n != -1) { + if (rb->received > r->headers_in.content_length_n) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client intended to send body data " + "larger than declared"); + + return NGX_HTTP_BAD_REQUEST; + } + + } else { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->client_max_body_size + && rb->received > clcf->client_max_body_size) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "client intended to send too large chunked body: " + "%O bytes", rb->received); + + return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; + } + } + + b->temporary = 1; + b->pos = buf->pos; + b->last = buf->last; + b->start = b->pos; + b->end = b->last; + + buf->pos = buf->last; + } + + if (!rb->rest) { + if (r->headers_in.content_length_n != -1 + && r->headers_in.content_length_n != rb->received) + { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client prematurely closed stream: " + "only %O out of %O bytes of request body received", + rb->received, r->headers_in.content_length_n); + + return NGX_HTTP_BAD_REQUEST; + } + + b->last_buf = 1; + } + + b->tag = (ngx_buf_tag_t) &ngx_http_v2_filter_request_body; + b->flush = r->request_body_no_buffering; + +update: + + rc = ngx_http_top_request_body_filter(r, cl); + + ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &cl, + (ngx_buf_tag_t) &ngx_http_v2_filter_request_body); + + return rc; +} + + static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r) { @@ -3678,7 +3696,7 @@ ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r) ngx_log_error(NGX_LOG_INFO, fc->log, NGX_ETIMEDOUT, "client timed out"); fc->timedout = 1; - r->stream->skip_data = NGX_HTTP_V2_DATA_DISCARD; + r->stream->skip_data = 1; ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT); return; @@ -3688,7 +3706,7 @@ ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r) ngx_log_error(NGX_LOG_INFO, fc->log, 0, "client prematurely closed stream"); - r->stream->skip_data = NGX_HTTP_V2_DATA_DISCARD; + r->stream->skip_data = 1; ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); return; @@ -3696,6 +3714,91 @@ ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r) } +ngx_int_t +ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r) +{ + size_t window; + ngx_buf_t *buf; + ngx_int_t rc; + ngx_connection_t *fc; + ngx_http_v2_stream_t *stream; + ngx_http_v2_connection_t *h2c; + ngx_http_core_loc_conf_t *clcf; + + stream = r->stream; + fc = r->connection; + + if (fc->read->timedout) { + if (stream->recv_window) { + stream->skip_data = 1; + fc->timedout = 1; + + return NGX_HTTP_REQUEST_TIME_OUT; + } + + fc->read->timedout = 0; + } + + if (fc->error) { + stream->skip_data = 1; + return NGX_HTTP_BAD_REQUEST; + } + + rc = ngx_http_v2_filter_request_body(r); + + if (rc != NGX_OK) { + stream->skip_data = 1; + return rc; + } + + if (!r->request_body->rest) { + return NGX_OK; + } + + if (r->request_body->busy != NULL) { + return NGX_AGAIN; + } + + buf = r->request_body->buf; + + buf->pos = buf->start; + buf->last = buf->start; + + window = buf->end - buf->start; + h2c = stream->connection; + + if (h2c->state.stream == stream) { + window -= h2c->state.length; + } + + if (window == stream->recv_window) { + return NGX_AGAIN; + } + + if (ngx_http_v2_send_window_update(h2c, stream->node->id, + window - stream->recv_window) + == NGX_ERROR) + { + stream->skip_data = 1; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) { + stream->skip_data = 1; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (stream->recv_window == 0) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + ngx_add_timer(fc->read, clcf->client_body_timeout); + } + + stream->recv_window = window; + + return NGX_AGAIN; +} + + static ngx_int_t ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, ngx_http_v2_stream_t *stream, ngx_uint_t status) @@ -3709,7 +3812,7 @@ ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, return NGX_ERROR; } - stream->out_closed = 1; + stream->rst_sent = 1; fc = stream->request->connection; fc->error = 1; @@ -3744,13 +3847,23 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) return; } - if (!stream->out_closed) { - if (ngx_http_v2_send_rst_stream(h2c, node->id, - fc->timedout ? NGX_HTTP_V2_PROTOCOL_ERROR - : NGX_HTTP_V2_INTERNAL_ERROR) - != NGX_OK) - { - h2c->connection->error = 1; + if (!stream->rst_sent && !h2c->connection->error) { + + if (!stream->out_closed) { + if (ngx_http_v2_send_rst_stream(h2c, node->id, + fc->timedout ? NGX_HTTP_V2_PROTOCOL_ERROR + : NGX_HTTP_V2_INTERNAL_ERROR) + != NGX_OK) + { + h2c->connection->error = 1; + } + + } else if (!stream->in_closed) { + if (ngx_http_v2_send_rst_stream(h2c, node->id, NGX_HTTP_V2_NO_ERROR) + != NGX_OK) + { + h2c->connection->error = 1; + } } } @@ -3942,23 +4055,23 @@ ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c, c = h2c->connection; - if (h2c->state.stream) { - h2c->state.stream->out_closed = 1; - ngx_http_v2_close_stream(h2c->state.stream, NGX_HTTP_BAD_REQUEST); - } - h2c->blocked = 1; if (!c->error && ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) { (void) ngx_http_v2_send_output_queue(h2c); } + c->error = 1; + + if (h2c->state.stream) { + ngx_http_v2_close_stream(h2c->state.stream, NGX_HTTP_BAD_REQUEST); + } + if (!h2c->processing) { ngx_http_close_connection(c); return; } - c->error = 1; c->read->handler = ngx_http_empty_handler; c->write->handler = ngx_http_empty_handler; diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 5a791e6..7a77c27 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -24,10 +24,6 @@ #define NGX_HTTP_V2_MAX_FIELD \ (127 + (1 << (NGX_HTTP_V2_INT_OCTETS - 1) * 7) - 1) -#define NGX_HTTP_V2_DATA_DISCARD 1 -#define NGX_HTTP_V2_DATA_ERROR 2 -#define NGX_HTTP_V2_DATA_INTERNAL_ERROR 3 - #define NGX_HTTP_V2_FRAME_HEADER_SIZE 9 /* frame types */ @@ -194,7 +190,9 @@ struct ngx_http_v2_stream_s { unsigned exhausted:1; unsigned in_closed:1; unsigned out_closed:1; - unsigned skip_data:2; + unsigned rst_sent:1; + unsigned no_flow_control:1; + unsigned skip_data:1; }; @@ -262,6 +260,7 @@ void ngx_http_v2_request_headers_init(void); ngx_int_t ngx_http_v2_read_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler); +ngx_int_t ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r); void ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc); diff --git a/src/http/v2/ngx_http_v2_module.c b/src/http/v2/ngx_http_v2_module.c index d99ac30..5a4561c 100644 --- a/src/http/v2/ngx_http_v2_module.c +++ b/src/http/v2/ngx_http_v2_module.c @@ -215,7 +215,7 @@ static ngx_http_variable_t ngx_http_v2_vars[] = { static ngx_int_t ngx_http_v2_add_variables(ngx_conf_t *cf) { - ngx_http_variable_t *var, *v; + ngx_http_variable_t *var, *v; for (v = ngx_http_v2_vars; v->name.len; v++) { var = ngx_http_add_variable(cf, &v->name, v->flags); diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index 07d0cb6..bfbf768 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -342,7 +342,7 @@ typedef struct { void *(*create_srv_conf)(ngx_conf_t *cf); char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, - void *conf); + void *conf); } ngx_mail_module_t; diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c index d93e946..39f9b17 100644 --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -431,7 +431,7 @@ ngx_mail_auth_http_ignore_status_line(ngx_mail_session_t *s, } ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, - "auth http server &V sent invalid response", + "auth http server %V sent invalid response", ctx->peer.name); ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c index 3802c3e..007284b 100644 --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -935,7 +935,7 @@ ngx_mail_proxy_handler(ngx_event_t *ev) do_write = ev->write ? 1 : 0; ngx_log_debug3(NGX_LOG_DEBUG_MAIL, ev->log, 0, - "mail proxy handler: %d, #%d > #%d", + "mail proxy handler: %ui, #%d > #%d", do_write, src->fd, dst->fd); for ( ;; ) { diff --git a/src/mail/ngx_mail_smtp_handler.c b/src/mail/ngx_mail_smtp_handler.c index 46d703e..81cc75f 100644 --- a/src/mail/ngx_mail_smtp_handler.c +++ b/src/mail/ngx_mail_smtp_handler.c @@ -42,7 +42,7 @@ static u_char smtp_username[] = "334 VXNlcm5hbWU6" CRLF; static u_char smtp_password[] = "334 UGFzc3dvcmQ6" CRLF; static u_char smtp_invalid_command[] = "500 5.5.1 Invalid command" CRLF; static u_char smtp_invalid_pipelining[] = - "503 5.5.0 Improper use of SMTP command pipelining" CRLF; + "503 5.5.0 Improper use of SMTP command pipelining" CRLF; static u_char smtp_invalid_argument[] = "501 5.5.4 Invalid argument" CRLF; static u_char smtp_auth_required[] = "530 5.7.1 Authentication required" CRLF; static u_char smtp_bad_sequence[] = "503 5.5.1 Bad sequence of commands" CRLF; diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c index 1075410..ff5c141 100644 --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -312,13 +312,13 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) conf->ssl.log = cf->log; if (conf->enable) { - mode = "ssl"; + mode = "ssl"; } else if (conf->starttls != NGX_MAIL_STARTTLS_OFF) { - mode = "starttls"; + mode = "starttls"; } else { - mode = ""; + mode = ""; } if (conf->file == NULL) { @@ -421,7 +421,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } -#ifndef LIBRESSL_VERSION_NUMBER +#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) SSL_CTX_set_tmp_rsa_callback(conf->ssl.ctx, ngx_ssl_rsa512_key_callback); #endif diff --git a/src/os/unix/ngx_atomic.h b/src/os/unix/ngx_atomic.h index 417cd86..74b8b7f 100644 --- a/src/os/unix/ngx_atomic.h +++ b/src/os/unix/ngx_atomic.h @@ -276,26 +276,26 @@ typedef volatile ngx_atomic_uint_t ngx_atomic_t; static ngx_inline ngx_atomic_uint_t ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, - ngx_atomic_uint_t set) + ngx_atomic_uint_t set) { - if (*lock == old) { - *lock = set; - return 1; - } + if (*lock == old) { + *lock = set; + return 1; + } - return 0; + return 0; } static ngx_inline ngx_atomic_int_t ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add) { - ngx_atomic_int_t old; + ngx_atomic_int_t old; - old = *value; - *value += add; + old = *value; + *value += add; - return old; + return old; } #define ngx_memory_barrier() diff --git a/src/os/unix/ngx_channel.h b/src/os/unix/ngx_channel.h index d7a9f6b..362cc64 100644 --- a/src/os/unix/ngx_channel.h +++ b/src/os/unix/ngx_channel.h @@ -15,10 +15,10 @@ typedef struct { - ngx_uint_t command; - ngx_pid_t pid; - ngx_int_t slot; - ngx_fd_t fd; + ngx_uint_t command; + ngx_pid_t pid; + ngx_int_t slot; + ngx_fd_t fd; } ngx_channel_t; diff --git a/src/os/unix/ngx_file_aio_read.c b/src/os/unix/ngx_file_aio_read.c index b11cf8a..aedc3c9 100644 --- a/src/os/unix/ngx_file_aio_read.c +++ b/src/os/unix/ngx_file_aio_read.c @@ -84,7 +84,7 @@ ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, } ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, - "aio complete:%d @%O:%z %V", + "aio complete:%d @%O:%uz %V", ev->complete, offset, size, &file->name); if (ev->complete) { diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c index bcef7ec..65c79a2 100644 --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -176,7 +176,7 @@ ngx_thread_read_handler(void *data, ngx_log_t *log) #endif ngx_log_debug4(NGX_LOG_DEBUG_CORE, log, 0, - "pread: %z (err: %i) of %uz @%O", + "pread: %z (err: %d) of %uz @%O", n, ctx->err, ctx->size, ctx->offset); } diff --git a/src/os/unix/ngx_linux_aio_read.c b/src/os/unix/ngx_linux_aio_read.c index b0a9236..9f0a6c1 100644 --- a/src/os/unix/ngx_linux_aio_read.c +++ b/src/os/unix/ngx_linux_aio_read.c @@ -73,7 +73,7 @@ ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, } ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, - "aio complete:%d @%O:%z %V", + "aio complete:%d @%O:%uz %V", ev->complete, offset, size, &file->name); if (ev->complete) { diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c index 50a9cea..3c0696a 100644 --- a/src/os/unix/ngx_linux_sendfile_chain.c +++ b/src/os/unix/ngx_linux_sendfile_chain.c @@ -451,7 +451,7 @@ again: #endif ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0, - "sendfile: %z (err: %i) of %uz @%O", + "sendfile: %z (err: %d) of %uz @%O", n, ctx->err, ctx->size, file->file_pos); if (ctx->err == NGX_EINTR) { diff --git a/src/os/unix/ngx_os.h b/src/os/unix/ngx_os.h index c0d59ef..e22f07c 100644 --- a/src/os/unix/ngx_os.h +++ b/src/os/unix/ngx_os.h @@ -39,7 +39,7 @@ void ngx_os_status(ngx_log_t *log); ngx_int_t ngx_os_specific_init(ngx_log_t *log); void ngx_os_specific_status(ngx_log_t *log); ngx_int_t ngx_daemon(ngx_log_t *log); -ngx_int_t ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_int_t pid); +ngx_int_t ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_pid_t pid); ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size); diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c index 6f3f385..24a63fb 100644 --- a/src/os/unix/ngx_process.c +++ b/src/os/unix/ngx_process.c @@ -611,7 +611,7 @@ ngx_debug_point(void) ngx_int_t -ngx_os_signal_process(ngx_cycle_t *cycle, char *name, ngx_int_t pid) +ngx_os_signal_process(ngx_cycle_t *cycle, char *name, ngx_pid_t pid) { ngx_signal_t *sig; diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c index 9be6376..7cee1c5 100644 --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -145,7 +145,7 @@ ngx_master_process_cycle(ngx_cycle_t *cycle) } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "termination cycle: %d", delay); + "termination cycle: %M", delay); itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; @@ -438,7 +438,7 @@ ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch) } ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0, - "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d", + "pass channel s:%i pid:%P fd:%d to s:%i pid:%P fd:%d", ch->slot, ch->pid, ch->fd, i, ngx_processes[i].pid, ngx_processes[i].channel[0]); @@ -492,7 +492,7 @@ ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo) for (i = 0; i < ngx_last_process; i++) { ngx_log_debug7(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "child: %d %P e:%d t:%d d:%d r:%d j:%d", + "child: %i %P e:%d t:%d d:%d r:%d j:%d", i, ngx_processes[i].pid, ngx_processes[i].exiting, @@ -570,7 +570,7 @@ ngx_reap_children(ngx_cycle_t *cycle) for (i = 0; i < ngx_last_process; i++) { ngx_log_debug7(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "child: %d %P e:%d t:%d d:%d r:%d j:%d", + "child: %i %P e:%d t:%d d:%d r:%d j:%d", i, ngx_processes[i].pid, ngx_processes[i].exiting, @@ -1047,7 +1047,7 @@ ngx_channel_handler(ngx_event_t *ev) } ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, - "channel command: %d", ch.command); + "channel command: %ui", ch.command); switch (ch.command) { diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c index 3544b4b..9953782 100644 --- a/src/os/unix/ngx_readv_chain.c +++ b/src/os/unix/ngx_readv_chain.c @@ -101,7 +101,7 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "readv: %d, last:%d", vec.nelts, iov->iov_len); + "readv: %ui, last:%uz", vec.nelts, iov->iov_len); do { n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts); diff --git a/src/os/unix/ngx_recv.c b/src/os/unix/ngx_recv.c index 86675df..fc7f76c 100644 --- a/src/os/unix/ngx_recv.c +++ b/src/os/unix/ngx_recv.c @@ -52,7 +52,7 @@ ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) n = recv(c->fd, buf, size, 0); ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "recv: fd:%d %d of %d", c->fd, n, size); + "recv: fd:%d %z of %uz", c->fd, n, size); if (n >= 0) { if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { @@ -139,7 +139,7 @@ ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) n = recv(c->fd, buf, size, 0); ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "recv: fd:%d %d of %d", c->fd, n, size); + "recv: fd:%d %z of %uz", c->fd, n, size); if (n == 0) { rev->ready = 0; diff --git a/src/os/unix/ngx_send.c b/src/os/unix/ngx_send.c index 80995ab..61ea202 100644 --- a/src/os/unix/ngx_send.c +++ b/src/os/unix/ngx_send.c @@ -34,7 +34,7 @@ ngx_unix_send(ngx_connection_t *c, u_char *buf, size_t size) n = send(c->fd, buf, size, 0); ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "send: fd:%d %d of %d", c->fd, n, size); + "send: fd:%d %z of %uz", c->fd, n, size); if (n > 0) { if (n < (ssize_t) size) { diff --git a/src/os/unix/ngx_sunpro_amd64.il b/src/os/unix/ngx_sunpro_amd64.il index dc454b2..07f3210 100644 --- a/src/os/unix/ngx_sunpro_amd64.il +++ b/src/os/unix/ngx_sunpro_amd64.il @@ -38,6 +38,6 @@ / / ld.so.1: nginx: fatal: hardware capability unsupported: 0x2000 [ PAUSE ] - .inline ngx_cpu_pause,0 - rep; nop - .end + .inline ngx_cpu_pause,0 + rep; nop + .end diff --git a/src/os/unix/ngx_sunpro_x86.il b/src/os/unix/ngx_sunpro_x86.il index fd1cc00..d7e127c 100644 --- a/src/os/unix/ngx_sunpro_x86.il +++ b/src/os/unix/ngx_sunpro_x86.il @@ -39,6 +39,6 @@ / / ld.so.1: nginx: fatal: hardware capability unsupported: 0x2000 [ PAUSE ] - .inline ngx_cpu_pause,0 - rep; nop - .end + .inline ngx_cpu_pause,0 + rep; nop + .end diff --git a/src/os/unix/ngx_udp_recv.c b/src/os/unix/ngx_udp_recv.c index 1c807a0..e03bf6c 100644 --- a/src/os/unix/ngx_udp_recv.c +++ b/src/os/unix/ngx_udp_recv.c @@ -25,7 +25,7 @@ ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) n = recv(c->fd, buf, size, 0); ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "recv: fd:%d %d of %d", c->fd, n, size); + "recv: fd:%d %z of %uz", c->fd, n, size); if (n >= 0) { if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { @@ -83,7 +83,7 @@ ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) n = recv(c->fd, buf, size, 0); ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "recv: fd:%d %d of %d", c->fd, n, size); + "recv: fd:%d %z of %uz", c->fd, n, size); if (n >= 0) { return n; diff --git a/src/stream/ngx_stream_limit_conn_module.c b/src/stream/ngx_stream_limit_conn_module.c index 732b089..f1d8a37 100644 --- a/src/stream/ngx_stream_limit_conn_module.c +++ b/src/stream/ngx_stream_limit_conn_module.c @@ -220,7 +220,7 @@ ngx_stream_limit_conn_handler(ngx_stream_session_t *s) } ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, - "limit conn: %08XD %d", node->key, lc->conn); + "limit conn: %08Xi %d", node->key, lc->conn); ngx_shmtx_unlock(&shpool->mutex); @@ -340,7 +340,7 @@ ngx_stream_limit_conn_cleanup(void *data) ngx_shmtx_lock(&shpool->mutex); ngx_log_debug2(NGX_LOG_DEBUG_STREAM, lccln->shm_zone->shm.log, 0, - "limit conn cleanup: %08XD %d", node->key, lc->conn); + "limit conn cleanup: %08Xi %d", node->key, lc->conn); lc->conn--; diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index 7abd9e1..e12da1b 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -276,7 +276,7 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } -#ifndef LIBRESSL_VERSION_NUMBER +#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) SSL_CTX_set_tmp_rsa_callback(conf->ssl.ctx, ngx_ssl_rsa512_key_callback); #endif diff --git a/src/stream/ngx_stream_upstream_least_conn_module.c b/src/stream/ngx_stream_upstream_least_conn_module.c index 677da45..c9719f9 100644 --- a/src/stream/ngx_stream_upstream_least_conn_module.c +++ b/src/stream/ngx_stream_upstream_least_conn_module.c @@ -254,7 +254,7 @@ failed: / (8 * sizeof(uintptr_t)); for (i = 0; i < n; i++) { - rrp->tried[i] = 0; + rrp->tried[i] = 0; } ngx_stream_upstream_rr_peers_unlock(peers); diff --git a/src/stream/ngx_stream_upstream_round_robin.c b/src/stream/ngx_stream_upstream_round_robin.c index efedb28..e1ab592 100644 --- a/src/stream/ngx_stream_upstream_round_robin.c +++ b/src/stream/ngx_stream_upstream_round_robin.c @@ -356,7 +356,7 @@ failed: / (8 * sizeof(uintptr_t)); for (i = 0; i < n; i++) { - rrp->tried[i] = 0; + rrp->tried[i] = 0; } ngx_stream_upstream_rr_peers_unlock(peers); From cfc16224c03487b79c12990251035aced699068b Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 19 Apr 2016 12:26:59 +0300 Subject: [PATCH 112/651] Fix changelog typo --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 7e366f3..6d5fd8a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -10,7 +10,7 @@ nginx (1.9.13-1) UNRELEASED; urgency=medium * debian/control: + Enable http/2, thread pool & WebDAV on nginx-light. In order for dynamic modules to be loadable in all nginx flavors we need - to ensure the share the same build signature. (Closes: #816095) + to ensure they share the same build signature. (Closes: #816095) + nginx-common & nginx-doc are now 'Multi-Arch: foreign'. (Closes: #812484) Thanks Elrond for the report and the initial patch. + Use secure VCS uri (lintian). From 8b10bd4f01381a69b57b9957c2eca7b258d8e7b8 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 18 Apr 2016 14:15:19 +0300 Subject: [PATCH 113/651] Release 1.9.14-1 --- debian/changelog | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 6d5fd8a..ae2f6fc 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,7 +1,7 @@ -nginx (1.9.13-1) UNRELEASED; urgency=medium +nginx (1.9.14-1) unstable; urgency=medium [ Christos Trochalakis ] - * New upstream release (1.9.13) (Closes: #812806) + * New upstream release (1.9.14) (Closes: #812806) * debian: + Setup dynamic module flow, and implement a simple dh_nginx helper for internal use. @@ -28,7 +28,7 @@ nginx (1.9.13-1) UNRELEASED; urgency=medium + Update http-auth-pam module to 1.5 and convert it to a dyn module. (Closes: #819062) - -- Christos Trochalakis Thu, 11 Feb 2016 15:06:38 +0200 + -- Christos Trochalakis Tue, 19 Apr 2016 11:05:35 +0300 nginx (1.9.10-1) unstable; urgency=medium From 58105135c4fde9f33b277f02ff07ba6189d57abf Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 27 Apr 2016 16:37:15 +0300 Subject: [PATCH 114/651] Fix upgrading nginx-extras from a non-dynamic version libnginx-mod-http-perl ships a common file with nginx-extras, adding a Replaces header fixes that. Note that the is no need to add a Breaks header since these packages are not co-installable (they explicitly depend on a different nginx-common version). --- debian/changelog | 8 ++++++++ debian/control | 1 + 2 files changed, 9 insertions(+) diff --git a/debian/changelog b/debian/changelog index ae2f6fc..42d09e1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +nginx (1.9.14-2) UNRELEASED; urgency=medium + + [ Christos Trochalakis ] + * debian/control: + + Fix upgrading nginx-extras from testing. (Closes: #822553) + + -- Christos Trochalakis Wed, 27 Apr 2016 16:34:16 +0300 + nginx (1.9.14-1) unstable; urgency=medium [ Christos Trochalakis ] diff --git a/debian/control b/debian/control index 2398e29..5bda8fe 100644 --- a/debian/control +++ b/debian/control @@ -280,6 +280,7 @@ Description: Stream module for Nginx Package: libnginx-mod-http-perl Architecture: any Depends: ${perl:Depends}, ${misc:Depends}, ${shlibs:Depends} +Replaces: nginx-extras (<< 1.9.14-1) Description: Perl module for Nginx Embed Perl runtime into nginx. . From 664bdf48f483d5a0682566077a79f63131b9ba94 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 28 Apr 2016 10:00:35 +0300 Subject: [PATCH 115/651] Bump standards to 3.9.8 --- debian/changelog | 1 + debian/control | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 42d09e1..84d382c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,6 +3,7 @@ nginx (1.9.14-2) UNRELEASED; urgency=medium [ Christos Trochalakis ] * debian/control: + Fix upgrading nginx-extras from testing. (Closes: #822553) + + Bump Standards to 3.9.8, no changes needed. -- Christos Trochalakis Wed, 27 Apr 2016 16:34:16 +0300 diff --git a/debian/control b/debian/control index 5bda8fe..52baf37 100644 --- a/debian/control +++ b/debian/control @@ -24,7 +24,7 @@ Build-Depends: autotools-dev, libxslt1-dev, po-debconf, zlib1g-dev -Standards-Version: 3.9.7.0 +Standards-Version: 3.9.8.0 Homepage: http://nginx.net Vcs-Git: https://anonscm.debian.org/cgit/collab-maint/nginx.git Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/nginx.git From c46cc7556bd04b652d74d2cdaf796487c3914a3c Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 28 Apr 2016 10:01:02 +0300 Subject: [PATCH 116/651] libnginx-mod-http-perl: Override wrong-section-according-to-package-name warning --- debian/changelog | 2 ++ debian/libnginx-mod-http-perl.lintian-overrides | 1 + 2 files changed, 3 insertions(+) create mode 100644 debian/libnginx-mod-http-perl.lintian-overrides diff --git a/debian/changelog b/debian/changelog index 84d382c..c3ba4d3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,8 @@ nginx (1.9.14-2) UNRELEASED; urgency=medium * debian/control: + Fix upgrading nginx-extras from testing. (Closes: #822553) + Bump Standards to 3.9.8, no changes needed. + * debian/libnginx-mod-http-perl.lintian-overrides: + + Override wrong-section-according-to-package-name warning. -- Christos Trochalakis Wed, 27 Apr 2016 16:34:16 +0300 diff --git a/debian/libnginx-mod-http-perl.lintian-overrides b/debian/libnginx-mod-http-perl.lintian-overrides new file mode 100644 index 0000000..cda1f30 --- /dev/null +++ b/debian/libnginx-mod-http-perl.lintian-overrides @@ -0,0 +1 @@ +libnginx-mod-http-perl: wrong-section-according-to-package-name libnginx-mod-http-perl => perl From a66bea579bb35c6335beee0a46ad1b1535113f97 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 27 Apr 2016 16:44:22 +0300 Subject: [PATCH 117/651] Release 1.9.14-2 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index c3ba4d3..4d4885f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.9.14-2) UNRELEASED; urgency=medium +nginx (1.9.14-2) unstable; urgency=medium [ Christos Trochalakis ] * debian/control: @@ -7,7 +7,7 @@ nginx (1.9.14-2) UNRELEASED; urgency=medium * debian/libnginx-mod-http-perl.lintian-overrides: + Override wrong-section-according-to-package-name warning. - -- Christos Trochalakis Wed, 27 Apr 2016 16:34:16 +0300 + -- Christos Trochalakis Wed, 27 Apr 2016 16:43:02 +0300 nginx (1.9.14-1) unstable; urgency=medium From 95a2b168be9b408dd778f23476a22f2c9c1d2784 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 29 Apr 2016 10:30:33 +0300 Subject: [PATCH 118/651] Imported Upstream version 1.10.0 --- CHANGES | 24 ++++ CHANGES.ru | 23 ++++ auto/cc/icc | 4 +- contrib/vim/syntax/nginx.vim | 2 +- src/core/nginx.h | 4 +- src/core/ngx_inet.c | 2 +- src/core/ngx_regex.c | 2 +- src/core/ngx_resolver.c | 4 +- src/core/ngx_thread_pool.c | 4 + src/event/modules/ngx_epoll_module.c | 2 +- src/http/modules/ngx_http_fastcgi_module.c | 5 + src/http/modules/ngx_http_mp4_module.c | 8 +- src/http/modules/ngx_http_ssi_filter_module.c | 6 +- src/http/v2/ngx_http_v2.c | 100 +++++++++++----- src/http/v2/ngx_http_v2.h | 1 + src/os/unix/ngx_readv_chain.c | 50 ++++---- src/os/unix/ngx_recv.c | 107 +++++------------- src/os/unix/ngx_udp_recv.c | 53 +-------- 18 files changed, 201 insertions(+), 200 deletions(-) diff --git a/CHANGES b/CHANGES index e1e596e..408f952 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,28 @@ +Changes with nginx 1.10.0 26 Apr 2016 + + *) 1.10.x stable branch. + + +Changes with nginx 1.9.15 19 Apr 2016 + + *) Bugfix: "recv() failed" errors might occur when using HHVM as a + FastCGI server. + + *) Bugfix: when using HTTP/2 and the "limit_req" or "auth_request" + directives a timeout or a "client violated flow control" error might + occur while reading client request body; the bug had appeared in + 1.9.14. + + *) Workaround: a response might not be shown by some browsers if HTTP/2 + was used and client request body was not fully read; the bug had + appeared in 1.9.14. + + *) Bugfix: connections might hang when using the "aio threads" + directive. + Thanks to Mindaugas Rasiukevicius. + + Changes with nginx 1.9.14 05 Apr 2016 *) Feature: OpenSSL 1.1.0 compatibility. diff --git a/CHANGES.ru b/CHANGES.ru index c6e6e84..4e6002e 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,27 @@ +Изменения в nginx 1.10.0 26.04.2016 + + *) Стабильная ветка 1.10.x. + + +Изменения в nginx 1.9.15 19.04.2016 + + *) Исправление: при использовании HHVM в качестве FastCGI-сервера могли + возникать ошибки "recv() failed". + + *) Исправление: при использовании HTTP/2 и директив limit_req или + auth_request при чтении тела запроса мог произойти таймаут или ошибка + "client violated flow control"; ошибка появилась в 1.9.14. + + *) Изменение: при использовании HTTP/2 ответ мог не показываться + некоторыми браузерами, если тело запроса было прочитано не целиком; + ошибка появилась в 1.9.14. + + *) Исправление: при использовании директивы "aio threads" соединения + могли зависать. + Спасибо Mindaugas Rasiukevicius. + + Изменения в nginx 1.9.14 05.04.2016 *) Добавление: совместимость с OpenSSL 1.1.0. diff --git a/auto/cc/icc b/auto/cc/icc index 1d83ed3..1c0df1a 100644 --- a/auto/cc/icc +++ b/auto/cc/icc @@ -89,7 +89,7 @@ CFLAGS="$CFLAGS -wd1419" case "$NGX_ICC_VER" in 9.*) - # "cc" clobber ignored, warnings for Liunx's htonl()/htons() + # "cc" clobber ignored, warnings for Linux's htonl()/htons() CFLAGS="$CFLAGS -wd1469" # explicit conversion of a 64-bit integral type to a smaller # integral type @@ -103,7 +103,7 @@ case "$NGX_ICC_VER" in ;; 8.*) - # "cc" clobber ignored, warnings for Liunx's htonl()/htons() + # "cc" clobber ignored, warnings for Linux's htonl()/htons() CFLAGS="$CFLAGS -wd1469" # floating-point equality and inequality comparisons are unreliable, # warning on SvTRUE() diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim index 8f13017..f1fd48a 100644 --- a/contrib/vim/syntax/nginx.vim +++ b/contrib/vim/syntax/nginx.vim @@ -604,7 +604,7 @@ syn keyword ngxDirectiveThirdParty echo_subrequest syn keyword ngxDirectiveThirdParty echo_subrequest_async " Events Module -" Privides options for start/stop events. +" Provides options for start/stop events. syn keyword ngxDirectiveThirdParty on_start syn keyword ngxDirectiveThirdParty on_stop diff --git a/src/core/nginx.h b/src/core/nginx.h index d0a6f65..fe78745 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1009014 -#define NGINX_VERSION "1.9.14" +#define nginx_version 1010000 +#define NGINX_VERSION "1.10.0" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c index a4e80ed..33b303d 100644 --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -348,7 +348,7 @@ ngx_inet6_ntop(u_char *p, u_char *text, size_t len) continue; } - dst = ngx_sprintf(dst, "%uxd", p[i] * 256 + p[i + 1]); + dst = ngx_sprintf(dst, "%xd", p[i] * 256 + p[i + 1]); if (i < 14) { *dst++ = ':'; diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c index 416622d..9939dce 100644 --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -32,7 +32,7 @@ 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_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, 0, offsetof(ngx_regex_conf_t, pcre_jit), diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index 3c52de8..e00fe22 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -1733,7 +1733,7 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n, trunc = flags & 0x0200; ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0, - "resolver DNS response %ui fl:%04Xui %ui/%ui/%ud/%ud", + "resolver DNS response %ui fl:%04Xi %ui/%ui/%ud/%ud", ident, flags, nqs, nan, (response->nns_hi << 8) + response->nns_lo, (response->nar_hi << 8) + response->nar_lo); @@ -1741,7 +1741,7 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n, /* response to a standard query */ if ((flags & 0xf870) != 0x8000 || (trunc && tcp)) { ngx_log_error(r->log_level, r->log, 0, - "invalid %s DNS response %ui fl:%04Xui", + "invalid %s DNS response %ui fl:%04Xi", tcp ? "TCP" : "UDP", ident, flags); return; } diff --git a/src/core/ngx_thread_pool.c b/src/core/ngx_thread_pool.c index 0353085..f3655aa 100644 --- a/src/core/ngx_thread_pool.c +++ b/src/core/ngx_thread_pool.c @@ -345,6 +345,8 @@ ngx_thread_pool_cycle(void *data) *ngx_thread_pool_done.last = task; ngx_thread_pool_done.last = &task->next; + ngx_memory_barrier(); + ngx_unlock(&ngx_thread_pool_done_lock); (void) ngx_notify(ngx_thread_pool_handler); @@ -366,6 +368,8 @@ ngx_thread_pool_handler(ngx_event_t *ev) ngx_thread_pool_done.first = NULL; ngx_thread_pool_done.last = &ngx_thread_pool_done.first; + ngx_memory_barrier(); + ngx_unlock(&ngx_thread_pool_done_lock); while (task) { diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c index 828e4d1..166c461 100644 --- a/src/event/modules/ngx_epoll_module.c +++ b/src/event/modules/ngx_epoll_module.c @@ -910,7 +910,7 @@ ngx_epoll_eventfd_handler(ngx_event_t *ev) for (i = 0; i < events; i++) { ngx_log_debug4(NGX_LOG_DEBUG_EVENT, ev->log, 0, - "io_event: %uXL %uXL %L %L", + "io_event: %XL %XL %L %L", event[i].data, event[i].obj, event[i].res, event[i].res2); diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index a861203..2d288ce 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -1177,6 +1177,11 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r) while (body) { + if (ngx_buf_special(body->buf)) { + body = body->next; + continue; + } + if (body->buf->in_file) { file_pos = body->buf->file_pos; diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index 6cb3ccf..16ef83c 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -1433,10 +1433,10 @@ typedef struct { u_char layer[2]; u_char group[2]; u_char volume[2]; - u_char reverved3[2]; + u_char reserved3[2]; u_char matrix[36]; u_char width[4]; - u_char heigth[4]; + u_char height[4]; } ngx_mp4_tkhd_atom_t; typedef struct { @@ -1453,10 +1453,10 @@ typedef struct { u_char layer[2]; u_char group[2]; u_char volume[2]; - u_char reverved3[2]; + u_char reserved3[2]; u_char matrix[36]; u_char width[4]; - u_char heigth[4]; + u_char height[4]; } ngx_mp4_tkhd64_atom_t; diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index b997aaa..fc6e65b 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -2005,7 +2005,7 @@ ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, if (uri && file) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "inlcusion may be either virtual=\"%V\" or file=\"%V\"", + "inclusion may be either virtual=\"%V\" or file=\"%V\"", uri, file); return NGX_HTTP_SSI_ERROR; } @@ -2525,7 +2525,7 @@ ngx_http_ssi_if(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "evaluted left: \"%V\"", &left); + "evaluated left: \"%V\"", &left); if (p == last) { if (left.len) { @@ -2589,7 +2589,7 @@ ngx_http_ssi_if(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "evaluted right: \"%V\"", &right); + "evaluated right: \"%V\"", &right); if (noregex) { if (left.len != right.len) { diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 4bd85b8..278c9ab 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -948,6 +948,7 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, { size_t size; ngx_uint_t padded, priority, depend, dependency, excl, weight; + ngx_uint_t status; ngx_http_v2_node_t *node; ngx_http_v2_stream_t *stream; ngx_http_v2_srv_conf_t *h2scf; @@ -1040,15 +1041,8 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, "client sent HEADERS frame for stream %ui " "with incorrect dependency", h2c->state.sid); - if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, - NGX_HTTP_V2_PROTOCOL_ERROR) - != NGX_OK) - { - return ngx_http_v2_connection_error(h2c, - NGX_HTTP_V2_INTERNAL_ERROR); - } - - return ngx_http_v2_state_header_block(h2c, pos, end); + status = NGX_HTTP_V2_PROTOCOL_ERROR; + goto rst_stream; } h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, @@ -1060,15 +1054,18 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, "concurrent streams exceeded %ui", h2c->processing); - if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, - NGX_HTTP_V2_REFUSED_STREAM) - != NGX_OK) - { - return ngx_http_v2_connection_error(h2c, - NGX_HTTP_V2_INTERNAL_ERROR); - } + status = NGX_HTTP_V2_REFUSED_STREAM; + goto rst_stream; + } - return ngx_http_v2_state_header_block(h2c, pos, end); + if (!h2c->settings_ack && !(h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG)) + { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent stream with data " + "before settings were acknowledged"); + + status = NGX_HTTP_V2_REFUSED_STREAM; + goto rst_stream; } node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 1); @@ -1104,6 +1101,14 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, ngx_http_v2_set_dependency(h2c, node, depend, excl); } + return ngx_http_v2_state_header_block(h2c, pos, end); + +rst_stream: + + if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, status) != NGX_OK) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + } + return ngx_http_v2_state_header_block(h2c, pos, end); } @@ -1883,7 +1888,7 @@ ngx_http_v2_state_settings(ngx_http_v2_connection_t *h2c, u_char *pos, return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); } - /* TODO settings acknowledged */ + h2c->settings_ack = 1; return ngx_http_v2_state_complete(h2c, pos, end); } @@ -3409,6 +3414,7 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r, ngx_http_v2_stream_t *stream; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; + ngx_http_v2_connection_t *h2c; stream = r->stream; @@ -3468,6 +3474,7 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r, } if (rb->buf == NULL) { + stream->skip_data = 1; return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -3476,20 +3483,31 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r, return ngx_http_v2_process_request_body(r, NULL, 0, 1); } - if (r->request_body_no_buffering) { - stream->no_flow_control = 0; - stream->recv_window = (size_t) len; + if (len) { + if (r->request_body_no_buffering) { + stream->recv_window = (size_t) len; - } else { - stream->no_flow_control = 1; - stream->recv_window = NGX_HTTP_V2_MAX_WINDOW; - } + } else { + stream->no_flow_control = 1; + stream->recv_window = NGX_HTTP_V2_MAX_WINDOW; + } - if (ngx_http_v2_send_window_update(stream->connection, stream->node->id, - stream->recv_window) - == NGX_ERROR) - { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + if (ngx_http_v2_send_window_update(stream->connection, stream->node->id, + stream->recv_window) + == NGX_ERROR) + { + stream->skip_data = 1; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + h2c = stream->connection; + + if (!h2c->blocked) { + if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) { + stream->skip_data = 1; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + } } ngx_add_timer(r->connection->read, clcf->client_body_timeout); @@ -3859,11 +3877,33 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) } } else if (!stream->in_closed) { +#if 0 if (ngx_http_v2_send_rst_stream(h2c, node->id, NGX_HTTP_V2_NO_ERROR) != NGX_OK) { h2c->connection->error = 1; } +#else + /* + * At the time of writing at least the latest versions of Chrome + * do not properly handle RST_STREAM with NO_ERROR status. + * + * See: https://bugs.chromium.org/p/chromium/issues/detail?id=603182 + * + * As a workaround, the stream window is maximized before closing + * the stream. This allows a client to send up to 2 GB of data + * before getting blocked on flow control. + */ + + if (stream->recv_window < NGX_HTTP_V2_MAX_WINDOW + && ngx_http_v2_send_window_update(h2c, node->id, + NGX_HTTP_V2_MAX_WINDOW + - stream->recv_window) + != NGX_OK) + { + h2c->connection->error = 1; + } +#endif } } diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 7a77c27..1adf8de 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -141,6 +141,7 @@ struct ngx_http_v2_connection_s { ngx_uint_t last_sid; unsigned closed_nodes:8; + unsigned settings_ack:1; unsigned blocked:1; }; diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c index 9953782..d23508e 100644 --- a/src/os/unix/ngx_readv_chain.c +++ b/src/os/unix/ngx_readv_chain.c @@ -106,7 +106,27 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) do { n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts); - if (n >= 0) { + if (n == 0) { + rev->ready = 0; + rev->eof = 1; + +#if (NGX_HAVE_KQUEUE) + + /* + * on FreeBSD readv() may return 0 on closed socket + * even if kqueue reported about available data + */ + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + rev->available = 0; + } + +#endif + + return 0; + } + + if (n > 0) { #if (NGX_HAVE_KQUEUE) @@ -115,7 +135,7 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) /* * rev->available may be negative here because some additional - * bytes may be received between kevent() and recv() + * bytes may be received between kevent() and readv() */ if (rev->available <= 0) { @@ -123,42 +143,18 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) rev->ready = 0; } - if (rev->available < 0) { - rev->available = 0; - } - } - - if (n == 0) { - - /* - * on FreeBSD recv() may return 0 on closed socket - * even if kqueue reported about available data - */ - -#if 0 - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "readv() returned 0 while kevent() reported " - "%d available bytes", rev->available); -#endif - - rev->ready = 0; - rev->eof = 1; rev->available = 0; } return n; } -#endif /* NGX_HAVE_KQUEUE */ +#endif if (n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) { rev->ready = 0; } - if (n == 0) { - rev->eof = 1; - } - return n; } diff --git a/src/os/unix/ngx_recv.c b/src/os/unix/ngx_recv.c index fc7f76c..5013ae3 100644 --- a/src/os/unix/ngx_recv.c +++ b/src/os/unix/ngx_recv.c @@ -10,8 +10,6 @@ #include -#if (NGX_HAVE_KQUEUE) - ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) { @@ -21,6 +19,8 @@ ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) rev = c->read; +#if (NGX_HAVE_KQUEUE) + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "recv: eof:%d, avail:%d, err:%d", @@ -48,13 +48,38 @@ ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) } } +#endif + do { n = recv(c->fd, buf, size, 0); ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "recv: fd:%d %z of %uz", c->fd, n, size); - if (n >= 0) { + if (n == 0) { + rev->ready = 0; + rev->eof = 1; + +#if (NGX_HAVE_KQUEUE) + + /* + * on FreeBSD recv() may return 0 on closed socket + * even if kqueue reported about available data + */ + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + rev->available = 0; + } + +#endif + + return 0; + } + + if (n > 0) { + +#if (NGX_HAVE_KQUEUE) + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { rev->available -= n; @@ -68,85 +93,13 @@ ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) rev->ready = 0; } - if (rev->available < 0) { - rev->available = 0; - } - } - - if (n == 0) { - - /* - * on FreeBSD recv() may return 0 on closed socket - * even if kqueue reported about available data - */ - - rev->ready = 0; - rev->eof = 1; rev->available = 0; } return n; } - if ((size_t) n < size - && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) - { - rev->ready = 0; - } - - if (n == 0) { - rev->eof = 1; - } - - return n; - } - - err = ngx_socket_errno; - - if (err == NGX_EAGAIN || err == NGX_EINTR) { - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, - "recv() not ready"); - n = NGX_AGAIN; - - } else { - n = ngx_connection_error(c, err, "recv() failed"); - break; - } - - } while (err == NGX_EINTR); - - rev->ready = 0; - - if (n == NGX_ERROR) { - rev->error = 1; - } - - return n; -} - -#else /* ! NGX_HAVE_KQUEUE */ - -ssize_t -ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) -{ - ssize_t n; - ngx_err_t err; - ngx_event_t *rev; - - rev = c->read; - - do { - n = recv(c->fd, buf, size, 0); - - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "recv: fd:%d %z of %uz", c->fd, n, size); - - if (n == 0) { - rev->ready = 0; - rev->eof = 1; - return n; - - } else if (n > 0) { +#endif if ((size_t) n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) @@ -179,5 +132,3 @@ ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) return n; } - -#endif /* NGX_HAVE_KQUEUE */ diff --git a/src/os/unix/ngx_udp_recv.c b/src/os/unix/ngx_udp_recv.c index e03bf6c..6d544c2 100644 --- a/src/os/unix/ngx_udp_recv.c +++ b/src/os/unix/ngx_udp_recv.c @@ -10,8 +10,6 @@ #include -#if (NGX_HAVE_KQUEUE) - ssize_t ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) { @@ -28,6 +26,9 @@ ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) "recv: fd:%d %z of %uz", c->fd, n, size); if (n >= 0) { + +#if (NGX_HAVE_KQUEUE) + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { rev->available -= n; @@ -42,6 +43,8 @@ ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) } } +#endif + return n; } @@ -67,49 +70,3 @@ ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) return n; } - -#else /* ! NGX_HAVE_KQUEUE */ - -ssize_t -ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) -{ - ssize_t n; - ngx_err_t err; - ngx_event_t *rev; - - rev = c->read; - - do { - n = recv(c->fd, buf, size, 0); - - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "recv: fd:%d %z of %uz", c->fd, n, size); - - if (n >= 0) { - return n; - } - - err = ngx_socket_errno; - - if (err == NGX_EAGAIN || err == NGX_EINTR) { - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, - "recv() not ready"); - n = NGX_AGAIN; - - } else { - n = ngx_connection_error(c, err, "recv() failed"); - break; - } - - } while (err == NGX_EINTR); - - rev->ready = 0; - - if (n == NGX_ERROR) { - rev->error = 1; - } - - return n; -} - -#endif /* NGX_HAVE_KQUEUE */ From 6706bbedf8ee04027fda78f8ab0e86b4947a4242 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 29 Apr 2016 10:31:44 +0300 Subject: [PATCH 119/651] New upstream release --- debian/changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index 4d4885f..411e3cd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.10.0-1) UNRELEASED; urgency=medium + + [ Christos Trochalakis ] + * New upstream release (1.10.0) + + -- Christos Trochalakis Fri, 29 Apr 2016 10:31:21 +0300 + nginx (1.9.14-2) unstable; urgency=medium [ Christos Trochalakis ] From 00cd95bfc14c7ee8035623f85f6be4359f5d75b0 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 29 Apr 2016 10:31:53 +0300 Subject: [PATCH 120/651] Release 1.10.0-1 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 411e3cd..8e4cdbe 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,9 +1,9 @@ -nginx (1.10.0-1) UNRELEASED; urgency=medium +nginx (1.10.0-1) unstable; urgency=medium [ Christos Trochalakis ] * New upstream release (1.10.0) - -- Christos Trochalakis Fri, 29 Apr 2016 10:31:21 +0300 + -- Christos Trochalakis Fri, 29 Apr 2016 10:31:46 +0300 nginx (1.9.14-2) unstable; urgency=medium From 7ffd2fc6a928e8f981a8d7375870d408817fe4ef Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 31 May 2016 15:54:45 +0300 Subject: [PATCH 121/651] Generate dbgsym packages only if dh_strip supports it Makes backporting easier. --- debian/changelog | 3 +++ debian/rules | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 8e4cdbe..69fb1f9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,9 @@ nginx (1.10.0-1) unstable; urgency=medium [ Christos Trochalakis ] * New upstream release (1.10.0) + * debian/control: + + Generate dbgsym packages only if dh_strip supports it. + Thanks Faidon Liambotis for the hint. -- Christos Trochalakis Fri, 29 Apr 2016 10:31:46 +0300 diff --git a/debian/rules b/debian/rules index 63abd77..c21c307 100755 --- a/debian/rules +++ b/debian/rules @@ -148,7 +148,7 @@ strip.arch.%: dh_strip --package=nginx-$(*) --dbg-package=nginx-$(*)-dbg strip.mods.%: - dh_strip --package=libnginx-mod-$(*) --automatic-dbgsym + dh_strip --package=libnginx-mod-$(*) -O--automatic-dbgsym config.arch.%: dh_testdir From 1b192da67cc8ce82a2fcc1c9889030cedd4a0182 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 31 May 2016 21:55:00 +0300 Subject: [PATCH 122/651] Imported Upstream version 1.10.1 --- CHANGES | 7 +++++++ CHANGES.ru | 7 +++++++ src/core/nginx.h | 4 ++-- src/os/unix/ngx_files.c | 5 +++++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 408f952..4396472 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,11 @@ +Changes with nginx 1.10.1 31 May 2016 + + *) Security: a segmentation fault might occur in a worker process while + writing a specially crafted request body to a temporary file + (CVE-2016-4450); the bug had appeared in 1.3.9. + + Changes with nginx 1.10.0 26 Apr 2016 *) 1.10.x stable branch. diff --git a/CHANGES.ru b/CHANGES.ru index 4e6002e..c96cf93 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,11 @@ +Изменения в nginx 1.10.1 31.05.2016 + + *) Безопасность: при записи тела специально созданного запроса во + временный файл в рабочем процессе мог происходить segmentation fault + (CVE-2016-4450); ошибка появилась в 1.3.9. + + Изменения в nginx 1.10.0 26.04.2016 *) Стабильная ветка 1.10.x. diff --git a/src/core/nginx.h b/src/core/nginx.h index fe78745..e2b8005 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1010000 -#define NGINX_VERSION "1.10.0" +#define nginx_version 1010001 +#define NGINX_VERSION "1.10.1" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c index 65c79a2..7fbb7c9 100644 --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -356,6 +356,11 @@ ngx_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *cl) n = 0; for ( /* void */ ; cl; cl = cl->next) { + + if (ngx_buf_special(cl->buf)) { + continue; + } + size = cl->buf->last - cl->buf->pos; if (prev == cl->buf->pos) { From a1e2085dd78be871f4e226de667480a8c6e4e661 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 31 May 2016 22:00:26 +0300 Subject: [PATCH 123/651] Correctly add changelog entry to 1.10.0-2 --- debian/changelog | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 69fb1f9..451f3d1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,10 +1,16 @@ +nginx (1.10.0-2) UNRELEASED; urgency=medium + + [ Christos Trochalakis ] + * debian/control: + + Generate dbgsym packages only if dh_strip supports it. + Thanks Faidon Liambotis for the hint. + + -- Christos Trochalakis Tue, 31 May 2016 21:59:40 +0300 + nginx (1.10.0-1) unstable; urgency=medium [ Christos Trochalakis ] * New upstream release (1.10.0) - * debian/control: - + Generate dbgsym packages only if dh_strip supports it. - Thanks Faidon Liambotis for the hint. -- Christos Trochalakis Fri, 29 Apr 2016 10:31:46 +0300 From 52025f4a8e64ffe9485c0bf10f286c710a2af6d3 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 31 May 2016 22:01:40 +0300 Subject: [PATCH 124/651] Release 1.10.1-1 --- debian/changelog | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 451f3d1..d2f3264 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,11 +1,16 @@ -nginx (1.10.0-2) UNRELEASED; urgency=medium +nginx (1.10.1-1) unstable; urgency=medium [ Christos Trochalakis ] + * New upstream release (1.10.1) + Fixes CVE-2016-4450 + NULL pointer dereference while writing client request body. + (Closes: #825960) + * debian/control: + Generate dbgsym packages only if dh_strip supports it. Thanks Faidon Liambotis for the hint. - -- Christos Trochalakis Tue, 31 May 2016 21:59:40 +0300 + -- Christos Trochalakis Tue, 31 May 2016 22:01:25 +0300 nginx (1.10.0-1) unstable; urgency=medium From 6322b86a76ef2ec18d64b4c35bd3175981c16496 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 31 May 2016 22:55:48 +0300 Subject: [PATCH 125/651] Release 1.6.2-5+deb8u2 --- debian/changelog | 9 +++++ ...pecial-buffers-on-writing-ticket-981.patch | 39 +++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 49 insertions(+) create mode 100644 debian/patches/0009-Core-skip-special-buffers-on-writing-ticket-981.patch diff --git a/debian/changelog b/debian/changelog index f1aaee0..06ee64b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +nginx (1.6.2-5+deb8u2) jessie-security; urgency=high + + [ Christos Trochalakis ] + * Fixes CVE-2016-4450 + NULL pointer dereference while writing client request body. + (Closes: #825960) + + -- Christos Trochalakis Tue, 31 May 2016 22:55:34 +0300 + nginx (1.6.2-5+deb8u1) jessie-security; urgency=high [ Christos Trochalakis ] diff --git a/debian/patches/0009-Core-skip-special-buffers-on-writing-ticket-981.patch b/debian/patches/0009-Core-skip-special-buffers-on-writing-ticket-981.patch new file mode 100644 index 0000000..149dab0 --- /dev/null +++ b/debian/patches/0009-Core-skip-special-buffers-on-writing-ticket-981.patch @@ -0,0 +1,39 @@ +From: Maxim Dounin +Date: Tue, 31 May 2016 05:13:30 +0300 +Subject: Core: skip special buffers on writing (ticket #981). + +A special last buffer with cl->buf->pos set to NULL can be present in +a chain when writing request body if chunked encoding was used. This +resulted in a NULL pointer dereference if it happened to be the only +buffer left after a do...while loop iteration in ngx_write_chain_to_file(). + +The problem originally appeared in nginx 1.3.9 with chunked encoding +support. Additionally, rev. 3832b608dc8d (nginx 1.9.13) changed the +minimum number of buffers to trigger this from IOV_MAX (typically 1024) +to NGX_IOVS_PREALLOCATE (typically 64). + +Fix is to skip such buffers in ngx_chain_to_iovec(), much like it is +done in other places. + +Backported by 1.11.1 for debian. +--- + src/os/unix/ngx_files.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c +index c3ae47f..1970184 100644 +--- a/src/os/unix/ngx_files.c ++++ b/src/os/unix/ngx_files.c +@@ -183,6 +183,12 @@ ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, + /* create the iovec and coalesce the neighbouring bufs */ + + while (cl && vec.nelts < IOV_MAX) { ++ ++ if (ngx_buf_special(cl->buf)) { ++ cl = cl->next; ++ continue; ++ } ++ + if (prev == cl->buf->pos) { + iov->iov_len += cl->buf->last - cl->buf->pos; + diff --git a/debian/patches/series b/debian/patches/series index 93af595..f204855 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -5,3 +5,4 @@ perl-use-dpkg-buildflags.patch 0006-Resolver-changed-the-ngx_resolver_create_-_query-arg.patch 0007-Resolver-fixed-use-after-free-memory-accesses-with-C.patch 0008-Resolver-limited-CNAME-recursion.patch +0009-Core-skip-special-buffers-on-writing-ticket-981.patch From 60cdfb206953b55792c1303420d664c072fcfff2 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 7 Jun 2016 10:46:33 +0300 Subject: [PATCH 126/651] Only build against liblua5.1-0-dev when libluajit is not available --- debian/changelog | 9 +++++++++ debian/control | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index d2f3264..bad7a82 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +nginx (1.10.1-2) UNRELEASED; urgency=medium + + [ Christos Trochalakis ] + * debian/control: + Don't allow building against liblua5.1-0-dev on architectures + that libluajit is available. + + -- Christos Trochalakis Tue, 07 Jun 2016 10:47:36 +0300 + nginx (1.10.1-1) unstable; urgency=medium [ Christos Trochalakis ] diff --git a/debian/control b/debian/control index 52baf37..0c7f2cb 100644 --- a/debian/control +++ b/debian/control @@ -15,7 +15,8 @@ Build-Depends: autotools-dev, libexpat-dev, libgd-dev, libgeoip-dev, - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 armel armhf powerpc powerpcspe mips mipsel] | liblua5.1-0-dev, + libluajit-5.1-dev [i386 amd64 kfreebsd-i386 armel armhf powerpc powerpcspe mips mipsel], + liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !armel !armhf !powerpc !powerpcspe !mips !mipsel], libmhash-dev, libpam0g-dev, libpcre3-dev, From b2867579bbbe1dc64a6c1eb9930f8cfca85b49d8 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 7 Jun 2016 11:26:43 +0300 Subject: [PATCH 127/651] Release 1.6.2-5+deb8u2~bpo70+1 --- debian/changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index 06ee64b..2209d99 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.6.2-5+deb8u2~bpo70+1) wheezy-backports; urgency=high + + [ Christos Trochalakis ] + * Rebuild for wheezy-backports. + + -- Christos Trochalakis Tue, 07 Jun 2016 11:18:23 +0300 + nginx (1.6.2-5+deb8u2) jessie-security; urgency=high [ Christos Trochalakis ] From 15695dee6eafdc463f3b8d7844ec6241e2919864 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 7 Jul 2016 11:25:23 +0300 Subject: [PATCH 128/651] Re-enable experimental flow for 1.11.x --- debian/README.Packaging | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/debian/README.Packaging b/debian/README.Packaging index 61358da..bbb7875 100644 --- a/debian/README.Packaging +++ b/debian/README.Packaging @@ -25,15 +25,10 @@ split each module to a separate source. [0] https://www.nginx.com/blog/dynamic-modules-nginx-1-9-11/ -Workflow for Experimental (not-active) -====================================== +Workflow for Experimental +========================= -Now that nginx 1.6.0 is released there is no plan to package mainline 1.7 -releases to experimental. The following guide is been kept as a reference. - --------- - -Nginx mainline releases (1.5.x series) are been packaged for experimental, +Nginx mainline releases (1.11.x series) are been packaged for experimental, as they lack security support. The workflow we use is based on the assumption that packaging work happens on @@ -41,7 +36,7 @@ origin/master and experimental builds are a trivial patch away from that. The direct consequense of treating experimental as a patchset for origin/master is that the relevant branches are forced-pushed whenever we release a new -1.5.x version. In other words, **it is not safe to base your work on the +1.11.x version. In other words, **it is not safe to base your work on the experimental branch**. This is a brief description of our experimental branches and how we are using @@ -50,27 +45,27 @@ them. * experimental-base Force-pushed when origin/master changes. - experimental-base tracks the changes needed for building the 1.5.x branch, - such as new configure parameters, etc. On new 1.5.x releases, it is rebased + experimental-base tracks the changes needed for building the 1.11.x branch, + such as new configure parameters, etc. On new 1.11.x releases, it is rebased on origin/master so it is always up-to-date with our latest packaging work. * experimental - Force-pushed on every 1.5.x release. + Force-pushed on every 1.11.x release. - This branch points to the latest 1.5.x release. + This branch points to the latest 1.11.x release. Before release this branch is reset to experimental-base, and then merged - with the new upstream-1.5 branch. Finally all the release specific changes + with the new upstream-1.11 branch. Finally all the release specific changes are commited (changelog entry etc) and the build is made. -* upstream-1.5 - Force-pushed on every 1.5.x release. +* upstream-1.11 + Force-pushed on every 1.11.x release. - Before a new 1.5.x release the branch is reset to origin/upstream. - This is a technicallity so we can avoid resolving conflicts when a new 1.4.x + Before a new 1.11.x release the branch is reset to origin/upstream. + This is a technicallity so we can avoid resolving conflicts when a new 1.10.x release happens between two experimental releases. -Older 1.5.x releases are not referenced by any branch, but they can be found by -the relevant debian/* tag. +Older 1.11.x releases are not referenced by any branch, but they can be found +by the relevant debian/* tag. 3rd party experimental workflow =============================== From a4f9f837e7b2bf4fba78462df3e226e03e88b4ac Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Sat, 16 Jul 2016 17:30:40 -0700 Subject: [PATCH 129/651] Implemented patch in bug 826061. --- debian/changelog | 7 +++++- ...ource-on-other-glibc-based-platforms.patch | 23 +++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch diff --git a/debian/changelog b/debian/changelog index bad7a82..f2a7ab6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -5,7 +5,12 @@ nginx (1.10.1-2) UNRELEASED; urgency=medium Don't allow building against liblua5.1-0-dev on architectures that libluajit is available. - -- Christos Trochalakis Tue, 07 Jun 2016 10:47:36 +0300 + [ Michael Lustfield ] + * debian/patches/0003-*.patch: + + Use _GNU_SOURCE on GNU/kFreeBSD (Closes: #826061) + Thanks Steven Chamberlain for the patch. + + -- Michael Lustfield Sat, 16 Jul 2016 17:24:40 -0700 nginx (1.10.1-1) unstable; urgency=medium diff --git a/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch b/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch new file mode 100644 index 0000000..bb9b089 --- /dev/null +++ b/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch @@ -0,0 +1,23 @@ +Date: Sat, 16 Jul 2016 23:52:50 +0100 +From: Steven Chamberlain +Subject: Use _GNU_SOURCE on GNU/kFreeBSD + +Define _GNU_SOURCE not only on GNU/Hurd, but also other glibc-based +platforms including GNU/kFreeBSD. +--- a/src/os/unix/ngx_posix_config.h ++++ b/src/os/unix/ngx_posix_config.h +@@ -21,10 +21,13 @@ + #endif + + +-#if (NGX_GNU_HURD) ++#if defined(__GLIBC__) + #ifndef _GNU_SOURCE + #define _GNU_SOURCE /* accept4() */ + #endif ++#endif ++ ++#if (NGX_GNU_HURD) + #define _FILE_OFFSET_BITS 64 + #endif + diff --git a/debian/patches/series b/debian/patches/series index 04b971f..f3ccceb 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1,3 @@ perl-use-dpkg-buildflags.patch 0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch +0003-define_gnu_source-on-other-glibc-based-platforms.patch From 1b3fa883bbc71ab8fe1ddf0199f60850726a3957 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Sat, 16 Jul 2016 19:14:08 -0700 Subject: [PATCH 130/651] Make nginx-*.postinst use invoke-rc.d. --- debian/changelog | 5 ++++- debian/nginx-extras.postinst | 15 +-------------- debian/nginx-full.postinst | 15 +-------------- debian/nginx-light.postinst | 15 +-------------- 4 files changed, 7 insertions(+), 43 deletions(-) diff --git a/debian/changelog b/debian/changelog index f2a7ab6..52c4dcf 100644 --- a/debian/changelog +++ b/debian/changelog @@ -7,8 +7,11 @@ nginx (1.10.1-2) UNRELEASED; urgency=medium [ Michael Lustfield ] * debian/patches/0003-*.patch: - + Use _GNU_SOURCE on GNU/kFreeBSD (Closes: #826061) + + Use _GNU_SOURCE on GNU/kFreeBSD. (Closes: #826061) Thanks Steven Chamberlain for the patch. + * debian/nginx-*.postinst: + + Make nginx-*.postinst use invoke-rc.d. (Closes: #823435) + Thanks Simon Deziel for the patch. -- Michael Lustfield Sat, 16 Jul 2016 17:24:40 -0700 diff --git a/debian/nginx-extras.postinst b/debian/nginx-extras.postinst index bd9c818..4ea6d9d 100644 --- a/debian/nginx-extras.postinst +++ b/debian/nginx-extras.postinst @@ -13,20 +13,7 @@ esac if [ -x /etc/init.d/nginx ]; then if [ -f /run/nginx.pid ] && pidof /usr/sbin/nginx >/dev/null; then - NGX_PID=`cat /run/nginx.pid` - if kill -s USR2 $NGX_PID 2>/dev/null; then - while [ ! -s /run/nginx.pid.oldbin ] || [ ! -s /run/nginx.pid ]; do - cnt=`expr $cnt + 1` - if [ $cnt -gt 10 ]; then - kill -s KILL $NGX_PID - invoke-rc.d nginx start - exit 0 - fi - sleep 1 - done - NGX_OLD_PID=`cat /run/nginx.pid.oldbin` - kill -s QUIT $NGX_OLD_PID - fi + invoke-rc.d nginx upgrade || exit $? else invoke-rc.d nginx start || exit $? fi diff --git a/debian/nginx-full.postinst b/debian/nginx-full.postinst index bd9c818..4ea6d9d 100644 --- a/debian/nginx-full.postinst +++ b/debian/nginx-full.postinst @@ -13,20 +13,7 @@ esac if [ -x /etc/init.d/nginx ]; then if [ -f /run/nginx.pid ] && pidof /usr/sbin/nginx >/dev/null; then - NGX_PID=`cat /run/nginx.pid` - if kill -s USR2 $NGX_PID 2>/dev/null; then - while [ ! -s /run/nginx.pid.oldbin ] || [ ! -s /run/nginx.pid ]; do - cnt=`expr $cnt + 1` - if [ $cnt -gt 10 ]; then - kill -s KILL $NGX_PID - invoke-rc.d nginx start - exit 0 - fi - sleep 1 - done - NGX_OLD_PID=`cat /run/nginx.pid.oldbin` - kill -s QUIT $NGX_OLD_PID - fi + invoke-rc.d nginx upgrade || exit $? else invoke-rc.d nginx start || exit $? fi diff --git a/debian/nginx-light.postinst b/debian/nginx-light.postinst index bd9c818..4ea6d9d 100644 --- a/debian/nginx-light.postinst +++ b/debian/nginx-light.postinst @@ -13,20 +13,7 @@ esac if [ -x /etc/init.d/nginx ]; then if [ -f /run/nginx.pid ] && pidof /usr/sbin/nginx >/dev/null; then - NGX_PID=`cat /run/nginx.pid` - if kill -s USR2 $NGX_PID 2>/dev/null; then - while [ ! -s /run/nginx.pid.oldbin ] || [ ! -s /run/nginx.pid ]; do - cnt=`expr $cnt + 1` - if [ $cnt -gt 10 ]; then - kill -s KILL $NGX_PID - invoke-rc.d nginx start - exit 0 - fi - sleep 1 - done - NGX_OLD_PID=`cat /run/nginx.pid.oldbin` - kill -s QUIT $NGX_OLD_PID - fi + invoke-rc.d nginx upgrade || exit $? else invoke-rc.d nginx start || exit $? fi From 1445c1403ca7cc0eb3030cb74525f2bbc4b8e9f8 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 29 Jul 2016 16:16:43 +0300 Subject: [PATCH 131/651] *.postinst: Make sure we restart nginx if on-the-fly upgrade fails Complements Mike's 1b3fa883. --- debian/nginx-extras.postinst | 3 ++- debian/nginx-full.postinst | 3 ++- debian/nginx-light.postinst | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/debian/nginx-extras.postinst b/debian/nginx-extras.postinst index 4ea6d9d..9c2605d 100644 --- a/debian/nginx-extras.postinst +++ b/debian/nginx-extras.postinst @@ -13,7 +13,8 @@ esac if [ -x /etc/init.d/nginx ]; then if [ -f /run/nginx.pid ] && pidof /usr/sbin/nginx >/dev/null; then - invoke-rc.d nginx upgrade || exit $? + invoke-rc.d nginx upgrade || invoke-rc.d nginx restart + exit $? else invoke-rc.d nginx start || exit $? fi diff --git a/debian/nginx-full.postinst b/debian/nginx-full.postinst index 4ea6d9d..9c2605d 100644 --- a/debian/nginx-full.postinst +++ b/debian/nginx-full.postinst @@ -13,7 +13,8 @@ esac if [ -x /etc/init.d/nginx ]; then if [ -f /run/nginx.pid ] && pidof /usr/sbin/nginx >/dev/null; then - invoke-rc.d nginx upgrade || exit $? + invoke-rc.d nginx upgrade || invoke-rc.d nginx restart + exit $? else invoke-rc.d nginx start || exit $? fi diff --git a/debian/nginx-light.postinst b/debian/nginx-light.postinst index 4ea6d9d..9c2605d 100644 --- a/debian/nginx-light.postinst +++ b/debian/nginx-light.postinst @@ -13,7 +13,8 @@ esac if [ -x /etc/init.d/nginx ]; then if [ -f /run/nginx.pid ] && pidof /usr/sbin/nginx >/dev/null; then - invoke-rc.d nginx upgrade || exit $? + invoke-rc.d nginx upgrade || invoke-rc.d nginx restart + exit $? else invoke-rc.d nginx start || exit $? fi From 0f2905a7e013b0604e77c5640d10203476012ef9 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 29 Jul 2016 16:31:20 +0300 Subject: [PATCH 132/651] mod: Upgrade nginx-lua to v0.10.5 --- debian/changelog | 2 + debian/modules/README.Modules-versions | 2 +- debian/modules/nginx-lua/README.markdown | 17 +- debian/modules/nginx-lua/config | 47 +++++ .../modules/nginx-lua/doc/HttpLuaModule.wiki | 17 +- .../nginx-lua/dtrace/ngx_lua_provider.d | 24 +-- .../nginx-lua/src/api/ngx_http_lua_api.h | 2 +- .../nginx-lua/src/ngx_http_lua_balancer.c | 6 +- .../nginx-lua/src/ngx_http_lua_common.h | 5 +- .../nginx-lua/src/ngx_http_lua_control.c | 5 +- .../nginx-lua/src/ngx_http_lua_directive.c | 23 +-- .../nginx-lua/src/ngx_http_lua_initworkerby.c | 25 ++- .../modules/nginx-lua/src/ngx_http_lua_misc.c | 8 + .../nginx-lua/src/ngx_http_lua_module.c | 69 +++++-- .../nginx-lua/src/ngx_http_lua_output.c | 14 +- .../nginx-lua/src/ngx_http_lua_regex.c | 42 +++-- .../nginx-lua/src/ngx_http_lua_req_body.c | 35 +++- .../nginx-lua/src/ngx_http_lua_semaphore.c | 173 ++++++++++-------- .../nginx-lua/src/ngx_http_lua_semaphore.h | 18 +- .../nginx-lua/src/ngx_http_lua_socket_tcp.c | 4 +- .../nginx-lua/src/ngx_http_lua_ssl_certby.c | 13 ++ .../nginx-lua/src/ngx_http_lua_ssl_ocsp.c | 6 + .../nginx-lua/src/ngx_http_lua_timer.c | 1 - .../modules/nginx-lua/src/ngx_http_lua_util.c | 10 +- .../nginx-lua/src/ngx_http_lua_variable.c | 3 +- .../nginx-lua/src/ngx_http_lua_worker.c | 13 ++ debian/modules/nginx-lua/t/015-status.t | 23 ++- debian/modules/nginx-lua/t/024-access/mixed.t | 14 ++ debian/modules/nginx-lua/t/034-match.t | 23 ++- debian/modules/nginx-lua/t/043-shdict.t | 2 +- debian/modules/nginx-lua/t/044-req-body.t | 108 +++++++++++ debian/modules/nginx-lua/t/058-tcp-socket.t | 4 +- debian/modules/nginx-lua/t/087-udp-socket.t | 4 +- debian/modules/nginx-lua/t/129-ssl-socket.t | 36 +++- debian/modules/nginx-lua/t/132-lua-blocks.t | 35 +++- debian/modules/nginx-lua/t/135-worker-id.t | 66 ++++++- debian/modules/nginx-lua/t/139-ssl-cert-by.t | 95 ++++++++++ debian/modules/nginx-lua/t/140-ssl-c-api.t | 138 +++++++++++++- debian/modules/nginx-lua/t/141-luajit.t | 47 +++++ .../t/data/fake-module/ngx_http_fake_module.c | 2 - debian/modules/nginx-lua/util/build.sh | 2 +- 41 files changed, 961 insertions(+), 222 deletions(-) create mode 100644 debian/modules/nginx-lua/t/141-luajit.t diff --git a/debian/changelog b/debian/changelog index 52c4dcf..a0528da 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,8 @@ nginx (1.10.1-2) UNRELEASED; urgency=medium * debian/control: Don't allow building against liblua5.1-0-dev on architectures that libluajit is available. + * debian/modules/nginx-lua: + + Update nginx-lua to v0.10.5 [ Michael Lustfield ] * debian/patches/0003-*.patch: diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index d7f35a4..b71b1e0 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -22,7 +22,7 @@ README for Modules versions nginx-lua Homepage: https://github.com/openresty/lua-nginx-module - Version: v0.10.2 + Version: v0.10.5 nginx-upstream-fair Homepage: https://github.com/gnosek/nginx-upstream-fair diff --git a/debian/modules/nginx-lua/README.markdown b/debian/modules/nginx-lua/README.markdown index 4e8f9bd..14e9ecc 100644 --- a/debian/modules/nginx-lua/README.markdown +++ b/debian/modules/nginx-lua/README.markdown @@ -62,7 +62,7 @@ Production ready. Version ======= -This document describes ngx_lua [v0.10.2](https://github.com/openresty/lua-nginx-module/tags) released on 8 March 2016. +This document describes ngx_lua [v0.10.5](https://github.com/openresty/lua-nginx-module/tags) released on 25 May 2016. Synopsis ======== @@ -249,7 +249,7 @@ Nginx Compatibility The latest version of this module is compatible with the following versions of Nginx: -* 1.9.x (last tested: 1.9.7) +* 1.9.x (last tested: 1.9.15) * 1.8.x * 1.7.x (last tested: 1.7.10) * 1.6.x @@ -274,9 +274,9 @@ Build the source with this module: ```bash - wget 'http://nginx.org/download/nginx-1.9.7.tar.gz' - tar -xzvf nginx-1.9.7.tar.gz - cd nginx-1.9.7/ + wget 'http://nginx.org/download/nginx-1.9.15.tar.gz' + tar -xzvf nginx-1.9.15.tar.gz + cd nginx-1.9.15/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib @@ -926,7 +926,7 @@ filtering chain determines the final output, for example. The correct adding ord * memcached: listening on the default port, 11211. * redis: listening on the default port, 6379. -See also the [developer build script](https://github.com/openresty/lua-nginx-module/blob/master/util/build2.sh) for more details on setting up the testing environment. +See also the [developer build script](https://github.com/openresty/lua-nginx-module/blob/master/util/build.sh) for more details on setting up the testing environment. To run the whole test suite in the default testing mode: @@ -1060,6 +1060,11 @@ Directives * [lua_max_running_timers](#lua_max_running_timers) +The basic building blocks of scripting Nginx with Lua are directives. Directives are used to specify when the user Lua code is run and +how the result will be used. Below is a diagram showing the order in which directives are executed. + +![Lua Nginx Modules Directives](https://cloud.githubusercontent.com/assets/2137369/15272097/77d1c09e-1a37-11e6-97ef-d9767035fc3e.png) + [Back to TOC](#table-of-contents) lua_use_default_type diff --git a/debian/modules/nginx-lua/config b/debian/modules/nginx-lua/config index 3c2548b..c91a07e 100644 --- a/debian/modules/nginx-lua/config +++ b/debian/modules/nginx-lua/config @@ -466,6 +466,53 @@ ngx_feature_test='setsockopt(1, SOL_SOCKET, SO_PASSCRED, NULL, 0);' . auto/feature +ngx_feature="mmap(sbrk(0))" +ngx_feature_libs= +ngx_feature_name="NGX_HTTP_LUA_HAVE_MMAP_SBRK" +ngx_feature_run=yes +ngx_feature_incs="#include +#include +#include +#include +#define align_ptr(p, a) \ + (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1)) +" +ngx_feature_test=" +#if defined(__x86_64__) +exit(mmap(align_ptr(sbrk(0), getpagesize()), 1, PROT_READ, + MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0) < (void *) 0x40000000LL + ? 0 : 1); +#else +exit(1); +#endif +" +SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" +CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS" + +. auto/feature + +CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" + +ngx_feature="__attribute__(constructor)" +ngx_feature_libs= +ngx_feature_name="NGX_HTTP_LUA_HAVE_CONSTRUCTOR" +ngx_feature_run=yes +ngx_feature_incs="#include +int a = 2; +__attribute__((constructor)) +static void foo(void) +{ + a = 0; +} +" +ngx_feature_test="exit(a);" +SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" +CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS" + +. auto/feature + +CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" + if test -n "$ngx_module_link"; then ngx_module_type=HTTP_AUX_FILTER ngx_module_name=$ngx_addon_name diff --git a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki index f6824ef..78ce13c 100644 --- a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.2] released on 8 March 2016. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.5] released on 25 May 2016. = Synopsis = @@ -186,7 +186,7 @@ The Lua state (Lua VM instance) is shared across all the requests handled by a s The latest version of this module is compatible with the following versions of Nginx: -* 1.9.x (last tested: 1.9.7) +* 1.9.x (last tested: 1.9.15) * 1.8.x * 1.7.x (last tested: 1.7.10) * 1.6.x @@ -207,9 +207,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.9.7.tar.gz' - tar -xzvf nginx-1.9.7.tar.gz - cd nginx-1.9.7/ + wget 'http://nginx.org/download/nginx-1.9.15.tar.gz' + tar -xzvf nginx-1.9.15.tar.gz + cd nginx-1.9.15/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib @@ -754,7 +754,7 @@ filtering chain determines the final output, for example. The correct adding ord ** memcached: listening on the default port, 11211. ** redis: listening on the default port, 6379. -See also the [https://github.com/openresty/lua-nginx-module/blob/master/util/build2.sh developer build script] for more details on setting up the testing environment. +See also the [https://github.com/openresty/lua-nginx-module/blob/master/util/build.sh developer build script] for more details on setting up the testing environment. To run the whole test suite in the default testing mode: @@ -820,6 +820,11 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +The basic building blocks of scripting Nginx with Lua are directives. Directives are used to specify when the user Lua code is run and +how the result will be used. Below is a diagram showing the order in which directives are executed. + +![Lua Nginx Modules Directives](https://cloud.githubusercontent.com/assets/2137369/15272097/77d1c09e-1a37-11e6-97ef-d9767035fc3e.png) + == lua_use_default_type == '''syntax:''' ''lua_use_default_type on | off'' diff --git a/debian/modules/nginx-lua/dtrace/ngx_lua_provider.d b/debian/modules/nginx-lua/dtrace/ngx_lua_provider.d index 3767f9b..394484c 100644 --- a/debian/modules/nginx-lua/dtrace/ngx_lua_provider.d +++ b/debian/modules/nginx-lua/dtrace/ngx_lua_provider.d @@ -4,48 +4,48 @@ provider nginx_lua { /* lua_State *L */ probe http__lua__register__preload__package(void *L, u_char *pkg); - probe http__lua__req__socket__consume__preread(ngx_http_request_t *r, + probe http__lua__req__socket__consume__preread(void *r, u_char *data, size_t len); /* lua_State *parent, lua_State *child */ - probe http__lua__user__coroutine__create(ngx_http_request_t *r, + probe http__lua__user__coroutine__create(void *r, void *parent, void *child); /* lua_State *parent, lua_State *child */ - probe http__lua__user__coroutine__resume(ngx_http_request_t *r, + probe http__lua__user__coroutine__resume(void *r, void *parent, void *child); /* lua_State *parent, lua_State *child */ - probe http__lua__user__coroutine__yield(ngx_http_request_t *r, + probe http__lua__user__coroutine__yield(void *r, void *parent, void *child); /* lua_State *L */ - probe http__lua__thread__yield(ngx_http_request_t *r, void *L); + probe http__lua__thread__yield(void *r, void *L); /* ngx_http_lua_socket_tcp_upstream_t *u */ - probe http__lua__socket__tcp__send__start(ngx_http_request_t *r, + probe http__lua__socket__tcp__send__start(void *r, void *u, u_char *data, size_t len); /* ngx_http_lua_socket_tcp_upstream_t *u */ - probe http__lua__socket__tcp__receive__done(ngx_http_request_t *r, + probe http__lua__socket__tcp__receive__done(void *r, void *u, u_char *data, size_t len); /* ngx_http_lua_socket_tcp_upstream_t *u */ probe http__lua__socket__tcp__setkeepalive__buf__unread( - ngx_http_request_t *r, void *u, u_char *data, size_t len); + void *r, void *u, u_char *data, size_t len); /* lua_State *creator, lua_State *newthread */ - probe http__lua__user__thread__spawn(ngx_http_request_t *r, + probe http__lua__user__thread__spawn(void *r, void *creator, void *newthread); /* lua_State *thread, ngx_http_lua_ctx_t *ctx */ - probe http__lua__thread__delete(ngx_http_request_t *r, void *thread, void *ctx); + probe http__lua__thread__delete(void *r, void *thread, void *ctx); /* lua_State *thread */ - probe http__lua__run__posted__thread(ngx_http_request_t *r, void *thread, + probe http__lua__run__posted__thread(void *r, void *thread, int status); - probe http__lua__coroutine__done(ngx_http_request_t *r, void *co, + probe http__lua__coroutine__done(void *r, void *co, int success); /* lua_State *parent, lua_State *child */ diff --git a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h index a15d40e..4bac0f6 100644 --- a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10001 +#define ngx_http_lua_version 10005 typedef struct { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c b/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c index a2c66be..5fa289b 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c @@ -29,7 +29,7 @@ struct ngx_http_lua_balancer_peer_data_s { struct sockaddr *sockaddr; socklen_t socklen; - ngx_str_t host; + ngx_str_t *host; in_port_t port; int last_peer_state; @@ -322,9 +322,9 @@ ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) if (bp->sockaddr && bp->socklen) { pc->sockaddr = bp->sockaddr; pc->socklen = bp->socklen; - pc->name = &bp->host; pc->cached = 0; pc->connection = NULL; + pc->name = bp->host; bp->rrp.peers->single = 0; @@ -525,7 +525,7 @@ ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r, if (url.addrs && url.addrs[0].sockaddr) { bp->sockaddr = url.addrs[0].sockaddr; bp->socklen = url.addrs[0].socklen; - bp->host = url.addrs[0].name; + bp->host = &url.addrs[0].name; } else { *err = "no host allowed"; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_common.h b/debian/modules/nginx-lua/src/ngx_http_lua_common.h index e7b9969..758c42a 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_common.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_common.h @@ -123,7 +123,7 @@ typedef struct ngx_http_lua_balancer_peer_data_s ngx_http_lua_balancer_peer_data_t; -typedef struct ngx_http_lua_semaphore_mm_s ngx_http_lua_semaphore_mm_t; +typedef struct ngx_http_lua_sema_mm_s ngx_http_lua_sema_mm_t; typedef ngx_int_t (*ngx_http_lua_main_conf_handler_pt)(ngx_log_t *log, @@ -182,7 +182,7 @@ struct ngx_http_lua_main_conf_s { ngx_uint_t shm_zones_inited; - ngx_http_lua_semaphore_mm_t *semaphore_mm; + ngx_http_lua_sema_mm_t *sema_mm; unsigned requires_header_filter:1; unsigned requires_body_filter:1; @@ -502,6 +502,7 @@ typedef struct ngx_http_lua_ctx_s { socket */ unsigned acquired_raw_req_socket:1; /* whether a raw req socket is acquired */ + unsigned seen_body_data:1; } ngx_http_lua_ctx_t; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_control.c b/debian/modules/nginx-lua/src/ngx_http_lua_control.c index 0e1dd47..4c5f65e 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_control.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_control.c @@ -459,6 +459,7 @@ ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, u_char *err, | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER | NGX_HTTP_LUA_CONTEXT_HEADER_FILTER + | NGX_HTTP_LUA_CONTEXT_BALANCER | NGX_HTTP_LUA_CONTEXT_SSL_CERT, err, errlen) != NGX_OK) @@ -519,7 +520,9 @@ ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, u_char *err, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua exit with code %i", ctx->exit_code); - if (ctx->context & NGX_HTTP_LUA_CONTEXT_HEADER_FILTER) { + if (ctx->context & (NGX_HTTP_LUA_CONTEXT_HEADER_FILTER + | NGX_HTTP_LUA_CONTEXT_BALANCER)) + { return NGX_DONE; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c b/debian/modules/nginx-lua/src/ngx_http_lua_directive.c index 7ac8c28..e6bc339 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_directive.c @@ -1417,20 +1417,8 @@ ngx_http_lua_conf_lua_block_parse(ngx_conf_t *cf, ngx_command_t *cmd) break; case FOUND_LBRACKET_STR: - - break; - case FOUND_LBRACKET_CMT: - - break; - case FOUND_RIGHT_LBRACKET: - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "unexpected lua closing long-bracket"); - goto failed; - - break; - case FOUND_COMMENT_LINE: case FOUND_DOUBLE_QUOTED: case FOUND_SINGLE_QUOTED: @@ -1492,7 +1480,10 @@ ngx_http_lua_conf_read_lua_token(ngx_conf_t *cf, for ( ;; ) { - if (b->pos >= b->last) { + if (b->pos >= b->last + || (b->last - b->pos < (b->end - b->start) / 3 + && cf->conf_file->file.offset < file_size)) + { if (cf->conf_file->file.offset >= file_size) { @@ -1505,7 +1496,7 @@ ngx_http_lua_conf_read_lua_token(ngx_conf_t *cf, return NGX_ERROR; } - len = b->pos - start; + len = b->last - start; if (len == buf_size) { @@ -1543,8 +1534,8 @@ ngx_http_lua_conf_read_lua_token(ngx_conf_t *cf, return NGX_ERROR; } - b->pos = b->start + len; - b->last = b->pos + n; + b->pos = b->start + (b->pos - start); + b->last = b->start + len + n; start = b->start; #if nginx_version >= 1009002 diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c b/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c index 8a374c2..6754b4b 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c @@ -34,7 +34,7 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) ngx_http_request_t *r = NULL; ngx_http_lua_ctx_t *ctx; ngx_http_conf_ctx_t *conf_ctx, http_ctx; - ngx_http_lua_loc_conf_t *llcf, *top_llcf; + ngx_http_lua_loc_conf_t *top_llcf; ngx_http_lua_main_conf_t *lmcf; ngx_http_core_loc_conf_t *clcf, *top_clcf; @@ -198,9 +198,17 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) http_ctx.loc_conf[modules[i]->ctx_index] = cur; if (module->merge_loc_conf) { - prev = module->create_loc_conf(&conf); - if (prev == NULL) { - return NGX_ERROR; + if (modules[i] == &ngx_http_lua_module) { + prev = top_llcf; + + } else if (modules[i] == &ngx_http_core_module) { + prev = top_clcf; + + } else { + prev = module->create_loc_conf(&conf); + if (prev == NULL) { + return NGX_ERROR; + } } rv = module->merge_loc_conf(&conf, prev, cur); @@ -254,10 +262,6 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) #endif - if (top_clcf->resolver) { - clcf->resolver = top_clcf->resolver; - } - ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { goto failed; @@ -267,11 +271,6 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) ctx->cur_co_ctx = NULL; r->read_event_handler = ngx_http_block_reading; - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - if (top_llcf->log_socket_errors != NGX_CONF_UNSET) { - llcf->log_socket_errors = top_llcf->log_socket_errors; - } - ngx_http_lua_set_req(lmcf->lua, r); (void) lmcf->init_worker_handler(cycle->log, lmcf, lmcf->lua); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_misc.c b/debian/modules/nginx-lua/src/ngx_http_lua_misc.c index e3c7ec7..f96e2f2 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_misc.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_misc.c @@ -160,6 +160,10 @@ ngx_http_lua_ngx_set(lua_State *L) return 0; } + if (r->err_status) { + r->err_status = 0; + } + ngx_http_lua_check_fake_request(L, r); /* get the value */ @@ -235,6 +239,10 @@ ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int status) r->headers_out.status = status; + if (r->err_status) { + r->err_status = 0; + } + if (status == 101) { /* * XXX work-around a bug in the Nginx core older than 1.5.5 diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_module.c b/debian/modules/nginx-lua/src/ngx_http_lua_module.c index 11eb653..867661c 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_module.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_module.c @@ -43,6 +43,14 @@ static char *ngx_http_lua_lowat_check(ngx_conf_t *cf, void *post, void *data); static ngx_int_t ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf); #endif +#if (NGX_HTTP_LUA_HAVE_MMAP_SBRK) && (NGX_LINUX) +/* we cannot use "static" for this function since it may lead to compiler + * warnings */ +void ngx_http_lua_limit_data_segment(void); +# if !(NGX_HTTP_LUA_HAVE_CONSTRUCTOR) +static ngx_int_t ngx_http_lua_pre_config(ngx_conf_t *cf); +# endif +#endif static ngx_conf_post_t ngx_http_lua_lowat_post = @@ -545,7 +553,13 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_module_t ngx_http_lua_module_ctx = { +#if (NGX_HTTP_LUA_HAVE_MMAP_SBRK) \ + && (NGX_LINUX) \ + && !(NGX_HTTP_LUA_HAVE_CONSTRUCTOR) + ngx_http_lua_pre_config, /* preconfiguration */ +#else NULL, /* preconfiguration */ +#endif ngx_http_lua_init, /* postconfiguration */ ngx_http_lua_create_main_conf, /* create main configuration */ @@ -675,7 +689,7 @@ ngx_http_lua_init(ngx_conf_t *cf) } cln->data = lmcf; - cln->handler = ngx_http_lua_cleanup_semaphore_mm; + cln->handler = ngx_http_lua_sema_mm_cleanup; #endif @@ -747,8 +761,9 @@ ngx_http_lua_lowat_check(ngx_conf_t *cf, void *post, void *data) static void * ngx_http_lua_create_main_conf(ngx_conf_t *cf) { + ngx_int_t rc; + ngx_http_lua_main_conf_t *lmcf; - ngx_http_lua_semaphore_mm_t *mm; lmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_main_conf_t)); if (lmcf == NULL) { @@ -787,24 +802,10 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) lmcf->postponed_to_rewrite_phase_end = NGX_CONF_UNSET; lmcf->postponed_to_access_phase_end = NGX_CONF_UNSET; - mm = ngx_palloc(cf->pool, sizeof(ngx_http_lua_semaphore_mm_t)); - if (mm == NULL) { + rc = ngx_http_lua_sema_mm_init(cf, lmcf); + if (rc != NGX_OK) { return NULL; } - - lmcf->semaphore_mm = mm; - mm->lmcf = lmcf; - - ngx_queue_init(&mm->free_queue); - mm->cur_epoch = 0; - mm->total = 0; - mm->used = 0; - - /* it's better to be 4096, but it needs some space for - * ngx_http_lua_semaphore_mm_block_t, one is enough, so it is 4095 - */ - mm->num_per_block = 4095; - dd("nginx Lua module main config structure initialized!"); return lmcf; @@ -876,6 +877,7 @@ ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) if (conf->ssl.cert_src.len == 0) { conf->ssl.cert_src = prev->ssl.cert_src; + conf->ssl.cert_src_key = prev->ssl.cert_src_key; conf->ssl.cert_handler = prev->ssl.cert_handler; } @@ -1158,4 +1160,35 @@ ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf) #endif /* NGX_HTTP_SSL */ + +#if (NGX_HTTP_LUA_HAVE_MMAP_SBRK) \ + && (NGX_LINUX) \ + && !(NGX_HTTP_LUA_HAVE_CONSTRUCTOR) +static ngx_int_t +ngx_http_lua_pre_config(ngx_conf_t *cf) +{ + ngx_http_lua_limit_data_segment(); + return NGX_OK; +} +#endif + + +/* + * we simply assume that LuaJIT is used. it does little harm when the + * standard Lua 5.1 interpreter is used instead. + */ +#if (NGX_HTTP_LUA_HAVE_MMAP_SBRK) && (NGX_LINUX) +# if (NGX_HTTP_LUA_HAVE_CONSTRUCTOR) +__attribute__((constructor)) +# endif +void +ngx_http_lua_limit_data_segment(void) +{ + if (sbrk(0) < (void *) 0x40000000LL) { + mmap(ngx_align_ptr(sbrk(0), getpagesize()), 1, PROT_READ, + MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0); + } +} +#endif + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_output.c b/debian/modules/nginx-lua/src/ngx_http_lua_output.c index ef816d2..b410ba4 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_output.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_output.c @@ -147,11 +147,19 @@ ngx_http_lua_ngx_echo(lua_State *L, unsigned newline) } if (size == 0) { - /* do nothing for empty strings */ + rc = ngx_http_lua_send_header_if_needed(r, ctx); + if (rc == NGX_ERROR || rc > NGX_OK) { + lua_pushnil(L); + lua_pushliteral(L, "nginx output filter error"); + return 2; + } + lua_pushinteger(L, 1); return 1; } + ctx->seen_body_data = 1; + cl = ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool, &ctx->free_bufs, size); @@ -511,7 +519,9 @@ ngx_http_lua_ngx_flush(lua_State *L) } #if 1 - if (!r->header_sent && !ctx->header_sent) { + if ((!r->header_sent && !ctx->header_sent) + || (!ctx->seen_body_data && !wait)) + { lua_pushnil(L); lua_pushliteral(L, "nothing to flush"); return 2; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c b/debian/modules/nginx-lua/src/ngx_http_lua_regex.c index be110e3..d882061 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_regex.c @@ -152,6 +152,7 @@ ngx_http_lua_ngx_re_match_helper(lua_State *L, int wantcaps) int nargs; int *cap = NULL; int ovecsize; + int has_ctx = 0; ngx_uint_t flags; ngx_pool_t *pool, *old_pool; ngx_http_lua_main_conf_t *lmcf; @@ -184,29 +185,34 @@ ngx_http_lua_ngx_re_match_helper(lua_State *L, int wantcaps) if (nargs >= 3) { opts.data = (u_char *) luaL_checklstring(L, 3, &opts.len); - if (nargs == 4) { - luaL_checktype(L, 4, LUA_TTABLE); - lua_getfield(L, 4, "pos"); - if (lua_isnumber(L, -1)) { - pos = (ngx_int_t) lua_tointeger(L, -1); - if (pos <= 0) { + if (nargs >= 4) { + if (!lua_isnil(L, 4)) { + luaL_checktype(L, 4, LUA_TTABLE); + has_ctx = 1; + + lua_getfield(L, 4, "pos"); + if (lua_isnumber(L, -1)) { + pos = (ngx_int_t) lua_tointeger(L, -1); + if (pos <= 0) { + pos = 0; + + } else { + pos--; /* 1-based on the Lua land */ + } + + } else if (lua_isnil(L, -1)) { pos = 0; } else { - pos--; /* 1-based on the Lua land */ + msg = lua_pushfstring(L, "bad pos field type in the ctx " + "table argument: %s", + luaL_typename(L, -1)); + + return luaL_argerror(L, 4, msg); } - } else if (lua_isnil(L, -1)) { - pos = 0; - - } else { - msg = lua_pushfstring(L, "bad pos field type in the ctx table " - "argument: %s", luaL_typename(L, -1)); - - return luaL_argerror(L, 4, msg); + lua_pop(L, 1); } - - lua_pop(L, 1); } } else { @@ -555,7 +561,7 @@ exec: dd("rc = %d", (int) rc); - if (nargs == 4) { /* having ctx table */ + if (has_ctx) { /* having ctx table */ pos = cap[1]; lua_pushinteger(L, (lua_Integer) (pos + 1)); lua_setfield(L, 4, "pos"); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c b/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c index 591d2cd..6f2ae38 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c @@ -548,7 +548,7 @@ ngx_http_lua_ngx_req_init_body(lua_State *L) if (n == 1) { num = luaL_checkinteger(L, 1); - if (num <= 0) { + if (num < 0) { return luaL_error(L, "bad size argument: %d", (int) num); } @@ -558,13 +558,10 @@ ngx_http_lua_ngx_req_init_body(lua_State *L) clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); size = clcf->client_body_buffer_size; + } - size += size >> 2; - - /* avoid allocating an unnecessary large buffer */ - if (size > (size_t) r->headers_in.content_length_n) { - size = (size_t) r->headers_in.content_length_n; - } + if (size == 0) { + r->request_body_in_file_only = 1; } rb = r->request_body; @@ -622,6 +619,8 @@ ngx_http_lua_ngx_req_append_body(lua_State *L) ngx_str_t body; size_t size, rest; size_t offset = 0; + ngx_chain_t chain; + ngx_buf_t buf; n = lua_gettop(L); @@ -642,7 +641,25 @@ ngx_http_lua_ngx_req_append_body(lua_State *L) || r->request_body->buf == NULL || r->request_body->bufs == NULL) { - return luaL_error(L, "request_body not initalized"); + return luaL_error(L, "request_body not initialized"); + } + + if (r->request_body_in_file_only) { + buf.start = body.data; + buf.pos = buf.start; + buf.last = buf.start + body.len; + buf.end = buf.last; + buf.temporary = 1; + + chain.buf = &buf; + chain.next = NULL; + + if (ngx_http_lua_write_request_body(r, &chain) != NGX_OK) { + return luaL_error(L, "fail to write file"); + } + + r->headers_in.content_length_n += body.len; + return 0; } rb = r->request_body; @@ -705,7 +722,7 @@ ngx_http_lua_ngx_req_body_finish(lua_State *L) || r->request_body->buf == NULL || r->request_body->bufs == NULL) { - return luaL_error(L, "request_body not initalized"); + return luaL_error(L, "request_body not initialized"); } rb = r->request_body; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c b/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c index 8d4ac07..8a3f832 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c @@ -21,21 +21,21 @@ #include "ngx_http_lua_contentby.h" -ngx_int_t ngx_http_lua_semaphore_init_mm(ngx_http_lua_semaphore_mm_t *mm); -static ngx_http_lua_semaphore_t *ngx_http_lua_alloc_semaphore(void); -void ngx_http_lua_cleanup_semaphore_mm(void *data); -static void ngx_http_lua_free_semaphore(ngx_http_lua_semaphore_t *sem); -static ngx_int_t ngx_http_lua_semaphore_resume(ngx_http_request_t *r); -int ngx_http_lua_ffi_semaphore_new(ngx_http_lua_semaphore_t **psem, +ngx_int_t ngx_http_lua_sema_mm_init(ngx_conf_t *cf, + ngx_http_lua_main_conf_t *lmcf); +void ngx_http_lua_sema_mm_cleanup(void *data); +static ngx_http_lua_sema_t *ngx_http_lua_alloc_sema(void); +static void ngx_http_lua_free_sema(ngx_http_lua_sema_t *sem); +static ngx_int_t ngx_http_lua_sema_resume(ngx_http_request_t *r); +int ngx_http_lua_ffi_sema_new(ngx_http_lua_sema_t **psem, int n, char **errmsg); -int ngx_http_lua_ffi_semaphore_post(ngx_http_lua_semaphore_t *sem, - int n); -int ngx_http_lua_ffi_semaphore_wait(ngx_http_request_t *r, - ngx_http_lua_semaphore_t *sem, int wait_ms, u_char *err, size_t *errlen); -static void ngx_http_lua_semaphore_cleanup(void *data); -static void ngx_http_lua_semaphore_handler(ngx_event_t *ev); -static void ngx_http_lua_semaphore_timeout_handler(ngx_event_t *ev); -void ngx_http_lua_ffi_semaphore_gc(ngx_http_lua_semaphore_t *sem); +int ngx_http_lua_ffi_sema_post(ngx_http_lua_sema_t *sem, int n); +int ngx_http_lua_ffi_sema_wait(ngx_http_request_t *r, + ngx_http_lua_sema_t *sem, int wait_ms, u_char *err, size_t *errlen); +static void ngx_http_lua_sema_cleanup(void *data); +static void ngx_http_lua_sema_handler(ngx_event_t *ev); +static void ngx_http_lua_sema_timeout_handler(ngx_event_t *ev); +void ngx_http_lua_ffi_sema_gc(ngx_http_lua_sema_t *sem); enum { @@ -44,34 +44,61 @@ enum { }; -static ngx_http_lua_semaphore_t * -ngx_http_lua_alloc_semaphore(void) +ngx_int_t +ngx_http_lua_sema_mm_init(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf) +{ + ngx_http_lua_sema_mm_t *mm; + + mm = ngx_palloc(cf->pool, sizeof(ngx_http_lua_sema_mm_t)); + if (mm == NULL) { + return NGX_ERROR; + } + + lmcf->sema_mm = mm; + mm->lmcf = lmcf; + + ngx_queue_init(&mm->free_queue); + mm->cur_epoch = 0; + mm->total = 0; + mm->used = 0; + + /* it's better to be 4096, but it needs some space for + * ngx_http_lua_sema_mm_block_t, one is enough, so it is 4095 + */ + mm->num_per_block = 4095; + + return NGX_OK; +} + + +static ngx_http_lua_sema_t * +ngx_http_lua_alloc_sema(void) { - ngx_http_lua_semaphore_t *sem, *iter; - ngx_http_lua_main_conf_t *lmcf; - ngx_queue_t *q; ngx_uint_t i, n; - ngx_http_lua_semaphore_mm_block_t *block; - ngx_http_lua_semaphore_mm_t *mm; + ngx_queue_t *q; + ngx_http_lua_sema_t *sem, *iter; + ngx_http_lua_sema_mm_t *mm; + ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_sema_mm_block_t *block; ngx_http_lua_assert(ngx_cycle && ngx_cycle->conf_ctx); lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle, ngx_http_lua_module); - mm = lmcf->semaphore_mm; + mm = lmcf->sema_mm; if (!ngx_queue_empty(&mm->free_queue)) { q = ngx_queue_head(&mm->free_queue); ngx_queue_remove(q); - sem = ngx_queue_data(q, ngx_http_lua_semaphore_t, chain); + sem = ngx_queue_data(q, ngx_http_lua_sema_t, chain); sem->block->used++; ngx_memzero(&sem->sem_event, sizeof(ngx_event_t)); - sem->sem_event.handler = ngx_http_lua_semaphore_handler; + sem->sem_event.handler = ngx_http_lua_sema_handler; sem->sem_event.data = sem; sem->sem_event.log = ngx_cycle->log; @@ -85,12 +112,12 @@ ngx_http_lua_alloc_semaphore(void) /* free_queue is empty */ - n = sizeof(ngx_http_lua_semaphore_mm_block_t) - + mm->num_per_block * sizeof(ngx_http_lua_semaphore_t); + n = sizeof(ngx_http_lua_sema_mm_block_t) + + mm->num_per_block * sizeof(ngx_http_lua_sema_t); dd("block size: %d, item size: %d", - (int) sizeof(ngx_http_lua_semaphore_mm_block_t), - (int) sizeof(ngx_http_lua_semaphore_t)); + (int) sizeof(ngx_http_lua_sema_mm_block_t), + (int) sizeof(ngx_http_lua_sema_t)); block = ngx_alloc(n, ngx_cycle->log); if (block == NULL) { @@ -104,13 +131,13 @@ ngx_http_lua_alloc_semaphore(void) block->mm = mm; block->epoch = mm->cur_epoch; - sem = (ngx_http_lua_semaphore_t *) (block + 1); + sem = (ngx_http_lua_sema_t *) (block + 1); sem->block = block; sem->block->used = 1; ngx_memzero(&sem->sem_event, sizeof(ngx_event_t)); - sem->sem_event.handler = ngx_http_lua_semaphore_handler; + sem->sem_event.handler = ngx_http_lua_sema_handler; sem->sem_event.data = sem; sem->sem_event.log = ngx_cycle->log; @@ -127,32 +154,32 @@ ngx_http_lua_alloc_semaphore(void) void -ngx_http_lua_cleanup_semaphore_mm(void *data) +ngx_http_lua_sema_mm_cleanup(void *data) { - ngx_http_lua_semaphore_t *sem, *iter; ngx_uint_t i; - ngx_http_lua_main_conf_t *lmcf; ngx_queue_t *q; - ngx_http_lua_semaphore_mm_block_t *block; - ngx_http_lua_semaphore_mm_t *mm; + ngx_http_lua_sema_t *sem, *iter; + ngx_http_lua_sema_mm_t *mm; + ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_sema_mm_block_t *block; lmcf = (ngx_http_lua_main_conf_t *) data; - mm = lmcf->semaphore_mm; + mm = lmcf->sema_mm; while (!ngx_queue_empty(&mm->free_queue)) { q = ngx_queue_head(&mm->free_queue); - sem = ngx_queue_data(q, ngx_http_lua_semaphore_t, chain); + sem = ngx_queue_data(q, ngx_http_lua_sema_t, chain); block = sem->block; if (block->used == 0) { - iter = (ngx_http_lua_semaphore_t *) (block + 1); + iter = (ngx_http_lua_sema_t *) (block + 1); for (i = 0; i < block->mm->num_per_block; i++, iter++) { ngx_queue_remove(&iter->chain); } - dd("free semaphore block: %p at final", block); + dd("free sema block: %p at final", block); ngx_free(block); @@ -160,24 +187,24 @@ ngx_http_lua_cleanup_semaphore_mm(void *data) /* just return directly when some thing goes wrong */ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "ngx_http_lua_cleanup_semaphore_mm when cleanup" - " block %p is still used by someone", block); + "lua sema mm: freeing a block %p that is still " + " used by someone", block); return; } } - dd("ngx_http_lua_cleanup_semaphore_mm"); + dd("lua sema mm cleanup done"); } static void -ngx_http_lua_free_semaphore(ngx_http_lua_semaphore_t *sem) +ngx_http_lua_free_sema(ngx_http_lua_sema_t *sem) { - ngx_http_lua_semaphore_t *iter; - ngx_uint_t i, mid_epoch; - ngx_http_lua_semaphore_mm_block_t *block; - ngx_http_lua_semaphore_mm_t *mm; + ngx_http_lua_sema_t *iter; + ngx_uint_t i, mid_epoch; + ngx_http_lua_sema_mm_block_t *block; + ngx_http_lua_sema_mm_t *mm; block = sem->block; block->used--; @@ -209,7 +236,7 @@ ngx_http_lua_free_semaphore(ngx_http_lua_semaphore_t *sem) && block->epoch < mid_epoch) { /* load <= 50% and it's on the older side */ - iter = (ngx_http_lua_semaphore_t *) (block + 1); + iter = (ngx_http_lua_sema_t *) (block + 1); for (i = 0; i < mm->num_per_block; i++, iter++) { ngx_queue_remove(&iter->chain); @@ -226,7 +253,7 @@ ngx_http_lua_free_semaphore(ngx_http_lua_semaphore_t *sem) static ngx_int_t -ngx_http_lua_semaphore_resume(ngx_http_request_t *r) +ngx_http_lua_sema_resume(ngx_http_request_t *r) { lua_State *vm; ngx_connection_t *c; @@ -278,12 +305,12 @@ ngx_http_lua_semaphore_resume(ngx_http_request_t *r) int -ngx_http_lua_ffi_semaphore_new(ngx_http_lua_semaphore_t **psem, +ngx_http_lua_ffi_sema_new(ngx_http_lua_sema_t **psem, int n, char **errmsg) { - ngx_http_lua_semaphore_t *sem; + ngx_http_lua_sema_t *sem; - sem = ngx_http_lua_alloc_semaphore(); + sem = ngx_http_lua_alloc_sema(); if (sem == NULL) { *errmsg = "no memory"; return NGX_ERROR; @@ -304,7 +331,7 @@ ngx_http_lua_ffi_semaphore_new(ngx_http_lua_semaphore_t **psem, int -ngx_http_lua_ffi_semaphore_post(ngx_http_lua_semaphore_t *sem, int n) +ngx_http_lua_ffi_sema_post(ngx_http_lua_sema_t *sem, int n) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "http lua semaphore post: %p, n: %d, resources: %d", @@ -325,8 +352,8 @@ ngx_http_lua_ffi_semaphore_post(ngx_http_lua_semaphore_t *sem, int n) int -ngx_http_lua_ffi_semaphore_wait(ngx_http_request_t *r, - ngx_http_lua_semaphore_t *sem, int wait_ms, u_char *err, size_t *errlen) +ngx_http_lua_ffi_sema_wait(ngx_http_request_t *r, + ngx_http_lua_sema_t *sem, int wait_ms, u_char *err, size_t *errlen) { ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *wait_co_ctx; @@ -361,7 +388,7 @@ ngx_http_lua_ffi_semaphore_wait(ngx_http_request_t *r, } /* we keep the order, will resume the older waited firtly - * in ngx_http_lua_semaphore_handler + * in ngx_http_lua_sema_handler */ if (ngx_queue_empty(&sem->wait_queue) && sem->resource_count > 0) { @@ -376,19 +403,19 @@ ngx_http_lua_ffi_semaphore_wait(ngx_http_request_t *r, sem->wait_count++; wait_co_ctx = ctx->cur_co_ctx; - wait_co_ctx->sleep.handler = ngx_http_lua_semaphore_timeout_handler; + wait_co_ctx->sleep.handler = ngx_http_lua_sema_timeout_handler; wait_co_ctx->sleep.data = ctx->cur_co_ctx; wait_co_ctx->sleep.log = r->connection->log; ngx_add_timer(&wait_co_ctx->sleep, (ngx_msec_t) wait_ms); - dd("ngx_http_lua_ffi_semaphore_wait add timer coctx:%p wait: %d(ms)", + dd("ngx_http_lua_ffi_sema_wait add timer coctx:%p wait: %d(ms)", wait_co_ctx, wait_ms); ngx_queue_insert_tail(&sem->wait_queue, &wait_co_ctx->sem_wait_queue); wait_co_ctx->data = sem; - wait_co_ctx->cleanup = ngx_http_lua_semaphore_cleanup; + wait_co_ctx->cleanup = ngx_http_lua_sema_cleanup; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "http lua semaphore wait yielding"); @@ -398,18 +425,18 @@ ngx_http_lua_ffi_semaphore_wait(ngx_http_request_t *r, int -ngx_http_lua_ffi_semaphore_count(ngx_http_lua_semaphore_t *sem) +ngx_http_lua_ffi_sema_count(ngx_http_lua_sema_t *sem) { return sem->resource_count - sem->wait_count; } static void -ngx_http_lua_semaphore_cleanup(void *data) +ngx_http_lua_sema_cleanup(void *data) { ngx_http_lua_co_ctx_t *coctx = data; ngx_queue_t *q; - ngx_http_lua_semaphore_t *sem; + ngx_http_lua_sema_t *sem; sem = coctx->data; @@ -429,9 +456,9 @@ ngx_http_lua_semaphore_cleanup(void *data) static void -ngx_http_lua_semaphore_handler(ngx_event_t *ev) +ngx_http_lua_sema_handler(ngx_event_t *ev) { - ngx_http_lua_semaphore_t *sem; + ngx_http_lua_sema_t *sem; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *wait_co_ctx; @@ -467,10 +494,10 @@ ngx_http_lua_semaphore_handler(ngx_event_t *ev) wait_co_ctx->sem_resume_status = SEMAPHORE_WAIT_SUCC; if (ctx->entered_content_phase) { - (void) ngx_http_lua_semaphore_resume(r); + (void) ngx_http_lua_sema_resume(r); } else { - ctx->resume_handler = ngx_http_lua_semaphore_resume; + ctx->resume_handler = ngx_http_lua_sema_resume; ngx_http_core_run_phases(r); } @@ -480,18 +507,18 @@ ngx_http_lua_semaphore_handler(ngx_event_t *ev) static void -ngx_http_lua_semaphore_timeout_handler(ngx_event_t *ev) +ngx_http_lua_sema_timeout_handler(ngx_event_t *ev) { ngx_http_lua_co_ctx_t *wait_co_ctx; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_connection_t *c; - ngx_http_lua_semaphore_t *sem; + ngx_http_lua_sema_t *sem; wait_co_ctx = ev->data; wait_co_ctx->cleanup = NULL; - dd("ngx_http_lua_semaphore_timeout_handler timeout coctx:%p", wait_co_ctx); + dd("ngx_http_lua_sema_timeout_handler timeout coctx:%p", wait_co_ctx); sem = wait_co_ctx->data; @@ -509,10 +536,10 @@ ngx_http_lua_semaphore_timeout_handler(ngx_event_t *ev) wait_co_ctx->sem_resume_status = SEMAPHORE_WAIT_TIMEOUT; if (ctx->entered_content_phase) { - (void) ngx_http_lua_semaphore_resume(r); + (void) ngx_http_lua_sema_resume(r); } else { - ctx->resume_handler = ngx_http_lua_semaphore_resume; + ctx->resume_handler = ngx_http_lua_sema_resume; ngx_http_core_run_phases(r); } @@ -521,7 +548,7 @@ ngx_http_lua_semaphore_timeout_handler(ngx_event_t *ev) void -ngx_http_lua_ffi_semaphore_gc(ngx_http_lua_semaphore_t *sem) +ngx_http_lua_ffi_sema_gc(ngx_http_lua_sema_t *sem) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "in lua gc, semaphore %p", sem); @@ -537,7 +564,7 @@ ngx_http_lua_ffi_semaphore_gc(ngx_http_lua_semaphore_t *sem) "destroyed", sem); } - ngx_http_lua_free_semaphore(sem); + ngx_http_lua_free_sema(sem); } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.h b/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.h index a71cc23..65ba8ff 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.h @@ -14,14 +14,14 @@ #include "ngx_http_lua_common.h" -typedef struct ngx_http_lua_semaphore_mm_block_s { +typedef struct ngx_http_lua_sema_mm_block_s { ngx_uint_t used; - ngx_http_lua_semaphore_mm_t *mm; + ngx_http_lua_sema_mm_t *mm; ngx_uint_t epoch; -} ngx_http_lua_semaphore_mm_block_t; +} ngx_http_lua_sema_mm_block_t; -struct ngx_http_lua_semaphore_mm_s { +struct ngx_http_lua_sema_mm_s { ngx_queue_t free_queue; ngx_uint_t total; ngx_uint_t used; @@ -31,18 +31,20 @@ struct ngx_http_lua_semaphore_mm_s { }; -typedef struct ngx_http_lua_semaphore_s { +typedef struct ngx_http_lua_sema_s { ngx_queue_t wait_queue; ngx_queue_t chain; ngx_event_t sem_event; - ngx_http_lua_semaphore_mm_block_t *block; + ngx_http_lua_sema_mm_block_t *block; int resource_count; unsigned wait_count; -} ngx_http_lua_semaphore_t; +} ngx_http_lua_sema_t; #ifndef NGX_LUA_NO_FFI_API -void ngx_http_lua_cleanup_semaphore_mm(void *data); +void ngx_http_lua_sema_mm_cleanup(void *data); +ngx_int_t ngx_http_lua_sema_mm_init(ngx_conf_t *cf, + ngx_http_lua_main_conf_t *lmcf); #endif diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c index 1a6594d..2bfdbd3 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c @@ -1181,8 +1181,8 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) /* Lua function arguments: self [,session] [,host] [,verify] */ n = lua_gettop(L); - if (n < 1 && n > 4) { - return luaL_error(L, "ngx.socket connect: expecting 1 ~ 4 " + if (n < 1 || n > 5) { + return luaL_error(L, "ngx.socket connect: expecting 1 ~ 5 " "arguments (including the object), but seen %d", n); } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c index c4e6a83..c06bc8e 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c @@ -656,6 +656,8 @@ failed: X509_free(x509); } + ERR_clear_error(); + return NGX_ERROR; # endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */ @@ -714,6 +716,8 @@ failed: BIO_free(bio); } + ERR_clear_error(); + return NGX_ERROR; } @@ -842,12 +846,15 @@ ngx_http_lua_ffi_cert_pem_to_der(const u_char *pem, size_t pem_len, u_char *der, bio = BIO_new_mem_buf((char *) pem, (int) pem_len); if (bio == NULL) { *err = "BIO_new_mem_buf() failed"; + ERR_clear_error(); return NGX_ERROR; } x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); if (x509 == NULL) { *err = "PEM_read_bio_X509_AUX() failed"; + BIO_free(bio); + ERR_clear_error(); return NGX_ERROR; } @@ -856,6 +863,7 @@ ngx_http_lua_ffi_cert_pem_to_der(const u_char *pem, size_t pem_len, u_char *der, *err = "i2d_X509() failed"; X509_free(x509); BIO_free(bio); + ERR_clear_error(); return NGX_ERROR; } @@ -881,6 +889,7 @@ ngx_http_lua_ffi_cert_pem_to_der(const u_char *pem, size_t pem_len, u_char *der, *err = "PEM_read_bio_X509() failed"; BIO_free(bio); + ERR_clear_error(); return NGX_ERROR; } @@ -889,6 +898,7 @@ ngx_http_lua_ffi_cert_pem_to_der(const u_char *pem, size_t pem_len, u_char *der, *err = "i2d_X509() failed"; X509_free(x509); BIO_free(bio); + ERR_clear_error(); return NGX_ERROR; } @@ -914,6 +924,7 @@ ngx_http_lua_ffi_priv_key_pem_to_der(const u_char *pem, size_t pem_len, in = BIO_new_mem_buf((char *) pem, (int) pem_len); if (in == NULL) { *err = "BIO_new_mem_buf() failed"; + ERR_clear_error(); return NGX_ERROR; } @@ -921,6 +932,7 @@ ngx_http_lua_ffi_priv_key_pem_to_der(const u_char *pem, size_t pem_len, if (pkey == NULL) { BIO_free(in); *err = "PEM_read_bio_PrivateKey failed"; + ERR_clear_error(); return NGX_ERROR; } @@ -930,6 +942,7 @@ ngx_http_lua_ffi_priv_key_pem_to_der(const u_char *pem, size_t pem_len, if (len < 0) { EVP_PKEY_free(pkey); *err = "i2d_PrivateKey failed"; + ERR_clear_error(); return NGX_ERROR; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c index 9f9e276..1bf4335 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c @@ -137,6 +137,10 @@ done: BIO_free(bio); } + if (rc == NGX_ERROR) { + ERR_clear_error(); + } + return rc; #endif /* NGX_HTTP_LUA_USE_OCSP */ @@ -229,6 +233,8 @@ ngx_http_lua_ffi_ssl_create_ocsp_request(const char *chain_data, X509_free(cert); BIO_free(bio); + ERR_clear_error(); + return NGX_OK; failed: diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c index 393eac7..96c0ace 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c @@ -359,7 +359,6 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) ngx_memcpy(&tctx, ev->data, sizeof(ngx_http_lua_timer_ctx_t)); ngx_free(ev); - ev = NULL; lmcf = tctx.lmcf; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.c b/debian/modules/nginx-lua/src/ngx_http_lua_util.c index 69eccae..1bd1388 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_util.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_util.c @@ -907,17 +907,17 @@ ngx_http_lua_request_cleanup(ngx_http_lua_ctx_t *ctx, int forcible) ngx_http_request_t *r; ngx_http_lua_main_conf_t *lmcf; - r = ctx->request; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua request cleanup: forcible=%d", forcible); - /* force coroutine handling the request quit */ if (ctx == NULL) { dd("ctx is NULL"); return; } + r = ctx->request; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua request cleanup: forcible=%d", forcible); + if (ctx->cleanup) { *ctx->cleanup = NULL; ctx->cleanup = NULL; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_variable.c b/debian/modules/nginx-lua/src/ngx_http_lua_variable.c index 0de9312..b26c862 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_variable.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_variable.c @@ -185,7 +185,7 @@ ngx_http_lua_var_set(lua_State *L) val = ngx_palloc(r->pool, len); if (val == NULL) { - return luaL_error(L, "memory allocation erorr"); + return luaL_error(L, "memory allocation error"); } ngx_memcpy(val, p, len); @@ -460,6 +460,7 @@ ngx_http_lua_ffi_var_set(ngx_http_request_t *r, u_char *name_data, if (p == NULL) { goto nomem; } + ngx_memcpy(p, value, value_len); value = p; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_worker.c b/debian/modules/nginx-lua/src/ngx_http_lua_worker.c index 44faf48..ff09b5b 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_worker.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_worker.c @@ -60,6 +60,13 @@ static int ngx_http_lua_ngx_worker_id(lua_State *L) { #if (nginx_version >= 1009001) + if (ngx_process != NGX_PROCESS_WORKER + && ngx_process != NGX_PROCESS_SINGLE) + { + lua_pushnil(L); + return 1; + } + lua_pushinteger(L, (lua_Integer) ngx_worker); #else lua_pushnil(L); @@ -93,6 +100,12 @@ int ngx_http_lua_ffi_worker_id(void) { #if (nginx_version >= 1009001) + if (ngx_process != NGX_PROCESS_WORKER + && ngx_process != NGX_PROCESS_SINGLE) + { + return -1; + } + return (int) ngx_worker; #else return -1; diff --git a/debian/modules/nginx-lua/t/015-status.t b/debian/modules/nginx-lua/t/015-status.t index 2e026f1..666dae7 100644 --- a/debian/modules/nginx-lua/t/015-status.t +++ b/debian/modules/nginx-lua/t/015-status.t @@ -9,7 +9,7 @@ log_level('warn'); #repeat_each(120); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 7); +plan tests => repeat_each() * (blocks() * 2 + 9); #no_diff(); #no_long_string(); @@ -270,3 +270,24 @@ ngx.status = 502 --- no_error_log [error] + + +=== TEST 16: ngx.status assignmnt should clear r->err_status +--- config +location = /t { + return 502; + header_filter_by_lua_block { + if ngx.status == 502 then + ngx.status = 654 + ngx.log(ngx.WARN, "ngx.status: ", ngx.status) + end + } +} +--- request +GET /t +--- response_body_like: Bad Gateway +--- error_log +ngx.status: 654 +--- no_error_log +[error] +--- error_code: 654 diff --git a/debian/modules/nginx-lua/t/024-access/mixed.t b/debian/modules/nginx-lua/t/024-access/mixed.t index d801216..a9f8039 100644 --- a/debian/modules/nginx-lua/t/024-access/mixed.t +++ b/debian/modules/nginx-lua/t/024-access/mixed.t @@ -245,3 +245,17 @@ access cached: hello --- log_level: info + + +=== TEST 7: I/O in access shortcuts content automatically +--- config + location = /t { + access_by_lua_block { + ngx.print("") + } + + echo ok; + } +--- request + GET /t +--- response_body diff --git a/debian/modules/nginx-lua/t/034-match.t b/debian/modules/nginx-lua/t/034-match.t index 4792ae6..35149f1 100644 --- a/debian/modules/nginx-lua/t/034-match.t +++ b/debian/modules/nginx-lua/t/034-match.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 14); +plan tests => repeat_each() * (blocks() * 2 + 15); #no_diff(); no_long_string(); @@ -1124,6 +1124,8 @@ failed to match 1: res size: 2 2: m size: 2 2: res size: 2 +--- no_error_log +[error] @@ -1169,3 +1171,22 @@ hello hello false + + +=== TEST 50: the 5th argument hides the 4th (GitHub #719) +--- config + location /re { + content_by_lua ' + local ctx, m = { pos = 5 }, {}; + local _, err = ngx.re.match("20172016-11-3 03:07:09", [=[(\d\d\d\d)]=], "", ctx, m); + if m then + ngx.say(m[0], " ", _[0], " ", ctx.pos) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +2016 2016 9 diff --git a/debian/modules/nginx-lua/t/043-shdict.t b/debian/modules/nginx-lua/t/043-shdict.t index 91a4196..cd160f7 100644 --- a/debian/modules/nginx-lua/t/043-shdict.t +++ b/debian/modules/nginx-lua/t/043-shdict.t @@ -1584,7 +1584,7 @@ cur value: hello hello hello hello hello hello hello hello hello hello1 content_by_lua ' local dogs = ngx.shared.dogs dogs:set("foo", 32, 0.01) - dogs:set("blah", 33, 0.1) + dogs:set("blah", 33, 0.3) ngx.sleep(0.02) local val, flags, stale = dogs:get_stale("foo") ngx.say(val, ", ", flags, ", ", stale) diff --git a/debian/modules/nginx-lua/t/044-req-body.t b/debian/modules/nginx-lua/t/044-req-body.t index 1c1be40..28fa818 100644 --- a/debian/modules/nginx-lua/t/044-req-body.t +++ b/debian/modules/nginx-lua/t/044-req-body.t @@ -1630,3 +1630,111 @@ request body:hello, world --- no_error_log [error] [alert] + + + +=== TEST 50: init & append & finish (content_length = 0) +--- config + location /t { + content_by_lua ' + local old_http_content_length = ngx.var.http_content_length + + ngx.req.read_body() + ngx.req.init_body() + ngx.req.append_body("he") + ngx.req.append_body("llo") + ngx.req.finish_body() + + ngx.say("old content length: ", old_http_content_length) + + local data = ngx.req.get_body_data() + local data_file = ngx.req.get_body_file() + + if not data and data_file then + ngx.say("no data in buf, go to data file") + end + + ngx.say("content length: ", ngx.var.http_content_length) + '; + } +--- request + GET /t +--- more_headers +Content-Length: 0 +--- response_body +old content length: 0 +content length: 5 +--- no_error_log +[error] +[alert] + + + +=== TEST 51: init & append & finish (init_body(0)) +--- config + location /t { + content_by_lua ' + local old_http_content_length = ngx.var.http_content_length + + ngx.req.read_body() + ngx.req.init_body(0) + ngx.req.append_body("he") + ngx.req.append_body("llo") + ngx.req.finish_body() + + ngx.say("old content length: ", old_http_content_length) + + local data = ngx.req.get_body_data() + local data_file = ngx.req.get_body_file() + + if not data and data_file then + ngx.say("no data in buf, go to data file") + end + + ngx.say("content length: ", ngx.var.http_content_length) + '; + } +--- request + GET /t +--- more_headers +Content-Length: 0 +--- response_body +old content length: 0 +no data in buf, go to data file +content length: 5 +--- no_error_log +[error] +[alert] + + + +=== TEST 52: init & append & finish (client_body_buffer_size = 0) +--- http_config + client_body_buffer_size 0; +--- config + location /t { + content_by_lua ' + ngx.req.read_body() + ngx.req.init_body() + ngx.req.append_body("he") + ngx.req.append_body("llo") + ngx.req.finish_body() + + local data = ngx.req.get_body_data() + local data_file = ngx.req.get_body_file() + + if not data and data_file then + ngx.say("no data in buf, go to data file") + end + + ngx.say("content length: ", ngx.var.http_content_length) + '; + } +--- request + GET /t +--- response_body +no data in buf, go to data file +content length: 5 +--- no_error_log +[error] +[alert] diff --git a/debian/modules/nginx-lua/t/058-tcp-socket.t b/debian/modules/nginx-lua/t/058-tcp-socket.t index b9e4175..acf69f0 100644 --- a/debian/modules/nginx-lua/t/058-tcp-socket.t +++ b/debian/modules/nginx-lua/t/058-tcp-socket.t @@ -2039,6 +2039,7 @@ resolve name done === TEST 34: github issue #215: Handle the posted requests in lua cosocket api (successfully resolved) --- config resolver $TEST_NGINX_RESOLVER; + resolver_timeout 5s; location = /sub { content_by_lua ' @@ -2053,7 +2054,7 @@ resolve name done local sock = ngx.socket.tcp() local ok, err = sock:connect(server, 80) if not ok then - ngx.say("failed to connect to agentzh.org: ", err) + ngx.say("failed to connect to ", server, ": ", err) return end ngx.say("successfully connected to xxx!") @@ -3298,6 +3299,7 @@ failed to receive a line: closed [] close: 1 nil --- no_error_log [error] +--- skip_eval: 3: system("ping6 -c 1 ::1 >/dev/null 2>&1") ne 0 diff --git a/debian/modules/nginx-lua/t/087-udp-socket.t b/debian/modules/nginx-lua/t/087-udp-socket.t index 39ff54f..79ba452 100644 --- a/debian/modules/nginx-lua/t/087-udp-socket.t +++ b/debian/modules/nginx-lua/t/087-udp-socket.t @@ -710,7 +710,7 @@ resolve name done === TEST 13: github issue #215: Handle the posted requests in lua cosocket api (successfully resolved) --- config resolver $TEST_NGINX_RESOLVER; - resolver_timeout 3s; + resolver_timeout 5s; location = /sub { content_by_lua ' @@ -725,7 +725,7 @@ resolve name done local sock = ngx.socket.udp() local ok, err = sock:setpeername(server, 80) if not ok then - ngx.say("failed to connect to agentzh.org: ", err) + ngx.say("failed to connect to ", server, ": ", err) return end ngx.say("successfully connected to xxx!") diff --git a/debian/modules/nginx-lua/t/129-ssl-socket.t b/debian/modules/nginx-lua/t/129-ssl-socket.t index 4921099..c19853d 100644 --- a/debian/modules/nginx-lua/t/129-ssl-socket.t +++ b/debian/modules/nginx-lua/t/129-ssl-socket.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 7); +plan tests => repeat_each() * 219; $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); @@ -2584,3 +2584,37 @@ SSL reused session [alert] --- timeout: 5 + + +=== TEST 32: handshake, too many arguments +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + location /t { + #set $port 5000; + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(2000) + + local ok, err = sock:connect("g.sregex.org", 443) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local session, err = sock.sslhandshake() + } + } + +--- request +GET /t +--- ignore_response +--- error_log eval +qr/\[error\] .* ngx.socket connect: expecting 1 ~ 5 arguments \(including the object\), but seen 0/ +--- no_error_log +[alert] +--- timeout: 5 diff --git a/debian/modules/nginx-lua/t/132-lua-blocks.t b/debian/modules/nginx-lua/t/132-lua-blocks.t index d157d27..e2933e9 100644 --- a/debian/modules/nginx-lua/t/132-lua-blocks.t +++ b/debian/modules/nginx-lua/t/132-lua-blocks.t @@ -10,7 +10,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 3 + 4); +plan tests => repeat_each() * (blocks() * 3 + 3); #no_diff(); no_long_string(); @@ -405,7 +405,7 @@ hello, world! -=== TEST 16: content_by_lua_block (unexpected closing long brackets) +=== TEST 16: content_by_lua_block unexpected closing long brackets must FAIL --- config location = /t { content_by_lua_block { @@ -414,15 +414,30 @@ hello, world! } --- request GET /t +--- error_code: 500 +--- error_log eval +qr{\[error\] .*? unexpected symbol near ']'} + + + +=== TEST 17: content_by_lua_block unexpected closing long brackets ignored (GitHub #748) +--- config + location = /t { + content_by_lua_block { + local t1, t2 = {"hello world"}, {1} + ngx.say(t1[t2[1]]) + } + } +--- request +GET /t +--- response_body +hello world --- no_error_log [error] ---- error_log eval -qr{\[emerg\] .*? unexpected lua closing long-bracket in .*?/nginx\.conf:41} ---- must_die -=== TEST 17: simple set_by_lua_block (integer) +=== TEST 18: simple set_by_lua_block (integer) --- config location /lua { set_by_lua_block $res { return 1+1 } @@ -437,7 +452,7 @@ GET /lua -=== TEST 18: ambiguous line comments inside a long bracket string (GitHub #596) +=== TEST 19: ambiguous line comments inside a long bracket string (GitHub #596) --- config location = /t { content_by_lua_block { @@ -459,7 +474,7 @@ done -=== TEST 19: double quotes in long brackets +=== TEST 20: double quotes in long brackets --- config location = /t { rewrite_by_lua_block { print([[Hey, it is "!]]) } content_by_lua_block { ngx.say([["]]) } @@ -475,7 +490,7 @@ Hey, it is "! -=== TEST 20: single quotes in long brackets +=== TEST 21: single quotes in long brackets --- config location = /t { rewrite_by_lua_block { print([[Hey, it is '!]]) } content_by_lua_block { ngx.say([[']]) } @@ -491,7 +506,7 @@ Hey, it is '! -=== TEST 21: lexer no match due to incomplete data chunks in a fixed size buffer +=== TEST 22: lexer no match due to incomplete data chunks in a fixed size buffer --- config location /test1 { content_by_lua_block { diff --git a/debian/modules/nginx-lua/t/135-worker-id.t b/debian/modules/nginx-lua/t/135-worker-id.t index 752b406..3c1f24d 100644 --- a/debian/modules/nginx-lua/t/135-worker-id.t +++ b/debian/modules/nginx-lua/t/135-worker-id.t @@ -3,13 +3,13 @@ use Test::Nginx::Socket::Lua; #worker_connections(1014); -#master_on(); +master_on(); workers(2); #log_level('warn'); -repeat_each(2); +#repeat_each(2); -plan tests => repeat_each() * (blocks() * 3); +plan tests => repeat_each() * (blocks() * 3 + 1); #no_diff(); #no_long_string(); @@ -31,3 +31,63 @@ GET /lua --- no_error_log [error] --- skip_nginx: 3: <=1.9.0 + + + +=== TEST 2: worker id should be nil for non-worker processes +--- http_config + proxy_cache_path conf/cache levels=1:2 keys_zone=my-cache:8m max_size=10m inactive=60m; + proxy_temp_path conf/temp; + + lua_shared_dict counters 1m; + + init_by_lua_block { + ngx.shared.counters:set("c", 0) + } + + init_worker_by_lua_block { + ngx.shared.counters:incr("c", 1) + ngx.log(ngx.INFO, ngx.worker.pid(), ": worker id ", ngx.worker.id()); + } +--- config + location = /t { + content_by_lua_block { + local counters = ngx.shared.counters + local ok, c + for i = 1, 45 do + c = counters:get("c") + if c >= 4 then + ok = true + break + end + local delay = 0.001 * i + if delay > 0.1 then + delay = 0.1 + end + ngx.sleep(delay) + end + if ok then + ngx.say("ok") + else + ngx.say("not ok: c=", c) + end + } + } + location /cache { + proxy_pass http://127.0.0.1:$server_port; + proxy_cache my-cache; + } +--- request +GET /t +--- response_body +ok +--- grep_error_log eval: qr/worker id nil/ +--- grep_error_log_out +worker id nil +worker id nil +--- no_error_log +[error] +--- wait: 0.1 +--- skip_nginx: 3: <=1.9.0 +--- log_level: info +--- timeout: 6 diff --git a/debian/modules/nginx-lua/t/139-ssl-cert-by.t b/debian/modules/nginx-lua/t/139-ssl-cert-by.t index e40fe85..9297a0d 100644 --- a/debian/modules/nginx-lua/t/139-ssl-cert-by.t +++ b/debian/modules/nginx-lua/t/139-ssl-cert-by.t @@ -1380,3 +1380,98 @@ close: 1 nil uthread: thread created: running uthread: hello in thread uthread: done + + + +=== TEST 17: simple logging - use ssl_certificiate_by_lua* on the http {} level +GitHub openresty/lua-resty-core#42 +--- http_config + ssl_certificate_by_lua_block { print("ssl cert by lua is running!") } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to recieve response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +ssl_certificate_by_lua:1: ssl cert by lua is running! + +--- no_error_log +[error] +[alert] diff --git a/debian/modules/nginx-lua/t/140-ssl-c-api.t b/debian/modules/nginx-lua/t/140-ssl-c-api.t index 9812de2..4ecc2cd 100644 --- a/debian/modules/nginx-lua/t/140-ssl-c-api.t +++ b/debian/modules/nginx-lua/t/140-ssl-c-api.t @@ -11,7 +11,7 @@ my $openssl_version = eval { `$NginxBinary -V 2>&1` }; if ($openssl_version =~ m/built with OpenSSL (0|1\.0\.(?:0|1[^\d]|2[a-d]).*)/) { plan(skip_all => "too old OpenSSL, need 1.0.2e, was $1"); } else { - plan tests => repeat_each() * (blocks() * 5); + plan tests => repeat_each() * (blocks() * 5 + 1); } $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); @@ -361,3 +361,139 @@ lua ssl server name: "test.com" --- no_error_log [error] [alert] + + + +=== TEST 3: Handshake continue when cert_pem_to_der errors +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate_by_lua_block { + collectgarbage() + + local ffi = require "ffi" + + ffi.cdef[[ + int ngx_http_lua_ffi_cert_pem_to_der(const unsigned char *pem, + size_t pem_len, unsigned char *der, char **err); + + int ngx_http_lua_ffi_priv_key_pem_to_der(const unsigned char *pem, + size_t pem_len, unsigned char *der, char **err); + ]] + + local errmsg = ffi.new("char *[1]") + + local r = getfenv(0).__ngx_req + if not r then + ngx.log(ngx.ERR, "no request found") + return + end + + local cert = "garbage data" + + local out = ffi.new("char [?]", #cert) + + local rc = ffi.C.ngx_http_lua_ffi_cert_pem_to_der(cert, #cert, out, errmsg) + if rc < 1 then + ngx.log(ngx.ERR, "failed to parse PEM cert: ", + ffi.string(errmsg[0])) + end + + local pkey = "garbage key data" + + out = ffi.new("char [?]", #pkey) + + local rc = ffi.C.ngx_http_lua_ffi_priv_key_pem_to_der(pkey, #pkey, out, errmsg) + if rc < 1 then + ngx.log(ngx.ERR, "failed to parse PEM priv key: ", + ffi.string(errmsg[0])) + end + } + + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to recieve response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +failed to parse PEM cert: PEM_read_bio_X509_AUX() +failed to parse PEM priv key: PEM_read_bio_PrivateKey failed + +--- no_error_log +[alert] diff --git a/debian/modules/nginx-lua/t/141-luajit.t b/debian/modules/nginx-lua/t/141-luajit.t new file mode 100644 index 0000000..be03fe3 --- /dev/null +++ b/debian/modules/nginx-lua/t/141-luajit.t @@ -0,0 +1,47 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +#no_diff(); +#no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: avoid the data segment from growing on Linux +This is to maximize the address space that can be used by LuaJIT. +--- config + location = /t { + content_by_lua_block { + local ffi = require "ffi" + ffi.cdef[[ + void *malloc(size_t size); + void free(void *p); + ]] + local p = ffi.C.malloc(1); + local num = tonumber(ffi.cast("uintptr_t", p)) + ffi.C.free(p) + if ffi.abi("64bit") then + if num < 2^31 then + ngx.say("fail: ", string.format("p = %#x", num)) + return + end + end + ngx.say("pass") + } + } +--- request +GET /t +--- response_body +pass +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c b/debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c index ec74aa4..42cde55 100644 --- a/debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c +++ b/debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c @@ -85,7 +85,6 @@ static char *ngx_http_fake_merge_srv_conf(ngx_conf_t *cf, void *prev, void *conf return NGX_CONF_ERROR; } - ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "merge srv conf ok"); return NGX_CONF_OK; } @@ -116,6 +115,5 @@ static char *ngx_http_fake_merge_loc_conf(ngx_conf_t *cf, void *prev, void *conf return NGX_CONF_ERROR; } - ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "merge loc conf ok"); return NGX_CONF_OK; } diff --git a/debian/modules/nginx-lua/util/build.sh b/debian/modules/nginx-lua/util/build.sh index 2aa79cc..17841ed 100755 --- a/debian/modules/nginx-lua/util/build.sh +++ b/debian/modules/nginx-lua/util/build.sh @@ -39,7 +39,7 @@ time ngx-build $force $version \ --without-http_memcached_module \ --without-http_auth_basic_module \ --without-http_userid_module \ - --add-module=$home/work/nginx/ngx_http_auth_request_module-0.2 \ + --with-http_auth_request_module \ --add-module=$root/../echo-nginx-module \ --add-module=$root/../memc-nginx-module \ --add-module=$root/../srcache-nginx-module \ From 8e280162c688d6b00fc47690a1c7e015e8ddbb35 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 29 Jul 2016 16:46:55 +0300 Subject: [PATCH 133/651] Imported Upstream version 1.11.3 --- CHANGES | 100 +- CHANGES.ru | 101 +- auto/cc/acc | 1 - auto/cc/clang | 6 - auto/cc/conf | 2 +- auto/cc/gcc | 19 +- auto/cc/icc | 4 - auto/cc/sunc | 9 +- auto/endianness | 2 +- auto/feature | 2 +- auto/include | 5 +- auto/lib/conf | 29 - auto/lib/make | 8 - auto/lib/md5/conf | 103 -- auto/lib/md5/make | 96 - auto/lib/md5/makefile.bcc | 22 - auto/lib/md5/makefile.msvc | 22 - auto/lib/md5/makefile.owc | 11 - auto/lib/sha1/conf | 79 - auto/lib/sha1/make | 96 - auto/lib/sha1/makefile.bcc | 22 - auto/lib/sha1/makefile.msvc | 22 - auto/lib/sha1/makefile.owc | 11 - auto/lib/test | 40 - auto/module | 18 +- auto/modules | 75 +- auto/options | 68 +- auto/os/darwin | 4 +- auto/os/linux | 17 + auto/os/solaris | 2 +- auto/sources | 1 + auto/summary | 14 - auto/types/sizeof | 2 +- auto/types/typedef | 2 +- auto/types/uintptr_t | 4 +- auto/unix | 79 +- src/core/nginx.h | 4 +- src/core/ngx_conf_file.h | 1 - src/core/ngx_connection.c | 13 +- src/core/ngx_connection.h | 8 +- src/core/ngx_crypt.c | 13 - src/core/ngx_file.c | 19 +- src/core/ngx_file.h | 4 +- src/core/ngx_inet.c | 196 +- src/core/ngx_inet.h | 36 +- src/core/ngx_md5.c | 6 - src/core/ngx_md5.h | 32 - src/core/ngx_module.h | 9 - src/core/ngx_proxy_protocol.c | 52 +- src/core/ngx_resolver.c | 54 +- src/core/ngx_sha1.c | 294 +++ src/core/ngx_sha1.h | 19 +- src/core/ngx_string.c | 4 +- src/event/modules/ngx_epoll_module.c | 93 +- src/event/ngx_event.c | 35 +- src/event/ngx_event.h | 20 +- src/event/ngx_event_accept.c | 19 +- src/event/ngx_event_connect.c | 153 ++ src/event/ngx_event_connect.h | 3 + src/event/ngx_event_openssl.c | 240 ++- src/event/ngx_event_openssl.h | 5 + src/event/ngx_event_openssl_stapling.c | 150 +- src/http/modules/ngx_http_dav_module.c | 6 + src/http/modules/ngx_http_fastcgi_module.c | 2 +- src/http/modules/ngx_http_log_module.c | 4 +- src/http/modules/ngx_http_map_module.c | 126 +- src/http/modules/ngx_http_memcached_module.c | 2 +- src/http/modules/ngx_http_proxy_module.c | 10 +- src/http/modules/ngx_http_realip_module.c | 66 +- src/http/modules/ngx_http_scgi_module.c | 2 +- src/http/modules/ngx_http_ssl_module.c | 66 +- src/http/modules/ngx_http_ssl_module.h | 5 +- src/http/modules/ngx_http_sub_filter_module.c | 124 +- .../ngx_http_upstream_keepalive_module.c | 2 +- .../modules/ngx_http_userid_filter_module.c | 2 +- src/http/modules/ngx_http_uwsgi_module.c | 10 +- src/http/ngx_http.c | 73 +- src/http/ngx_http_core_module.c | 18 +- src/http/ngx_http_core_module.h | 13 +- src/http/ngx_http_file_cache.c | 11 +- src/http/ngx_http_header_filter_module.c | 37 +- src/http/ngx_http_parse.c | 38 +- src/http/ngx_http_request.c | 14 +- src/http/ngx_http_request.h | 2 + src/http/ngx_http_script.c | 14 +- src/http/ngx_http_special_response.c | 15 +- src/http/ngx_http_upstream.c | 115 +- src/http/ngx_http_upstream.h | 3 + src/http/ngx_http_upstream_round_robin.c | 11 +- src/http/ngx_http_variables.c | 132 +- src/http/v2/ngx_http_v2.c | 220 ++- src/http/v2/ngx_http_v2.h | 7 +- src/http/v2/ngx_http_v2_filter_module.c | 55 +- src/http/v2/ngx_http_v2_module.c | 31 + src/http/v2/ngx_http_v2_module.h | 1 + src/mail/ngx_mail.c | 42 +- src/mail/ngx_mail.h | 13 +- src/mail/ngx_mail_auth_http_module.c | 29 +- src/mail/ngx_mail_core_module.c | 58 +- src/mail/ngx_mail_ssl_module.c | 64 +- src/mail/ngx_mail_ssl_module.h | 5 +- src/os/unix/ngx_readv_chain.c | 32 + src/os/unix/ngx_recv.c | 33 + src/os/unix/ngx_thread_mutex.c | 2 +- src/stream/ngx_stream.c | 65 +- src/stream/ngx_stream.h | 148 +- src/stream/ngx_stream_access_module.c | 1 + src/stream/ngx_stream_core_module.c | 197 ++- src/stream/ngx_stream_geo_module.c | 1572 +++++++++++++++++ src/stream/ngx_stream_geoip_module.c | 814 +++++++++ src/stream/ngx_stream_handler.c | 9 + src/stream/ngx_stream_limit_conn_module.c | 142 +- src/stream/ngx_stream_map_module.c | 574 ++++++ src/stream/ngx_stream_proxy_module.c | 546 +++++- src/stream/ngx_stream_return_module.c | 207 +++ src/stream/ngx_stream_script.c | 854 +++++++++ src/stream/ngx_stream_script.h | 123 ++ src/stream/ngx_stream_split_clients_module.c | 244 +++ src/stream/ngx_stream_ssl_module.c | 163 +- src/stream/ngx_stream_ssl_module.h | 5 +- src/stream/ngx_stream_upstream.c | 3 +- src/stream/ngx_stream_upstream.h | 16 + src/stream/ngx_stream_upstream_hash_module.c | 26 +- .../ngx_stream_upstream_least_conn_module.c | 3 +- src/stream/ngx_stream_upstream_round_robin.c | 135 ++ src/stream/ngx_stream_upstream_round_robin.h | 2 + src/stream/ngx_stream_upstream_zone_module.c | 3 +- src/stream/ngx_stream_variables.c | 971 ++++++++++ src/stream/ngx_stream_variables.h | 109 ++ 129 files changed, 8999 insertions(+), 2028 deletions(-) delete mode 100644 auto/lib/md5/conf delete mode 100644 auto/lib/md5/make delete mode 100644 auto/lib/md5/makefile.bcc delete mode 100644 auto/lib/md5/makefile.msvc delete mode 100644 auto/lib/md5/makefile.owc delete mode 100644 auto/lib/sha1/conf delete mode 100644 auto/lib/sha1/make delete mode 100644 auto/lib/sha1/makefile.bcc delete mode 100644 auto/lib/sha1/makefile.msvc delete mode 100644 auto/lib/sha1/makefile.owc delete mode 100644 auto/lib/test create mode 100644 src/core/ngx_sha1.c create mode 100644 src/stream/ngx_stream_geo_module.c create mode 100644 src/stream/ngx_stream_geoip_module.c create mode 100644 src/stream/ngx_stream_map_module.c create mode 100644 src/stream/ngx_stream_return_module.c create mode 100644 src/stream/ngx_stream_script.c create mode 100644 src/stream/ngx_stream_script.h create mode 100644 src/stream/ngx_stream_split_clients_module.c create mode 100644 src/stream/ngx_stream_variables.c create mode 100644 src/stream/ngx_stream_variables.h diff --git a/CHANGES b/CHANGES index 4396472..a795ef2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,14 +1,108 @@ -Changes with nginx 1.10.1 31 May 2016 +Changes with nginx 1.11.3 26 Jul 2016 + + *) Change: now the "accept_mutex" directive is turned off by default. + + *) Feature: now nginx uses EPOLLEXCLUSIVE on Linux. + + *) Feature: the ngx_stream_geo_module. + + *) Feature: the ngx_stream_geoip_module. + + *) Feature: the ngx_stream_split_clients_module. + + *) Feature: variables support in the "proxy_pass" and "proxy_ssl_name" + directives in the stream module. + + *) Bugfix: socket leak when using HTTP/2. + + *) Bugfix: in configure tests. + Thanks to Piotr Sikora. + + +Changes with nginx 1.11.2 05 Jul 2016 + + *) Change: now nginx always uses internal MD5 and SHA1 implementations; + the --with-md5 and --with-sha1 configure options were canceled. + + *) Feature: variables support in the stream module. + + *) Feature: the ngx_stream_map_module. + + *) Feature: the ngx_stream_return_module. + + *) Feature: a port can be specified in the "proxy_bind", "fastcgi_bind", + "memcached_bind", "scgi_bind", and "uwsgi_bind" directives. + + *) Feature: now nginx uses the IP_BIND_ADDRESS_NO_PORT socket option + when available. + + *) Bugfix: a segmentation fault might occur in a worker process when + using HTTP/2 and the "proxy_request_buffering" directive. + + *) Bugfix: the "Content-Length" request header line was always added to + requests passed to backends, including requests without body, when + using HTTP/2. + + *) Bugfix: "http request count is zero" alerts might appear in logs when + using HTTP/2. + + *) Bugfix: unnecessary buffering might occur when using the "sub_filter" + directive; the issue had appeared in 1.9.4. + + +Changes with nginx 1.11.1 31 May 2016 *) Security: a segmentation fault might occur in a worker process while writing a specially crafted request body to a temporary file (CVE-2016-4450); the bug had appeared in 1.3.9. -Changes with nginx 1.10.0 26 Apr 2016 +Changes with nginx 1.11.0 24 May 2016 - *) 1.10.x stable branch. + *) Feature: the "transparent" parameter of the "proxy_bind", + "fastcgi_bind", "memcached_bind", "scgi_bind", and "uwsgi_bind" + directives. + + *) Feature: the $request_id variable. + + *) Feature: the "map" directive supports combinations of multiple + variables as resulting values. + + *) Feature: now nginx checks if EPOLLRDHUP events are supported by + kernel, and optimizes connection handling accordingly if the "epoll" + method is used. + + *) Feature: the "ssl_certificate" and "ssl_certificate_key" directives + can be specified multiple times to load certificates of different + types (for example, RSA and ECDSA). + + *) Feature: the "ssl_ecdh_curve" directive now allows specifying a list + of curves when using OpenSSL 1.0.2 or newer; by default a list built + into OpenSSL is used. + + *) Change: to use DHE ciphers it is now required to specify parameters + using the "ssl_dhparam" directive. + + *) Feature: the $proxy_protocol_port variable. + + *) Feature: the $realip_remote_port variable in the + ngx_http_realip_module. + + *) Feature: the ngx_http_realip_module is now able to set the client + port in addition to the address. + + *) Change: the "421 Misdirected Request" response now used when + rejecting requests to a virtual server different from one negotiated + during an SSL handshake; this improves interoperability with some + HTTP/2 clients when using client certificates. + + *) Change: HTTP/2 clients can now start sending request body + immediately; the "http2_body_preread_size" directive controls size of + the buffer used before nginx will start reading client request body. + + *) Bugfix: cached error responses were not updated when using the + "proxy_cache_bypass" directive. Changes with nginx 1.9.15 19 Apr 2016 diff --git a/CHANGES.ru b/CHANGES.ru index c96cf93..cd424e9 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,14 +1,109 @@ -Изменения в nginx 1.10.1 31.05.2016 +Изменения в nginx 1.11.3 26.07.2016 + + *) Изменение: теперь accept_mutex по умолчанию выключен. + + *) Добавление: теперь nginx использует EPOLLEXCLUSIVE на Linux. + + *) Добавление: модуль ngx_stream_geo_module. + + *) Добавление: модуль ngx_stream_geoip_module. + + *) Добавление: модуль ngx_stream_split_clients_module. + + *) Добавление: директивы proxy_pass и proxy_ssl_name в модуле stream + поддерживают переменные. + + *) Исправление: утечки сокетов при использовании HTTP/2. + + *) Исправление: в configure. + Спасибо Piotr Sikora. + + +Изменения в nginx 1.11.2 05.07.2016 + + *) Изменение: теперь nginx всегда использует внутренние реализации MD5 и + SHA1; параметры configure --with-md5 и --with-sha1 упразднены. + + *) Добавление: поддержка переменных в модуле stream. + + *) Добавление: модуль ngx_stream_map_module. + + *) Добавление: модуль ngx_stream_return_module. + + *) Добавление: в директивах proxy_bind, fastcgi_bind, memcached_bind, + scgi_bind и uwsgi_bind теперь можно указывать порт. + + *) Добавление: теперь nginx использует опцию сокета + IP_BIND_ADDRESS_NO_PORT, если она доступна. + + *) Исправление: при использовании HTTP/2 и директивы + proxy_request_buffering в рабочем процессе мог произойти segmentation + fault. + + *) Исправление: при использовании HTTP/2 к запросам, передаваемым на + бэкенд, всегда добавлялась строка заголовка "Content-Length", даже + если у запроса не было тела. + + *) Исправление: при использовании HTTP/2 в логах могли появляться + сообщения "http request count is zero". + + *) Исправление: при использовании директивы sub_filter могло + буферизироваться больше данных, чем это необходимо; проблема + появилась в 1.9.4. + + +Изменения в nginx 1.11.1 31.05.2016 *) Безопасность: при записи тела специально созданного запроса во временный файл в рабочем процессе мог происходить segmentation fault (CVE-2016-4450); ошибка появилась в 1.3.9. -Изменения в nginx 1.10.0 26.04.2016 +Изменения в nginx 1.11.0 24.05.2016 - *) Стабильная ветка 1.10.x. + *) Добавление: параметр transparent директив proxy_bind, fastcgi_bind, + memcached_bind, scgi_bind и uwsgi_bind. + + *) Добавление: переменная $request_id. + + *) Добавление: директива map поддерживает комбинации нескольких + переменных в качестве результирующих значений. + + *) Добавление: теперь при использовании метода epoll nginx проверяет, + поддерживает ли ядро события EPOLLRDHUP, и соответственно + оптимизирует обработку соединений. + + *) Добавление: директивы ssl_certificate и ssl_certificate_key теперь + можно указывать несколько раз для загрузки сертификатов разных типов + (например, RSA и ECDSA). + + *) Добавление: при использовании OpenSSL 1.0.2 и новее с помощью + директивы ssl_ecdh_curve теперь можно задать список кривых; по + умолчанию используется встроенный в OpenSSL список кривых. + + *) Изменение: для использования DHE-шифров теперь надо явно задавать + файл параметров с помощью директивы ssl_dhparam. + + *) Добавление: переменная $proxy_protocol_port. + + *) Добавление: переменная $realip_remote_port в модуле + ngx_http_realip_module. + + *) Добавление: модуль ngx_http_realip_module теперь позволяет + устанавливать не только адрес, но и порт клиента. + + *) Изменение: при попытке запросить виртуальный сервер, отличающийся от + согласованного в процессе SSL handshake, теперь возвращается ответ + "421 Misdirected Request"; это улучшает совместимость с некоторыми + HTTP/2-клиентами в случае использования клиентских сертификатов. + + *) Изменение: HTTP/2-клиенты теперь могут сразу присылать тело запроса; + директива http2_body_preread_size позволяет указать размер буфера, + который будет использоваться до того, как nginx начнёт читать тело. + + *) Исправление: при использовании директивы proxy_cache_bypass не + обновлялись закэшированные ошибочные ответы. Изменения в nginx 1.9.15 19.04.2016 diff --git a/auto/cc/acc b/auto/cc/acc index 6baee67..64fa671 100644 --- a/auto/cc/acc +++ b/auto/cc/acc @@ -12,4 +12,3 @@ CC_TEST_FLAGS="-Ae" PCRE_OPT="$PCRE_OPT -Ae" ZLIB_OPT="$ZLIB_OPT -Ae" -MD5_OPT="$MD5_OPT -Ae" diff --git a/auto/cc/clang b/auto/cc/clang index 25707b4..19bdaaa 100644 --- a/auto/cc/clang +++ b/auto/cc/clang @@ -66,12 +66,6 @@ else PCRE_OPT="$PCRE_OPT -pipe" fi -if [ ".$MD5_OPT" = "." ]; then - MD5_OPT="-O2 -pipe $CPU_OPT" -else - MD5_OPT="$MD5_OPT -pipe" -fi - if [ ".$ZLIB_OPT" = "." ]; then ZLIB_OPT="-O2 -pipe $CPU_OPT" else diff --git a/auto/cc/conf b/auto/cc/conf index f2c25ed..b3b9f92 100644 --- a/auto/cc/conf +++ b/auto/cc/conf @@ -231,7 +231,7 @@ if [ "$NGX_PLATFORM" != win32 ]; then ngx_feature_incs= ngx_feature_path= ngx_feature_libs= - ngx_feature_test="__builtin_bswap64(0)" + ngx_feature_test="if (__builtin_bswap64(0)) return 1" . auto/feature diff --git a/auto/cc/gcc b/auto/cc/gcc index c9101fe..a5c5c18 100644 --- a/auto/cc/gcc +++ b/auto/cc/gcc @@ -128,12 +128,6 @@ else PCRE_OPT="$PCRE_OPT $PIPE" fi -if [ ".$MD5_OPT" = "." ]; then - MD5_OPT="-O2 -fomit-frame-pointer $PIPE $CPU_OPT" -else - MD5_OPT="$MD5_OPT $PIPE" -fi - if [ ".$ZLIB_OPT" = "." ]; then ZLIB_OPT="-O2 -fomit-frame-pointer $PIPE $CPU_OPT" else @@ -151,9 +145,13 @@ CFLAGS="$CFLAGS -Wall -Wpointer-arith" #CFLAGS="$CFLAGS -Winline" #CFLAGS="$CFLAGS -Wmissing-prototypes" - case "$NGX_GCC_VER" in - [3-5].*) + 2.*) + # we have a lot of the unused function arguments + CFLAGS="$CFLAGS -Wno-unused" + ;; + + *) # we have a lot of the unused function arguments CFLAGS="$CFLAGS -Wno-unused-parameter" # 4.2.1 shows the warning in wrong places @@ -164,11 +162,6 @@ case "$NGX_GCC_VER" in CFLAGS="$CFLAGS -Wno-deprecated-declarations" fi ;; - - *) - # we have a lot of the unused function arguments - CFLAGS="$CFLAGS -Wno-unused" - ;; esac diff --git a/auto/cc/icc b/auto/cc/icc index 1c0df1a..c47f6e4 100644 --- a/auto/cc/icc +++ b/auto/cc/icc @@ -43,10 +43,6 @@ if [ ".$PCRE_OPT" = "." ]; then PCRE_OPT="-O $CPU_OPT" fi -if [ ".$MD5_OPT" = "." ]; then - MD5_OPT="-O $CPU_OPT" -fi - if [ ".$ZLIB_OPT" = "." ]; then ZLIB_OPT="-O $CPU_OPT" fi diff --git a/auto/cc/sunc b/auto/cc/sunc index 8360c49..806ccc4 100644 --- a/auto/cc/sunc +++ b/auto/cc/sunc @@ -20,7 +20,10 @@ have=NGX_COMPILER value="\"Sun C $NGX_SUNC_VER\"" . auto/define cat << END > $NGX_AUTOTEST.c -int main() { printf("%d", __SUNPRO_C); } +int main(void) { + printf("%d", __SUNPRO_C); + return 0; +} END @@ -145,10 +148,6 @@ if [ ".$PCRE_OPT" = "." ]; then PCRE_OPT="$ngx_fast $IPO $CPU_OPT" fi -if [ ".$MD5_OPT" = "." ]; then - MD5_OPT="$ngx_fast $IPO $CPU_OPT" -fi - if [ ".$ZLIB_OPT" = "." ]; then ZLIB_OPT="$ngx_fast $IPO $CPU_OPT" fi diff --git a/auto/endianness b/auto/endianness index 70b0a10..1b552b6 100644 --- a/auto/endianness +++ b/auto/endianness @@ -15,7 +15,7 @@ END cat << END > $NGX_AUTOTEST.c -int main() { +int main(void) { int i = 0x11223344; char *p; diff --git a/auto/feature b/auto/feature index 1145f28..3561f59 100644 --- a/auto/feature +++ b/auto/feature @@ -31,7 +31,7 @@ cat << END > $NGX_AUTOTEST.c $NGX_INCLUDE_UNISTD_H $ngx_feature_incs -int main() { +int main(void) { $ngx_feature_test; return 0; } diff --git a/auto/include b/auto/include index e34dabd..c1bd364 100644 --- a/auto/include +++ b/auto/include @@ -20,7 +20,7 @@ cat << END > $NGX_AUTOTEST.c $NGX_INCLUDE_SYS_PARAM_H #include <$ngx_include> -int main() { +int main(void) { return 0; } @@ -45,9 +45,6 @@ if [ -x $NGX_AUTOTEST ]; then eval "NGX_INCLUDE_$ngx_name='#include <$ngx_include>'" - #STUB - eval "NGX_$ngx_name='#include <$ngx_include>'" - else echo " not found" diff --git a/auto/lib/conf b/auto/lib/conf index a6242e7..0b8545a 100644 --- a/auto/lib/conf +++ b/auto/lib/conf @@ -25,35 +25,6 @@ if [ $USE_OPENSSL = YES ]; then . auto/lib/openssl/conf fi -if [ $USE_MD5 = YES ]; then - - if [ $USE_OPENSSL = YES ]; then - have=NGX_HAVE_OPENSSL_MD5_H . auto/have - have=NGX_OPENSSL_MD5 . auto/have - have=NGX_HAVE_MD5 . auto/have - MD5=YES - MD5_LIB=OpenSSL - - else - . auto/lib/md5/conf - fi - -fi - -if [ $USE_SHA1 = YES ]; then - - if [ $USE_OPENSSL = YES ]; then - have=NGX_HAVE_OPENSSL_SHA1_H . auto/have - have=NGX_HAVE_SHA1 . auto/have - SHA1=YES - SHA1_LIB=OpenSSL - - else - . auto/lib/sha1/conf - fi - -fi - if [ $USE_ZLIB = YES ]; then . auto/lib/zlib/conf fi diff --git a/auto/lib/make b/auto/lib/make index 6298b94..b64e329 100644 --- a/auto/lib/make +++ b/auto/lib/make @@ -7,14 +7,6 @@ if [ $PCRE != NONE -a $PCRE != NO -a $PCRE != YES ]; then . auto/lib/pcre/make fi -if [ $MD5 != NONE -a $MD5 != NO -a $MD5 != YES ]; then - . auto/lib/md5/make -fi - -if [ $SHA1 != NONE -a $SHA1 != NO -a $SHA1 != YES ]; then - . auto/lib/sha1/make -fi - if [ $OPENSSL != NONE -a $OPENSSL != NO -a $OPENSSL != YES ]; then . auto/lib/openssl/make fi diff --git a/auto/lib/md5/conf b/auto/lib/md5/conf deleted file mode 100644 index 49c0ddf..0000000 --- a/auto/lib/md5/conf +++ /dev/null @@ -1,103 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) Nginx, Inc. - - -if [ $MD5 != NONE ]; then - - if grep MD5_Init $MD5/md5.h 2>&1 >/dev/null; then - # OpenSSL md5 - OPENSSL_MD5=YES - have=NGX_HAVE_OPENSSL_MD5 . auto/have - have=NGX_OPENSSL_MD5 . auto/have - else - # rsaref md5 - OPENSSL_MD5=NO - fi - - have=NGX_HAVE_MD5 . auto/have - CORE_INCS="$CORE_INCS $MD5" - - case "$NGX_CC_NAME" in - - msvc | owc | bcc) - LINK_DEPS="$LINK_DEPS $MD5/md5.lib" - CORE_LIBS="$CORE_LIBS $MD5/md5.lib" - ;; - - icc) - LINK_DEPS="$LINK_DEPS $MD5/libmd5.a" - - # to allow -ipo optimization we link with the *.o but not library - CORE_LIBS="$CORE_LIBS $MD5/md5_dgst.o" - - if [ $MD5_ASM = YES ]; then - CORE_LIBS="$CORE_LIBS $MD5/asm/mx86-elf.o" - fi - ;; - - *) - LINK_DEPS="$LINK_DEPS $MD5/libmd5.a" - CORE_LIBS="$CORE_LIBS $MD5/libmd5.a" - #CORE_LIBS="$CORE_LIBS -L $MD5 -lmd5" - ;; - - esac - -else - - if [ "$NGX_PLATFORM" != win32 ]; then - - MD5=NO - - # FreeBSD, Solaris 10 - - ngx_feature="md5 in system md library" - ngx_feature_name=NGX_HAVE_MD5 - ngx_feature_run=no - ngx_feature_incs="#include " - ngx_feature_path= - ngx_feature_libs="-lmd" - ngx_feature_test="MD5_CTX md5; MD5Init(&md5)" - . auto/feature - - ngx_md5_lib="system md" - - if [ $ngx_found = no ]; then - - # Solaris 8/9 - - ngx_feature="md5 in system md5 library" - ngx_feature_libs="-lmd5" - . auto/feature - - ngx_md5_lib="system md5" - fi - - if [ $ngx_found = no ]; then - - # OpenSSL crypto library - - ngx_feature="md5 in system OpenSSL crypto library" - ngx_feature_name="NGX_OPENSSL_MD5" - ngx_feature_incs="#include " - ngx_feature_libs="-lcrypto" - ngx_feature_test="MD5_CTX md5; MD5_Init(&md5)" - . auto/feature - - ngx_md5_lib="system crypto" - - if [ $ngx_found = yes ]; then - have=NGX_HAVE_OPENSSL_MD5_H . auto/have - have=NGX_HAVE_MD5 . auto/have - fi - fi - - if [ $ngx_found = yes ]; then - CORE_LIBS="$CORE_LIBS $ngx_feature_libs" - MD5=YES - MD5_LIB=$ngx_md5_lib - fi - fi - -fi diff --git a/auto/lib/md5/make b/auto/lib/md5/make deleted file mode 100644 index 7000b20..0000000 --- a/auto/lib/md5/make +++ /dev/null @@ -1,96 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) Nginx, Inc. - - -case "$NGX_CC_NAME" in - - msvc) - ngx_makefile=makefile.msvc - ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC MD5_ASM=$MD5_ASM" - ngx_md5="MD5=\"$MD5\"" - ;; - - owc) - ngx_makefile=makefile.owc - ngx_opt="CPU_OPT=\"$CPU_OPT\"" - ngx_md5=`echo MD5=\"$MD5\" | sed -e "s/\//$ngx_regex_dirsep/g"` - ;; - - bcc) - ngx_makefile=makefile.bcc - ngx_opt="-DCPU_OPT=\"$CPU_OPT\" -DMD5_ASM=$MD5_ASM" - ngx_md5=`echo \-DMD5=\"$MD5\" | sed -e "s/\//$ngx_regex_dirsep/g"` - ;; - -esac - - -done=NO - - -case "$NGX_PLATFORM" in - - win32) - cat << END >> $NGX_MAKEFILE - -`echo "$MD5/md5.lib: $NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"` - \$(MAKE) -f auto/lib/md5/$ngx_makefile $ngx_opt $ngx_md5 - -END - - done=YES - ;; - - SunOS:*:i86pc) - if [ $MD5_ASM = YES ]; then - - cat << END >> $NGX_MAKEFILE - -$MD5/libmd5.a: $NGX_MAKEFILE - cd $MD5 \\ - && \$(MAKE) CFLAGS="$MD5_OPT -DSOL -DMD5_ASM -DL_ENDIAN" \\ - CC="\$(CC)" CPP="\$(CPP)" \\ - MD5_ASM_OBJ=asm/mx86-sol.o clean libmd5.a - -END - - done=YES - fi - ;; - - # FreeBSD: i386 - # Linux: i686 - - *:i386 | *:i686) - if [ $MD5_ASM = YES ]; then - - cat << END >> $NGX_MAKEFILE - -$MD5/libmd5.a: $NGX_MAKEFILE - cd $MD5 \\ - && \$(MAKE) CFLAGS="$MD5_OPT -DELF -DMD5_ASM -DL_ENDIAN" \\ - CC="\$(CC)" CPP="\$(CPP)" \\ - MD5_ASM_OBJ=asm/mx86-elf.o clean libmd5.a - -END - - done=YES - fi - ;; - -esac - - -if [ $done = NO ]; then - - cat << END >> $NGX_MAKEFILE - -$MD5/libmd5.a: $NGX_MAKEFILE - cd $MD5 \\ - && \$(MAKE) CFLAGS="$MD5_OPT" \\ - CC="\$(CC)" MD5_ASM_OBJ= clean libmd5.a - -END - -fi diff --git a/auto/lib/md5/makefile.bcc b/auto/lib/md5/makefile.bcc deleted file mode 100644 index eb6fb62..0000000 --- a/auto/lib/md5/makefile.bcc +++ /dev/null @@ -1,22 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) Nginx, Inc. - - -CFLAGS = -q -O2 -tWM $(CPU_OPT) -DL_ENDIAN - -!if "$(MD5_ASM)" == "YES" - -md5.lib: - cd $(MD5) - bcc32 -c $(CFLAGS) -DMD5_ASM md5_dgst.c - tlib md5.lib +md5_dgst.obj +"asm\m-win32.obj" - -!else - -md5.lib: - cd $(MD5) - bcc32 -c $(CFLAGS) md5_dgst.c - tlib md5.lib +md5_dgst.obj - -!endif diff --git a/auto/lib/md5/makefile.msvc b/auto/lib/md5/makefile.msvc deleted file mode 100644 index 90d62fa..0000000 --- a/auto/lib/md5/makefile.msvc +++ /dev/null @@ -1,22 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) Nginx, Inc. - - -CFLAGS = -nologo -O2 -Ob1 -Oi -Gs $(LIBC) $(CPU_OPT) -D L_ENDIAN - -!IF "$(MD5_ASM)" == "YES" - -md5.lib: - cd $(MD5) - cl -c $(CFLAGS) -D MD5_ASM md5_dgst.c - link -lib -out:md5.lib md5_dgst.obj asm/m-win32.obj - -!ELSE - -md5.lib: - cd $(MD5) - cl -c $(CFLAGS) md5_dgst.c - link -lib -out:md5.lib md5_dgst.obj - -!ENDIF diff --git a/auto/lib/md5/makefile.owc b/auto/lib/md5/makefile.owc deleted file mode 100644 index 78c1e61..0000000 --- a/auto/lib/md5/makefile.owc +++ /dev/null @@ -1,11 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) Nginx, Inc. - - -CFLAGS = -zq -bt=nt -bm -ot -op -oi -oe -s $(CPU_OPT) - -md5.lib: - cd $(MD5) - wcl386 -c $(CFLAGS) -dL_ENDIAN md5_dgst.c - wlib -n md5.lib md5_dgst.obj diff --git a/auto/lib/sha1/conf b/auto/lib/sha1/conf deleted file mode 100644 index 78f9efd..0000000 --- a/auto/lib/sha1/conf +++ /dev/null @@ -1,79 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) Nginx, Inc. - - -if [ $SHA1 != NONE ]; then - - have=NGX_HAVE_SHA1 . auto/have - CORE_INCS="$CORE_INCS $SHA1" - - case "$NGX_CC_NAME" in - - msvc | owc | bcc) - LINK_DEPS="$LINK_DEPS $SHA1/sha1.lib" - CORE_LIBS="$CORE_LIBS $SHA1/sha1.lib" - ;; - - icc) - LINK_DEPS="$LINK_DEPS $SHA1/libsha.a" - - # to allow -ipo optimization we link with the *.o but not library - CORE_LIBS="$CORE_LIBS $SHA1/sha1_dgst.o" - - if [ $SHA1_ASM = YES ]; then - CORE_LIBS="$CORE_LIBS $SHA1/asm/sx86-elf.o" - fi - ;; - - *) - LINK_DEPS="$LINK_DEPS $SHA1/libsha.a" - CORE_LIBS="$CORE_LIBS $SHA1/libsha.a" - #CORE_LIBS="$CORE_LIBS -L $SHA1 -lsha" - ;; - - esac - -else - - if [ "$NGX_PLATFORM" != win32 ]; then - - SHA1=NO - - # FreeBSD - - ngx_feature="sha1 in system md library" - ngx_feature_name=NGX_HAVE_SHA1 - ngx_feature_run=no - ngx_feature_incs="#include " - ngx_feature_path= - ngx_feature_libs="-lmd" - ngx_feature_test="SHA_CTX sha1; SHA1_Init(&sha1)" - . auto/feature - - ngx_sha1_lib="system md" - - if [ $ngx_found = no ]; then - - # OpenSSL crypto library - - ngx_feature="sha1 in system OpenSSL crypto library" - ngx_feature_incs="#include " - ngx_feature_libs="-lcrypto" - . auto/feature - - ngx_sha1_lib="system crypto" - - if [ $ngx_found = yes ]; then - have=NGX_HAVE_OPENSSL_SHA1_H . auto/have - fi - fi - - if [ $ngx_found = yes ]; then - CORE_LIBS="$CORE_LIBS $ngx_feature_libs" - SHA1=YES - SHA1_LIB=$ngx_sha1_lib - fi - fi - -fi diff --git a/auto/lib/sha1/make b/auto/lib/sha1/make deleted file mode 100644 index fc3b340..0000000 --- a/auto/lib/sha1/make +++ /dev/null @@ -1,96 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) Nginx, Inc. - - -case "$NGX_CC_NAME" in - - msvc) - ngx_makefile=makefile.msvc - ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC SHA1_ASM=$SHA1_ASM" - ngx_sha1="SHA1=\"$SHA1\"" - ;; - - owc) - ngx_makefile=makefile.owc - ngx_opt="CPU_OPT=\"$CPU_OPT\"" - ngx_sha1=`echo SHA1=\"$SHA1\" | sed -e "s/\//$ngx_regex_dirsep/g"` - ;; - - bcc) - ngx_makefile=makefile.bcc - ngx_opt="-DCPU_OPT=\"$CPU_OPT\" -DSHA1_ASM=$SHA1_ASM" - ngx_sha1=`echo \-DSHA1=\"$SHA1\" | sed -e "s/\//$ngx_regex_dirsep/g"` - ;; - -esac - - -done=NO - - -case "$NGX_PLATFORM" in - - win32) - cat << END >> $NGX_MAKEFILE - -`echo "$SHA1/sha1.lib: $NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"` - \$(MAKE) -f auto/lib/sha1/$ngx_makefile $ngx_opt $ngx_sha1 - -END - - done=YES - ;; - - SunOS:*:i86pc) - if [ $SHA1_ASM = YES ]; then - - cat << END >> $NGX_MAKEFILE - -$SHA1/libsha.a: $NGX_MAKEFILE - cd $SHA1 \\ - && \$(MAKE) CFLAGS="$SHA1_OPT -DSOL -DSHA1_ASM -DL_ENDIAN" \\ - CC="\$(CC)" CPP="\$(CPP)" \\ - SHA_ASM_OBJ=asm/sx86-sol.o clean libsha.a - -END - - done=YES - fi - ;; - - # FreeBSD: i386 - # Linux: i686 - - *:i386 | *:i686) - if [ $SHA1_ASM = YES ]; then - - cat << END >> $NGX_MAKEFILE - -$SHA1/libsha.a: $NGX_MAKEFILE - cd $SHA1 \\ - && \$(MAKE) CFLAGS="$SHA1_OPT -DELF -DSHA1_ASM -DL_ENDIAN" \\ - CC="\$(CC)" CPP="\$(CPP)" \\ - SHA_ASM_OBJ=asm/sx86-elf.o clean libsha.a - -END - - done=YES - fi - ;; - -esac - - -if [ $done = NO ]; then - - cat << END >> $NGX_MAKEFILE - -$SHA1/libsha.a: $NGX_MAKEFILE - cd $SHA1 \\ - && \$(MAKE) CFLAGS="$SHA1_OPT" \\ - CC="\$(CC)" SHA_ASM_OBJ= clean libsha.a - -END - -fi diff --git a/auto/lib/sha1/makefile.bcc b/auto/lib/sha1/makefile.bcc deleted file mode 100644 index b0685fa..0000000 --- a/auto/lib/sha1/makefile.bcc +++ /dev/null @@ -1,22 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) Nginx, Inc. - - -CFLAGS = -q -O2 -tWM $(CPU_OPT) -DL_ENDIAN - -!if "$(SHA1_ASM)" == "YES" - -sha1.lib: - cd $(SHA1) - bcc32 -c $(CFLAGS) -DSHA1_ASM sha1dgst.c - tlib sha1.lib +sha1dgst.obj +"asm\s-win32.obj" - -!else - -sha1.lib: - cd $(SHA1) - bcc32 -c $(CFLAGS) sha1dgst.c - tlib sha1.lib +sha1dgst.obj - -!endif diff --git a/auto/lib/sha1/makefile.msvc b/auto/lib/sha1/makefile.msvc deleted file mode 100644 index 3cbd21b..0000000 --- a/auto/lib/sha1/makefile.msvc +++ /dev/null @@ -1,22 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) Nginx, Inc. - - -CFLAGS = -nologo -O2 -Ob1 -Oi -Gs $(LIBC) $(CPU_OPT) -D L_ENDIAN - -!IF "$(SHA1_ASM)" == "YES" - -sha1.lib: - cd $(SHA1) - cl -c $(CFLAGS) -D SHA1_ASM sha1dgst.c - link -lib -out:sha1.lib sha1dgst.obj asm/s-win32.obj - -!ELSE - -sha1.lib: - cd $(SHA1) - cl -c $(CFLAGS) sha1dgst.c - link -lib -out:sha1.lib sha1dgst.obj - -!ENDIF diff --git a/auto/lib/sha1/makefile.owc b/auto/lib/sha1/makefile.owc deleted file mode 100644 index fc095cc..0000000 --- a/auto/lib/sha1/makefile.owc +++ /dev/null @@ -1,11 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) Nginx, Inc. - - -CFLAGS = -zq -bt=nt -bm -ot -op -oi -oe -s $(CPU_OPT) - -sha1.lib: - cd $(SHA1) - wcl386 -c $(CFLAGS) -dL_ENDIAN sha1dgst.c - wlib -n sha1.lib sha1dgst.obj diff --git a/auto/lib/test b/auto/lib/test deleted file mode 100644 index ba943a2..0000000 --- a/auto/lib/test +++ /dev/null @@ -1,40 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) Nginx, Inc. - - -echo $ngx_n "checking for $ngx_lib ...$ngx_c" - -cat << END >> $NGX_AUTOCONF_ERR - ----------------------------------------- -checking for $ngx_lib - -END - -ngx_found=no - -cat << END > $NGX_AUTOTEST.c - -$ngx_lib_incs - -int main() { - $ngx_lib_test; - return 0; -} - - -eval "$CC $cc_test_flags $ngx_lib_cflags \ - -o $NGX_AUTOTEST $NGX_AUTOTEST.c $ngx_libs \ - >> $NGX_ERR 2>&1" - -if [ -x $NGX_AUTOTEST ]; then - echo " found" - - ngx_found=yes - -else - echo " not found" -fi - -rm -rf $NGX_AUTOTEST* diff --git a/auto/module b/auto/module index 16a816f..3b00a07 100644 --- a/auto/module +++ b/auto/module @@ -48,10 +48,14 @@ if [ "$ngx_module_link" = DYNAMIC ]; then fi ;; - PCRE | OPENSSL | MD5 | SHA1 | ZLIB) + PCRE | OPENSSL | ZLIB) eval USE_${lib}=YES ;; + MD5 | SHA1) + # obsolete + ;; + *) libs="$libs $lib" ;; @@ -79,10 +83,14 @@ elif [ "$ngx_module_link" = YES ]; then do case $lib in - PCRE | OPENSSL | MD5 | SHA1 | ZLIB | LIBXSLT | LIBGD | PERL | GEOIP) + PCRE | OPENSSL | ZLIB | LIBXSLT | LIBGD | PERL | GEOIP) eval USE_${lib}=YES ;; + MD5 | SHA1) + # obsolete + ;; + *) CORE_LIBS="$CORE_LIBS $lib" ;; @@ -109,10 +117,14 @@ elif [ "$ngx_module_link" = ADDON ]; then do case $lib in - PCRE | OPENSSL | MD5 | SHA1 | ZLIB | LIBXSLT | LIBGD | PERL | GEOIP) + PCRE | OPENSSL | ZLIB | LIBXSLT | LIBGD | PERL | GEOIP) eval USE_${lib}=YES ;; + MD5 | SHA1) + # obsolete + ;; + *) CORE_LIBS="$CORE_LIBS $lib" ;; diff --git a/auto/modules b/auto/modules index 22ff6d9..614037c 100644 --- a/auto/modules +++ b/auto/modules @@ -43,6 +43,7 @@ fi if [ $NGX_TEST_BUILD_EPOLL = YES ]; then have=NGX_HAVE_EPOLL . auto/have have=NGX_HAVE_EPOLLRDHUP . auto/have + have=NGX_HAVE_EPOLLEXCLUSIVE . auto/have have=NGX_HAVE_EVENTFD . auto/have have=NGX_TEST_BUILD_EPOLL . auto/have EVENT_MODULES="$EVENT_MODULES $EPOLL_MODULE" @@ -101,7 +102,6 @@ fi if [ $HTTP_CACHE = YES ]; then - USE_MD5=YES have=NGX_HTTP_CACHE . auto/have HTTP_SRCS="$HTTP_SRCS $HTTP_FILE_CACHE_SRCS" fi @@ -522,8 +522,6 @@ if [ $HTTP_AUTH_REQUEST = YES ]; then fi if [ $HTTP_AUTH_BASIC = YES ]; then - USE_MD5=YES - USE_SHA1=YES have=NGX_CRYPT . auto/have ngx_module_name=ngx_http_auth_basic_module @@ -682,7 +680,6 @@ fi if [ $HTTP_PROXY = YES ]; then have=NGX_HTTP_X_FORWARDED_FOR . auto/have - #USE_MD5=YES ngx_module_name=ngx_http_proxy_module ngx_module_incs= @@ -772,8 +769,6 @@ if [ $HTTP_BROWSER = YES ]; then fi if [ $HTTP_SECURE_LINK = YES ]; then - USE_MD5=YES - ngx_module_name=ngx_http_secure_link_module ngx_module_incs= ngx_module_deps= @@ -971,8 +966,6 @@ if [ $STREAM != NO ]; then STREAM_INCS= ngx_module_type=STREAM - ngx_module_libs= - ngx_module_link=YES ngx_module_order= @@ -982,9 +975,13 @@ if [ $STREAM != NO ]; then ngx_stream_upstream_module" ngx_module_incs="src/stream" ngx_module_deps="src/stream/ngx_stream.h \ + src/stream/ngx_stream_variables.h \ + src/stream/ngx_stream_script.h \ src/stream/ngx_stream_upstream.h \ src/stream/ngx_stream_upstream_round_robin.h" ngx_module_srcs="src/stream/ngx_stream.c \ + src/stream/ngx_stream_variables.c \ + src/stream/ngx_stream_script.c \ src/stream/ngx_stream_handler.c \ src/stream/ngx_stream_core_module.c \ src/stream/ngx_stream_proxy_module.c \ @@ -1002,6 +999,8 @@ if [ $STREAM != NO ]; then ngx_module_name=ngx_stream_ssl_module ngx_module_deps=src/stream/ngx_stream_ssl_module.h ngx_module_srcs=src/stream/ngx_stream_ssl_module.c + ngx_module_libs= + ngx_module_link=$STREAM_SSL . auto/module fi @@ -1010,6 +1009,8 @@ if [ $STREAM != NO ]; then ngx_module_name=ngx_stream_limit_conn_module ngx_module_deps= ngx_module_srcs=src/stream/ngx_stream_limit_conn_module.c + ngx_module_libs= + ngx_module_link=$STREAM_LIMIT_CONN . auto/module fi @@ -1018,6 +1019,58 @@ if [ $STREAM != NO ]; then ngx_module_name=ngx_stream_access_module ngx_module_deps= ngx_module_srcs=src/stream/ngx_stream_access_module.c + ngx_module_libs= + ngx_module_link=$STREAM_ACCESS + + . auto/module + fi + + if [ $STREAM_GEO = YES ]; then + ngx_module_name=ngx_stream_geo_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_geo_module.c + ngx_module_libs= + ngx_module_link=$STREAM_GEO + + . auto/module + fi + + if [ $STREAM_GEOIP != NO ]; then + ngx_module_name=ngx_stream_geoip_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_geoip_module.c + ngx_module_libs=GEOIP + ngx_module_link=$STREAM_GEOIP + + . auto/module + fi + + if [ $STREAM_MAP = YES ]; then + ngx_module_name=ngx_stream_map_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_map_module.c + ngx_module_libs= + ngx_module_link=$STREAM_MAP + + . auto/module + fi + + if [ $STREAM_SPLIT_CLIENTS = YES ]; then + ngx_module_name=ngx_stream_split_clients_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_split_clients_module.c + ngx_module_libs= + ngx_module_link=$STREAM_SPLIT_CLIENTS + + . auto/module + fi + + if [ $STREAM_RETURN = YES ]; then + ngx_module_name=ngx_stream_return_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_return_module.c + ngx_module_libs= + ngx_module_link=$STREAM_RETURN . auto/module fi @@ -1026,6 +1079,8 @@ if [ $STREAM != NO ]; then ngx_module_name=ngx_stream_upstream_hash_module ngx_module_deps= ngx_module_srcs=src/stream/ngx_stream_upstream_hash_module.c + ngx_module_libs= + ngx_module_link=$STREAM_UPSTREAM_HASH . auto/module fi @@ -1034,6 +1089,8 @@ if [ $STREAM != NO ]; then ngx_module_name=ngx_stream_upstream_least_conn_module ngx_module_deps= ngx_module_srcs=src/stream/ngx_stream_upstream_least_conn_module.c + ngx_module_libs= + ngx_module_link=$STREAM_UPSTREAM_LEAST_CONN . auto/module fi @@ -1044,6 +1101,8 @@ if [ $STREAM != NO ]; then ngx_module_name=ngx_stream_upstream_zone_module ngx_module_deps= ngx_module_srcs=src/stream/ngx_stream_upstream_zone_module.c + ngx_module_libs= + ngx_module_link=$STREAM_UPSTREAM_ZONE . auto/module fi diff --git a/auto/options b/auto/options index ac8beb1..a8fce30 100644 --- a/auto/options +++ b/auto/options @@ -117,6 +117,11 @@ STREAM=NO STREAM_SSL=NO STREAM_LIMIT_CONN=YES STREAM_ACCESS=YES +STREAM_GEO=YES +STREAM_GEOIP=NO +STREAM_MAP=YES +STREAM_SPLIT_CLIENTS=YES +STREAM_RETURN=YES STREAM_UPSTREAM_HASH=YES STREAM_UPSTREAM_LEAST_CONN=YES STREAM_UPSTREAM_ZONE=YES @@ -136,16 +141,6 @@ PCRE_JIT=NO USE_OPENSSL=NO OPENSSL=NONE -USE_MD5=NO -MD5=NONE -MD5_OPT= -MD5_ASM=NO - -USE_SHA1=NO -SHA1=NONE -SHA1_OPT= -SHA1_ASM=NO - USE_ZLIB=NO ZLIB=NONE ZLIB_OPT= @@ -301,9 +296,17 @@ use the \"--with-mail_ssl_module\" option instead" --with-stream) STREAM=YES ;; --with-stream=dynamic) STREAM=DYNAMIC ;; --with-stream_ssl_module) STREAM_SSL=YES ;; + --with-stream_geoip_module) STREAM_GEOIP=YES ;; + --with-stream_geoip_module=dynamic) + STREAM_GEOIP=DYNAMIC ;; --without-stream_limit_conn_module) STREAM_LIMIT_CONN=NO ;; --without-stream_access_module) STREAM_ACCESS=NO ;; + --without-stream_geo_module) STREAM_GEO=NO ;; + --without-stream_map_module) STREAM_MAP=NO ;; + --without-stream_split_clients_module) + STREAM_SPLIT_CLIENTS=NO ;; + --without-stream_return_module) STREAM_RETURN=NO ;; --without-stream_upstream_hash_module) STREAM_UPSTREAM_HASH=NO ;; --without-stream_upstream_least_conn_module) @@ -333,13 +336,31 @@ use the \"--with-mail_ssl_module\" option instead" --with-openssl=*) OPENSSL="$value" ;; --with-openssl-opt=*) OPENSSL_OPT="$value" ;; - --with-md5=*) MD5="$value" ;; - --with-md5-opt=*) MD5_OPT="$value" ;; - --with-md5-asm) MD5_ASM=YES ;; + --with-md5=*) + NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG +$0: warning: the \"--with-md5\" option is deprecated" + ;; + --with-md5-opt=*) + NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG +$0: warning: the \"--with-md5-opt\" option is deprecated" + ;; + --with-md5-asm) + NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG +$0: warning: the \"--with-md5-asm\" option is deprecated" + ;; - --with-sha1=*) SHA1="$value" ;; - --with-sha1-opt=*) SHA1_OPT="$value" ;; - --with-sha1-asm) SHA1_ASM=YES ;; + --with-sha1=*) + NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG +$0: warning: the \"--with-sha1\" option is deprecated" + ;; + --with-sha1-opt=*) + NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG +$0: warning: the \"--with-sha1-opt\" option is deprecated" + ;; + --with-sha1-asm) + NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG +$0: warning: the \"--with-sha1-asm\" option is deprecated" + ;; --with-zlib=*) ZLIB="$value" ;; --with-zlib-opt=*) ZLIB_OPT="$value" ;; @@ -482,8 +503,15 @@ cat << END --with-stream enable TCP/UDP proxy module --with-stream=dynamic enable dynamic TCP/UDP proxy module --with-stream_ssl_module enable ngx_stream_ssl_module + --with-stream_geoip_module enable ngx_stream_geoip_module + --with-stream_geoip_module=dynamic enable dynamic ngx_stream_geoip_module --without-stream_limit_conn_module disable ngx_stream_limit_conn_module --without-stream_access_module disable ngx_stream_access_module + --without-stream_geo_module disable ngx_stream_geo_module + --without-stream_map_module disable ngx_stream_map_module + --without-stream_split_clients_module + disable ngx_stream_split_clients_module + --without-stream_return_module disable ngx_stream_return_module --without-stream_upstream_hash_module disable ngx_stream_upstream_hash_module --without-stream_upstream_least_conn_module @@ -511,14 +539,6 @@ cat << END --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 - --with-md5-asm use md5 assembler sources - - --with-sha1=DIR set path to sha1 library sources - --with-sha1-opt=OPTIONS set additional build options for sha1 - --with-sha1-asm use sha1 assembler sources - --with-zlib=DIR set path to zlib library sources --with-zlib-opt=OPTIONS set additional build options for zlib --with-zlib-asm=CPU use zlib assembler sources optimized diff --git a/auto/os/darwin b/auto/os/darwin index 9b31b1f..b4b3ad3 100644 --- a/auto/os/darwin +++ b/auto/os/darwin @@ -113,6 +113,6 @@ ngx_feature_run=no ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs= -ngx_feature_test="int32_t lock, n; - n = OSAtomicCompareAndSwap32Barrier(0, 1, &lock)" +ngx_feature_test="int32_t lock = 0; + if (!OSAtomicCompareAndSwap32Barrier(0, 1, &lock)) return 1" . auto/feature diff --git a/auto/os/linux b/auto/os/linux index c932267..fae8842 100644 --- a/auto/os/linux +++ b/auto/os/linux @@ -44,6 +44,7 @@ ngx_feature_test="int efd = 0; struct epoll_event ee; ee.events = EPOLLIN|EPOLLOUT|EPOLLET; ee.data.ptr = NULL; + (void) ee; efd = epoll_create(100); if (efd == -1) return 1;" . auto/feature @@ -69,6 +70,22 @@ if [ $ngx_found = yes ]; then ee.data.ptr = NULL; epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ee)" . auto/feature + + + # EPOLLEXCLUSIVE appeared in Linux 4.5, glibc 2.24 + + ngx_feature="EPOLLEXCLUSIVE" + ngx_feature_name="NGX_HAVE_EPOLLEXCLUSIVE" + ngx_feature_run=no + ngx_feature_incs="#include " + ngx_feature_path= + ngx_feature_libs= + ngx_feature_test="int efd = 0, fd = 0; + struct epoll_event ee; + ee.events = EPOLLIN|EPOLLEXCLUSIVE; + ee.data.ptr = NULL; + epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ee)" + . auto/feature fi diff --git a/auto/os/solaris b/auto/os/solaris index d39df0b..1dcfe84 100644 --- a/auto/os/solaris +++ b/auto/os/solaris @@ -52,7 +52,7 @@ ngx_feature_run=no ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs= -ngx_feature_test="int n = port_create()" +ngx_feature_test="(void) port_create()" . auto/feature if [ $ngx_found = yes ]; then diff --git a/auto/sources b/auto/sources index 27849e6..216e900 100644 --- a/auto/sources +++ b/auto/sources @@ -61,6 +61,7 @@ CORE_SRCS="src/core/nginx.c \ src/core/ngx_crc32.c \ src/core/ngx_murmurhash.c \ src/core/ngx_md5.c \ + src/core/ngx_sha1.c \ src/core/ngx_rbtree.c \ src/core/ngx_radix_tree.c \ src/core/ngx_slab.c \ diff --git a/auto/summary b/auto/summary index dc8fe4f..9aa776e 100644 --- a/auto/summary +++ b/auto/summary @@ -28,20 +28,6 @@ case $OPENSSL in *) echo " + using OpenSSL library: $OPENSSL" ;; esac -case $MD5 in - YES) echo " + md5: using $MD5_LIB library" ;; - NONE) echo " + md5 library is not used" ;; - NO) echo " + using builtin md5 code" ;; - *) echo " + using md5 library: $MD5" ;; -esac - -case $SHA1 in - YES) echo " + sha1: using $SHA1_LIB library" ;; - NONE) echo " + sha1 library is not used" ;; - NO) echo " + sha1 library is not found" ;; - *) echo " + using sha1 library: $SHA1" ;; -esac - case $ZLIB in YES) echo " + using system zlib library" ;; NONE) echo " + zlib library is not used" ;; diff --git a/auto/types/sizeof b/auto/types/sizeof index b5b71bb..480d8cf 100644 --- a/auto/types/sizeof +++ b/auto/types/sizeof @@ -25,7 +25,7 @@ $NGX_INCLUDE_UNISTD_H $NGX_INCLUDE_INTTYPES_H $NGX_INCLUDE_AUTO_CONFIG_H -int main() { +int main(void) { printf("%d", (int) sizeof($ngx_type)); return 0; } diff --git a/auto/types/typedef b/auto/types/typedef index b55237e..d54c289 100644 --- a/auto/types/typedef +++ b/auto/types/typedef @@ -27,7 +27,7 @@ do #include $NGX_INCLUDE_INTTYPES_H -int main() { +int main(void) { $ngx_try i = 0; return (int) i; } diff --git a/auto/types/uintptr_t b/auto/types/uintptr_t index 2b7212e..a33d6d0 100644 --- a/auto/types/uintptr_t +++ b/auto/types/uintptr_t @@ -17,9 +17,9 @@ found=no cat << END > $NGX_AUTOTEST.c #include -$NGX_INTTYPES_H +$NGX_INCLUDE_INTTYPES_H -int main() { +int main(void) { uintptr_t i = 0; return (int) i; } diff --git a/auto/unix b/auto/unix index 8c0e813..dbc0f0e 100755 --- a/auto/unix +++ b/auto/unix @@ -75,7 +75,7 @@ if test -z "$NGX_KQUEUE_CHECKED"; then ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs= - ngx_feature_test="int kq; kq = kqueue()" + ngx_feature_test="(void) kqueue()" . auto/feature if [ $ngx_found = yes ]; then @@ -92,7 +92,8 @@ if test -z "$NGX_KQUEUE_CHECKED"; then ngx_feature_path= ngx_feature_libs= ngx_feature_test="struct kevent kev; - kev.fflags = NOTE_LOWAT;" + kev.fflags = NOTE_LOWAT; + (void) kev" . auto/feature @@ -260,11 +261,11 @@ ngx_feature_run=no ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs= -ngx_feature_test="dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); dlsym(NULL, NULL)" +ngx_feature_test="dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); dlsym(NULL, \"\")" . auto/feature -if [ $ngx_found != yes ]; then +if [ $ngx_found = no ]; then ngx_feature="dlopen() in libdl" ngx_feature_libs="-ldl" @@ -287,7 +288,7 @@ ngx_feature_test="sched_yield()" . auto/feature -if [ $ngx_found != yes ]; then +if [ $ngx_found = no ]; then ngx_feature="sched_yield() in librt" ngx_feature_libs="-lrt" @@ -329,6 +330,57 @@ ngx_feature_test="setsockopt(0, SOL_SOCKET, SO_ACCEPTFILTER, NULL, 0)" . auto/feature +# NetBSD bind to any address for transparent proxying + +ngx_feature="SO_BINDANY" +ngx_feature_name="NGX_HAVE_TRANSPARENT_PROXY" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="setsockopt(0, SOL_SOCKET, SO_BINDANY, NULL, 0)" +. auto/feature + + +# Linux IP_BIND_ADDRESS_NO_PORT + +ngx_feature="IP_BIND_ADDRESS_NO_PORT" +ngx_feature_name="NGX_HAVE_IP_BIND_ADDRESS_NO_PORT" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="setsockopt(0, IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT, NULL, 0)" +. auto/feature + + +# Linux transparent proxying + +ngx_feature="IP_TRANSPARENT" +ngx_feature_name="NGX_HAVE_TRANSPARENT_PROXY" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="setsockopt(0, IPPROTO_IP, IP_TRANSPARENT, NULL, 0)" +. auto/feature + + +# FreeBSD bind to any address for transparent proxying + +ngx_feature="IP_BINDANY" +ngx_feature_name="NGX_HAVE_TRANSPARENT_PROXY" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="setsockopt(0, IPPROTO_IP, IP_BINDANY, NULL, 0)" +. auto/feature + + # BSD way to get IPv4 datagram destination address ngx_feature="IP_RECVDSTADDR" @@ -441,9 +493,9 @@ if [ $NGX_FILE_AIO = YES ]; then ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs= - ngx_feature_test="int n; struct aiocb iocb; + ngx_feature_test="struct aiocb iocb; iocb.aio_sigevent.sigev_notify = SIGEV_KEVENT; - n = aio_read(&iocb)" + (void) aio_read(&iocb)" . auto/feature if [ $ngx_found = yes ]; then @@ -463,6 +515,7 @@ if [ $NGX_FILE_AIO = YES ]; then iocb.aio_lio_opcode = IOCB_CMD_PREAD; iocb.aio_flags = IOCB_FLAG_RESFD; iocb.aio_resfd = -1; + (void) iocb; (void) eventfd(0, 0)" . auto/feature @@ -478,11 +531,12 @@ if [ $NGX_FILE_AIO = YES ]; then ngx_feature="Linux AIO support (SYS_eventfd)" ngx_feature_incs="#include #include " - ngx_feature_test="int n = SYS_eventfd; - struct iocb iocb; + ngx_feature_test="struct iocb iocb; iocb.aio_lio_opcode = IOCB_CMD_PREAD; iocb.aio_flags = IOCB_FLAG_RESFD; - iocb.aio_resfd = -1;" + iocb.aio_resfd = -1; + (void) iocb; + (void) SYS_eventfd" . auto/feature if [ $ngx_found = yes ]; then @@ -520,7 +574,7 @@ else ngx_feature="eventfd() (SYS_eventfd)" ngx_feature_incs="#include " - ngx_feature_test="int n = SYS_eventfd" + ngx_feature_test="(void) SYS_eventfd" . auto/feature fi fi @@ -593,7 +647,8 @@ if [ $NGX_IPV6 = YES ]; then ngx_feature_path= ngx_feature_libs= ngx_feature_test="struct sockaddr_in6 sin6; - sin6.sin6_family = AF_INET6;" + sin6.sin6_family = AF_INET6; + (void) sin6" . auto/feature fi diff --git a/src/core/nginx.h b/src/core/nginx.h index e2b8005..e303e66 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1010001 -#define NGINX_VERSION "1.10.1" +#define nginx_version 1011003 +#define NGINX_VERSION "1.11.3" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h index 9ccee36..213611f 100644 --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -45,7 +45,6 @@ #define NGX_CONF_ANY 0x00000400 #define NGX_CONF_1MORE 0x00000800 #define NGX_CONF_2MORE 0x00001000 -#define NGX_CONF_MULTI 0x00000000 /* compatibility */ #define NGX_DIRECT_CONF 0x00010000 diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 5a53bac..16ba630 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -17,7 +17,8 @@ static void ngx_drain_connections(void); ngx_listening_t * -ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen) +ngx_create_listening(ngx_conf_t *cf, struct sockaddr *sockaddr, + socklen_t socklen) { size_t len; ngx_listening_t *ls; @@ -150,12 +151,12 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { - ls[i].sockaddr = ngx_palloc(cycle->pool, NGX_SOCKADDRLEN); + ls[i].sockaddr = ngx_palloc(cycle->pool, sizeof(ngx_sockaddr_t)); if (ls[i].sockaddr == NULL) { return NGX_ERROR; } - ls[i].socklen = NGX_SOCKADDRLEN; + ls[i].socklen = sizeof(ngx_sockaddr_t); if (getsockname(ls[i].fd, ls[i].sockaddr, &ls[i].socklen) == -1) { ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, "getsockname() of the inherited " @@ -1277,7 +1278,7 @@ ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s, { socklen_t len; ngx_uint_t addr; - u_char sa[NGX_SOCKADDRLEN]; + ngx_sockaddr_t sa; struct sockaddr_in *sin; #if (NGX_HAVE_INET6) ngx_uint_t i; @@ -1315,9 +1316,9 @@ ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s, if (addr == 0) { - len = NGX_SOCKADDRLEN; + len = sizeof(ngx_sockaddr_t); - if (getsockname(c->fd, (struct sockaddr *) &sa, &len) == -1) { + if (getsockname(c->fd, &sa.sockaddr, &len) == -1) { ngx_connection_error(c, ngx_socket_errno, "getsockname() failed"); return NGX_ERROR; } diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index b0d162a..e484c81 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -149,6 +149,7 @@ struct ngx_connection_s { ngx_str_t addr_text; ngx_str_t proxy_protocol_addr; + in_port_t proxy_protocol_port; #if (NGX_SSL) ngx_ssl_connection_t *ssl; @@ -169,7 +170,6 @@ struct ngx_connection_s { unsigned log_error:3; /* ngx_connection_log_error_e */ - unsigned unexpected_eof:1; unsigned timedout:1; unsigned error:1; unsigned destroyed:1; @@ -186,10 +186,6 @@ struct ngx_connection_s { unsigned need_last_buf:1; -#if (NGX_HAVE_IOCP) - unsigned accept_context_updated:1; -#endif - #if (NGX_HAVE_AIO_SENDFILE) unsigned busy_count:2; #endif @@ -211,7 +207,7 @@ struct ngx_connection_s { } -ngx_listening_t *ngx_create_listening(ngx_conf_t *cf, void *sockaddr, +ngx_listening_t *ngx_create_listening(ngx_conf_t *cf, struct sockaddr *sockaddr, socklen_t socklen); ngx_int_t ngx_clone_listening(ngx_conf_t *cf, ngx_listening_t *ls); ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle); diff --git a/src/core/ngx_crypt.c b/src/core/ngx_crypt.c index 9db74f4..868dc5d 100644 --- a/src/core/ngx_crypt.c +++ b/src/core/ngx_crypt.c @@ -8,9 +8,7 @@ #include #include #include -#if (NGX_HAVE_SHA1) #include -#endif #if (NGX_CRYPT) @@ -19,16 +17,11 @@ static ngx_int_t ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted); static ngx_int_t ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted); - -#if (NGX_HAVE_SHA1) - static ngx_int_t ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted); static ngx_int_t ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted); -#endif - static u_char *ngx_crypt_to64(u_char *p, uint32_t v, size_t n); @@ -42,13 +35,11 @@ ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) } else if (ngx_strncmp(salt, "{PLAIN}", sizeof("{PLAIN}") - 1) == 0) { return ngx_crypt_plain(pool, key, salt, encrypted); -#if (NGX_HAVE_SHA1) } else if (ngx_strncmp(salt, "{SSHA}", sizeof("{SSHA}") - 1) == 0) { return ngx_crypt_ssha(pool, key, salt, encrypted); } else if (ngx_strncmp(salt, "{SHA}", sizeof("{SHA}") - 1) == 0) { return ngx_crypt_sha(pool, key, salt, encrypted); -#endif } /* fallback to libc crypt() */ @@ -193,8 +184,6 @@ ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) } -#if (NGX_HAVE_SHA1) - static ngx_int_t ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) { @@ -278,6 +267,4 @@ ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) return NGX_OK; } -#endif /* NGX_HAVE_SHA1 */ - #endif /* NGX_CRYPT */ diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c index fc2dfd3..c1137cc 100644 --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -225,7 +225,7 @@ ngx_create_hashed_filename(ngx_path_t *path, u_char *file, size_t len) file[path->name.len + path->len] = '/'; - for (n = 0; n < 3; n++) { + for (n = 0; n < NGX_MAX_PATH_LEVEL; n++) { level = path->level[n]; if (level == 0) { @@ -249,7 +249,7 @@ ngx_create_path(ngx_file_t *file, ngx_path_t *path) pos = path->name.len; - for (i = 0; i < 3; i++) { + for (i = 0; i < NGX_MAX_PATH_LEVEL; i++) { if (path->level[i] == 0) { break; } @@ -399,6 +399,8 @@ char * ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path, ngx_path_t *prev, ngx_path_init_t *init) { + ngx_uint_t i; + if (*path) { return NGX_CONF_OK; } @@ -419,13 +421,10 @@ ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path, ngx_path_t *prev, return NGX_CONF_ERROR; } - (*path)->level[0] = init->level[0]; - (*path)->level[1] = init->level[1]; - (*path)->level[2] = init->level[2]; - - (*path)->len = init->level[0] + (init->level[0] ? 1 : 0) - + init->level[1] + (init->level[1] ? 1 : 0) - + init->level[2] + (init->level[2] ? 1 : 0); + for (i = 0; i < NGX_MAX_PATH_LEVEL; i++) { + (*path)->level[i] = init->level[i]; + (*path)->len += init->level[i] + (init->level[i] ? 1 : 0); + } if (ngx_add_path(cf, path) != NGX_OK) { return NGX_CONF_ERROR; @@ -518,7 +517,7 @@ ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot) return NGX_ERROR; } - for (n = 0; n < 3; n++) { + for (n = 0; n < NGX_MAX_PATH_LEVEL; n++) { if (p[i]->level[n] != path->level[n]) { if (path->conf_file == NULL) { if (p[i]->conf_file == NULL) { diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h index 5f8228b..a723c3d 100644 --- a/src/core/ngx_file.h +++ b/src/core/ngx_file.h @@ -49,7 +49,7 @@ typedef void (*ngx_path_loader_pt) (void *data); typedef struct { ngx_str_t name; size_t len; - size_t level[3]; + size_t level[NGX_MAX_PATH_LEVEL]; ngx_path_manager_pt manager; ngx_path_loader_pt loader; @@ -62,7 +62,7 @@ typedef struct { typedef struct { ngx_str_t name; - size_t level[3]; + size_t level[NGX_MAX_PATH_LEVEL]; } ngx_path_init_t; diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c index 33b303d..c4aaf3a 100644 --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -525,6 +525,68 @@ ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, size_t len) } +ngx_int_t +ngx_parse_addr_port(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, + size_t len) +{ + u_char *p, *last; + size_t plen; + ngx_int_t rc, port; + + rc = ngx_parse_addr(pool, addr, text, len); + + if (rc != NGX_DECLINED) { + return rc; + } + + last = text + len; + +#if (NGX_HAVE_INET6) + if (len && text[0] == '[') { + + p = ngx_strlchr(text, last, ']'); + + if (p == NULL || p == last - 1 || *++p != ':') { + return NGX_DECLINED; + } + + text++; + len -= 2; + + } else +#endif + + { + p = ngx_strlchr(text, last, ':'); + + if (p == NULL) { + return NGX_DECLINED; + } + } + + p++; + plen = last - p; + + port = ngx_atoi(p, plen); + + if (port < 1 || port > 65535) { + return NGX_DECLINED; + } + + len -= plen + 1; + + rc = ngx_parse_addr(pool, addr, text, len); + + if (rc != NGX_OK) { + return rc; + } + + ngx_inet_set_port(addr->sockaddr, (in_port_t) port); + + return NGX_OK; +} + + ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u) { @@ -763,7 +825,7 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u) return NGX_ERROR; } - ngx_memcpy(sin, u->sockaddr, sizeof(struct sockaddr_in)); + ngx_memcpy(sin, &u->sockaddr, sizeof(struct sockaddr_in)); u->addrs[0].sockaddr = (struct sockaddr *) sin; u->addrs[0].socklen = sizeof(struct sockaddr_in); @@ -790,7 +852,7 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u) u->family = u->addrs[0].sockaddr->sa_family; u->socklen = u->addrs[0].socklen; - ngx_memcpy(u->sockaddr, u->addrs[0].sockaddr, u->addrs[0].socklen); + ngx_memcpy(&u->sockaddr, u->addrs[0].sockaddr, u->addrs[0].socklen); switch (u->family) { @@ -843,47 +905,49 @@ ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u) return NGX_ERROR; } - if (last - p) { + port = p + 1; - port = p + 1; + uri = ngx_strlchr(port, last, '/'); - uri = ngx_strlchr(port, last, '/'); - - if (uri) { - if (u->listen || !u->uri_part) { - u->err = "invalid host"; - return NGX_ERROR; - } - - u->uri.len = last - uri; - u->uri.data = uri; - - last = uri; + if (uri) { + if (u->listen || !u->uri_part) { + u->err = "invalid host"; + return NGX_ERROR; } - if (*port == ':') { - port++; + u->uri.len = last - uri; + u->uri.data = uri; - len = last - port; + last = uri; + } - n = ngx_atoi(port, len); - - if (n < 1 || n > 65535) { - u->err = "invalid port"; - return NGX_ERROR; - } - - u->port = (in_port_t) n; - sin6->sin6_port = htons((in_port_t) n); - - u->port_text.len = len; - u->port_text.data = port; - - } else { - u->no_port = 1; - u->port = u->default_port; - sin6->sin6_port = htons(u->default_port); + if (port < last) { + if (*port != ':') { + u->err = "invalid host"; + return NGX_ERROR; } + + port++; + + len = last - port; + + n = ngx_atoi(port, len); + + if (n < 1 || n > 65535) { + u->err = "invalid port"; + return NGX_ERROR; + } + + u->port = (in_port_t) n; + sin6->sin6_port = htons((in_port_t) n); + + u->port_text.len = len; + u->port_text.data = port; + + } else { + u->no_port = 1; + u->port = u->default_port; + sin6->sin6_port = htons(u->default_port); } len = p - host; @@ -918,7 +982,7 @@ ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u) return NGX_ERROR; } - ngx_memcpy(sin6, u->sockaddr, sizeof(struct sockaddr_in6)); + ngx_memcpy(sin6, &u->sockaddr, sizeof(struct sockaddr_in6)); u->addrs[0].sockaddr = (struct sockaddr *) sin6; u->addrs[0].socklen = sizeof(struct sockaddr_in6); @@ -1275,3 +1339,61 @@ ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1, return NGX_OK; } + + +in_port_t +ngx_inet_get_port(struct sockaddr *sa) +{ + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + switch (sa->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) sa; + return ntohs(sin6->sin6_port); +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + return 0; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) sa; + return ntohs(sin->sin_port); + } +} + + +void +ngx_inet_set_port(struct sockaddr *sa, in_port_t port) +{ + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + switch (sa->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) sa; + sin6->sin6_port = htons(port); + break; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) sa; + sin->sin_port = htons(port); + break; + } +} diff --git a/src/core/ngx_inet.h b/src/core/ngx_inet.h index 0555750..97dc354 100644 --- a/src/core/ngx_inet.h +++ b/src/core/ngx_inet.h @@ -13,14 +13,6 @@ #include -/* - * TODO: autoconfigure NGX_SOCKADDRLEN and NGX_SOCKADDR_STRLEN as - * sizeof(struct sockaddr_storage) - * sizeof(struct sockaddr_un) - * sizeof(struct sockaddr_in6) - * sizeof(struct sockaddr_in) - */ - #define NGX_INET_ADDRSTRLEN (sizeof("255.255.255.255") - 1) #define NGX_INET6_ADDRSTRLEN \ (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - 1) @@ -29,15 +21,26 @@ #if (NGX_HAVE_UNIX_DOMAIN) #define NGX_SOCKADDR_STRLEN (sizeof("unix:") - 1 + NGX_UNIX_ADDRSTRLEN) -#else +#elif (NGX_HAVE_INET6) #define NGX_SOCKADDR_STRLEN (NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1) +#else +#define NGX_SOCKADDR_STRLEN (NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1) #endif -#if (NGX_HAVE_UNIX_DOMAIN) -#define NGX_SOCKADDRLEN sizeof(struct sockaddr_un) -#else -#define NGX_SOCKADDRLEN 512 +/* compatibility */ +#define NGX_SOCKADDRLEN sizeof(ngx_sockaddr_t) + + +typedef union { + struct sockaddr sockaddr; + struct sockaddr_in sockaddr_in; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 sockaddr_in6; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + struct sockaddr_un sockaddr_un; +#endif +} ngx_sockaddr_t; typedef struct { @@ -87,13 +90,12 @@ typedef struct { unsigned listen:1; unsigned uri_part:1; unsigned no_resolve:1; - unsigned one_addr:1; /* compatibility */ unsigned no_port:1; unsigned wildcard:1; socklen_t socklen; - u_char sockaddr[NGX_SOCKADDRLEN]; + ngx_sockaddr_t sockaddr; ngx_addr_t *addrs; ngx_uint_t naddrs; @@ -113,10 +115,14 @@ size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len); ngx_int_t ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr); ngx_int_t ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, size_t len); +ngx_int_t ngx_parse_addr_port(ngx_pool_t *pool, ngx_addr_t *addr, + u_char *text, size_t len); ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u); ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u); ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1, struct sockaddr *sa2, socklen_t slen2, ngx_uint_t cmp_port); +in_port_t ngx_inet_get_port(struct sockaddr *sa); +void ngx_inet_set_port(struct sockaddr *sa, in_port_t port); #endif /* _NGX_INET_H_INCLUDED_ */ diff --git a/src/core/ngx_md5.c b/src/core/ngx_md5.c index 440c75b..c25d002 100644 --- a/src/core/ngx_md5.c +++ b/src/core/ngx_md5.c @@ -3,8 +3,6 @@ * An internal implementation, based on Alexander Peslyak's * public domain implementation: * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 - * It is not expected to be optimal and is used only - * if no MD5 implementation was found in system. */ @@ -13,8 +11,6 @@ #include -#if !(NGX_HAVE_MD5) - static const u_char *ngx_md5_body(ngx_md5_t *ctx, const u_char *data, size_t size); @@ -285,5 +281,3 @@ ngx_md5_body(ngx_md5_t *ctx, const u_char *data, size_t size) return p; } - -#endif diff --git a/src/core/ngx_md5.h b/src/core/ngx_md5.h index 18d09d6..713b614 100644 --- a/src/core/ngx_md5.h +++ b/src/core/ngx_md5.h @@ -13,36 +13,6 @@ #include -#if (NGX_HAVE_MD5) - -#if (NGX_HAVE_OPENSSL_MD5_H) -#include -#else -#include -#endif - - -typedef MD5_CTX ngx_md5_t; - - -#if (NGX_OPENSSL_MD5) - -#define ngx_md5_init MD5_Init -#define ngx_md5_update MD5_Update -#define ngx_md5_final MD5_Final - -#else - -#define ngx_md5_init MD5Init -#define ngx_md5_update MD5Update -#define ngx_md5_final MD5Final - -#endif - - -#else /* !NGX_HAVE_MD5 */ - - typedef struct { uint64_t bytes; uint32_t a, b, c, d; @@ -55,6 +25,4 @@ void ngx_md5_update(ngx_md5_t *ctx, const void *data, size_t size); void ngx_md5_final(u_char result[16], ngx_md5_t *ctx); -#endif - #endif /* _NGX_MD5_H_INCLUDED_ */ diff --git a/src/core/ngx_module.h b/src/core/ngx_module.h index e911cb4..a1a0d6c 100644 --- a/src/core/ngx_module.h +++ b/src/core/ngx_module.h @@ -119,17 +119,8 @@ #define NGX_MODULE_SIGNATURE_16 "0" #endif -#if (NGX_HAVE_MD5) -#define NGX_MODULE_SIGNATURE_17 "1" -#else #define NGX_MODULE_SIGNATURE_17 "0" -#endif - -#if (NGX_HAVE_SHA1) -#define NGX_MODULE_SIGNATURE_18 "1" -#else #define NGX_MODULE_SIGNATURE_18 "0" -#endif #if (NGX_HAVE_OPENAT) #define NGX_MODULE_SIGNATURE_19 "1" diff --git a/src/core/ngx_proxy_protocol.c b/src/core/ngx_proxy_protocol.c index f347e7f..523ec35 100644 --- a/src/core/ngx_proxy_protocol.c +++ b/src/core/ngx_proxy_protocol.c @@ -12,8 +12,9 @@ u_char * ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last) { - size_t len; - u_char ch, *p, *addr; + size_t len; + u_char ch, *p, *addr, *port; + ngx_int_t n; p = buf; len = last - buf; @@ -71,8 +72,40 @@ ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last) ngx_memcpy(c->proxy_protocol_addr.data, addr, len); c->proxy_protocol_addr.len = len; - ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, - "PROXY protocol address: \"%V\"", &c->proxy_protocol_addr); + for ( ;; ) { + if (p == last) { + goto invalid; + } + + if (*p++ == ' ') { + break; + } + } + + port = p; + + for ( ;; ) { + if (p == last) { + goto invalid; + } + + if (*p++ == ' ') { + break; + } + } + + len = p - port - 1; + + n = ngx_atoi(port, len); + + if (n < 0 || n > 65535) { + goto invalid; + } + + c->proxy_protocol_port = (in_port_t) n; + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0, + "PROXY protocol address: %V %i", &c->proxy_protocol_addr, n); skip: @@ -108,19 +141,11 @@ ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *last) case AF_INET: buf = ngx_cpymem(buf, "PROXY TCP4 ", sizeof("PROXY TCP4 ") - 1); - - port = ntohs(((struct sockaddr_in *) c->sockaddr)->sin_port); - lport = ntohs(((struct sockaddr_in *) c->local_sockaddr)->sin_port); - break; #if (NGX_HAVE_INET6) case AF_INET6: buf = ngx_cpymem(buf, "PROXY TCP6 ", sizeof("PROXY TCP6 ") - 1); - - port = ntohs(((struct sockaddr_in6 *) c->sockaddr)->sin6_port); - lport = ntohs(((struct sockaddr_in6 *) c->local_sockaddr)->sin6_port); - break; #endif @@ -136,5 +161,8 @@ ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *last) buf += ngx_sock_ntop(c->local_sockaddr, c->local_socklen, buf, last - buf, 0); + port = ngx_inet_get_port(c->sockaddr); + lport = ngx_inet_get_port(c->local_sockaddr); + return ngx_slprintf(buf, last, " %ui %ui" CRLF, port, lport); } diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index e00fe22..53dae6b 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -2992,16 +2992,12 @@ failed: static void ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx) { - ngx_uint_t i; - u_char (*sockaddr)[NGX_SOCKADDRLEN]; - ngx_addr_t *addrs; - ngx_resolver_t *r; - struct sockaddr_in *sin; - ngx_resolver_ctx_t *ctx; - ngx_resolver_srv_name_t *srv; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif + ngx_uint_t i; + ngx_addr_t *addrs; + ngx_resolver_t *r; + ngx_sockaddr_t *sockaddr; + ngx_resolver_ctx_t *ctx; + ngx_resolver_srv_name_t *srv; r = cctx->resolver; ctx = cctx->data; @@ -3026,7 +3022,7 @@ ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx) return; } - sockaddr = ngx_resolver_alloc(r, cctx->naddrs * NGX_SOCKADDRLEN); + sockaddr = ngx_resolver_alloc(r, cctx->naddrs * sizeof(ngx_sockaddr_t)); if (sockaddr == NULL) { ngx_resolver_free(r, addrs); ngx_resolve_name_done(cctx); @@ -3039,23 +3035,13 @@ ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx) } for (i = 0; i < cctx->naddrs; i++) { - addrs[i].sockaddr = (struct sockaddr *) sockaddr[i]; + addrs[i].sockaddr = &sockaddr[i].sockaddr; addrs[i].socklen = cctx->addrs[i].socklen; - ngx_memcpy(sockaddr[i], cctx->addrs[i].sockaddr, + ngx_memcpy(&sockaddr[i], cctx->addrs[i].sockaddr, addrs[i].socklen); - switch (addrs[i].sockaddr->sa_family) { -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) addrs[i].sockaddr; - sin6->sin6_port = htons(srv->port); - break; -#endif - default: /* AF_INET */ - sin = (struct sockaddr_in *) addrs[i].sockaddr; - sin->sin_port = htons(srv->port); - } + ngx_inet_set_port(addrs[i].sockaddr, srv->port); } srv->addrs = addrs; @@ -4161,14 +4147,14 @@ static ngx_resolver_addr_t * ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn, ngx_uint_t rotate) { - ngx_uint_t d, i, j, n; - u_char (*sockaddr)[NGX_SOCKADDRLEN]; - in_addr_t *addr; - struct sockaddr_in *sin; - ngx_resolver_addr_t *dst; + ngx_uint_t d, i, j, n; + in_addr_t *addr; + ngx_sockaddr_t *sockaddr; + struct sockaddr_in *sin; + ngx_resolver_addr_t *dst; #if (NGX_HAVE_INET6) - struct in6_addr *addr6; - struct sockaddr_in6 *sin6; + struct in6_addr *addr6; + struct sockaddr_in6 *sin6; #endif n = rn->naddrs; @@ -4181,7 +4167,7 @@ ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn, return NULL; } - sockaddr = ngx_resolver_calloc(r, n * NGX_SOCKADDRLEN); + sockaddr = ngx_resolver_calloc(r, n * sizeof(ngx_sockaddr_t)); if (sockaddr == NULL) { ngx_resolver_free(r, dst); return NULL; @@ -4196,7 +4182,7 @@ ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn, addr = (rn->naddrs == 1) ? &rn->u.addr : rn->u.addrs; do { - sin = (struct sockaddr_in *) sockaddr[d]; + sin = &sockaddr[d].sockaddr_in; sin->sin_family = AF_INET; sin->sin_addr.s_addr = addr[j++]; dst[d].sockaddr = (struct sockaddr *) sin; @@ -4219,7 +4205,7 @@ ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn, addr6 = (rn->naddrs6 == 1) ? &rn->u6.addr6 : rn->u6.addrs6; do { - sin6 = (struct sockaddr_in6 *) sockaddr[d]; + sin6 = &sockaddr[d].sockaddr_in6; sin6->sin6_family = AF_INET6; ngx_memcpy(sin6->sin6_addr.s6_addr, addr6[j++].s6_addr, 16); dst[d].sockaddr = (struct sockaddr *) sin6; diff --git a/src/core/ngx_sha1.c b/src/core/ngx_sha1.c new file mode 100644 index 0000000..f00dc52 --- /dev/null +++ b/src/core/ngx_sha1.c @@ -0,0 +1,294 @@ + +/* + * Copyright (C) Maxim Dounin + * Copyright (C) Nginx, Inc. + * + * An internal SHA1 implementation. + */ + + +#include +#include +#include + + +static const u_char *ngx_sha1_body(ngx_sha1_t *ctx, const u_char *data, + size_t size); + + +void +ngx_sha1_init(ngx_sha1_t *ctx) +{ + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; + ctx->e = 0xc3d2e1f0; + + ctx->bytes = 0; +} + + +void +ngx_sha1_update(ngx_sha1_t *ctx, const void *data, size_t size) +{ + size_t used, free; + + used = (size_t) (ctx->bytes & 0x3f); + ctx->bytes += size; + + if (used) { + free = 64 - used; + + if (size < free) { + ngx_memcpy(&ctx->buffer[used], data, size); + return; + } + + ngx_memcpy(&ctx->buffer[used], data, free); + data = (u_char *) data + free; + size -= free; + (void) ngx_sha1_body(ctx, ctx->buffer, 64); + } + + if (size >= 64) { + data = ngx_sha1_body(ctx, data, size & ~(size_t) 0x3f); + size &= 0x3f; + } + + ngx_memcpy(ctx->buffer, data, size); +} + + +void +ngx_sha1_final(u_char result[20], ngx_sha1_t *ctx) +{ + size_t used, free; + + used = (size_t) (ctx->bytes & 0x3f); + + ctx->buffer[used++] = 0x80; + + free = 64 - used; + + if (free < 8) { + ngx_memzero(&ctx->buffer[used], free); + (void) ngx_sha1_body(ctx, ctx->buffer, 64); + used = 0; + free = 64; + } + + ngx_memzero(&ctx->buffer[used], free - 8); + + ctx->bytes <<= 3; + ctx->buffer[56] = (u_char) (ctx->bytes >> 56); + ctx->buffer[57] = (u_char) (ctx->bytes >> 48); + ctx->buffer[58] = (u_char) (ctx->bytes >> 40); + ctx->buffer[59] = (u_char) (ctx->bytes >> 32); + ctx->buffer[60] = (u_char) (ctx->bytes >> 24); + ctx->buffer[61] = (u_char) (ctx->bytes >> 16); + ctx->buffer[62] = (u_char) (ctx->bytes >> 8); + ctx->buffer[63] = (u_char) ctx->bytes; + + (void) ngx_sha1_body(ctx, ctx->buffer, 64); + + result[0] = (u_char) (ctx->a >> 24); + result[1] = (u_char) (ctx->a >> 16); + result[2] = (u_char) (ctx->a >> 8); + result[3] = (u_char) ctx->a; + result[4] = (u_char) (ctx->b >> 24); + result[5] = (u_char) (ctx->b >> 16); + result[6] = (u_char) (ctx->b >> 8); + result[7] = (u_char) ctx->b; + result[8] = (u_char) (ctx->c >> 24); + result[9] = (u_char) (ctx->c >> 16); + result[10] = (u_char) (ctx->c >> 8); + result[11] = (u_char) ctx->c; + result[12] = (u_char) (ctx->d >> 24); + result[13] = (u_char) (ctx->d >> 16); + result[14] = (u_char) (ctx->d >> 8); + result[15] = (u_char) ctx->d; + result[16] = (u_char) (ctx->e >> 24); + result[17] = (u_char) (ctx->e >> 16); + result[18] = (u_char) (ctx->e >> 8); + result[19] = (u_char) ctx->e; + + ngx_memzero(ctx, sizeof(*ctx)); +} + + +/* + * Helper functions. + */ + +#define ROTATE(bits, word) (((word) << (bits)) | ((word) >> (32 - (bits)))) + +#define F1(b, c, d) (((b) & (c)) | ((~(b)) & (d))) +#define F2(b, c, d) ((b) ^ (c) ^ (d)) +#define F3(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) + +#define STEP(f, a, b, c, d, e, w, t) \ + temp = ROTATE(5, (a)) + f((b), (c), (d)) + (e) + (w) + (t); \ + (e) = (d); \ + (d) = (c); \ + (c) = ROTATE(30, (b)); \ + (b) = (a); \ + (a) = temp; + + +/* + * GET() reads 4 input bytes in big-endian byte order and returns + * them as uint32_t. + */ + +#define GET(n) \ + ((uint32_t) p[n * 4 + 3] | \ + ((uint32_t) p[n * 4 + 2] << 8) | \ + ((uint32_t) p[n * 4 + 1] << 16) | \ + ((uint32_t) p[n * 4] << 24)) + + +/* + * This processes one or more 64-byte data blocks, but does not update + * the bit counters. There are no alignment requirements. + */ + +static const u_char * +ngx_sha1_body(ngx_sha1_t *ctx, const u_char *data, size_t size) +{ + uint32_t a, b, c, d, e, temp; + uint32_t saved_a, saved_b, saved_c, saved_d, saved_e; + uint32_t words[80]; + ngx_uint_t i; + const u_char *p; + + p = data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + e = ctx->e; + + do { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + saved_e = e; + + /* Load data block into the words array */ + + for (i = 0; i < 16; i++) { + words[i] = GET(i); + } + + for (i = 16; i < 80; i++) { + words[i] = ROTATE(1, words[i - 3] ^ words[i - 8] ^ words[i - 14] + ^ words[i - 16]); + } + + /* Transformations */ + + STEP(F1, a, b, c, d, e, words[0], 0x5a827999); + STEP(F1, a, b, c, d, e, words[1], 0x5a827999); + STEP(F1, a, b, c, d, e, words[2], 0x5a827999); + STEP(F1, a, b, c, d, e, words[3], 0x5a827999); + STEP(F1, a, b, c, d, e, words[4], 0x5a827999); + STEP(F1, a, b, c, d, e, words[5], 0x5a827999); + STEP(F1, a, b, c, d, e, words[6], 0x5a827999); + STEP(F1, a, b, c, d, e, words[7], 0x5a827999); + STEP(F1, a, b, c, d, e, words[8], 0x5a827999); + STEP(F1, a, b, c, d, e, words[9], 0x5a827999); + STEP(F1, a, b, c, d, e, words[10], 0x5a827999); + STEP(F1, a, b, c, d, e, words[11], 0x5a827999); + STEP(F1, a, b, c, d, e, words[12], 0x5a827999); + STEP(F1, a, b, c, d, e, words[13], 0x5a827999); + STEP(F1, a, b, c, d, e, words[14], 0x5a827999); + STEP(F1, a, b, c, d, e, words[15], 0x5a827999); + STEP(F1, a, b, c, d, e, words[16], 0x5a827999); + STEP(F1, a, b, c, d, e, words[17], 0x5a827999); + STEP(F1, a, b, c, d, e, words[18], 0x5a827999); + STEP(F1, a, b, c, d, e, words[19], 0x5a827999); + + STEP(F2, a, b, c, d, e, words[20], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[21], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[22], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[23], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[24], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[25], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[26], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[27], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[28], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[29], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[30], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[31], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[32], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[33], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[34], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[35], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[36], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[37], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[38], 0x6ed9eba1); + STEP(F2, a, b, c, d, e, words[39], 0x6ed9eba1); + + STEP(F3, a, b, c, d, e, words[40], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[41], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[42], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[43], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[44], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[45], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[46], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[47], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[48], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[49], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[50], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[51], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[52], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[53], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[54], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[55], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[56], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[57], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[58], 0x8f1bbcdc); + STEP(F3, a, b, c, d, e, words[59], 0x8f1bbcdc); + + STEP(F2, a, b, c, d, e, words[60], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[61], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[62], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[63], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[64], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[65], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[66], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[67], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[68], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[69], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[70], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[71], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[72], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[73], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[74], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[75], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[76], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[77], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[78], 0xca62c1d6); + STEP(F2, a, b, c, d, e, words[79], 0xca62c1d6); + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + e += saved_e; + + p += 64; + + } while (size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + ctx->e = e; + + return p; +} diff --git a/src/core/ngx_sha1.h b/src/core/ngx_sha1.h index 81c909e..4a98f71 100644 --- a/src/core/ngx_sha1.h +++ b/src/core/ngx_sha1.h @@ -13,19 +13,16 @@ #include -#if (NGX_HAVE_OPENSSL_SHA1_H) -#include -#else -#include -#endif +typedef struct { + uint64_t bytes; + uint32_t a, b, c, d, e, f; + u_char buffer[64]; +} ngx_sha1_t; -typedef SHA_CTX ngx_sha1_t; - - -#define ngx_sha1_init SHA1_Init -#define ngx_sha1_update SHA1_Update -#define ngx_sha1_final SHA1_Final +void ngx_sha1_init(ngx_sha1_t *ctx); +void ngx_sha1_update(ngx_sha1_t *ctx, const void *data, size_t size); +void ngx_sha1_final(u_char result[20], ngx_sha1_t *ctx); #endif /* _NGX_SHA1_H_INCLUDED_ */ diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index cf665a4..7a73ef5 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -1563,7 +1563,7 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) n = 0; while (size) { - if (escape[*src >> 5] & (1 << (*src & 0x1f))) { + if (escape[*src >> 5] & (1U << (*src & 0x1f))) { n++; } src++; @@ -1574,7 +1574,7 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) } while (size) { - if (escape[*src >> 5] & (1 << (*src & 0x1f))) { + if (escape[*src >> 5] & (1U << (*src & 0x1f))) { *dst++ = '%'; *dst++ = hex[*src >> 4]; *dst++ = hex[*src & 0xf]; diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c index 166c461..c267fd6 100644 --- a/src/event/modules/ngx_epoll_module.c +++ b/src/event/modules/ngx_epoll_module.c @@ -17,18 +17,19 @@ #define EPOLLIN 0x001 #define EPOLLPRI 0x002 #define EPOLLOUT 0x004 +#define EPOLLERR 0x008 +#define EPOLLHUP 0x010 #define EPOLLRDNORM 0x040 #define EPOLLRDBAND 0x080 #define EPOLLWRNORM 0x100 #define EPOLLWRBAND 0x200 #define EPOLLMSG 0x400 -#define EPOLLERR 0x008 -#define EPOLLHUP 0x010 #define EPOLLRDHUP 0x2000 -#define EPOLLET 0x80000000 +#define EPOLLEXCLUSIVE 0x10000000 #define EPOLLONESHOT 0x40000000 +#define EPOLLET 0x80000000 #define EPOLL_CTL_ADD 1 #define EPOLL_CTL_DEL 2 @@ -105,6 +106,9 @@ static ngx_int_t ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer); static ngx_int_t ngx_epoll_notify_init(ngx_log_t *log); static void ngx_epoll_notify_handler(ngx_event_t *ev); #endif +#if (NGX_HAVE_EPOLLRDHUP) +static void ngx_epoll_test_rdhup(ngx_cycle_t *cycle); +#endif static void ngx_epoll_done(ngx_cycle_t *cycle); static ngx_int_t ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); @@ -146,6 +150,10 @@ static ngx_connection_t ngx_eventfd_conn; #endif +#if (NGX_HAVE_EPOLLRDHUP) +ngx_uint_t ngx_use_epoll_rdhup; +#endif + static ngx_str_t epoll_name = ngx_string("epoll"); static ngx_command_t ngx_epoll_commands[] = { @@ -334,9 +342,11 @@ ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer) #endif #if (NGX_HAVE_FILE_AIO) - ngx_epoll_aio_init(cycle, epcf); +#endif +#if (NGX_HAVE_EPOLLRDHUP) + ngx_epoll_test_rdhup(cycle); #endif } @@ -449,6 +459,73 @@ ngx_epoll_notify_handler(ngx_event_t *ev) #endif +#if (NGX_HAVE_EPOLLRDHUP) + +static void +ngx_epoll_test_rdhup(ngx_cycle_t *cycle) +{ + int s[2], events; + struct epoll_event ee; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "socketpair() failed"); + return; + } + + ee.events = EPOLLET|EPOLLIN|EPOLLRDHUP; + + if (epoll_ctl(ep, EPOLL_CTL_ADD, s[0], &ee) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "epoll_ctl() failed"); + goto failed; + } + + if (close(s[1]) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "close() failed"); + s[1] = -1; + goto failed; + } + + s[1] = -1; + + events = epoll_wait(ep, &ee, 1, 5000); + + if (events == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "epoll_wait() failed"); + goto failed; + } + + if (events) { + ngx_use_epoll_rdhup = ee.events & EPOLLRDHUP; + + } else { + ngx_log_error(NGX_LOG_ALERT, cycle->log, NGX_ETIMEDOUT, + "epoll_wait() timed out"); + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "testing the EPOLLRDHUP flag: %s", + ngx_use_epoll_rdhup ? "success" : "fail"); + +failed: + + if (s[1] != -1 && close(s[1]) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "close() failed"); + } + + if (close(s[0]) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "close() failed"); + } +} + +#endif + + static void ngx_epoll_done(ngx_cycle_t *cycle) { @@ -534,6 +611,12 @@ ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) op = EPOLL_CTL_ADD; } +#if (NGX_HAVE_EPOLLEXCLUSIVE && NGX_HAVE_EPOLLRDHUP) + if (flags & NGX_EXCLUSIVE_EVENT) { + events &= ~EPOLLRDHUP; + } +#endif + ee.events = events | (uint32_t) flags; ee.data.ptr = (void *) ((uintptr_t) c | ev->instance); @@ -808,6 +891,8 @@ ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) if (revents & EPOLLRDHUP) { rev->pending_eof = 1; } + + rev->available = 1; #endif rev->ready = 1; diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index c8ae5b2..9d6c4c9 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -822,15 +822,38 @@ ngx_event_process_init(ngx_cycle_t *cycle) rev->handler = (c->type == SOCK_STREAM) ? ngx_event_accept : ngx_event_recvmsg; - if (ngx_use_accept_mutex #if (NGX_HAVE_REUSEPORT) - && !ls[i].reuseport -#endif - ) - { + + if (ls[i].reuseport) { + if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { + return NGX_ERROR; + } + continue; } +#endif + + if (ngx_use_accept_mutex) { + continue; + } + +#if (NGX_HAVE_EPOLLEXCLUSIVE) + + if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) + && ccf->worker_processes > 1) + { + if (ngx_add_event(rev, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT) + == NGX_ERROR) + { + return NGX_ERROR; + } + + continue; + } + +#endif + if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } @@ -1261,7 +1284,7 @@ ngx_event_core_init_conf(ngx_cycle_t *cycle, void *conf) ngx_conf_init_ptr_value(ecf->name, event_module->name->data); ngx_conf_init_value(ecf->multi_accept, 0); - ngx_conf_init_value(ecf->accept_mutex, 1); + ngx_conf_init_value(ecf->accept_mutex, 0); ngx_conf_init_msec_value(ecf->accept_mutex_delay, 500); return NGX_CONF_OK; diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index ed0682c..27139ee 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -76,11 +76,6 @@ struct ngx_event_s { unsigned cancelable:1; -#if (NGX_WIN32) - /* setsockopt(SO_UPDATE_ACCEPT_CONTEXT) was successful */ - unsigned accept_context_updated:1; -#endif - #if (NGX_HAVE_KQUEUE) unsigned kq_vnode:1; @@ -96,6 +91,10 @@ struct ngx_event_s { * write: available space in buffer when event is ready * or lowat when event is set with NGX_LOWAT_EVENT flag * + * epoll with EPOLLRDHUP: + * accept: 1 if accept many, 0 otherwise + * read: 1 if there can be data to read, 0 otherwise + * * iocp: TODO * * otherwise: @@ -196,6 +195,9 @@ typedef struct { extern ngx_event_actions_t ngx_event_actions; +#if (NGX_HAVE_EPOLLRDHUP) +extern ngx_uint_t ngx_use_epoll_rdhup; +#endif /* @@ -365,6 +367,9 @@ extern ngx_event_actions_t ngx_event_actions; #define NGX_ONESHOT_EVENT EPOLLONESHOT #endif +#if (NGX_HAVE_EPOLLEXCLUSIVE) +#define NGX_EXCLUSIVE_EVENT EPOLLEXCLUSIVE +#endif #elif (NGX_HAVE_POLL) @@ -393,6 +398,11 @@ extern ngx_event_actions_t ngx_event_actions; #endif +#if (NGX_TEST_BUILD_EPOLL) +#define NGX_EXCLUSIVE_EVENT 0 +#endif + + #ifndef NGX_CLEAR_EVENT #define NGX_CLEAR_EVENT 0 /* dummy declaration */ #endif diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index 1c87a34..4445adc 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -28,10 +28,10 @@ ngx_event_accept(ngx_event_t *ev) ngx_uint_t level; ngx_socket_t s; ngx_event_t *rev, *wev; + ngx_sockaddr_t sa; ngx_listening_t *ls; ngx_connection_t *c, *lc; ngx_event_conf_t *ecf; - u_char sa[NGX_SOCKADDRLEN]; #if (NGX_HAVE_ACCEPT4) static ngx_uint_t use_accept4 = 1; #endif @@ -58,17 +58,16 @@ ngx_event_accept(ngx_event_t *ev) "accept on %V, ready: %d", &ls->addr_text, ev->available); do { - socklen = NGX_SOCKADDRLEN; + socklen = sizeof(ngx_sockaddr_t); #if (NGX_HAVE_ACCEPT4) if (use_accept4) { - s = accept4(lc->fd, (struct sockaddr *) sa, &socklen, - SOCK_NONBLOCK); + s = accept4(lc->fd, &sa.sockaddr, &socklen, SOCK_NONBLOCK); } else { - s = accept(lc->fd, (struct sockaddr *) sa, &socklen); + s = accept(lc->fd, &sa.sockaddr, &socklen); } #else - s = accept(lc->fd, (struct sockaddr *) sa, &socklen); + s = accept(lc->fd, &sa.sockaddr, &socklen); #endif if (s == (ngx_socket_t) -1) { @@ -171,7 +170,7 @@ ngx_event_accept(ngx_event_t *ev) return; } - ngx_memcpy(c->sockaddr, sa, socklen); + ngx_memcpy(c->sockaddr, &sa, socklen); log = ngx_palloc(c->pool, sizeof(ngx_log_t)); if (log == NULL) { @@ -217,8 +216,6 @@ ngx_event_accept(ngx_event_t *ev) c->local_sockaddr = ls->sockaddr; c->local_socklen = ls->socklen; - c->unexpected_eof = 1; - #if (NGX_HAVE_UNIX_DOMAIN) if (c->sockaddr->sa_family == AF_UNIX) { c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; @@ -330,10 +327,10 @@ ngx_event_recvmsg(ngx_event_t *ev) ngx_event_t *rev, *wev; struct iovec iov[1]; struct msghdr msg; + ngx_sockaddr_t sa; ngx_listening_t *ls; ngx_event_conf_t *ecf; ngx_connection_t *c, *lc; - u_char sa[NGX_SOCKADDRLEN]; static u_char buffer[65535]; #if (NGX_HAVE_MSGHDR_MSG_CONTROL) @@ -378,7 +375,7 @@ ngx_event_recvmsg(ngx_event_t *ev) iov[0].iov_len = sizeof(buffer); msg.msg_name = &sa; - msg.msg_namelen = sizeof(sa); + msg.msg_namelen = sizeof(ngx_sockaddr_t); msg.msg_iov = iov; msg.msg_iovlen = 1; diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c index 8aca862..30cb59a 100644 --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -11,10 +11,19 @@ #include +#if (NGX_HAVE_TRANSPARENT_PROXY) +static ngx_int_t ngx_event_connect_set_transparent(ngx_peer_connection_t *pc, + ngx_socket_t s); +#endif + + ngx_int_t ngx_event_connect_peer(ngx_peer_connection_t *pc) { int rc, type; +#if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX) + in_port_t port; +#endif ngx_int_t event; ngx_err_t err; ngx_uint_t level; @@ -72,6 +81,62 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc) } if (pc->local) { + +#if (NGX_HAVE_TRANSPARENT_PROXY) + if (pc->transparent) { + if (ngx_event_connect_set_transparent(pc, s) != NGX_OK) { + goto failed; + } + } +#endif + +#if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX) + port = ngx_inet_get_port(pc->sockaddr); +#endif + +#if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT) + + if (pc->sockaddr->sa_family != AF_UNIX && port == 0) { + static int bind_address_no_port = 1; + + if (bind_address_no_port) { + if (setsockopt(s, IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT, + (const void *) &bind_address_no_port, + sizeof(int)) == -1) + { + err = ngx_socket_errno; + + if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT) { + ngx_log_error(NGX_LOG_ALERT, pc->log, err, + "setsockopt(IP_BIND_ADDRESS_NO_PORT) " + "failed, ignored"); + + } else { + bind_address_no_port = 0; + } + } + } + } + +#endif + +#if (NGX_LINUX) + + if (pc->type == SOCK_DGRAM && port != 0) { + int reuse_addr = 1; + + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (const void *) &reuse_addr, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, + "setsockopt(SO_REUSEADDR) failed"); + goto failed; + } + } + +#endif + if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) { ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno, "bind(%V) failed", &pc->local->name); @@ -249,6 +314,94 @@ failed: } +#if (NGX_HAVE_TRANSPARENT_PROXY) + +static ngx_int_t +ngx_event_connect_set_transparent(ngx_peer_connection_t *pc, ngx_socket_t s) +{ + int value; + + value = 1; + +#if defined(SO_BINDANY) + + if (setsockopt(s, SOL_SOCKET, SO_BINDANY, + (const void *) &value, sizeof(int)) == -1) + { + ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, + "setsockopt(SO_BINDANY) failed"); + return NGX_ERROR; + } + +#else + + switch (pc->local->sockaddr->sa_family) { + + case AF_INET: + +#if defined(IP_TRANSPARENT) + + if (setsockopt(s, IPPROTO_IP, IP_TRANSPARENT, + (const void *) &value, sizeof(int)) == -1) + { + ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, + "setsockopt(IP_TRANSPARENT) failed"); + return NGX_ERROR; + } + +#elif defined(IP_BINDANY) + + if (setsockopt(s, IPPROTO_IP, IP_BINDANY, + (const void *) &value, sizeof(int)) == -1) + { + ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, + "setsockopt(IP_BINDANY) failed"); + return NGX_ERROR; + } + +#endif + + break; + +#if (NGX_HAVE_INET6) + + case AF_INET6: + +#if defined(IPV6_TRANSPARENT) + + if (setsockopt(s, IPPROTO_IPV6, IPV6_TRANSPARENT, + (const void *) &value, sizeof(int)) == -1) + { + ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, + "setsockopt(IPV6_TRANSPARENT) failed"); + return NGX_ERROR; + } + +#elif defined(IPV6_BINDANY) + + if (setsockopt(s, IPPROTO_IPV6, IPV6_BINDANY, + (const void *) &value, sizeof(int)) == -1) + { + ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, + "setsockopt(IPV6_BINDANY) failed"); + return NGX_ERROR; + } + +#endif + break; + +#endif /* NGX_HAVE_INET6 */ + + } + +#endif /* SO_BINDANY */ + + return NGX_OK; +} + +#endif + + ngx_int_t ngx_event_get_peer(ngx_peer_connection_t *pc, void *data) { diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h index 1bacf82..10b72a1 100644 --- a/src/event/ngx_event_connect.h +++ b/src/event/ngx_event_connect.h @@ -61,6 +61,9 @@ struct ngx_peer_connection_s { ngx_log_t *log; unsigned cached:1; +#if (NGX_HAVE_TRANSPARENT_PROXY) + unsigned transparent:1; +#endif /* ngx_connection_log_error_e */ unsigned log_error:2; diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index de10296..bb9a900 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -105,6 +105,7 @@ int ngx_ssl_server_conf_index; int ngx_ssl_session_cache_index; int ngx_ssl_session_ticket_keys_index; int ngx_ssl_certificate_index; +int ngx_ssl_next_certificate_index; int ngx_ssl_stapling_index; @@ -187,11 +188,17 @@ ngx_ssl_init(ngx_log_t *log) return NGX_ERROR; } - ngx_ssl_stapling_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, - NULL); + ngx_ssl_next_certificate_index = X509_get_ex_new_index(0, NULL, NULL, NULL, + NULL); + if (ngx_ssl_next_certificate_index == -1) { + ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed"); + return NGX_ERROR; + } + + ngx_ssl_stapling_index = X509_get_ex_new_index(0, NULL, NULL, NULL, NULL); + if (ngx_ssl_stapling_index == -1) { - ngx_ssl_error(NGX_LOG_ALERT, log, 0, - "SSL_CTX_get_ex_new_index() failed"); + ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed"); return NGX_ERROR; } @@ -215,6 +222,12 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) return NGX_ERROR; } + if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, NULL) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_set_ex_data() failed"); + return NGX_ERROR; + } + ssl->buffer_size = NGX_SSL_BUFSIZE; /* client side options */ @@ -308,6 +321,29 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) } +ngx_int_t +ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *certs, + ngx_array_t *keys, ngx_array_t *passwords) +{ + ngx_str_t *cert, *key; + ngx_uint_t i; + + cert = certs->elts; + key = keys->elts; + + for (i = 0; i < certs->nelts; i++) { + + if (ngx_ssl_certificate(cf, ssl, &cert[i], &key[i], passwords) + != NGX_OK) + { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords) @@ -351,6 +387,16 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, return NGX_ERROR; } + if (X509_set_ex_data(x509, ngx_ssl_next_certificate_index, + SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index)) + == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed"); + X509_free(x509); + BIO_free(bio); + return NGX_ERROR; + } + if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509) == 0) { @@ -361,8 +407,6 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, return NGX_ERROR; } - X509_free(x509); - /* read rest of the chain */ for ( ;; ) { @@ -387,6 +431,24 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, return NGX_ERROR; } +#ifdef SSL_CTRL_CHAIN_CERT + + /* + * SSL_CTX_add0_chain_cert() is needed to add chain to + * a particular certificate when multiple certificates are used; + * only available in OpenSSL 1.0.2+ + */ + + if (SSL_CTX_add0_chain_cert(ssl->ctx, x509) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_add0_chain_cert(\"%s\") failed", + cert->data); + X509_free(x509); + BIO_free(bio); + return NGX_ERROR; + } + +#else if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509) == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_add_extra_chain_cert(\"%s\") failed", @@ -395,6 +457,7 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, BIO_free(bio); return NGX_ERROR; } +#endif } BIO_free(bio); @@ -528,6 +591,30 @@ ngx_ssl_password_callback(char *buf, int size, int rwflag, void *userdata) } +ngx_int_t +ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers, + ngx_uint_t prefer_server_ciphers) +{ + if (SSL_CTX_set_cipher_list(ssl->ctx, (char *) ciphers->data) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_set_cipher_list(\"%V\") failed", + ciphers); + return NGX_ERROR; + } + + if (prefer_server_ciphers) { + SSL_CTX_set_options(ssl->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); + } + +#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) + /* a temporary 512-bit RSA key is required for export versions of MSIE */ + SSL_CTX_set_tmp_rsa_callback(ssl->ctx, ngx_ssl_rsa512_key_callback); +#endif + + return NGX_OK; +} + + ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_int_t depth) @@ -918,52 +1005,7 @@ ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) DH *dh; BIO *bio; - /* - * -----BEGIN DH PARAMETERS----- - * MIGHAoGBALu8LcrYRnSQfEP89YDpz9vZWKP1aLQtSwju1OsPs1BMbAMCducQgAxc - * y7qokiYUxb7spWWl/fHSh6K8BJvmd4Bg6RqSp1fjBI9osHb302zI8pul34HcLKcl - * 7OZicMyaUDXYzs7vnqAnSmOrHlj6/UmI0PZdFGdX2gcd8EXP4WubAgEC - * -----END DH PARAMETERS----- - */ - - static unsigned char dh1024_p[] = { - 0xBB, 0xBC, 0x2D, 0xCA, 0xD8, 0x46, 0x74, 0x90, 0x7C, 0x43, 0xFC, 0xF5, - 0x80, 0xE9, 0xCF, 0xDB, 0xD9, 0x58, 0xA3, 0xF5, 0x68, 0xB4, 0x2D, 0x4B, - 0x08, 0xEE, 0xD4, 0xEB, 0x0F, 0xB3, 0x50, 0x4C, 0x6C, 0x03, 0x02, 0x76, - 0xE7, 0x10, 0x80, 0x0C, 0x5C, 0xCB, 0xBA, 0xA8, 0x92, 0x26, 0x14, 0xC5, - 0xBE, 0xEC, 0xA5, 0x65, 0xA5, 0xFD, 0xF1, 0xD2, 0x87, 0xA2, 0xBC, 0x04, - 0x9B, 0xE6, 0x77, 0x80, 0x60, 0xE9, 0x1A, 0x92, 0xA7, 0x57, 0xE3, 0x04, - 0x8F, 0x68, 0xB0, 0x76, 0xF7, 0xD3, 0x6C, 0xC8, 0xF2, 0x9B, 0xA5, 0xDF, - 0x81, 0xDC, 0x2C, 0xA7, 0x25, 0xEC, 0xE6, 0x62, 0x70, 0xCC, 0x9A, 0x50, - 0x35, 0xD8, 0xCE, 0xCE, 0xEF, 0x9E, 0xA0, 0x27, 0x4A, 0x63, 0xAB, 0x1E, - 0x58, 0xFA, 0xFD, 0x49, 0x88, 0xD0, 0xF6, 0x5D, 0x14, 0x67, 0x57, 0xDA, - 0x07, 0x1D, 0xF0, 0x45, 0xCF, 0xE1, 0x6B, 0x9B - }; - - static unsigned char dh1024_g[] = { 0x02 }; - - if (file->len == 0) { - - dh = DH_new(); - if (dh == NULL) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "DH_new() failed"); - return NGX_ERROR; - } - - dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL); - dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL); - - if (dh->p == NULL || dh->g == NULL) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "BN_bin2bn() failed"); - DH_free(dh); - return NGX_ERROR; - } - - SSL_CTX_set_tmp_dh(ssl->ctx, dh); - - DH_free(dh); - return NGX_OK; } @@ -1000,27 +1042,69 @@ ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name) { #if OPENSSL_VERSION_NUMBER >= 0x0090800fL #ifndef OPENSSL_NO_ECDH - int nid; - EC_KEY *ecdh; /* * Elliptic-Curve Diffie-Hellman parameters are either "named curves" * from RFC 4492 section 5.1.1, or explicitly described curves over - * binary fields. OpenSSL only supports the "named curves", which provide + * binary fields. OpenSSL only supports the "named curves", which provide * maximum interoperability. */ - nid = OBJ_sn2nid((const char *) name->data); +#ifdef SSL_CTRL_SET_CURVES_LIST + + /* + * OpenSSL 1.0.2+ allows configuring a curve list instead of a single + * curve previously supported. By default an internal list is used, + * with prime256v1 being preferred by server in OpenSSL 1.0.2b+ + * and X25519 in OpenSSL 1.1.0+. + * + * By default a curve preferred by the client will be used for + * key exchange. The SSL_OP_CIPHER_SERVER_PREFERENCE option can + * be used to prefer server curves instead, similar to what it + * does for ciphers. + */ + + SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_ECDH_USE); + +#if SSL_CTRL_SET_ECDH_AUTO + /* not needed in OpenSSL 1.1.0+ */ + SSL_CTX_set_ecdh_auto(ssl->ctx, 1); +#endif + + if (ngx_strcmp(name->data, "auto") == 0) { + return NGX_OK; + } + + if (SSL_CTX_set1_curves_list(ssl->ctx, (char *) name->data) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_set1_curves_list(\"%s\") failed", name->data); + return NGX_ERROR; + } + +#else + + int nid; + char *curve; + EC_KEY *ecdh; + + if (ngx_strcmp(name->data, "auto") == 0) { + curve = "prime256v1"; + + } else { + curve = (char *) name->data; + } + + nid = OBJ_sn2nid(curve); if (nid == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "Unknown curve name \"%s\"", name->data); + "OBJ_sn2nid(\"%s\") failed: unknown curve", curve); return NGX_ERROR; } ecdh = EC_KEY_new_by_curve_name(nid); if (ecdh == NULL) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "Unable to create curve \"%s\"", name->data); + "EC_KEY_new_by_curve_name(\"%s\") failed", curve); return NGX_ERROR; } @@ -1030,6 +1114,7 @@ ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name) EC_KEY_free(ecdh); #endif +#endif #endif return NGX_OK; @@ -2102,7 +2187,7 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, * session reuse (see SSL_SESS_CACHE_OFF above), then * Outlook Express fails to upload a sent email to * the Sent Items folder on the IMAP server via a separate IMAP - * connection in the background. Therefore we have a special + * connection in the background. Therefore we have a special * mode (SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_INTERNAL_STORE) * where the server pretends that it supports session reuse, * but it does not actually store any session. @@ -2164,7 +2249,7 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx) /* * Session ID context is set based on the string provided, - * the server certificate, and the client CA list. + * the server certificates, and the client CA list. */ md = EVP_MD_CTX_create(); @@ -2184,18 +2269,21 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx) goto failed; } - cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index); + for (cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index); + cert; + cert = X509_get_ex_data(cert, ngx_ssl_next_certificate_index)) + { + if (X509_digest(cert, EVP_sha1(), buf, &len) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "X509_digest() failed"); + goto failed; + } - if (X509_digest(cert, EVP_sha1(), buf, &len) == 0) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "X509_digest() failed"); - goto failed; - } - - if (EVP_DigestUpdate(md, buf, len) == 0) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "EVP_DigestUpdate() failed"); - goto failed; + if (EVP_DigestUpdate(md, buf, len) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "EVP_DigestUpdate() failed"); + goto failed; + } } list = SSL_CTX_get_client_CA_list(ssl->ctx); @@ -2951,6 +3039,16 @@ ngx_ssl_cleanup_ctx(void *data) { ngx_ssl_t *ssl = data; + X509 *cert, *next; + + cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index); + + while (cert) { + next = X509_get_ex_data(cert, ngx_ssl_next_certificate_index); + X509_free(cert); + cert = next; + } + SSL_CTX_free(ssl->ctx); } @@ -3526,7 +3624,7 @@ ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) value = cf->args->elts; - engine = ENGINE_by_id((const char *) value[1].data); + engine = ENGINE_by_id((char *) value[1].data); if (engine == NULL) { ngx_ssl_error(NGX_LOG_WARN, cf->log, 0, diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 09654db..3367d10 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -140,8 +140,12 @@ typedef struct { ngx_int_t ngx_ssl_init(ngx_log_t *log); ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data); +ngx_int_t ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_array_t *certs, ngx_array_t *keys, ngx_array_t *passwords); ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords); +ngx_int_t ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers, + ngx_uint_t prefer_server_ciphers); ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_int_t depth); ngx_int_t ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, @@ -227,6 +231,7 @@ extern int ngx_ssl_server_conf_index; extern int ngx_ssl_session_cache_index; extern int ngx_ssl_session_ticket_keys_index; extern int ngx_ssl_certificate_index; +extern int ngx_ssl_next_certificate_index; extern int ngx_ssl_stapling_index; diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c index 5322b1b..cce8e9e 100644 --- a/src/event/ngx_event_openssl_stapling.c +++ b/src/event/ngx_event_openssl_stapling.c @@ -83,11 +83,14 @@ struct ngx_ssl_ocsp_ctx_s { }; +static ngx_int_t ngx_ssl_stapling_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, + X509 *cert, ngx_str_t *file, ngx_str_t *responder, ngx_uint_t verify); static ngx_int_t ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl, - ngx_str_t *file); -static ngx_int_t ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl); + ngx_ssl_stapling_t *staple, ngx_str_t *file); +static ngx_int_t ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_ssl_stapling_t *staple); static ngx_int_t ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl, - ngx_str_t *responder); + ngx_ssl_stapling_t *staple, ngx_str_t *responder); static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data); @@ -121,9 +124,32 @@ ngx_int_t ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file, ngx_str_t *responder, ngx_uint_t verify) { - ngx_int_t rc; - ngx_pool_cleanup_t *cln; - ngx_ssl_stapling_t *staple; + X509 *cert; + + for (cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index); + cert; + cert = X509_get_ex_data(cert, ngx_ssl_next_certificate_index)) + { + if (ngx_ssl_stapling_certificate(cf, ssl, cert, file, responder, verify) + != NGX_OK) + { + return NGX_ERROR; + } + } + + SSL_CTX_set_tlsext_status_cb(ssl->ctx, ngx_ssl_certificate_status_callback); + + return NGX_OK; +} + + +static ngx_int_t +ngx_ssl_stapling_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, X509 *cert, + ngx_str_t *file, ngx_str_t *responder, ngx_uint_t verify) +{ + ngx_int_t rc; + ngx_pool_cleanup_t *cln; + ngx_ssl_stapling_t *staple; staple = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_stapling_t)); if (staple == NULL) { @@ -138,29 +164,27 @@ ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file, cln->handler = ngx_ssl_stapling_cleanup; cln->data = staple; - if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_stapling_index, staple) - == 0) - { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "SSL_CTX_set_ex_data() failed"); + if (X509_set_ex_data(cert, ngx_ssl_stapling_index, staple) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed"); return NGX_ERROR; } staple->ssl_ctx = ssl->ctx; staple->timeout = 60000; staple->verify = verify; + staple->cert = cert; if (file->len) { /* use OCSP response from the file */ - if (ngx_ssl_stapling_file(cf, ssl, file) != NGX_OK) { + if (ngx_ssl_stapling_file(cf, ssl, staple, file) != NGX_OK) { return NGX_ERROR; } - goto done; + return NGX_OK; } - rc = ngx_ssl_stapling_issuer(cf, ssl); + rc = ngx_ssl_stapling_issuer(cf, ssl, staple); if (rc == NGX_DECLINED) { return NGX_OK; @@ -170,7 +194,7 @@ ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file, return NGX_ERROR; } - rc = ngx_ssl_stapling_responder(cf, ssl, responder); + rc = ngx_ssl_stapling_responder(cf, ssl, staple, responder); if (rc == NGX_DECLINED) { return NGX_OK; @@ -180,25 +204,18 @@ ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file, return NGX_ERROR; } -done: - - SSL_CTX_set_tlsext_status_cb(ssl->ctx, ngx_ssl_certificate_status_callback); - SSL_CTX_set_tlsext_status_arg(ssl->ctx, staple); - return NGX_OK; } static ngx_int_t -ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) +ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_ssl_stapling_t *staple, ngx_str_t *file) { - BIO *bio; - int len; - u_char *p, *buf; - OCSP_RESPONSE *response; - ngx_ssl_stapling_t *staple; - - staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index); + BIO *bio; + int len; + u_char *p, *buf; + OCSP_RESPONSE *response; if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) { return NGX_ERROR; @@ -259,19 +276,24 @@ failed: static ngx_int_t -ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl) +ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_ssl_stapling_t *staple) { - int i, n, rc; - X509 *cert, *issuer; - X509_STORE *store; - X509_STORE_CTX *store_ctx; - STACK_OF(X509) *chain; - ngx_ssl_stapling_t *staple; + int i, n, rc; + X509 *cert, *issuer; + X509_STORE *store; + X509_STORE_CTX *store_ctx; + STACK_OF(X509) *chain; - staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index); - cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index); + cert = staple->cert; -#if OPENSSL_VERSION_NUMBER >= 0x10001000L +#ifdef SSL_CTRL_SELECT_CURRENT_CERT + /* OpenSSL 1.0.2+ */ + SSL_CTX_select_current_cert(ssl->ctx, cert); +#endif + +#ifdef SSL_CTRL_GET_EXTRA_CHAIN_CERTS + /* OpenSSL 1.0.1+ */ SSL_CTX_get_extra_chain_certs(ssl->ctx, &chain); #else chain = ssl->ctx->extra_certs; @@ -294,7 +316,6 @@ ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl) ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0, "SSL get issuer: found %p in extra certs", issuer); - staple->cert = cert; staple->issuer = issuer; return NGX_OK; @@ -343,7 +364,6 @@ ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl) ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0, "SSL get issuer: found %p in cert store", issuer); - staple->cert = cert; staple->issuer = issuer; return NGX_OK; @@ -351,15 +371,13 @@ ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl) static ngx_int_t -ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *responder) +ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_ssl_stapling_t *staple, ngx_str_t *responder) { ngx_url_t u; char *s; - ngx_ssl_stapling_t *staple; STACK_OF(OPENSSL_STRING) *aia; - staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index); - if (responder->len == 0) { /* extract OCSP responder URL from certificate */ @@ -443,12 +461,17 @@ ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_resolver_t *resolver, ngx_msec_t resolver_timeout) { + X509 *cert; ngx_ssl_stapling_t *staple; - staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index); - - staple->resolver = resolver; - staple->resolver_timeout = resolver_timeout; + for (cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index); + cert; + cert = X509_get_ex_data(cert, ngx_ssl_next_certificate_index)) + { + staple = X509_get_ex_data(cert, ngx_ssl_stapling_index); + staple->resolver = resolver; + staple->resolver_timeout = resolver_timeout; + } return NGX_OK; } @@ -458,6 +481,7 @@ static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data) { int rc; + X509 *cert; u_char *p; ngx_connection_t *c; ngx_ssl_stapling_t *staple; @@ -467,9 +491,15 @@ ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data) ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL certificate status callback"); - staple = data; rc = SSL_TLSEXT_ERR_NOACK; + cert = SSL_get_certificate(ssl_conn); + staple = X509_get_ex_data(cert, ngx_ssl_stapling_index); + + if (staple == NULL) { + return rc; + } + if (staple->staple.len && staple->valid >= ngx_time()) { @@ -597,7 +627,13 @@ ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx) goto error; } -#if OPENSSL_VERSION_NUMBER >= 0x10001000L +#ifdef SSL_CTRL_SELECT_CURRENT_CERT + /* OpenSSL 1.0.2+ */ + SSL_CTX_select_current_cert(staple->ssl_ctx, ctx->cert); +#endif + +#ifdef SSL_CTRL_GET_EXTRA_CHAIN_CERTS + /* OpenSSL 1.0.1+ */ SSL_CTX_get_extra_chain_certs(staple->ssl_ctx, &chain); #else chain = staple->ssl_ctx->extra_certs; @@ -884,7 +920,6 @@ ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve) u_char *p; size_t len; - in_port_t port; socklen_t socklen; ngx_uint_t i; struct sockaddr *sockaddr; @@ -926,8 +961,6 @@ ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve) goto failed; } - port = htons(ctx->port); - for (i = 0; i < resolve->naddrs; i++) { socklen = resolve->addrs[i].socklen; @@ -938,16 +971,7 @@ ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve) } ngx_memcpy(sockaddr, resolve->addrs[i].sockaddr, socklen); - - switch (sockaddr->sa_family) { -#if (NGX_HAVE_INET6) - case AF_INET6: - ((struct sockaddr_in6 *) sockaddr)->sin6_port = port; - break; -#endif - default: /* AF_INET */ - ((struct sockaddr_in *) sockaddr)->sin_port = port; - } + ngx_inet_set_port(sockaddr, ctx->port); ctx->addrs[i].sockaddr = sockaddr; ctx->addrs[i].socklen = socklen; diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c index 3600265..012a0fb 100644 --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -161,6 +161,12 @@ ngx_http_dav_handler(ngx_http_request_t *r) return NGX_HTTP_CONFLICT; } + if (r->headers_in.content_range) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "PUT with range is unsupported"); + return NGX_HTTP_NOT_IMPLEMENTED; + } + r->request_body_in_file_only = 1; r->request_body_in_persistent_file = 1; r->request_body_in_clean_file = 1; diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 2d288ce..62502b0 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -279,7 +279,7 @@ static ngx_command_t ngx_http_fastcgi_commands[] = { NULL }, { ngx_string("fastcgi_bind"), - 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_TAKE12, ngx_http_upstream_bind_set_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_fastcgi_loc_conf_t, upstream.local), diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c index df9424f..c42fb08 100644 --- a/src/http/modules/ngx_http_log_module.c +++ b/src/http/modules/ngx_http_log_module.c @@ -1000,7 +1000,7 @@ ngx_http_log_escape(u_char *dst, u_char *src, size_t size) n = 0; while (size) { - if (escape[*src >> 5] & (1 << (*src & 0x1f))) { + if (escape[*src >> 5] & (1U << (*src & 0x1f))) { n++; } src++; @@ -1011,7 +1011,7 @@ ngx_http_log_escape(u_char *dst, u_char *src, size_t size) } while (size) { - if (escape[*src >> 5] & (1 << (*src & 0x1f))) { + if (escape[*src >> 5] & (1U << (*src & 0x1f))) { *dst++ = '\\'; *dst++ = 'x'; *dst++ = hex[*src >> 4]; diff --git a/src/http/modules/ngx_http_map_module.c b/src/http/modules/ngx_http_map_module.c index 091ff09..732aa5d 100644 --- a/src/http/modules/ngx_http_map_module.c +++ b/src/http/modules/ngx_http_map_module.c @@ -20,7 +20,6 @@ typedef struct { ngx_hash_keys_arrays_t keys; ngx_array_t *values_hash; - ngx_array_t var_values; #if (NGX_PCRE) ngx_array_t regexes; #endif @@ -110,7 +109,8 @@ ngx_http_map_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, { ngx_http_map_ctx_t *map = (ngx_http_map_ctx_t *) data; - ngx_str_t val; + ngx_str_t val, str; + ngx_http_complex_value_t *cv; ngx_http_variable_value_t *value; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -131,14 +131,21 @@ ngx_http_map_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, } if (!value->valid) { - value = ngx_http_get_flushed_variable(r, (uintptr_t) value->data); + cv = (ngx_http_complex_value_t *) value->data; - if (value == NULL || value->not_found) { - value = &ngx_http_variable_null_value; + if (ngx_http_complex_value(r, cv, &str) != NGX_OK) { + return NGX_ERROR; } - } - *v = *value; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->len = str.len; + v->data = str.data; + + } else { + *v = *value; + } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http map: \"%V\" \"%v\"", &val, v); @@ -246,14 +253,6 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - if (ngx_array_init(&ctx.var_values, cf->pool, 2, - sizeof(ngx_http_variable_value_t)) - != NGX_OK) - { - ngx_destroy_pool(pool); - return NGX_CONF_ERROR; - } - #if (NGX_PCRE) if (ngx_array_init(&ctx.regexes, cf->pool, 2, sizeof(ngx_http_map_regex_t)) != NGX_OK) @@ -375,11 +374,15 @@ ngx_http_map_cmp_dns_wildcards(const void *one, const void *two) static char * ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) { - ngx_int_t rv, index; - ngx_str_t *value, name; - ngx_uint_t i, key; - ngx_http_map_conf_ctx_t *ctx; - ngx_http_variable_value_t *var, **vp; + u_char *data; + size_t len; + ngx_int_t rv; + ngx_str_t *value, v; + ngx_uint_t i, key; + ngx_http_map_conf_ctx_t *ctx; + ngx_http_complex_value_t cv, *cvp; + ngx_http_variable_value_t *var, **vp; + ngx_http_compile_complex_value_t ccv; ctx = cf->ctx; @@ -401,39 +404,6 @@ ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) return ngx_conf_include(cf, dummy, conf); } - if (value[1].data[0] == '$') { - name = value[1]; - name.len--; - name.data++; - - index = ngx_http_get_variable_index(ctx->cf, &name); - if (index == NGX_ERROR) { - return NGX_CONF_ERROR; - } - - var = ctx->var_values.elts; - - for (i = 0; i < ctx->var_values.nelts; i++) { - if (index == (intptr_t) var[i].data) { - var = &var[i]; - goto found; - } - } - - var = ngx_array_push(&ctx->var_values); - if (var == NULL) { - return NGX_CONF_ERROR; - } - - var->valid = 0; - var->no_cacheable = 0; - var->not_found = 0; - var->len = 0; - var->data = (u_char *) (intptr_t) index; - - goto found; - } - key = 0; for (i = 0; i < value[1].len; i++) { @@ -446,11 +416,22 @@ ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) if (vp) { for (i = 0; i < ctx->values_hash[key].nelts; i++) { - if (value[1].len != (size_t) vp[i]->len) { + + if (vp[i]->valid) { + data = vp[i]->data; + len = vp[i]->len; + + } else { + cvp = (ngx_http_complex_value_t *) vp[i]->data; + data = cvp->value.data; + len = cvp->value.len; + } + + if (value[1].len != len) { continue; } - if (ngx_strncmp(value[1].data, vp[i]->data, value[1].len) == 0) { + if (ngx_strncmp(value[1].data, data, len) == 0) { var = vp[i]; goto found; } @@ -470,13 +451,40 @@ ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) return NGX_CONF_ERROR; } - var->len = value[1].len; - var->data = ngx_pstrdup(ctx->keys.pool, &value[1]); - if (var->data == NULL) { + v.len = value[1].len; + v.data = ngx_pstrdup(ctx->keys.pool, &value[1]); + if (v.data == NULL) { return NGX_CONF_ERROR; } - var->valid = 1; + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = ctx->cf; + ccv.value = &v; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + cvp = ngx_palloc(ctx->keys.pool, sizeof(ngx_http_complex_value_t)); + if (cvp == NULL) { + return NGX_CONF_ERROR; + } + + *cvp = cv; + + var->len = 0; + var->data = (u_char *) cvp; + var->valid = 0; + + } else { + var->len = v.len; + var->data = v.data; + var->valid = 1; + } + var->no_cacheable = 0; var->not_found = 0; diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c index d31996a..69f28fa 100644 --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -61,7 +61,7 @@ static ngx_command_t ngx_http_memcached_commands[] = { NULL }, { ngx_string("memcached_bind"), - 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_TAKE12, ngx_http_upstream_bind_set_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_memcached_loc_conf_t, upstream.local), diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index c24ef17..4f49a52 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -316,7 +316,7 @@ static ngx_command_t ngx_http_proxy_commands[] = { NULL }, { ngx_string("proxy_bind"), - 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_TAKE12, ngx_http_upstream_bind_set_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_proxy_loc_conf_t, upstream.local), @@ -4323,13 +4323,9 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) } } - if (SSL_CTX_set_cipher_list(plcf->upstream.ssl->ctx, - (const char *) plcf->ssl_ciphers.data) - == 0) + if (ngx_ssl_ciphers(cf, plcf->upstream.ssl, &plcf->ssl_ciphers, 0) + != NGX_OK) { - ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, - "SSL_CTX_set_cipher_list(\"%V\") failed", - &plcf->ssl_ciphers); return NGX_ERROR; } diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c index b7befe6..490a53d 100644 --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -45,10 +45,14 @@ static char *ngx_http_realip_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); static ngx_int_t ngx_http_realip_add_variables(ngx_conf_t *cf); static ngx_int_t ngx_http_realip_init(ngx_conf_t *cf); +static ngx_http_realip_ctx_t *ngx_http_realip_get_module_ctx( + ngx_http_request_t *r); static ngx_int_t ngx_http_realip_remote_addr_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_realip_remote_port_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_command_t ngx_http_realip_commands[] = { @@ -115,6 +119,9 @@ static ngx_http_variable_t ngx_http_realip_vars[] = { { ngx_string("realip_remote_addr"), NULL, ngx_http_realip_remote_addr_variable, 0, 0, 0 }, + { ngx_string("realip_remote_port"), NULL, + ngx_http_realip_remote_port_variable, 0, 0, 0 }, + { ngx_null_string, NULL, NULL, 0, 0, 0 } }; @@ -230,6 +237,10 @@ found: rlcf->recursive) != NGX_DECLINED) { + if (rlcf->type == NGX_HTTP_REALIP_PROXY) { + ngx_inet_set_port(addr.sockaddr, c->proxy_protocol_port); + } + return ngx_http_realip_set_addr(r, &addr); } @@ -358,6 +369,10 @@ ngx_http_realip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; + if (rlcf->type != NGX_CONF_UNSET_UINT) { + return "is duplicate"; + } + value = cf->args->elts; if (ngx_strcmp(value[1].data, "X-Real-IP") == 0) { @@ -475,11 +490,9 @@ ngx_http_realip_init(ngx_conf_t *cf) } -static ngx_int_t -ngx_http_realip_remote_addr_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) +static ngx_http_realip_ctx_t * +ngx_http_realip_get_module_ctx(ngx_http_request_t *r) { - ngx_str_t *addr_text; ngx_pool_cleanup_t *cln; ngx_http_realip_ctx_t *ctx; @@ -500,6 +513,19 @@ ngx_http_realip_remote_addr_variable(ngx_http_request_t *r, } } + return ctx; +} + + +static ngx_int_t +ngx_http_realip_remote_addr_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_str_t *addr_text; + ngx_http_realip_ctx_t *ctx; + + ctx = ngx_http_realip_get_module_ctx(r); + addr_text = ctx ? &ctx->addr_text : &r->connection->addr_text; v->len = addr_text->len; @@ -510,3 +536,35 @@ ngx_http_realip_remote_addr_variable(ngx_http_request_t *r, return NGX_OK; } + + +static ngx_int_t +ngx_http_realip_remote_port_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_uint_t port; + struct sockaddr *sa; + ngx_http_realip_ctx_t *ctx; + + ctx = ngx_http_realip_get_module_ctx(r); + + sa = ctx ? ctx->sockaddr : r->connection->sockaddr; + + v->len = 0; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + v->data = ngx_pnalloc(r->pool, sizeof("65535") - 1); + if (v->data == NULL) { + return NGX_ERROR; + } + + port = ngx_inet_get_port(sa); + + if (port > 0 && port < 65536) { + v->len = ngx_sprintf(v->data, "%ui", port) - v->data; + } + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index f09617e..36656ec 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -136,7 +136,7 @@ static ngx_command_t ngx_http_scgi_commands[] = { NULL }, { ngx_string("scgi_bind"), - 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_TAKE12, ngx_http_upstream_bind_set_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_scgi_loc_conf_t, upstream.local), diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 6a4108c..d685ae9 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -15,7 +15,7 @@ typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c, #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" -#define NGX_DEFAULT_ECDH_CURVE "prime256v1" +#define NGX_DEFAULT_ECDH_CURVE "auto" #define NGX_HTTP_NPN_ADVERTISE "\x08http/1.1" @@ -81,16 +81,16 @@ static ngx_command_t ngx_http_ssl_commands[] = { { ngx_string("ssl_certificate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_conf_set_str_array_slot, NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_ssl_srv_conf_t, certificate), + offsetof(ngx_http_ssl_srv_conf_t, certificates), NULL }, { ngx_string("ssl_certificate_key"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_conf_set_str_array_slot, NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_ssl_srv_conf_t, certificate_key), + offsetof(ngx_http_ssl_srv_conf_t, certificate_keys), NULL }, { ngx_string("ssl_password_file"), @@ -508,8 +508,6 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) * set by ngx_pcalloc(): * * sscf->protocols = 0; - * sscf->certificate = { 0, NULL }; - * sscf->certificate_key = { 0, NULL }; * sscf->dhparam = { 0, NULL }; * sscf->ecdh_curve = { 0, NULL }; * sscf->client_certificate = { 0, NULL }; @@ -526,6 +524,8 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) sscf->buffer_size = NGX_CONF_UNSET_SIZE; sscf->verify = NGX_CONF_UNSET_UINT; sscf->verify_depth = NGX_CONF_UNSET_UINT; + sscf->certificates = NGX_CONF_UNSET_PTR; + sscf->certificate_keys = NGX_CONF_UNSET_PTR; sscf->passwords = NGX_CONF_UNSET_PTR; sscf->builtin_session_cache = NGX_CONF_UNSET; sscf->session_timeout = NGX_CONF_UNSET; @@ -573,8 +573,9 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_uint_value(conf->verify, prev->verify, 0); ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1); - ngx_conf_merge_str_value(conf->certificate, prev->certificate, ""); - ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, ""); + ngx_conf_merge_ptr_value(conf->certificates, prev->certificates, NULL); + ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys, + NULL); ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL); @@ -601,7 +602,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) if (conf->enable) { - if (conf->certificate.len == 0) { + if (conf->certificates == NULL) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no \"ssl_certificate\" is defined for " "the \"ssl\" directive in %s:%ui", @@ -609,7 +610,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } - if (conf->certificate_key.len == 0) { + if (conf->certificate_keys == NULL) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no \"ssl_certificate_key\" is defined for " "the \"ssl\" directive in %s:%ui", @@ -617,16 +618,31 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } + if (conf->certificate_keys->nelts < conf->certificates->nelts) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate_key\" is defined " + "for certificate \"%V\" and " + "the \"ssl\" directive in %s:%ui", + ((ngx_str_t *) conf->certificates->elts) + + conf->certificates->nelts - 1, + conf->file, conf->line); + return NGX_CONF_ERROR; + } + } else { - if (conf->certificate.len == 0) { + if (conf->certificates == NULL) { return NGX_CONF_OK; } - if (conf->certificate_key.len == 0) { + if (conf->certificate_keys == NULL + || conf->certificate_keys->nelts < conf->certificates->nelts) + { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no \"ssl_certificate_key\" is defined " - "for certificate \"%V\"", &conf->certificate); + "for certificate \"%V\"", + ((ngx_str_t *) conf->certificates->elts) + + conf->certificates->nelts - 1); return NGX_CONF_ERROR; } } @@ -666,20 +682,17 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) cln->handler = ngx_ssl_cleanup_ctx; cln->data = &conf->ssl; - if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate, - &conf->certificate_key, conf->passwords) + if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates, + conf->certificate_keys, conf->passwords) != NGX_OK) { return NGX_CONF_ERROR; } - if (SSL_CTX_set_cipher_list(conf->ssl.ctx, - (const char *) conf->ciphers.data) - == 0) + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, + conf->prefer_server_ciphers) + != NGX_OK) { - ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, - "SSL_CTX_set_cipher_list(\"%V\") failed", - &conf->ciphers); return NGX_CONF_ERROR; } @@ -714,15 +727,6 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } - if (conf->prefer_server_ciphers) { - SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); - } - -#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) - /* a temporary 512-bit RSA key is required for export versions of MSIE */ - SSL_CTX_set_tmp_rsa_callback(conf->ssl.ctx, ngx_ssl_rsa512_key_callback); -#endif - if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h index 8e69e9e..57f5941 100644 --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -32,8 +32,9 @@ typedef struct { time_t session_timeout; - ngx_str_t certificate; - ngx_str_t certificate_key; + ngx_array_t *certificates; + ngx_array_t *certificate_keys; + ngx_str_t dhparam; ngx_str_t ecdh_curve; ngx_str_t client_certificate; diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c index bb1c50b..e8d1d80 100644 --- a/src/http/modules/ngx_http_sub_filter_module.c +++ b/src/http/modules/ngx_http_sub_filter_module.c @@ -83,7 +83,9 @@ static ngx_uint_t ngx_http_sub_cmp_index; static ngx_int_t ngx_http_sub_output(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx); static ngx_int_t ngx_http_sub_parse(ngx_http_request_t *r, - ngx_http_sub_ctx_t *ctx); + ngx_http_sub_ctx_t *ctx, ngx_uint_t flush); +static ngx_int_t ngx_http_sub_match(ngx_http_sub_ctx_t *ctx, ngx_int_t start, + ngx_str_t *m); static char * ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -285,6 +287,7 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_int_t rc; ngx_buf_t *b; ngx_str_t *sub; + ngx_uint_t flush, last; ngx_chain_t *cl; ngx_http_sub_ctx_t *ctx; ngx_http_sub_match_t *match; @@ -326,6 +329,9 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http sub filter \"%V\"", &r->uri); + flush = 0; + last = 0; + while (ctx->in || ctx->buf) { if (ctx->buf == NULL) { @@ -334,11 +340,19 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ctx->pos = ctx->buf->pos; } + if (ctx->buf->flush || ctx->buf->recycled) { + flush = 1; + } + + if (ctx->in == NULL) { + last = flush; + } + b = NULL; while (ctx->pos < ctx->buf->last) { - rc = ngx_http_sub_parse(r, ctx); + rc = ngx_http_sub_parse(r, ctx, last); ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "parse: %i, looked: \"%V\" %p-%p", @@ -590,9 +604,10 @@ ngx_http_sub_output(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) static ngx_int_t -ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) +ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx, + ngx_uint_t flush) { - u_char *p, *last, *pat, *pat_end, c; + u_char *p, c; ngx_str_t *m; ngx_int_t offset, start, next, end, len, rc; ngx_uint_t shift, i, j; @@ -602,6 +617,7 @@ ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module); tables = ctx->tables; + match = ctx->matches->elts; offset = ctx->offset; end = ctx->buf->last - ctx->pos; @@ -628,7 +644,6 @@ ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) /* a potential match */ start = offset - (ngx_int_t) tables->min_match_len + 1; - match = ctx->matches->elts; i = ngx_max(tables->index[c], ctx->index); j = tables->index[c + 1]; @@ -641,41 +656,15 @@ ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) m = &match[i].match; - pat = m->data; - pat_end = m->data + m->len; + rc = ngx_http_sub_match(ctx, start, m); - if (start >= 0) { - p = ctx->pos + start; - - } else { - last = ctx->looked.data + ctx->looked.len; - p = last + start; - - while (p < last && pat < pat_end) { - if (ngx_tolower(*p) != *pat) { - goto next; - } - - p++; - pat++; - } - - p = ctx->pos; - } - - while (p < ctx->buf->last && pat < pat_end) { - if (ngx_tolower(*p) != *pat) { - goto next; - } - - p++; - pat++; + if (rc == NGX_DECLINED) { + goto next; } ctx->index = i; - if (pat != pat_end) { - /* partial match */ + if (rc == NGX_AGAIN) { goto again; } @@ -695,6 +684,26 @@ ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) ctx->index = 0; } + if (flush) { + for ( ;; ) { + start = offset - (ngx_int_t) tables->min_match_len + 1; + + if (start >= end) { + break; + } + + for (i = 0; i < ctx->matches->nelts; i++) { + m = &match[i].match; + + if (ngx_http_sub_match(ctx, start, m) == NGX_AGAIN) { + goto again; + } + } + + offset++; + } + } + again: ctx->offset = offset; @@ -731,6 +740,51 @@ done: } +static ngx_int_t +ngx_http_sub_match(ngx_http_sub_ctx_t *ctx, ngx_int_t start, ngx_str_t *m) +{ + u_char *p, *last, *pat, *pat_end; + + pat = m->data; + pat_end = m->data + m->len; + + if (start >= 0) { + p = ctx->pos + start; + + } else { + last = ctx->looked.data + ctx->looked.len; + p = last + start; + + while (p < last && pat < pat_end) { + if (ngx_tolower(*p) != *pat) { + return NGX_DECLINED; + } + + p++; + pat++; + } + + p = ctx->pos; + } + + while (p < ctx->buf->last && pat < pat_end) { + if (ngx_tolower(*p) != *pat) { + return NGX_DECLINED; + } + + p++; + pat++; + } + + if (pat != pat_end) { + /* partial match */ + return NGX_AGAIN; + } + + return NGX_OK; +} + + static char * ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c b/src/http/modules/ngx_http_upstream_keepalive_module.c index 85bfcdb..0048e6b 100644 --- a/src/http/modules/ngx_http_upstream_keepalive_module.c +++ b/src/http/modules/ngx_http_upstream_keepalive_module.c @@ -29,7 +29,7 @@ typedef struct { ngx_connection_t *connection; socklen_t socklen; - u_char sockaddr[NGX_SOCKADDRLEN]; + ngx_sockaddr_t sockaddr; } ngx_http_upstream_keepalive_cache_t; diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c index 1487c09..0dbacba 100644 --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -836,7 +836,7 @@ ngx_http_userid_init_worker(ngx_cycle_t *cycle) ngx_gettimeofday(&tp); /* use the most significant usec part that fits to 16 bits */ - start_value = ((tp.tv_usec / 20) << 16) | ngx_pid; + start_value = (((uint32_t) tp.tv_usec / 20) << 16) | ngx_pid; return NGX_OK; } diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index fef2c46..7f916e8 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -196,7 +196,7 @@ static ngx_command_t ngx_http_uwsgi_commands[] = { NULL }, { ngx_string("uwsgi_bind"), - 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_TAKE12, ngx_http_upstream_bind_set_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_uwsgi_loc_conf_t, upstream.local), @@ -2325,13 +2325,9 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf) } } - if (SSL_CTX_set_cipher_list(uwcf->upstream.ssl->ctx, - (const char *) uwcf->ssl_ciphers.data) - == 0) + if (ngx_ssl_ciphers(cf, uwcf->upstream.ssl, &uwcf->ssl_ciphers, 0) + != NGX_OK) { - ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, - "SSL_CTX_set_cipher_list(\"%V\") failed", - &uwcf->ssl_ciphers); return NGX_ERROR; } diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index 0ceb613..7a46b3e 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1144,12 +1144,8 @@ ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, in_port_t p; ngx_uint_t i; struct sockaddr *sa; - struct sockaddr_in *sin; ngx_http_conf_port_t *port; ngx_http_core_main_conf_t *cmcf; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); @@ -1161,28 +1157,8 @@ ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, } } - sa = &lsopt->u.sockaddr; - - switch (sa->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = &lsopt->u.sockaddr_in6; - p = sin6->sin6_port; - break; -#endif - -#if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - p = 0; - break; -#endif - - default: /* AF_INET */ - sin = &lsopt->u.sockaddr_in; - p = sin->sin_port; - break; - } + sa = &lsopt->sockaddr.sockaddr; + p = ngx_inet_get_port(sa); port = cmcf->ports->elts; for (i = 0; i < cmcf->ports->nelts; i++) { @@ -1215,14 +1191,8 @@ static ngx_int_t ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt) { - u_char *p; - size_t len, off; ngx_uint_t i, default_server, proxy_protocol; - struct sockaddr *sa; ngx_http_conf_addr_t *addr; -#if (NGX_HAVE_UNIX_DOMAIN) - struct sockaddr_un *saun; -#endif #if (NGX_HTTP_SSL) ngx_uint_t ssl; #endif @@ -1235,37 +1205,15 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, * may fill some fields in inherited sockaddr struct's */ - sa = &lsopt->u.sockaddr; - - switch (sa->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - off = offsetof(struct sockaddr_in6, sin6_addr); - len = 16; - break; -#endif - -#if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - off = offsetof(struct sockaddr_un, sun_path); - len = sizeof(saun->sun_path); - break; -#endif - - default: /* AF_INET */ - off = offsetof(struct sockaddr_in, sin_addr); - len = 4; - break; - } - - p = lsopt->u.sockaddr_data + off; - addr = port->addrs.elts; for (i = 0; i < port->addrs.nelts; i++) { - if (ngx_memcmp(p, addr[i].opt.u.sockaddr_data + off, len) != 0) { + if (ngx_cmp_sockaddr(&lsopt->sockaddr.sockaddr, lsopt->socklen, + &addr[i].opt.sockaddr.sockaddr, + addr[i].opt.socklen, 0) + != NGX_OK) + { continue; } @@ -1756,7 +1704,8 @@ ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; - ls = ngx_create_listening(cf, &addr->opt.u.sockaddr, addr->opt.socklen); + ls = ngx_create_listening(cf, &addr->opt.sockaddr.sockaddr, + addr->opt.socklen); if (ls == NULL) { return NULL; } @@ -1846,7 +1795,7 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport, for (i = 0; i < hport->naddrs; i++) { - sin = &addr[i].opt.u.sockaddr_in; + sin = &addr[i].opt.sockaddr.sockaddr_in; addrs[i].addr = sin->sin_addr.s_addr; addrs[i].conf.default_server = addr[i].default_server; #if (NGX_HTTP_SSL) @@ -1911,7 +1860,7 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport, for (i = 0; i < hport->naddrs; i++) { - sin6 = &addr[i].opt.u.sockaddr_in6; + sin6 = &addr[i].opt.sockaddr.sockaddr_in6; addrs6[i].addr6 = sin6->sin6_addr; addrs6[i].conf.default_server = addr[i].default_server; #if (NGX_HTTP_SSL) diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index bd36aec..76917bb 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -793,8 +793,6 @@ ngx_http_handler(ngx_http_request_t *r) r->connection->log->action = NULL; - r->connection->unexpected_eof = 0; - if (!r->internal) { switch (r->headers_in.connection_type) { case 0: @@ -2912,7 +2910,9 @@ ngx_http_get_forwarded_addr_internal(ngx_http_request_t *r, ngx_addr_t *addr, } } - if (ngx_parse_addr(r->pool, &paddr, p, xfflen - (p - xff)) != NGX_OK) { + if (ngx_parse_addr_port(r->pool, &paddr, p, xfflen - (p - xff)) + != NGX_OK) + { return NGX_DECLINED; } @@ -3032,7 +3032,7 @@ ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) if (rv == NGX_CONF_OK && !cscf->listen) { ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t)); - sin = &lsopt.u.sockaddr_in; + sin = &lsopt.sockaddr.sockaddr_in; sin->sin_family = AF_INET; #if (NGX_WIN32) @@ -3055,8 +3055,8 @@ ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) #endif lsopt.wildcard = 1; - (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.socklen, lsopt.addr, - NGX_SOCKADDR_STRLEN, 1); + (void) ngx_sock_ntop(&lsopt.sockaddr.sockaddr, lsopt.socklen, + lsopt.addr, NGX_SOCKADDR_STRLEN, 1); if (ngx_http_add_listen(cf, cscf, &lsopt) != NGX_OK) { return NGX_CONF_ERROR; @@ -4000,7 +4000,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t)); - ngx_memcpy(&lsopt.u.sockaddr, u.sockaddr, u.socklen); + ngx_memcpy(&lsopt.sockaddr.sockaddr, &u.sockaddr, u.socklen); lsopt.socklen = u.socklen; lsopt.backlog = NGX_LISTEN_BACKLOG; @@ -4017,7 +4017,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) lsopt.ipv6only = 1; #endif - (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.socklen, lsopt.addr, + (void) ngx_sock_ntop(&lsopt.sockaddr.sockaddr, lsopt.socklen, lsopt.addr, NGX_SOCKADDR_STRLEN, 1); for (n = 2; n < cf->args->nelts; n++) { @@ -4146,7 +4146,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) struct sockaddr *sa; - sa = &lsopt.u.sockaddr; + sa = &lsopt.sockaddr.sockaddr; if (sa->sa_family == AF_INET6) { diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 6c446a0..773c215 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -58,18 +58,7 @@ typedef struct ngx_http_core_loc_conf_s ngx_http_core_loc_conf_t; typedef struct { - union { - struct sockaddr sockaddr; - struct sockaddr_in sockaddr_in; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 sockaddr_in6; -#endif -#if (NGX_HAVE_UNIX_DOMAIN) - struct sockaddr_un sockaddr_un; -#endif - u_char sockaddr_data[NGX_SOCKADDRLEN]; - } u; - + ngx_sockaddr_t sockaddr; socklen_t socklen; unsigned set:1; diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index 37cd377..4bf0f7f 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -101,7 +101,7 @@ ngx_http_file_cache_init(ngx_shm_zone_t *shm_zone, void *data) return NGX_ERROR; } - for (n = 0; n < 3; n++) { + for (n = 0; n < NGX_MAX_PATH_LEVEL; n++) { if (cache->path->level[n] != ocache->path->level[n]) { ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, "cache \"%V\" had previously different levels", @@ -1403,6 +1403,7 @@ ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf) ngx_shmtx_lock(&cache->shpool->mutex); c->node->count--; + c->node->error = 0; c->node->uniq = uniq; c->node->body_start = c->body_start; @@ -2256,7 +2257,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) p = value[i].data + 7; last = value[i].data + value[i].len; - for (n = 0; n < 3 && p < last; n++) { + for (n = 0; n < NGX_MAX_PATH_LEVEL && p < last; n++) { if (*p > '0' && *p < '3') { @@ -2267,7 +2268,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) break; } - if (*p++ == ':' && n < 2 && p != last) { + if (*p++ == ':' && n < NGX_MAX_PATH_LEVEL - 1 && p < last) { continue; } @@ -2277,7 +2278,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) goto invalid_levels; } - if (cache->path->len < 10 + 3) { + if (cache->path->len < 10 + NGX_MAX_PATH_LEVEL) { continue; } @@ -2449,7 +2450,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_memcpy(p, "/temp", sizeof("/temp")); ngx_memcpy(&cache->temp_path->level, &cache->path->level, - 3 * sizeof(size_t)); + NGX_MAX_PATH_LEVEL * sizeof(size_t)); cache->temp_path->len = cache->path->len; cache->temp_path->conf_file = cf->conf_file->file.name.data; diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c index 507dc93..f000b2e 100644 --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -95,17 +95,17 @@ static ngx_str_t ngx_http_status_lines[] = { ngx_string("414 Request-URI Too Large"), ngx_string("415 Unsupported Media Type"), ngx_string("416 Requested Range Not Satisfiable"), + ngx_null_string, /* "417 Expectation Failed" */ + ngx_null_string, /* "418 unused" */ + ngx_null_string, /* "419 unused" */ + ngx_null_string, /* "420 unused" */ + ngx_string("421 Misdirected Request"), - /* ngx_null_string, */ /* "417 Expectation Failed" */ - /* ngx_null_string, */ /* "418 unused" */ - /* ngx_null_string, */ /* "419 unused" */ - /* ngx_null_string, */ /* "420 unused" */ - /* ngx_null_string, */ /* "421 unused" */ /* ngx_null_string, */ /* "422 Unprocessable Entity" */ /* ngx_null_string, */ /* "423 Locked" */ /* ngx_null_string, */ /* "424 Failed Dependency" */ -#define NGX_HTTP_LAST_4XX 417 +#define NGX_HTTP_LAST_4XX 422 #define NGX_HTTP_OFF_5XX (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX) ngx_string("500 Internal Server Error"), @@ -113,10 +113,10 @@ static ngx_str_t ngx_http_status_lines[] = { ngx_string("502 Bad Gateway"), ngx_string("503 Service Temporarily Unavailable"), ngx_string("504 Gateway Time-out"), - ngx_null_string, /* "505 HTTP Version Not Supported" */ ngx_null_string, /* "506 Variant Also Negotiates" */ ngx_string("507 Insufficient Storage"), + /* ngx_null_string, */ /* "508 unused" */ /* ngx_null_string, */ /* "509 unused" */ /* ngx_null_string, */ /* "510 Not Extended" */ @@ -161,10 +161,6 @@ ngx_http_header_filter(ngx_http_request_t *r) ngx_connection_t *c; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; - struct sockaddr_in *sin; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif u_char addr[NGX_SOCKADDR_STRLEN]; if (r->header_sent) { @@ -333,24 +329,7 @@ ngx_http_header_filter(ngx_http_request_t *r) } } - switch (c->local_sockaddr->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) c->local_sockaddr; - port = ntohs(sin6->sin6_port); - break; -#endif -#if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - port = 0; - break; -#endif - default: /* AF_INET */ - sin = (struct sockaddr_in *) c->local_sockaddr; - port = ntohs(sin->sin_port); - break; - } + port = ngx_inet_get_port(c->local_sockaddr); len += sizeof("Location: https://") - 1 + host.len diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index 0e0b3a2..bd6c9c9 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -481,7 +481,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) /* check "/.", "//", "%", and "\" (Win32) in URI */ case sw_after_slash_in_uri: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { state = sw_check_uri; break; } @@ -540,7 +540,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) /* check "/", "%" and "\" (Win32) in URI */ case sw_check_uri: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { break; } @@ -626,7 +626,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) /* URI */ case sw_uri: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { break; } @@ -737,6 +737,10 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) return NGX_HTTP_PARSE_INVALID_REQUEST; } + if (r->http_major > 99) { + return NGX_HTTP_PARSE_INVALID_REQUEST; + } + r->http_major = r->http_major * 10 + ch - '0'; break; @@ -770,6 +774,10 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) return NGX_HTTP_PARSE_INVALID_REQUEST; } + if (r->http_minor > 99) { + return NGX_HTTP_PARSE_INVALID_REQUEST; + } + r->http_minor = r->http_minor * 10 + ch - '0'; break; @@ -1123,7 +1131,7 @@ ngx_http_parse_uri(ngx_http_request_t *r) /* check "/.", "//", "%", and "\" (Win32) in URI */ case sw_after_slash_in_uri: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { state = sw_check_uri; break; } @@ -1171,7 +1179,7 @@ ngx_http_parse_uri(ngx_http_request_t *r) /* check "/", "%" and "\" (Win32) in URI */ case sw_check_uri: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { break; } @@ -1220,7 +1228,7 @@ ngx_http_parse_uri(ngx_http_request_t *r) /* URI */ case sw_uri: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { break; } @@ -1281,7 +1289,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) case sw_usual: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { *u++ = ch; ch = *p++; break; @@ -1350,7 +1358,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) case sw_slash: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { state = sw_usual; *u++ = ch; ch = *p++; @@ -1393,7 +1401,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) case sw_dot: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { state = sw_usual; *u++ = ch; ch = *p++; @@ -1434,7 +1442,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) case sw_dot_dot: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { state = sw_usual; *u++ = ch; ch = *p++; @@ -1680,6 +1688,10 @@ ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b, return NGX_ERROR; } + if (r->http_major > 99) { + return NGX_ERROR; + } + r->http_major = r->http_major * 10 + ch - '0'; break; @@ -1704,6 +1716,10 @@ ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b, return NGX_ERROR; } + if (r->http_minor > 99) { + return NGX_ERROR; + } + r->http_minor = r->http_minor * 10 + ch - '0'; break; @@ -1820,7 +1836,7 @@ ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri, continue; } - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { continue; } diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 7d6cada..6ff7903 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -110,6 +110,10 @@ ngx_http_header_t ngx_http_headers_in[] = { offsetof(ngx_http_headers_in_t, content_length), ngx_http_process_unique_header_line }, + { ngx_string("Content-Range"), + offsetof(ngx_http_headers_in_t, content_range), + ngx_http_process_unique_header_line }, + { ngx_string("Content-Type"), offsetof(ngx_http_headers_in_t, content_type), ngx_http_process_header_line }, @@ -2064,8 +2068,8 @@ ngx_http_set_virtual_server(ngx_http_request_t *r, ngx_str_t *host) if (sscf->verify) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client attempted to request the server name " - "different from that one was negotiated"); - ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + "different from the one that was negotiated"); + ngx_http_finalize_request(r, NGX_HTTP_MISDIRECTED_REQUEST); return NGX_ERROR; } } @@ -2752,9 +2756,13 @@ ngx_http_test_reading(ngx_http_request_t *r) #if (NGX_HAVE_EPOLLRDHUP) - if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && rev->pending_eof) { + if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ngx_use_epoll_rdhup) { socklen_t len; + if (!rev->pending_eof) { + return; + } + rev->eof = 1; c->error = 1; diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index cfde7dc..499c1ef 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -95,6 +95,7 @@ #define NGX_HTTP_REQUEST_URI_TOO_LARGE 414 #define NGX_HTTP_UNSUPPORTED_MEDIA_TYPE 415 #define NGX_HTTP_RANGE_NOT_SATISFIABLE 416 +#define NGX_HTTP_MISDIRECTED_REQUEST 421 /* Our own HTTP codes */ @@ -182,6 +183,7 @@ typedef struct { ngx_table_elt_t *user_agent; ngx_table_elt_t *referer; ngx_table_elt_t *content_length; + ngx_table_elt_t *content_range; ngx_table_elt_t *content_type; ngx_table_elt_t *range; diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c index bff9525..c2b1658 100644 --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -350,11 +350,9 @@ ngx_http_script_compile(ngx_http_script_compile_t *sc) goto invalid_variable; } -#if (NGX_PCRE) - { - ngx_uint_t n; - if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') { +#if (NGX_PCRE) + ngx_uint_t n; n = sc->source->data[i] - '0'; @@ -371,9 +369,13 @@ ngx_http_script_compile(ngx_http_script_compile_t *sc) i++; continue; - } - } +#else + ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, + "using variable \"$%c\" requires " + "PCRE library", sc->source->data[i]); + return NGX_ERROR; #endif + } if (sc->source->data[i] == '{') { bracket = 1; diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c index 2771e58..64e5acd 100644 --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -210,6 +210,14 @@ static char ngx_http_error_416_page[] = ; +static char ngx_http_error_421_page[] = +"" CRLF +"421 Misdirected Request" CRLF +"" CRLF +"

421 Misdirected Request

" CRLF +; + + static char ngx_http_error_494_page[] = "" CRLF "400 Request Header Or Cookie Too Large" @@ -334,8 +342,13 @@ static ngx_str_t ngx_http_error_pages[] = { ngx_string(ngx_http_error_414_page), ngx_string(ngx_http_error_415_page), ngx_string(ngx_http_error_416_page), + ngx_null_string, /* 417 */ + ngx_null_string, /* 418 */ + ngx_null_string, /* 419 */ + ngx_null_string, /* 420 */ + ngx_string(ngx_http_error_421_page), -#define NGX_HTTP_LAST_4XX 417 +#define NGX_HTTP_LAST_4XX 422 #define NGX_HTTP_OFF_5XX (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX) ngx_string(ngx_http_error_494_page), /* 494, request header too large */ diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 1386bdb..0f6b3ae 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -165,8 +165,8 @@ static char *ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy); static char *ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static ngx_addr_t *ngx_http_upstream_get_local(ngx_http_request_t *r, - ngx_http_upstream_local_t *local); +static ngx_int_t ngx_http_upstream_set_local(ngx_http_request_t *r, + ngx_http_upstream_t *u, ngx_http_upstream_local_t *local); static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf); static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf); @@ -588,7 +588,10 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) return; } - u->peer.local = ngx_http_upstream_get_local(r, u->conf->local); + if (ngx_http_upstream_set_local(r, u, u->conf->local) != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); @@ -1219,9 +1222,13 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, #if (NGX_HAVE_EPOLLRDHUP) - if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ev->pending_eof) { + if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ngx_use_epoll_rdhup) { socklen_t len; + if (!ev->pending_eof) { + return; + } + ev->eof = 1; c->error = 1; @@ -5785,7 +5792,7 @@ ngx_http_upstream_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, value = cf->args->elts; - if (ngx_strcmp(value[1].data, "off") == 0) { + if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "off") == 0) { *plocal = NULL; return NGX_CONF_OK; } @@ -5815,34 +5822,52 @@ ngx_http_upstream_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, *local->value = cv; - return NGX_CONF_OK; + } else { + local->addr = ngx_palloc(cf->pool, sizeof(ngx_addr_t)); + if (local->addr == NULL) { + return NGX_CONF_ERROR; + } + + rc = ngx_parse_addr_port(cf->pool, local->addr, value[1].data, + value[1].len); + + switch (rc) { + case NGX_OK: + local->addr->name = value[1]; + break; + + case NGX_DECLINED: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid address \"%V\"", &value[1]); + /* fall through */ + + default: + return NGX_CONF_ERROR; + } } - local->addr = ngx_palloc(cf->pool, sizeof(ngx_addr_t)); - if (local->addr == NULL) { - return NGX_CONF_ERROR; + if (cf->args->nelts > 2) { + if (ngx_strcmp(value[2].data, "transparent") == 0) { +#if (NGX_HAVE_TRANSPARENT_PROXY) + local->transparent = 1; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "transparent proxying is not supported " + "on this platform, ignored"); +#endif + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } } - rc = ngx_parse_addr(cf->pool, local->addr, value[1].data, value[1].len); - - switch (rc) { - case NGX_OK: - local->addr->name = value[1]; - return NGX_CONF_OK; - - case NGX_DECLINED: - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid address \"%V\"", &value[1]); - /* fall through */ - - default: - return NGX_CONF_ERROR; - } + return NGX_CONF_OK; } -static ngx_addr_t * -ngx_http_upstream_get_local(ngx_http_request_t *r, +static ngx_int_t +ngx_http_upstream_set_local(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_http_upstream_local_t *local) { ngx_int_t rc; @@ -5850,41 +5875,47 @@ ngx_http_upstream_get_local(ngx_http_request_t *r, ngx_addr_t *addr; if (local == NULL) { - return NULL; + u->peer.local = NULL; + return NGX_OK; } +#if (NGX_HAVE_TRANSPARENT_PROXY) + u->peer.transparent = local->transparent; +#endif + if (local->value == NULL) { - return local->addr; + u->peer.local = local->addr; + return NGX_OK; } if (ngx_http_complex_value(r, local->value, &val) != NGX_OK) { - return NULL; + return NGX_ERROR; } if (val.len == 0) { - return NULL; + return NGX_OK; } addr = ngx_palloc(r->pool, sizeof(ngx_addr_t)); if (addr == NULL) { - return NULL; + return NGX_ERROR; } - rc = ngx_parse_addr(r->pool, addr, val.data, val.len); + rc = ngx_parse_addr_port(r->pool, addr, val.data, val.len); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } - switch (rc) { - case NGX_OK: - addr->name = val; - return addr; - - case NGX_DECLINED: + if (rc != NGX_OK) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "invalid local address \"%V\"", &val); - /* fall through */ - - default: - return NULL; + return NGX_OK; } + + addr->name = val; + u->peer.local = addr; + + return NGX_OK; } diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index 7595dcf..b288f28 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -133,6 +133,9 @@ struct ngx_http_upstream_srv_conf_s { typedef struct { ngx_addr_t *addr; ngx_http_complex_value_t *value; +#if (NGX_HAVE_TRANSPARENT_PROXY) + ngx_uint_t transparent; /* unsigned transparent:1; */ +#endif } ngx_http_upstream_local_t; diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c index 8342dc8..8479c42 100644 --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -354,16 +354,7 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, } ngx_memcpy(sockaddr, ur->addrs[i].sockaddr, socklen); - - switch (sockaddr->sa_family) { -#if (NGX_HAVE_INET6) - case AF_INET6: - ((struct sockaddr_in6 *) sockaddr)->sin6_port = htons(ur->port); - break; -#endif - default: /* AF_INET */ - ((struct sockaddr_in *) sockaddr)->sin_port = htons(ur->port); - } + ngx_inet_set_port(sockaddr, ur->port); p = ngx_pnalloc(r->pool, NGX_SOCKADDR_STRLEN); if (p == NULL) { diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index f8271ab..7e65b2e 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -58,6 +58,8 @@ static ngx_int_t ngx_http_variable_remote_port(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_proxy_protocol_addr(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_proxy_protocol_port(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_server_addr(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_server_port(ngx_http_request_t *r, @@ -98,6 +100,8 @@ static ngx_int_t ngx_http_variable_request_length(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_request_time(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_request_id(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_status(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); @@ -192,6 +196,9 @@ static ngx_http_variable_t ngx_http_core_variables[] = { { ngx_string("proxy_protocol_addr"), NULL, ngx_http_variable_proxy_protocol_addr, 0, 0, 0 }, + { ngx_string("proxy_protocol_port"), NULL, + ngx_http_variable_proxy_protocol_port, 0, 0, 0 }, + { ngx_string("server_addr"), NULL, ngx_http_variable_server_addr, 0, 0, 0 }, { ngx_string("server_port"), NULL, ngx_http_variable_server_port, 0, 0, 0 }, @@ -274,6 +281,10 @@ static ngx_http_variable_t ngx_http_core_variables[] = { { ngx_string("request_time"), NULL, ngx_http_variable_request_time, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, + { ngx_string("request_id"), NULL, + ngx_http_variable_request_id, + 0, 0, 0 }, + { ngx_string("status"), NULL, ngx_http_variable_status, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, @@ -1190,11 +1201,7 @@ static ngx_int_t ngx_http_variable_remote_port(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - ngx_uint_t port; - struct sockaddr_in *sin; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif + ngx_uint_t port; v->len = 0; v->valid = 1; @@ -1206,26 +1213,7 @@ ngx_http_variable_remote_port(ngx_http_request_t *r, return NGX_ERROR; } - switch (r->connection->sockaddr->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) r->connection->sockaddr; - port = ntohs(sin6->sin6_port); - break; -#endif - -#if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - port = 0; - break; -#endif - - default: /* AF_INET */ - sin = (struct sockaddr_in *) r->connection->sockaddr; - port = ntohs(sin->sin_port); - break; - } + port = ngx_inet_get_port(r->connection->sockaddr); if (port > 0 && port < 65536) { v->len = ngx_sprintf(v->data, "%ui", port) - v->data; @@ -1249,6 +1237,32 @@ ngx_http_variable_proxy_protocol_addr(ngx_http_request_t *r, } +static ngx_int_t +ngx_http_variable_proxy_protocol_port(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_uint_t port; + + v->len = 0; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + v->data = ngx_pnalloc(r->pool, sizeof("65535") - 1); + if (v->data == NULL) { + return NGX_ERROR; + } + + port = r->connection->proxy_protocol_port; + + if (port > 0 && port < 65536) { + v->len = ngx_sprintf(v->data, "%ui", port) - v->data; + } + + return NGX_OK; +} + + static ngx_int_t ngx_http_variable_server_addr(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) @@ -1284,11 +1298,7 @@ static ngx_int_t ngx_http_variable_server_port(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - ngx_uint_t port; - struct sockaddr_in *sin; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif + ngx_uint_t port; v->len = 0; v->valid = 1; @@ -1304,26 +1314,7 @@ ngx_http_variable_server_port(ngx_http_request_t *r, return NGX_ERROR; } - switch (r->connection->local_sockaddr->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) r->connection->local_sockaddr; - port = ntohs(sin6->sin6_port); - break; -#endif - -#if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - port = 0; - break; -#endif - - default: /* AF_INET */ - sin = (struct sockaddr_in *) r->connection->local_sockaddr; - port = ntohs(sin->sin_port); - break; - } + port = ngx_inet_get_port(r->connection->local_sockaddr); if (port > 0 && port < 65536) { v->len = ngx_sprintf(v->data, "%ui", port) - v->data; @@ -2067,6 +2058,47 @@ ngx_http_variable_request_time(ngx_http_request_t *r, } +static ngx_int_t +ngx_http_variable_request_id(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *id; + +#if (NGX_OPENSSL) + u_char random_bytes[16]; +#endif + + id = ngx_pnalloc(r->pool, 32); + if (id == NULL) { + return NGX_ERROR; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + v->len = 32; + v->data = id; + +#if (NGX_OPENSSL) + + if (RAND_bytes(random_bytes, 16) == 1) { + ngx_hex_dump(id, random_bytes, 16); + return NGX_OK; + } + + ngx_ssl_error(NGX_LOG_ERR, r->connection->log, 0, "RAND_bytes() failed"); + +#endif + + ngx_sprintf(id, "%08xD%08xD%08xD%08xD", + (uint32_t) ngx_random(), (uint32_t) ngx_random(), + (uint32_t) ngx_random(), (uint32_t) ngx_random()); + + return NGX_OK; +} + + static ngx_int_t ngx_http_variable_connection(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 278c9ab..d0cd2ab 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -48,11 +48,6 @@ #define NGX_HTTP_V2_DEFAULT_FRAME_SIZE (1 << 14) -#define NGX_HTTP_V2_MAX_WINDOW ((1U << 31) - 1) -#define NGX_HTTP_V2_DEFAULT_WINDOW 65535 - -#define NGX_HTTP_V2_INITIAL_WINDOW 0 - #define NGX_HTTP_V2_ROOT (void *) -1 @@ -415,6 +410,16 @@ ngx_http_v2_write_handler(ngx_event_t *wev) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 write handler"); + if (h2c->last_out == NULL && !c->buffered) { + + if (wev->timer_set) { + ngx_del_timer(wev); + } + + ngx_http_v2_handle_connection(h2c); + return; + } + h2c->blocked = 1; rc = ngx_http_v2_send_output_queue(h2c); @@ -473,7 +478,7 @@ ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c) wev = c->write; if (!wev->ready) { - return NGX_OK; + return NGX_AGAIN; } cl = NULL; @@ -544,15 +549,6 @@ ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c) c->tcp_nodelay = NGX_TCP_NODELAY_SET; } - if (cl) { - ngx_add_timer(wev, clcf->send_timeout); - - } else { - if (wev->timer_set) { - ngx_del_timer(wev); - } - } - for ( /* void */ ; out; out = fn) { fn = out->next; @@ -577,6 +573,15 @@ ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c) h2c->last_out = frame; + if (!wev->ready) { + ngx_add_timer(wev, clcf->send_timeout); + return NGX_AGAIN; + } + + if (wev->timer_set) { + ngx_del_timer(wev); + } + return NGX_OK; error: @@ -594,7 +599,8 @@ error: static void ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) { - ngx_connection_t *c; + ngx_int_t rc; + ngx_connection_t *c; ngx_http_v2_srv_conf_t *h2scf; if (h2c->last_out || h2c->processing) { @@ -609,7 +615,22 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) } if (c->buffered) { - return; + h2c->blocked = 1; + + rc = ngx_http_v2_send_output_queue(h2c); + + h2c->blocked = 0; + + if (rc == NGX_ERROR) { + ngx_http_close_connection(c); + return; + } + + if (rc == NGX_AGAIN) { + return; + } + + /* rc == NGX_OK */ } h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, @@ -620,7 +641,7 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) } if (ngx_terminate || ngx_exiting) { - ngx_http_close_connection(c); + ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR); return; } @@ -879,8 +900,6 @@ ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) return ngx_http_v2_state_skip_padded(h2c, pos, end); } - stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; - h2c->state.stream = stream; return ngx_http_v2_state_read_data(h2c, pos, end); @@ -891,10 +910,12 @@ static u_char * ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) { - size_t size; - ngx_int_t rc; - ngx_uint_t last; - ngx_http_v2_stream_t *stream; + size_t size; + ngx_buf_t *buf; + ngx_int_t rc; + ngx_http_request_t *r; + ngx_http_v2_stream_t *stream; + ngx_http_v2_srv_conf_t *h2scf; stream = h2c->state.stream; @@ -913,17 +934,42 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, if (size >= h2c->state.length) { size = h2c->state.length; - last = stream->in_closed; - - } else { - last = 0; + stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; } - rc = ngx_http_v2_process_request_body(stream->request, pos, size, last); + r = stream->request; - if (rc != NGX_OK) { - stream->skip_data = 1; - ngx_http_finalize_request(stream->request, rc); + if (r->request_body) { + rc = ngx_http_v2_process_request_body(r, pos, size, stream->in_closed); + + if (rc != NGX_OK) { + stream->skip_data = 1; + ngx_http_finalize_request(r, rc); + } + + } else if (size) { + buf = stream->preread; + + if (buf == NULL) { + h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module); + + buf = ngx_create_temp_buf(r->pool, h2scf->preread_size); + if (buf == NULL) { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + stream->preread = buf; + } + + if (size > (size_t) (buf->end - buf->last)) { + ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, + "http2 preread buffer overflow"); + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + buf->last = ngx_cpymem(buf->last, pos, size); } pos += size; @@ -1058,7 +1104,9 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, goto rst_stream; } - if (!h2c->settings_ack && !(h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG)) + if (!h2c->settings_ack + && !(h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG) + && h2scf->preread_size < NGX_HTTP_V2_DEFAULT_WINDOW) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, "client sent stream with data " @@ -2434,8 +2482,7 @@ ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, ngx_uint_t ack) buf->last = ngx_http_v2_write_uint16(buf->last, NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING); - buf->last = ngx_http_v2_write_uint32(buf->last, - NGX_HTTP_V2_INITIAL_WINDOW); + buf->last = ngx_http_v2_write_uint32(buf->last, h2scf->preread_size); buf->last = ngx_http_v2_write_uint16(buf->last, NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING); @@ -2643,6 +2690,7 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c) ngx_http_log_ctx_t *ctx; ngx_http_request_t *r; ngx_http_v2_stream_t *stream; + ngx_http_v2_srv_conf_t *h2scf; ngx_http_core_srv_conf_t *cscf; fc = h2c->free_fake_connections; @@ -2756,8 +2804,10 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c) stream->request = r; stream->connection = h2c; + h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module); + stream->send_window = h2c->init_window; - stream->recv_window = NGX_HTTP_V2_INITIAL_WINDOW; + stream->recv_window = h2scf->preread_size; h2c->processing++; @@ -3400,7 +3450,9 @@ ngx_http_v2_run_request(ngx_http_request_t *r) return; } - r->headers_in.chunked = (r->headers_in.content_length_n == -1); + if (r->headers_in.content_length_n == -1 && !r->stream->in_closed) { + r->headers_in.chunked = 1; + } ngx_http_process_request(r); } @@ -3411,7 +3463,11 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler) { off_t len; + size_t size; + ngx_buf_t *buf; + ngx_int_t rc; ngx_http_v2_stream_t *stream; + ngx_http_v2_srv_conf_t *h2scf; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; ngx_http_v2_connection_t *h2c; @@ -3444,24 +3500,34 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r, r->request_body = rb; + h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); len = r->headers_in.content_length_n; if (r->request_body_no_buffering && !stream->in_closed) { - r->request_body_in_file_only = 0; if (len < 0 || len > (off_t) clcf->client_body_buffer_size) { len = clcf->client_body_buffer_size; } + /* + * We need a room to store data up to the stream's initial window size, + * at least until this window will be exhausted. + */ + + if (len < (off_t) h2scf->preread_size) { + len = h2scf->preread_size; + } + if (len > NGX_HTTP_V2_MAX_WINDOW) { len = NGX_HTTP_V2_MAX_WINDOW; } - } - if (len >= 0 && len <= (off_t) clcf->client_body_buffer_size - && !r->request_body_in_file_only) + rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); + + } else if (len >= 0 && len <= (off_t) clcf->client_body_buffer_size + && !r->request_body_in_file_only) { rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); @@ -3478,22 +3544,44 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r, return NGX_HTTP_INTERNAL_SERVER_ERROR; } + buf = stream->preread; + if (stream->in_closed) { r->request_body_no_buffering = 0; + + if (buf) { + rc = ngx_http_v2_process_request_body(r, buf->pos, + buf->last - buf->pos, 1); + ngx_pfree(r->pool, buf->start); + return rc; + } + return ngx_http_v2_process_request_body(r, NULL, 0, 1); } - if (len) { - if (r->request_body_no_buffering) { - stream->recv_window = (size_t) len; + if (buf) { + rc = ngx_http_v2_process_request_body(r, buf->pos, + buf->last - buf->pos, 0); - } else { - stream->no_flow_control = 1; - stream->recv_window = NGX_HTTP_V2_MAX_WINDOW; + ngx_pfree(r->pool, buf->start); + + if (rc != NGX_OK) { + stream->skip_data = 1; + return rc; } + } - if (ngx_http_v2_send_window_update(stream->connection, stream->node->id, - stream->recv_window) + if (r->request_body_no_buffering) { + size = (size_t) len - h2scf->preread_size; + + } else { + stream->no_flow_control = 1; + size = NGX_HTTP_V2_MAX_WINDOW - stream->recv_window; + } + + if (size) { + if (ngx_http_v2_send_window_update(stream->connection, + stream->node->id, size) == NGX_ERROR) { stream->skip_data = 1; @@ -3508,9 +3596,13 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r, return NGX_HTTP_INTERNAL_SERVER_ERROR; } } + + stream->recv_window += size; } - ngx_add_timer(r->connection->read, clcf->client_body_timeout); + if (!buf) { + ngx_add_timer(r->connection->read, clcf->client_body_timeout); + } r->read_event_handler = ngx_http_v2_read_client_request_body_handler; r->write_event_handler = ngx_http_request_empty_handler; @@ -3529,13 +3621,8 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; - rb = r->request_body; - - if (rb == NULL) { - return NGX_OK; - } - fc = r->connection; + rb = r->request_body; buf = rb->buf; if (size) { @@ -3579,7 +3666,7 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, rb->buf = NULL; } - if (r->headers_in.content_length_n == -1) { + if (r->headers_in.chunked) { r->headers_in.content_length_n = rb->received; } @@ -3789,7 +3876,14 @@ ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r) window -= h2c->state.length; } - if (window == stream->recv_window) { + if (window <= stream->recv_window) { + if (window < stream->recv_window) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "http2 negative window update"); + stream->skip_data = 1; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + return NGX_AGAIN; } @@ -3824,6 +3918,10 @@ ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, ngx_event_t *rev; ngx_connection_t *fc; + if (stream->rst_sent) { + return NGX_OK; + } + if (ngx_http_v2_send_rst_stream(h2c, stream->node->id, status) == NGX_ERROR) { @@ -3831,6 +3929,7 @@ ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, } stream->rst_sent = 1; + stream->skip_data = 1; fc = stream->request->connection; fc->error = 1; @@ -3862,6 +3961,7 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) if (stream->queued) { fc->write->handler = ngx_http_v2_close_stream_handler; + fc->read->handler = ngx_http_empty_handler; return; } @@ -4103,10 +4203,6 @@ ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c, c->error = 1; - if (h2c->state.stream) { - ngx_http_v2_close_stream(h2c->state.stream, NGX_HTTP_BAD_REQUEST); - } - if (!h2c->processing) { ngx_http_close_connection(c); return; diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 1adf8de..d712d38 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -46,6 +46,9 @@ #define NGX_HTTP_V2_PADDED_FLAG 0x08 #define NGX_HTTP_V2_PRIORITY_FLAG 0x20 +#define NGX_HTTP_V2_MAX_WINDOW ((1U << 31) - 1) +#define NGX_HTTP_V2_DEFAULT_WINDOW 65535 + typedef struct ngx_http_v2_connection_s ngx_http_v2_connection_t; typedef struct ngx_http_v2_node_s ngx_http_v2_node_t; @@ -174,6 +177,8 @@ struct ngx_http_v2_stream_s { ssize_t send_window; size_t recv_window; + ngx_buf_t *preread; + ngx_http_v2_out_frame_t *free_frames; ngx_chain_t *free_frame_headers; ngx_chain_t *free_bufs; @@ -293,7 +298,7 @@ size_t ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst, #define ngx_http_v2_parse_uint16(p) ((p)[0] << 8 | (p)[1]) #define ngx_http_v2_parse_uint32(p) \ - ((p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3]) + ((uint32_t) (p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3]) #endif diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index caa835d..4ab7791 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -137,10 +137,6 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) ngx_http_v2_out_frame_t *frame; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; - struct sockaddr_in *sin; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif u_char addr[NGX_SOCKADDR_STRLEN]; static const u_char nginx[5] = "\x84\xaa\x63\x55\xe7"; @@ -169,6 +165,12 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) return NGX_OK; } + fc = r->connection; + + if (fc->error) { + return NGX_ERROR; + } + if (r->method == NGX_HTTP_HEAD) { r->header_only = 1; } @@ -259,8 +261,6 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) len += 1 + ngx_http_v2_literal_size("Wed, 31 Dec 1986 18:00:00 GMT"); } - fc = r->connection; - if (r->headers_out.location && r->headers_out.location->value.len) { if (r->headers_out.location->value.data[0] == '/') { @@ -280,24 +280,7 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) } } - switch (fc->local_sockaddr->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) fc->local_sockaddr; - port = ntohs(sin6->sin6_port); - break; -#endif -#if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - port = 0; - break; -#endif - default: /* AF_INET */ - sin = (struct sockaddr_in *) fc->local_sockaddr; - port = ntohs(sin->sin_port); - break; - } + port = ngx_inet_get_port(fc->local_sockaddr); location.len = sizeof("https://") - 1 + host.len + r->headers_out.location->value.len; @@ -995,12 +978,11 @@ static ngx_http_v2_out_frame_t * ngx_http_v2_filter_get_data_frame(ngx_http_v2_stream_t *stream, size_t len, ngx_chain_t *first, ngx_chain_t *last) { - u_char flags; - ngx_buf_t *buf; - ngx_chain_t *cl; + u_char flags; + ngx_buf_t *buf; + ngx_chain_t *cl; ngx_http_v2_out_frame_t *frame; - frame = stream->free_frames; if (frame) { @@ -1028,7 +1010,7 @@ ngx_http_v2_filter_get_data_frame(ngx_http_v2_stream_t *stream, buf = cl->buf; - if (!buf->start) { + if (buf->start == NULL) { buf->start = ngx_palloc(stream->request->pool, NGX_HTTP_V2_FRAME_HEADER_SIZE); if (buf->start == NULL) { @@ -1203,7 +1185,6 @@ ngx_http_v2_data_frame_handler(ngx_http_v2_connection_t *h2c, ngx_http_v2_stream_t *stream; stream = frame->stream; - cl = frame->first; if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_module) { @@ -1313,18 +1294,20 @@ static ngx_inline void ngx_http_v2_handle_stream(ngx_http_v2_connection_t *h2c, ngx_http_v2_stream_t *stream) { - ngx_event_t *wev; + ngx_connection_t *fc; - if (stream->handled || stream->blocked || stream->exhausted) { + if (stream->handled || stream->blocked) { return; } - wev = stream->request->connection->write; + fc = stream->request->connection; - if (!wev->delayed) { - stream->handled = 1; - ngx_queue_insert_tail(&h2c->posted, &stream->queue); + if (!fc->error && (stream->exhausted || fc->write->delayed)) { + return; } + + stream->handled = 1; + ngx_queue_insert_tail(&h2c->posted, &stream->queue); } diff --git a/src/http/v2/ngx_http_v2_module.c b/src/http/v2/ngx_http_v2_module.c index 5a4561c..b7d99e0 100644 --- a/src/http/v2/ngx_http_v2_module.c +++ b/src/http/v2/ngx_http_v2_module.c @@ -30,6 +30,7 @@ static char *ngx_http_v2_merge_loc_conf(ngx_conf_t *cf, void *parent, static char *ngx_http_v2_recv_buffer_size(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_v2_pool_size(ngx_conf_t *cf, void *post, void *data); +static char *ngx_http_v2_preread_size(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_v2_streams_index_mask(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_v2_chunk_size(ngx_conf_t *cf, void *post, void *data); @@ -41,6 +42,8 @@ static ngx_conf_post_t ngx_http_v2_recv_buffer_size_post = { ngx_http_v2_recv_buffer_size }; static ngx_conf_post_t ngx_http_v2_pool_size_post = { ngx_http_v2_pool_size }; +static ngx_conf_post_t ngx_http_v2_preread_size_post = + { ngx_http_v2_preread_size }; static ngx_conf_post_t ngx_http_v2_streams_index_mask_post = { ngx_http_v2_streams_index_mask }; static ngx_conf_post_t ngx_http_v2_chunk_size_post = @@ -84,6 +87,13 @@ static ngx_command_t ngx_http_v2_commands[] = { offsetof(ngx_http_v2_srv_conf_t, max_header_size), NULL }, + { ngx_string("http2_body_preread_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v2_srv_conf_t, preread_size), + &ngx_http_v2_preread_size_post }, + { ngx_string("http2_streams_index_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, @@ -316,6 +326,8 @@ ngx_http_v2_create_srv_conf(ngx_conf_t *cf) h2scf->max_field_size = NGX_CONF_UNSET_SIZE; h2scf->max_header_size = NGX_CONF_UNSET_SIZE; + h2scf->preread_size = NGX_CONF_UNSET_SIZE; + h2scf->streams_index_mask = NGX_CONF_UNSET_UINT; h2scf->recv_timeout = NGX_CONF_UNSET_MSEC; @@ -341,6 +353,8 @@ ngx_http_v2_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_size_value(conf->max_header_size, prev->max_header_size, 16384); + ngx_conf_merge_size_value(conf->preread_size, prev->preread_size, 65536); + ngx_conf_merge_uint_value(conf->streams_index_mask, prev->streams_index_mask, 32 - 1); @@ -419,6 +433,23 @@ ngx_http_v2_pool_size(ngx_conf_t *cf, void *post, void *data) } +static char * +ngx_http_v2_preread_size(ngx_conf_t *cf, void *post, void *data) +{ + size_t *sp = data; + + if (*sp > NGX_HTTP_V2_MAX_WINDOW) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the maximum body preread buffer size is %uz", + NGX_HTTP_V2_MAX_WINDOW); + + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + static char * ngx_http_v2_streams_index_mask(ngx_conf_t *cf, void *post, void *data) { diff --git a/src/http/v2/ngx_http_v2_module.h b/src/http/v2/ngx_http_v2_module.h index 95cc7d8..91f97c2 100644 --- a/src/http/v2/ngx_http_v2_module.h +++ b/src/http/v2/ngx_http_v2_module.h @@ -25,6 +25,7 @@ typedef struct { ngx_uint_t concurrent_streams; size_t max_field_size; size_t max_header_size; + size_t preread_size; ngx_uint_t streams_index_mask; ngx_msec_t recv_timeout; ngx_msec_t idle_timeout; diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c index 6ad5a67..e5a77b0 100644 --- a/src/mail/ngx_mail.c +++ b/src/mail/ngx_mail.c @@ -228,35 +228,11 @@ ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports, in_port_t p; ngx_uint_t i; struct sockaddr *sa; - struct sockaddr_in *sin; ngx_mail_conf_port_t *port; ngx_mail_conf_addr_t *addr; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif - sa = &listen->u.sockaddr; - - switch (sa->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = &listen->u.sockaddr_in6; - p = sin6->sin6_port; - break; -#endif - -#if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - p = 0; - break; -#endif - - default: /* AF_INET */ - sin = &listen->u.sockaddr_in; - p = sin->sin_port; - break; - } + sa = &listen->sockaddr.sockaddr; + p = ngx_inet_get_port(sa); port = ports->elts; for (i = 0; i < ports->nelts; i++) { @@ -340,7 +316,7 @@ ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) continue; } - ls = ngx_create_listening(cf, &addr[i].opt.u.sockaddr, + ls = ngx_create_listening(cf, &addr[i].opt.sockaddr.sockaddr, addr[i].opt.socklen); if (ls == NULL) { return NGX_CONF_ERROR; @@ -423,7 +399,7 @@ ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport, for (i = 0; i < mport->naddrs; i++) { - sin = &addr[i].opt.u.sockaddr_in; + sin = &addr[i].opt.sockaddr.sockaddr_in; addrs[i].addr = sin->sin_addr.s_addr; addrs[i].conf.ctx = addr[i].opt.ctx; @@ -431,8 +407,8 @@ ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport, addrs[i].conf.ssl = addr[i].opt.ssl; #endif - len = ngx_sock_ntop(&addr[i].opt.u.sockaddr, addr[i].opt.socklen, buf, - NGX_SOCKADDR_STRLEN, 1); + len = ngx_sock_ntop(&addr[i].opt.sockaddr.sockaddr, addr[i].opt.socklen, + buf, NGX_SOCKADDR_STRLEN, 1); p = ngx_pnalloc(cf->pool, len); if (p == NULL) { @@ -472,7 +448,7 @@ ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport, for (i = 0; i < mport->naddrs; i++) { - sin6 = &addr[i].opt.u.sockaddr_in6; + sin6 = &addr[i].opt.sockaddr.sockaddr_in6; addrs6[i].addr6 = sin6->sin6_addr; addrs6[i].conf.ctx = addr[i].opt.ctx; @@ -480,8 +456,8 @@ ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport, addrs6[i].conf.ssl = addr[i].opt.ssl; #endif - len = ngx_sock_ntop(&addr[i].opt.u.sockaddr, addr[i].opt.socklen, buf, - NGX_SOCKADDR_STRLEN, 1); + len = ngx_sock_ntop(&addr[i].opt.sockaddr.sockaddr, addr[i].opt.socklen, + buf, NGX_SOCKADDR_STRLEN, 1); p = ngx_pnalloc(cf->pool, len); if (p == NULL) { diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index bfbf768..ae1aa41 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -27,18 +27,7 @@ typedef struct { typedef struct { - union { - struct sockaddr sockaddr; - struct sockaddr_in sockaddr_in; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 sockaddr_in6; -#endif -#if (NGX_HAVE_UNIX_DOMAIN) - struct sockaddr_un sockaddr_un; -#endif - u_char sockaddr_data[NGX_SOCKADDRLEN]; - } u; - + ngx_sockaddr_t sockaddr; socklen_t socklen; /* server ctx */ diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c index 39f9b17..a94434a 100644 --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -462,15 +462,11 @@ static void ngx_mail_auth_http_process_headers(ngx_mail_session_t *s, ngx_mail_auth_http_ctx_t *ctx) { - u_char *p; - time_t timer; - size_t len, size; - ngx_int_t rc, port, n; - ngx_addr_t *peer; - struct sockaddr_in *sin; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif + u_char *p; + time_t timer; + size_t len, size; + ngx_int_t rc, port, n; + ngx_addr_t *peer; ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, "mail auth http process headers"); @@ -813,20 +809,7 @@ ngx_mail_auth_http_process_headers(ngx_mail_session_t *s, return; } - switch (peer->sockaddr->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) peer->sockaddr; - sin6->sin6_port = htons((in_port_t) port); - break; -#endif - - default: /* AF_INET */ - sin = (struct sockaddr_in *) peer->sockaddr; - sin->sin_port = htons((in_port_t) port); - break; - } + ngx_inet_set_port(peer->sockaddr, (in_port_t) port); len = ctx->addr.len + 1 + ctx->port.len; diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index 8ea8ea9..d992402 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -288,19 +288,12 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_mail_core_srv_conf_t *cscf = conf; - size_t len, off; - in_port_t port; ngx_str_t *value; ngx_url_t u; ngx_uint_t i, m; - struct sockaddr *sa; ngx_mail_listen_t *ls; ngx_mail_module_t *module; - struct sockaddr_in *sin; ngx_mail_core_main_conf_t *cmcf; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif value = cf->args->elts; @@ -325,49 +318,13 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) for (i = 0; i < cmcf->listen.nelts; i++) { - sa = &ls[i].u.sockaddr; - - if (sa->sa_family != u.family) { - continue; - } - - switch (sa->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - off = offsetof(struct sockaddr_in6, sin6_addr); - len = 16; - sin6 = &ls[i].u.sockaddr_in6; - port = ntohs(sin6->sin6_port); - break; -#endif - -#if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - off = offsetof(struct sockaddr_un, sun_path); - len = sizeof(((struct sockaddr_un *) sa)->sun_path); - port = 0; - break; -#endif - - default: /* AF_INET */ - off = offsetof(struct sockaddr_in, sin_addr); - len = 4; - sin = &ls[i].u.sockaddr_in; - port = ntohs(sin->sin_port); - break; - } - - if (ngx_memcmp(ls[i].u.sockaddr_data + off, u.sockaddr + off, len) - != 0) + if (ngx_cmp_sockaddr(&ls[i].sockaddr.sockaddr, ls[i].socklen, + (struct sockaddr *) &u.sockaddr, u.socklen, 1) + != NGX_OK) { continue; } - if (port != u.port) { - continue; - } - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "duplicate \"%V\" address and port pair", &u.url); return NGX_CONF_ERROR; @@ -380,7 +337,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_memzero(ls, sizeof(ngx_mail_listen_t)); - ngx_memcpy(&ls->u.sockaddr, u.sockaddr, u.socklen); + ngx_memcpy(&ls->sockaddr.sockaddr, &u.sockaddr, u.socklen); ls->socklen = u.socklen; ls->backlog = NGX_LISTEN_BACKLOG; @@ -434,11 +391,10 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) { #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + size_t len; u_char buf[NGX_SOCKADDR_STRLEN]; - sa = &ls->u.sockaddr; - - if (sa->sa_family == AF_INET6) { + if (ls->sockaddr.sockaddr.sa_family == AF_INET6) { if (ngx_strcmp(&value[i].data[10], "n") == 0) { ls->ipv6only = 1; @@ -456,7 +412,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ls->bind = 1; } else { - len = ngx_sock_ntop(sa, ls->socklen, buf, + len = ngx_sock_ntop(&ls->sockaddr.sockaddr, ls->socklen, buf, NGX_SOCKADDR_STRLEN, 1); ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c index ff5c141..11e428c 100644 --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -11,7 +11,7 @@ #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" -#define NGX_DEFAULT_ECDH_CURVE "prime256v1" +#define NGX_DEFAULT_ECDH_CURVE "auto" static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf); @@ -73,16 +73,16 @@ static ngx_command_t ngx_mail_ssl_commands[] = { { ngx_string("ssl_certificate"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_conf_set_str_array_slot, NGX_MAIL_SRV_CONF_OFFSET, - offsetof(ngx_mail_ssl_conf_t, certificate), + offsetof(ngx_mail_ssl_conf_t, certificates), NULL }, { ngx_string("ssl_certificate_key"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_conf_set_str_array_slot, NGX_MAIL_SRV_CONF_OFFSET, - offsetof(ngx_mail_ssl_conf_t, certificate_key), + offsetof(ngx_mail_ssl_conf_t, certificate_keys), NULL }, { ngx_string("ssl_password_file"), @@ -238,8 +238,6 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf) * set by ngx_pcalloc(): * * scf->protocols = 0; - * scf->certificate = { 0, NULL }; - * scf->certificate_key = { 0, NULL }; * scf->dhparam = { 0, NULL }; * scf->ecdh_curve = { 0, NULL }; * scf->client_certificate = { 0, NULL }; @@ -251,6 +249,8 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf) scf->enable = NGX_CONF_UNSET; scf->starttls = NGX_CONF_UNSET_UINT; + scf->certificates = NGX_CONF_UNSET_PTR; + scf->certificate_keys = NGX_CONF_UNSET_PTR; scf->passwords = NGX_CONF_UNSET_PTR; scf->prefer_server_ciphers = NGX_CONF_UNSET; scf->verify = NGX_CONF_UNSET_UINT; @@ -290,8 +290,9 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_uint_value(conf->verify, prev->verify, 0); ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1); - ngx_conf_merge_str_value(conf->certificate, prev->certificate, ""); - ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, ""); + ngx_conf_merge_ptr_value(conf->certificates, prev->certificates, NULL); + ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys, + NULL); ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL); @@ -328,7 +329,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) if (*mode) { - if (conf->certificate.len == 0) { + if (conf->certificates == NULL) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no \"ssl_certificate\" is defined for " "the \"%s\" directive in %s:%ui", @@ -336,7 +337,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } - if (conf->certificate_key.len == 0) { + if (conf->certificate_keys == NULL) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no \"ssl_certificate_key\" is defined for " "the \"%s\" directive in %s:%ui", @@ -344,17 +345,31 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } + if (conf->certificate_keys->nelts < conf->certificates->nelts) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate_key\" is defined " + "for certificate \"%V\" and " + "the \"ssl\" directive in %s:%ui", + ((ngx_str_t *) conf->certificates->elts) + + conf->certificates->nelts - 1, + conf->file, conf->line); + return NGX_CONF_ERROR; + } + } else { - if (conf->certificate.len == 0) { + if (conf->certificates == NULL) { return NGX_CONF_OK; } - if (conf->certificate_key.len == 0) { + if (conf->certificate_keys == NULL + || conf->certificate_keys->nelts < conf->certificates->nelts) + { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no \"ssl_certificate_key\" is defined " "for certificate \"%V\"", - &conf->certificate); + ((ngx_str_t *) conf->certificates->elts) + + conf->certificates->nelts - 1); return NGX_CONF_ERROR; } } @@ -371,8 +386,8 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) cln->handler = ngx_ssl_cleanup_ctx; cln->data = &conf->ssl; - if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate, - &conf->certificate_key, conf->passwords) + if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates, + conf->certificate_keys, conf->passwords) != NGX_OK) { return NGX_CONF_ERROR; @@ -407,24 +422,13 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) } } - if (SSL_CTX_set_cipher_list(conf->ssl.ctx, - (const char *) conf->ciphers.data) - == 0) + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, + conf->prefer_server_ciphers) + != NGX_OK) { - ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, - "SSL_CTX_set_cipher_list(\"%V\") failed", - &conf->ciphers); return NGX_CONF_ERROR; } - if (conf->prefer_server_ciphers) { - SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); - } - -#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) - SSL_CTX_set_tmp_rsa_callback(conf->ssl.ctx, ngx_ssl_rsa512_key_callback); -#endif - if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { return NGX_CONF_ERROR; } diff --git a/src/mail/ngx_mail_ssl_module.h b/src/mail/ngx_mail_ssl_module.h index 296a6a2..26628d5 100644 --- a/src/mail/ngx_mail_ssl_module.h +++ b/src/mail/ngx_mail_ssl_module.h @@ -35,8 +35,9 @@ typedef struct { time_t session_timeout; - ngx_str_t certificate; - ngx_str_t certificate_key; + ngx_array_t *certificates; + ngx_array_t *certificate_keys; + ngx_str_t dhparam; ngx_str_t ecdh_curve; ngx_str_t client_certificate; diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c index d23508e..454cfdc 100644 --- a/src/os/unix/ngx_readv_chain.c +++ b/src/os/unix/ngx_readv_chain.c @@ -51,6 +51,20 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) } } +#endif + +#if (NGX_HAVE_EPOLLRDHUP) + + if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "readv: eof:%d, avail:%d", + rev->pending_eof, rev->available); + + if (!rev->available && !rev->pending_eof) { + return NGX_AGAIN; + } + } + #endif prev = NULL; @@ -149,6 +163,24 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) return n; } +#endif + +#if (NGX_HAVE_EPOLLRDHUP) + + if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) + && ngx_use_epoll_rdhup) + { + if (n < size) { + if (!rev->pending_eof) { + rev->ready = 0; + } + + rev->available = 0; + } + + return n; + } + #endif if (n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) { diff --git a/src/os/unix/ngx_recv.c b/src/os/unix/ngx_recv.c index 5013ae3..c85fd45 100644 --- a/src/os/unix/ngx_recv.c +++ b/src/os/unix/ngx_recv.c @@ -48,6 +48,21 @@ ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) } } +#endif + +#if (NGX_HAVE_EPOLLRDHUP) + + if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "recv: eof:%d, avail:%d", + rev->pending_eof, rev->available); + + if (!rev->available && !rev->pending_eof) { + rev->ready = 0; + return NGX_AGAIN; + } + } + #endif do { @@ -99,6 +114,24 @@ ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) return n; } +#endif + +#if (NGX_HAVE_EPOLLRDHUP) + + if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) + && ngx_use_epoll_rdhup) + { + if ((size_t) n < size) { + if (!rev->pending_eof) { + rev->ready = 0; + } + + rev->available = 0; + } + + return n; + } + #endif if ((size_t) n < size diff --git a/src/os/unix/ngx_thread_mutex.c b/src/os/unix/ngx_thread_mutex.c index 6e8385e..a0ef693 100644 --- a/src/os/unix/ngx_thread_mutex.c +++ b/src/os/unix/ngx_thread_mutex.c @@ -49,7 +49,7 @@ * for each mutex from 10 to 100 based on spin count taken * previously. * FreeBSD: Deadlock detection. The default spin count is 2000. - * It can be overriden using LIBPTHREAD_SPINLOOPS environment + * It can be overridden using LIBPTHREAD_SPINLOOPS environment * variable or by pthread_mutex_setspinloops_np(). If a lock * is still busy, sched_yield() can be called on both UP and * SMP systems. The default yield loop count is zero, but diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c index 3bd8f6d..c195171 100644 --- a/src/stream/ngx_stream.c +++ b/src/stream/ngx_stream.c @@ -143,11 +143,26 @@ ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } - /* parse inside the stream{} block */ - pcf = *cf; cf->ctx = ctx; + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_STREAM_MODULE) { + continue; + } + + module = cf->cycle->modules[m]->ctx; + + if (module->preconfiguration) { + if (module->preconfiguration(cf) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + } + + + /* parse inside the stream{} block */ + cf->module_type = NGX_STREAM_MODULE; cf->cmd_type = NGX_STREAM_MAIN_CONF; rv = ngx_conf_parse(cf, NULL); @@ -215,6 +230,10 @@ ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } + if (ngx_stream_variables_init_vars(cf) != NGX_OK) { + return NGX_CONF_ERROR; + } + *cf = pcf; @@ -243,35 +262,11 @@ ngx_stream_add_ports(ngx_conf_t *cf, ngx_array_t *ports, in_port_t p; ngx_uint_t i; struct sockaddr *sa; - struct sockaddr_in *sin; ngx_stream_conf_port_t *port; ngx_stream_conf_addr_t *addr; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif - sa = &listen->u.sockaddr; - - switch (sa->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = &listen->u.sockaddr_in6; - p = sin6->sin6_port; - break; -#endif - -#if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - p = 0; - break; -#endif - - default: /* AF_INET */ - sin = &listen->u.sockaddr_in; - p = sin->sin_port; - break; - } + sa = &listen->sockaddr.sockaddr; + p = ngx_inet_get_port(sa); port = ports->elts; for (i = 0; i < ports->nelts; i++) { @@ -359,7 +354,7 @@ ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) continue; } - ls = ngx_create_listening(cf, &addr[i].opt.u.sockaddr, + ls = ngx_create_listening(cf, &addr[i].opt.sockaddr.sockaddr, addr[i].opt.socklen); if (ls == NULL) { return NGX_CONF_ERROR; @@ -453,7 +448,7 @@ ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *stport, for (i = 0; i < stport->naddrs; i++) { - sin = &addr[i].opt.u.sockaddr_in; + sin = &addr[i].opt.sockaddr.sockaddr_in; addrs[i].addr = sin->sin_addr.s_addr; addrs[i].conf.ctx = addr[i].opt.ctx; @@ -461,8 +456,8 @@ ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *stport, addrs[i].conf.ssl = addr[i].opt.ssl; #endif - len = ngx_sock_ntop(&addr[i].opt.u.sockaddr, addr[i].opt.socklen, buf, - NGX_SOCKADDR_STRLEN, 1); + len = ngx_sock_ntop(&addr[i].opt.sockaddr.sockaddr, addr[i].opt.socklen, + buf, NGX_SOCKADDR_STRLEN, 1); p = ngx_pnalloc(cf->pool, len); if (p == NULL) { @@ -502,7 +497,7 @@ ngx_stream_add_addrs6(ngx_conf_t *cf, ngx_stream_port_t *stport, for (i = 0; i < stport->naddrs; i++) { - sin6 = &addr[i].opt.u.sockaddr_in6; + sin6 = &addr[i].opt.sockaddr.sockaddr_in6; addrs6[i].addr6 = sin6->sin6_addr; addrs6[i].conf.ctx = addr[i].opt.ctx; @@ -510,8 +505,8 @@ ngx_stream_add_addrs6(ngx_conf_t *cf, ngx_stream_port_t *stport, addrs6[i].conf.ssl = addr[i].opt.ssl; #endif - len = ngx_sock_ntop(&addr[i].opt.u.sockaddr, addr[i].opt.socklen, buf, - NGX_SOCKADDR_STRLEN, 1); + len = ngx_sock_ntop(&addr[i].opt.sockaddr.sockaddr, addr[i].opt.socklen, + buf, NGX_SOCKADDR_STRLEN, 1); p = ngx_pnalloc(cf->pool, len); if (p == NULL) { diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h index 49efa45..807ab5b 100644 --- a/src/stream/ngx_stream.h +++ b/src/stream/ngx_stream.h @@ -20,75 +20,66 @@ typedef struct ngx_stream_session_s ngx_stream_session_t; +#include +#include #include #include typedef struct { - void **main_conf; - void **srv_conf; + void **main_conf; + void **srv_conf; } ngx_stream_conf_ctx_t; typedef struct { - union { - struct sockaddr sockaddr; - struct sockaddr_in sockaddr_in; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 sockaddr_in6; -#endif -#if (NGX_HAVE_UNIX_DOMAIN) - struct sockaddr_un sockaddr_un; -#endif - u_char sockaddr_data[NGX_SOCKADDRLEN]; - } u; - - socklen_t socklen; + ngx_sockaddr_t sockaddr; + socklen_t socklen; /* server ctx */ - ngx_stream_conf_ctx_t *ctx; + ngx_stream_conf_ctx_t *ctx; - unsigned bind:1; - unsigned wildcard:1; + unsigned bind:1; + unsigned wildcard:1; #if (NGX_STREAM_SSL) - unsigned ssl:1; + unsigned ssl:1; #endif #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) - unsigned ipv6only:1; + unsigned ipv6only:1; #endif #if (NGX_HAVE_REUSEPORT) - unsigned reuseport:1; + unsigned reuseport:1; #endif - unsigned so_keepalive:2; + unsigned so_keepalive:2; #if (NGX_HAVE_KEEPALIVE_TUNABLE) - int tcp_keepidle; - int tcp_keepintvl; - int tcp_keepcnt; + int tcp_keepidle; + int tcp_keepintvl; + int tcp_keepcnt; #endif - int backlog; - int type; + int backlog; + int type; } ngx_stream_listen_t; typedef struct { - ngx_stream_conf_ctx_t *ctx; - ngx_str_t addr_text; + ngx_stream_conf_ctx_t *ctx; + ngx_str_t addr_text; #if (NGX_STREAM_SSL) - ngx_uint_t ssl; /* unsigned ssl:1; */ + ngx_uint_t ssl; /* unsigned ssl:1; */ #endif } ngx_stream_addr_conf_t; typedef struct { - in_addr_t addr; - ngx_stream_addr_conf_t conf; + in_addr_t addr; + ngx_stream_addr_conf_t conf; } ngx_stream_in_addr_t; #if (NGX_HAVE_INET6) typedef struct { - struct in6_addr addr6; - ngx_stream_addr_conf_t conf; + struct in6_addr addr6; + ngx_stream_addr_conf_t conf; } ngx_stream_in6_addr_t; #endif @@ -96,21 +87,21 @@ typedef struct { typedef struct { /* ngx_stream_in_addr_t or ngx_stream_in6_addr_t */ - void *addrs; - ngx_uint_t naddrs; + void *addrs; + ngx_uint_t naddrs; } ngx_stream_port_t; typedef struct { - int family; - int type; - in_port_t port; - ngx_array_t addrs; /* array of ngx_stream_conf_addr_t */ + int family; + int type; + in_port_t port; + ngx_array_t addrs; /* array of ngx_stream_conf_addr_t */ } ngx_stream_conf_port_t; typedef struct { - ngx_stream_listen_t opt; + ngx_stream_listen_t opt; } ngx_stream_conf_addr_t; @@ -118,10 +109,21 @@ typedef ngx_int_t (*ngx_stream_access_pt)(ngx_stream_session_t *s); typedef struct { - ngx_array_t servers; /* ngx_stream_core_srv_conf_t */ - ngx_array_t listen; /* ngx_stream_listen_t */ - ngx_stream_access_pt limit_conn_handler; - ngx_stream_access_pt access_handler; + ngx_array_t servers; /* ngx_stream_core_srv_conf_t */ + ngx_array_t listen; /* ngx_stream_listen_t */ + + ngx_stream_access_pt limit_conn_handler; + ngx_stream_access_pt access_handler; + + ngx_hash_t variables_hash; + + ngx_array_t variables; /* ngx_stream_variable_t */ + ngx_uint_t ncaptures; + + ngx_uint_t variables_hash_max_size; + ngx_uint_t variables_hash_bucket_size; + + ngx_hash_keys_arrays_t *variables_keys; } ngx_stream_core_main_conf_t; @@ -129,41 +131,57 @@ typedef void (*ngx_stream_handler_pt)(ngx_stream_session_t *s); typedef struct { - ngx_stream_handler_pt handler; - ngx_stream_conf_ctx_t *ctx; - u_char *file_name; - ngx_int_t line; - ngx_log_t *error_log; - ngx_flag_t tcp_nodelay; + ngx_stream_handler_pt handler; + + ngx_stream_conf_ctx_t *ctx; + + u_char *file_name; + ngx_int_t line; + + ngx_flag_t tcp_nodelay; + + ngx_log_t *error_log; + + ngx_msec_t resolver_timeout; + ngx_resolver_t *resolver; } ngx_stream_core_srv_conf_t; struct ngx_stream_session_s { - uint32_t signature; /* "STRM" */ + uint32_t signature; /* "STRM" */ - ngx_connection_t *connection; + ngx_connection_t *connection; - off_t received; + off_t received; - ngx_log_handler_pt log_handler; + ngx_log_handler_pt log_handler; - void **ctx; - void **main_conf; - void **srv_conf; + void **ctx; + void **main_conf; + void **srv_conf; - ngx_stream_upstream_t *upstream; + ngx_stream_upstream_t *upstream; + + ngx_stream_variable_value_t *variables; + +#if (NGX_PCRE) + ngx_uint_t ncaptures; + int *captures; + u_char *captures_data; +#endif }; typedef struct { - ngx_int_t (*postconfiguration)(ngx_conf_t *cf); + ngx_int_t (*preconfiguration)(ngx_conf_t *cf); + ngx_int_t (*postconfiguration)(ngx_conf_t *cf); - void *(*create_main_conf)(ngx_conf_t *cf); - char *(*init_main_conf)(ngx_conf_t *cf, void *conf); + void *(*create_main_conf)(ngx_conf_t *cf); + char *(*init_main_conf)(ngx_conf_t *cf, void *conf); - void *(*create_srv_conf)(ngx_conf_t *cf); - char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, - void *conf); + void *(*create_srv_conf)(ngx_conf_t *cf); + char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, + void *conf); } ngx_stream_module_t; diff --git a/src/stream/ngx_stream_access_module.c b/src/stream/ngx_stream_access_module.c index 64869d2..6985d36 100644 --- a/src/stream/ngx_stream_access_module.c +++ b/src/stream/ngx_stream_access_module.c @@ -88,6 +88,7 @@ static ngx_command_t ngx_stream_access_commands[] = { static ngx_stream_module_t ngx_stream_access_module_ctx = { + NULL, /* preconfiguration */ ngx_stream_access_init, /* postconfiguration */ NULL, /* create main configuration */ diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c index ebc2b1c..70b9e2d 100644 --- a/src/stream/ngx_stream_core_module.c +++ b/src/stream/ngx_stream_core_module.c @@ -10,7 +10,9 @@ #include +static ngx_int_t ngx_stream_core_preconfiguration(ngx_conf_t *cf); static void *ngx_stream_core_create_main_conf(ngx_conf_t *cf); +static char *ngx_stream_core_init_main_conf(ngx_conf_t *cf, void *conf); static void *ngx_stream_core_create_srv_conf(ngx_conf_t *cf); static char *ngx_stream_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child); @@ -20,10 +22,26 @@ static char *ngx_stream_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_stream_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_command_t ngx_stream_core_commands[] = { + { ngx_string("variables_hash_max_size"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_STREAM_MAIN_CONF_OFFSET, + offsetof(ngx_stream_core_main_conf_t, variables_hash_max_size), + NULL }, + + { ngx_string("variables_hash_bucket_size"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_STREAM_MAIN_CONF_OFFSET, + offsetof(ngx_stream_core_main_conf_t, variables_hash_bucket_size), + NULL }, + { ngx_string("server"), NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, ngx_stream_core_server, @@ -45,6 +63,20 @@ static ngx_command_t ngx_stream_core_commands[] = { 0, NULL }, + { ngx_string("resolver"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE, + ngx_stream_core_resolver, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("resolver_timeout"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_core_srv_conf_t, resolver_timeout), + NULL }, + { ngx_string("tcp_nodelay"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -57,10 +89,11 @@ static ngx_command_t ngx_stream_core_commands[] = { static ngx_stream_module_t ngx_stream_core_module_ctx = { + ngx_stream_core_preconfiguration, /* preconfiguration */ NULL, /* postconfiguration */ ngx_stream_core_create_main_conf, /* create main configuration */ - NULL, /* init main configuration */ + ngx_stream_core_init_main_conf, /* init main configuration */ ngx_stream_core_create_srv_conf, /* create server configuration */ ngx_stream_core_merge_srv_conf /* merge server configuration */ @@ -83,6 +116,13 @@ ngx_module_t ngx_stream_core_module = { }; +static ngx_int_t +ngx_stream_core_preconfiguration(ngx_conf_t *cf) +{ + return ngx_stream_variables_add_core_vars(cf); +} + + static void * ngx_stream_core_create_main_conf(ngx_conf_t *cf) { @@ -106,10 +146,32 @@ ngx_stream_core_create_main_conf(ngx_conf_t *cf) return NULL; } + cmcf->variables_hash_max_size = NGX_CONF_UNSET_UINT; + cmcf->variables_hash_bucket_size = NGX_CONF_UNSET_UINT; + return cmcf; } +static char * +ngx_stream_core_init_main_conf(ngx_conf_t *cf, void *conf) +{ + ngx_stream_core_main_conf_t *cmcf = conf; + + ngx_conf_init_uint_value(cmcf->variables_hash_max_size, 1024); + ngx_conf_init_uint_value(cmcf->variables_hash_bucket_size, 64); + + cmcf->variables_hash_bucket_size = + ngx_align(cmcf->variables_hash_bucket_size, ngx_cacheline_size); + + if (cmcf->ncaptures) { + cmcf->ncaptures = (cmcf->ncaptures + 1) * 3; + } + + return NGX_CONF_OK; +} + + static void * ngx_stream_core_create_srv_conf(ngx_conf_t *cf) { @@ -129,6 +191,7 @@ ngx_stream_core_create_srv_conf(ngx_conf_t *cf) cscf->file_name = cf->conf_file->file.name.data; cscf->line = cf->conf_file->line; + cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; cscf->tcp_nodelay = NGX_CONF_UNSET; return cscf; @@ -141,6 +204,27 @@ ngx_stream_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_stream_core_srv_conf_t *prev = parent; ngx_stream_core_srv_conf_t *conf = child; + ngx_conf_merge_msec_value(conf->resolver_timeout, + prev->resolver_timeout, 30000); + + if (conf->resolver == NULL) { + + if (prev->resolver == NULL) { + + /* + * create dummy resolver in stream {} context + * to inherit it in all servers + */ + + prev->resolver = ngx_resolver_create(cf, NULL, 0); + if (prev->resolver == NULL) { + return NGX_CONF_ERROR; + } + } + + conf->resolver = prev->resolver; + } + if (conf->handler == NULL) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no handler for server in %s:%ui", @@ -248,18 +332,11 @@ ngx_stream_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) static char * ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - size_t len, off; - in_port_t port; ngx_str_t *value; ngx_url_t u; ngx_uint_t i, backlog; - struct sockaddr *sa; - struct sockaddr_in *sin; - ngx_stream_listen_t *ls; + ngx_stream_listen_t *ls, *als; ngx_stream_core_main_conf_t *cmcf; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif value = cf->args->elts; @@ -280,58 +357,6 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); - ls = cmcf->listen.elts; - - for (i = 0; i < cmcf->listen.nelts; i++) { - - sa = &ls[i].u.sockaddr; - - if (sa->sa_family != u.family) { - continue; - } - - switch (sa->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - off = offsetof(struct sockaddr_in6, sin6_addr); - len = 16; - sin6 = &ls[i].u.sockaddr_in6; - port = sin6->sin6_port; - break; -#endif - -#if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - off = offsetof(struct sockaddr_un, sun_path); - len = sizeof(((struct sockaddr_un *) sa)->sun_path); - port = 0; - break; -#endif - - default: /* AF_INET */ - off = offsetof(struct sockaddr_in, sin_addr); - len = 4; - sin = &ls[i].u.sockaddr_in; - port = sin->sin_port; - break; - } - - if (ngx_memcmp(ls[i].u.sockaddr_data + off, u.sockaddr + off, len) - != 0) - { - continue; - } - - if (port != u.port) { - continue; - } - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "duplicate \"%V\" address and port pair", &u.url); - return NGX_CONF_ERROR; - } - ls = ngx_array_push(&cmcf->listen); if (ls == NULL) { return NGX_CONF_ERROR; @@ -339,7 +364,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_memzero(ls, sizeof(ngx_stream_listen_t)); - ngx_memcpy(&ls->u.sockaddr, u.sockaddr, u.socklen); + ngx_memcpy(&ls->sockaddr.sockaddr, &u.sockaddr, u.socklen); ls->socklen = u.socklen; ls->backlog = NGX_LISTEN_BACKLOG; @@ -384,11 +409,10 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) { #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + size_t len; u_char buf[NGX_SOCKADDR_STRLEN]; - sa = &ls->u.sockaddr; - - if (sa->sa_family == AF_INET6) { + if (ls->sockaddr.sockaddr.sa_family == AF_INET6) { if (ngx_strcmp(&value[i].data[10], "n") == 0) { ls->ipv6only = 1; @@ -406,7 +430,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ls->bind = 1; } else { - len = ngx_sock_ntop(sa, ls->socklen, buf, + len = ngx_sock_ntop(&ls->sockaddr.sockaddr, ls->socklen, buf, NGX_SOCKADDR_STRLEN, 1); ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -558,5 +582,46 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } + als = cmcf->listen.elts; + + for (i = 0; i < cmcf->listen.nelts - 1; i++) { + if (ls->type != als[i].type) { + continue; + } + + if (ngx_cmp_sockaddr(&als[i].sockaddr.sockaddr, als[i].socklen, + &ls->sockaddr.sockaddr, ls->socklen, 1) + != NGX_OK) + { + continue; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate \"%V\" address and port pair", &u.url); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_stream_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_core_srv_conf_t *cscf = conf; + + ngx_str_t *value; + + if (cscf->resolver) { + return "is duplicate"; + } + + value = cf->args->elts; + + cscf->resolver = ngx_resolver_create(cf, &value[1], cf->args->nelts - 1); + if (cscf->resolver == NULL) { + return NGX_CONF_ERROR; + } + return NGX_CONF_OK; } diff --git a/src/stream/ngx_stream_geo_module.c b/src/stream/ngx_stream_geo_module.c new file mode 100644 index 0000000..ed1a488 --- /dev/null +++ b/src/stream/ngx_stream_geo_module.c @@ -0,0 +1,1572 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_stream_variable_value_t *value; + u_short start; + u_short end; +} ngx_stream_geo_range_t; + + +typedef struct { + ngx_radix_tree_t *tree; +#if (NGX_HAVE_INET6) + ngx_radix_tree_t *tree6; +#endif +} ngx_stream_geo_trees_t; + + +typedef struct { + ngx_stream_geo_range_t **low; + ngx_stream_variable_value_t *default_value; +} ngx_stream_geo_high_ranges_t; + + +typedef struct { + ngx_str_node_t sn; + ngx_stream_variable_value_t *value; + size_t offset; +} ngx_stream_geo_variable_value_node_t; + + +typedef struct { + ngx_stream_variable_value_t *value; + ngx_str_t *net; + ngx_stream_geo_high_ranges_t high; + ngx_radix_tree_t *tree; +#if (NGX_HAVE_INET6) + ngx_radix_tree_t *tree6; +#endif + ngx_rbtree_t rbtree; + ngx_rbtree_node_t sentinel; + ngx_pool_t *pool; + ngx_pool_t *temp_pool; + + size_t data_size; + + ngx_str_t include_name; + ngx_uint_t includes; + ngx_uint_t entries; + + unsigned ranges:1; + unsigned outside_entries:1; + unsigned allow_binary_include:1; + unsigned binary_include:1; +} ngx_stream_geo_conf_ctx_t; + + +typedef struct { + union { + ngx_stream_geo_trees_t trees; + ngx_stream_geo_high_ranges_t high; + } u; + + ngx_int_t index; +} ngx_stream_geo_ctx_t; + + +static ngx_int_t ngx_stream_geo_addr(ngx_stream_session_t *s, + ngx_stream_geo_ctx_t *ctx, ngx_addr_t *addr); + +static char *ngx_stream_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); +static char *ngx_stream_geo_range(ngx_conf_t *cf, + ngx_stream_geo_conf_ctx_t *ctx, ngx_str_t *value); +static char *ngx_stream_geo_add_range(ngx_conf_t *cf, + ngx_stream_geo_conf_ctx_t *ctx, in_addr_t start, in_addr_t end); +static ngx_uint_t ngx_stream_geo_delete_range(ngx_conf_t *cf, + ngx_stream_geo_conf_ctx_t *ctx, in_addr_t start, in_addr_t end); +static char *ngx_stream_geo_cidr(ngx_conf_t *cf, + ngx_stream_geo_conf_ctx_t *ctx, ngx_str_t *value); +static char *ngx_stream_geo_cidr_add(ngx_conf_t *cf, + ngx_stream_geo_conf_ctx_t *ctx, ngx_cidr_t *cidr, ngx_str_t *value, + ngx_str_t *net); +static ngx_stream_variable_value_t *ngx_stream_geo_value(ngx_conf_t *cf, + ngx_stream_geo_conf_ctx_t *ctx, ngx_str_t *value); +static ngx_int_t ngx_stream_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net, + ngx_cidr_t *cidr); +static char *ngx_stream_geo_include(ngx_conf_t *cf, + ngx_stream_geo_conf_ctx_t *ctx, ngx_str_t *name); +static ngx_int_t ngx_stream_geo_include_binary_base(ngx_conf_t *cf, + ngx_stream_geo_conf_ctx_t *ctx, ngx_str_t *name); +static void ngx_stream_geo_create_binary_base(ngx_stream_geo_conf_ctx_t *ctx); +static u_char *ngx_stream_geo_copy_values(u_char *base, u_char *p, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); + + +static ngx_command_t ngx_stream_geo_commands[] = { + + { ngx_string("geo"), + NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12, + ngx_stream_geo_block, + 0, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_geo_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_geo_module = { + NGX_MODULE_V1, + &ngx_stream_geo_module_ctx, /* module context */ + ngx_stream_geo_commands, /* module directives */ + NGX_STREAM_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 +}; + + +typedef struct { + u_char GEORNG[6]; + u_char version; + u_char ptr_size; + uint32_t endianness; + uint32_t crc32; +} ngx_stream_geo_header_t; + + +static ngx_stream_geo_header_t ngx_stream_geo_header = { + { 'G', 'E', 'O', 'R', 'N', 'G' }, 0, sizeof(void *), 0x12345678, 0 +}; + + +/* geo range is AF_INET only */ + +static ngx_int_t +ngx_stream_geo_cidr_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_stream_geo_ctx_t *ctx = (ngx_stream_geo_ctx_t *) data; + + in_addr_t inaddr; + ngx_addr_t addr; + struct sockaddr_in *sin; + ngx_stream_variable_value_t *vv; +#if (NGX_HAVE_INET6) + u_char *p; + struct in6_addr *inaddr6; +#endif + + if (ngx_stream_geo_addr(s, ctx, &addr) != NGX_OK) { + vv = (ngx_stream_variable_value_t *) + ngx_radix32tree_find(ctx->u.trees.tree, INADDR_NONE); + goto done; + } + + switch (addr.sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr; + p = inaddr6->s6_addr; + + if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { + inaddr = p[12] << 24; + inaddr += p[13] << 16; + inaddr += p[14] << 8; + inaddr += p[15]; + + vv = (ngx_stream_variable_value_t *) + ngx_radix32tree_find(ctx->u.trees.tree, inaddr); + + } else { + vv = (ngx_stream_variable_value_t *) + ngx_radix128tree_find(ctx->u.trees.tree6, p); + } + + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) addr.sockaddr; + inaddr = ntohl(sin->sin_addr.s_addr); + + vv = (ngx_stream_variable_value_t *) + ngx_radix32tree_find(ctx->u.trees.tree, inaddr); + + break; + } + +done: + + *v = *vv; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream geo: %v", v); + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geo_range_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_stream_geo_ctx_t *ctx = (ngx_stream_geo_ctx_t *) data; + + in_addr_t inaddr; + ngx_addr_t addr; + ngx_uint_t n; + struct sockaddr_in *sin; + ngx_stream_geo_range_t *range; +#if (NGX_HAVE_INET6) + u_char *p; + struct in6_addr *inaddr6; +#endif + + *v = *ctx->u.high.default_value; + + if (ngx_stream_geo_addr(s, ctx, &addr) == NGX_OK) { + + switch (addr.sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr; + + if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { + p = inaddr6->s6_addr; + + inaddr = p[12] << 24; + inaddr += p[13] << 16; + inaddr += p[14] << 8; + inaddr += p[15]; + + } else { + inaddr = INADDR_NONE; + } + + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) addr.sockaddr; + inaddr = ntohl(sin->sin_addr.s_addr); + break; + } + + } else { + inaddr = INADDR_NONE; + } + + if (ctx->u.high.low) { + range = ctx->u.high.low[inaddr >> 16]; + + if (range) { + n = inaddr & 0xffff; + do { + if (n >= (ngx_uint_t) range->start + && n <= (ngx_uint_t) range->end) + { + *v = *range->value; + break; + } + } while ((++range)->value); + } + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream geo: %v", v); + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geo_addr(ngx_stream_session_t *s, ngx_stream_geo_ctx_t *ctx, + ngx_addr_t *addr) +{ + ngx_stream_variable_value_t *v; + + if (ctx->index == -1) { + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream geo started: %V", &s->connection->addr_text); + + addr->sockaddr = s->connection->sockaddr; + addr->socklen = s->connection->socklen; + /* addr->name = s->connection->addr_text; */ + + return NGX_OK; + } + + v = ngx_stream_get_flushed_variable(s, ctx->index); + + if (v == NULL || v->not_found) { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream geo not found"); + + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream geo started: %v", v); + + if (ngx_parse_addr(s->connection->pool, addr, v->data, v->len) == NGX_OK) { + return NGX_OK; + } + + return NGX_ERROR; +} + + +static char * +ngx_stream_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *rv; + size_t len; + ngx_str_t *value, name; + ngx_uint_t i; + ngx_conf_t save; + ngx_pool_t *pool; + ngx_array_t *a; + ngx_stream_variable_t *var; + ngx_stream_geo_ctx_t *geo; + ngx_stream_geo_conf_ctx_t ctx; +#if (NGX_HAVE_INET6) + static struct in6_addr zero; +#endif + + value = cf->args->elts; + + geo = ngx_palloc(cf->pool, sizeof(ngx_stream_geo_ctx_t)); + if (geo == NULL) { + return NGX_CONF_ERROR; + } + + name = value[1]; + + if (name.data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &name); + return NGX_CONF_ERROR; + } + + name.len--; + name.data++; + + if (cf->args->nelts == 3) { + + geo->index = ngx_stream_get_variable_index(cf, &name); + if (geo->index == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + name = value[2]; + + if (name.data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &name); + return NGX_CONF_ERROR; + } + + name.len--; + name.data++; + + } else { + geo->index = -1; + } + + var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log); + if (pool == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(&ctx, sizeof(ngx_stream_geo_conf_ctx_t)); + + ctx.temp_pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log); + if (ctx.temp_pool == NULL) { + return NGX_CONF_ERROR; + } + + ngx_rbtree_init(&ctx.rbtree, &ctx.sentinel, ngx_str_rbtree_insert_value); + + ctx.pool = cf->pool; + ctx.data_size = sizeof(ngx_stream_geo_header_t) + + sizeof(ngx_stream_variable_value_t) + + 0x10000 * sizeof(ngx_stream_geo_range_t *); + ctx.allow_binary_include = 1; + + save = *cf; + cf->pool = pool; + cf->ctx = &ctx; + cf->handler = ngx_stream_geo; + cf->handler_conf = conf; + + rv = ngx_conf_parse(cf, NULL); + + *cf = save; + + if (ctx.ranges) { + + if (ctx.high.low && !ctx.binary_include) { + for (i = 0; i < 0x10000; i++) { + a = (ngx_array_t *) ctx.high.low[i]; + + if (a == NULL || a->nelts == 0) { + continue; + } + + len = a->nelts * sizeof(ngx_stream_geo_range_t); + + ctx.high.low[i] = ngx_palloc(cf->pool, len + sizeof(void *)); + if (ctx.high.low[i] == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memcpy(ctx.high.low[i], a->elts, len); + ctx.high.low[i][a->nelts].value = NULL; + ctx.data_size += len + sizeof(void *); + } + + if (ctx.allow_binary_include + && !ctx.outside_entries + && ctx.entries > 100000 + && ctx.includes == 1) + { + ngx_stream_geo_create_binary_base(&ctx); + } + } + + if (ctx.high.default_value == NULL) { + ctx.high.default_value = &ngx_stream_variable_null_value; + } + + geo->u.high = ctx.high; + + var->get_handler = ngx_stream_geo_range_variable; + var->data = (uintptr_t) geo; + + ngx_destroy_pool(ctx.temp_pool); + ngx_destroy_pool(pool); + + } else { + if (ctx.tree == NULL) { + ctx.tree = ngx_radix_tree_create(cf->pool, -1); + if (ctx.tree == NULL) { + return NGX_CONF_ERROR; + } + } + + geo->u.trees.tree = ctx.tree; + +#if (NGX_HAVE_INET6) + if (ctx.tree6 == NULL) { + ctx.tree6 = ngx_radix_tree_create(cf->pool, -1); + if (ctx.tree6 == NULL) { + return NGX_CONF_ERROR; + } + } + + geo->u.trees.tree6 = ctx.tree6; +#endif + + var->get_handler = ngx_stream_geo_cidr_variable; + var->data = (uintptr_t) geo; + + ngx_destroy_pool(ctx.temp_pool); + ngx_destroy_pool(pool); + + if (ngx_radix32tree_insert(ctx.tree, 0, 0, + (uintptr_t) &ngx_stream_variable_null_value) + == NGX_ERROR) + { + return NGX_CONF_ERROR; + } + + /* NGX_BUSY is okay (default was set explicitly) */ + +#if (NGX_HAVE_INET6) + if (ngx_radix128tree_insert(ctx.tree6, zero.s6_addr, zero.s6_addr, + (uintptr_t) &ngx_stream_variable_null_value) + == NGX_ERROR) + { + return NGX_CONF_ERROR; + } +#endif + } + + return rv; +} + + +static char * +ngx_stream_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +{ + char *rv; + ngx_str_t *value; + ngx_stream_geo_conf_ctx_t *ctx; + + ctx = cf->ctx; + + value = cf->args->elts; + + if (cf->args->nelts == 1) { + + if (ngx_strcmp(value[0].data, "ranges") == 0) { + + if (ctx->tree +#if (NGX_HAVE_INET6) + || ctx->tree6 +#endif + ) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the \"ranges\" directive must be " + "the first directive inside \"geo\" block"); + goto failed; + } + + ctx->ranges = 1; + + rv = NGX_CONF_OK; + + goto done; + } + } + + if (cf->args->nelts != 2) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid number of the geo parameters"); + goto failed; + } + + if (ngx_strcmp(value[0].data, "include") == 0) { + + rv = ngx_stream_geo_include(cf, ctx, &value[1]); + + goto done; + } + + if (ctx->ranges) { + rv = ngx_stream_geo_range(cf, ctx, value); + + } else { + rv = ngx_stream_geo_cidr(cf, ctx, value); + } + +done: + + ngx_reset_pool(cf->pool); + + return rv; + +failed: + + ngx_reset_pool(cf->pool); + + return NGX_CONF_ERROR; +} + + +static char * +ngx_stream_geo_range(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx, + ngx_str_t *value) +{ + u_char *p, *last; + in_addr_t start, end; + ngx_str_t *net; + ngx_uint_t del; + + if (ngx_strcmp(value[0].data, "default") == 0) { + + if (ctx->high.default_value) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "duplicate default geo range value: \"%V\", old value: \"%v\"", + &value[1], ctx->high.default_value); + } + + ctx->high.default_value = ngx_stream_geo_value(cf, ctx, &value[1]); + if (ctx->high.default_value == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; + } + + if (ctx->binary_include) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "binary geo range base \"%s\" cannot be mixed with usual entries", + ctx->include_name.data); + return NGX_CONF_ERROR; + } + + if (ctx->high.low == NULL) { + ctx->high.low = ngx_pcalloc(ctx->pool, + 0x10000 * sizeof(ngx_stream_geo_range_t *)); + if (ctx->high.low == NULL) { + return NGX_CONF_ERROR; + } + } + + ctx->entries++; + ctx->outside_entries = 1; + + if (ngx_strcmp(value[0].data, "delete") == 0) { + net = &value[1]; + del = 1; + + } else { + net = &value[0]; + del = 0; + } + + last = net->data + net->len; + + p = ngx_strlchr(net->data, last, '-'); + + if (p == NULL) { + goto invalid; + } + + start = ngx_inet_addr(net->data, p - net->data); + + if (start == INADDR_NONE) { + goto invalid; + } + + start = ntohl(start); + + p++; + + end = ngx_inet_addr(p, last - p); + + if (end == INADDR_NONE) { + goto invalid; + } + + end = ntohl(end); + + if (start > end) { + goto invalid; + } + + if (del) { + if (ngx_stream_geo_delete_range(cf, ctx, start, end)) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "no address range \"%V\" to delete", net); + } + + return NGX_CONF_OK; + } + + ctx->value = ngx_stream_geo_value(cf, ctx, &value[1]); + + if (ctx->value == NULL) { + return NGX_CONF_ERROR; + } + + ctx->net = net; + + return ngx_stream_geo_add_range(cf, ctx, start, end); + +invalid: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid range \"%V\"", net); + + return NGX_CONF_ERROR; +} + + +/* the add procedure is optimized to add a growing up sequence */ + +static char * +ngx_stream_geo_add_range(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx, + in_addr_t start, in_addr_t end) +{ + in_addr_t n; + ngx_uint_t h, i, s, e; + ngx_array_t *a; + ngx_stream_geo_range_t *range; + + for (n = start; n <= end; n = (n + 0x10000) & 0xffff0000) { + + h = n >> 16; + + if (n == start) { + s = n & 0xffff; + } else { + s = 0; + } + + if ((n | 0xffff) > end) { + e = end & 0xffff; + + } else { + e = 0xffff; + } + + a = (ngx_array_t *) ctx->high.low[h]; + + if (a == NULL) { + a = ngx_array_create(ctx->temp_pool, 64, + sizeof(ngx_stream_geo_range_t)); + if (a == NULL) { + return NGX_CONF_ERROR; + } + + ctx->high.low[h] = (ngx_stream_geo_range_t *) a; + } + + i = a->nelts; + range = a->elts; + + while (i) { + + i--; + + if (e < (ngx_uint_t) range[i].start) { + continue; + } + + if (s > (ngx_uint_t) range[i].end) { + + /* add after the range */ + + range = ngx_array_push(a); + if (range == NULL) { + return NGX_CONF_ERROR; + } + + range = a->elts; + + ngx_memmove(&range[i + 2], &range[i + 1], + (a->nelts - 2 - i) * sizeof(ngx_stream_geo_range_t)); + + range[i + 1].start = (u_short) s; + range[i + 1].end = (u_short) e; + range[i + 1].value = ctx->value; + + goto next; + } + + if (s == (ngx_uint_t) range[i].start + && e == (ngx_uint_t) range[i].end) + { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "duplicate range \"%V\", value: \"%v\", old value: \"%v\"", + ctx->net, ctx->value, range[i].value); + + range[i].value = ctx->value; + + goto next; + } + + if (s > (ngx_uint_t) range[i].start + && e < (ngx_uint_t) range[i].end) + { + /* split the range and insert the new one */ + + range = ngx_array_push(a); + if (range == NULL) { + return NGX_CONF_ERROR; + } + + range = ngx_array_push(a); + if (range == NULL) { + return NGX_CONF_ERROR; + } + + range = a->elts; + + ngx_memmove(&range[i + 3], &range[i + 1], + (a->nelts - 3 - i) * sizeof(ngx_stream_geo_range_t)); + + range[i + 2].start = (u_short) (e + 1); + range[i + 2].end = range[i].end; + range[i + 2].value = range[i].value; + + range[i + 1].start = (u_short) s; + range[i + 1].end = (u_short) e; + range[i + 1].value = ctx->value; + + range[i].end = (u_short) (s - 1); + + goto next; + } + + if (s == (ngx_uint_t) range[i].start + && e < (ngx_uint_t) range[i].end) + { + /* shift the range start and insert the new range */ + + range = ngx_array_push(a); + if (range == NULL) { + return NGX_CONF_ERROR; + } + + range = a->elts; + + ngx_memmove(&range[i + 1], &range[i], + (a->nelts - 1 - i) * sizeof(ngx_stream_geo_range_t)); + + range[i + 1].start = (u_short) (e + 1); + + range[i].start = (u_short) s; + range[i].end = (u_short) e; + range[i].value = ctx->value; + + goto next; + } + + if (s > (ngx_uint_t) range[i].start + && e == (ngx_uint_t) range[i].end) + { + /* shift the range end and insert the new range */ + + range = ngx_array_push(a); + if (range == NULL) { + return NGX_CONF_ERROR; + } + + range = a->elts; + + ngx_memmove(&range[i + 2], &range[i + 1], + (a->nelts - 2 - i) * sizeof(ngx_stream_geo_range_t)); + + range[i + 1].start = (u_short) s; + range[i + 1].end = (u_short) e; + range[i + 1].value = ctx->value; + + range[i].end = (u_short) (s - 1); + + goto next; + } + + s = (ngx_uint_t) range[i].start; + e = (ngx_uint_t) range[i].end; + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "range \"%V\" overlaps \"%d.%d.%d.%d-%d.%d.%d.%d\"", + ctx->net, + h >> 8, h & 0xff, s >> 8, s & 0xff, + h >> 8, h & 0xff, e >> 8, e & 0xff); + + return NGX_CONF_ERROR; + } + + /* add the first range */ + + range = ngx_array_push(a); + if (range == NULL) { + return NGX_CONF_ERROR; + } + + range->start = (u_short) s; + range->end = (u_short) e; + range->value = ctx->value; + + next: + + continue; + } + + return NGX_CONF_OK; +} + + +static ngx_uint_t +ngx_stream_geo_delete_range(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx, + in_addr_t start, in_addr_t end) +{ + in_addr_t n; + ngx_uint_t h, i, s, e, warn; + ngx_array_t *a; + ngx_stream_geo_range_t *range; + + warn = 0; + + for (n = start; n <= end; n += 0x10000) { + + h = n >> 16; + + if (n == start) { + s = n & 0xffff; + } else { + s = 0; + } + + if ((n | 0xffff) > end) { + e = end & 0xffff; + + } else { + e = 0xffff; + } + + a = (ngx_array_t *) ctx->high.low[h]; + + if (a == NULL) { + warn = 1; + continue; + } + + range = a->elts; + for (i = 0; i < a->nelts; i++) { + + if (s == (ngx_uint_t) range[i].start + && e == (ngx_uint_t) range[i].end) + { + ngx_memmove(&range[i], &range[i + 1], + (a->nelts - 1 - i) * sizeof(ngx_stream_geo_range_t)); + + a->nelts--; + + break; + } + + if (s != (ngx_uint_t) range[i].start + && e != (ngx_uint_t) range[i].end) + { + continue; + } + + warn = 1; + } + } + + return warn; +} + + +static char * +ngx_stream_geo_cidr(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx, + ngx_str_t *value) +{ + char *rv; + ngx_int_t rc, del; + ngx_str_t *net; + ngx_cidr_t cidr; + + if (ctx->tree == NULL) { + ctx->tree = ngx_radix_tree_create(ctx->pool, -1); + if (ctx->tree == NULL) { + return NGX_CONF_ERROR; + } + } + +#if (NGX_HAVE_INET6) + if (ctx->tree6 == NULL) { + ctx->tree6 = ngx_radix_tree_create(ctx->pool, -1); + if (ctx->tree6 == NULL) { + return NGX_CONF_ERROR; + } + } +#endif + + if (ngx_strcmp(value[0].data, "default") == 0) { + cidr.family = AF_INET; + cidr.u.in.addr = 0; + cidr.u.in.mask = 0; + + rv = ngx_stream_geo_cidr_add(cf, ctx, &cidr, &value[1], &value[0]); + + if (rv != NGX_CONF_OK) { + return rv; + } + +#if (NGX_HAVE_INET6) + cidr.family = AF_INET6; + ngx_memzero(&cidr.u.in6, sizeof(ngx_in6_cidr_t)); + + rv = ngx_stream_geo_cidr_add(cf, ctx, &cidr, &value[1], &value[0]); + + if (rv != NGX_CONF_OK) { + return rv; + } +#endif + + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[0].data, "delete") == 0) { + net = &value[1]; + del = 1; + + } else { + net = &value[0]; + del = 0; + } + + if (ngx_stream_geo_cidr_value(cf, net, &cidr) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cidr.family == AF_INET) { + cidr.u.in.addr = ntohl(cidr.u.in.addr); + cidr.u.in.mask = ntohl(cidr.u.in.mask); + } + + if (del) { + switch (cidr.family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + rc = ngx_radix128tree_delete(ctx->tree6, + cidr.u.in6.addr.s6_addr, + cidr.u.in6.mask.s6_addr); + break; +#endif + + default: /* AF_INET */ + rc = ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr, + cidr.u.in.mask); + break; + } + + if (rc != NGX_OK) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "no network \"%V\" to delete", net); + } + + return NGX_CONF_OK; + } + + return ngx_stream_geo_cidr_add(cf, ctx, &cidr, &value[1], net); +} + + +static char * +ngx_stream_geo_cidr_add(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx, + ngx_cidr_t *cidr, ngx_str_t *value, ngx_str_t *net) +{ + ngx_int_t rc; + ngx_stream_variable_value_t *val, *old; + + val = ngx_stream_geo_value(cf, ctx, value); + + if (val == NULL) { + return NGX_CONF_ERROR; + } + + switch (cidr->family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + rc = ngx_radix128tree_insert(ctx->tree6, cidr->u.in6.addr.s6_addr, + cidr->u.in6.mask.s6_addr, + (uintptr_t) val); + + if (rc == NGX_OK) { + return NGX_CONF_OK; + } + + if (rc == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + /* rc == NGX_BUSY */ + + old = (ngx_stream_variable_value_t *) + ngx_radix128tree_find(ctx->tree6, + cidr->u.in6.addr.s6_addr); + + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "duplicate network \"%V\", value: \"%v\", old value: \"%v\"", + net, val, old); + + rc = ngx_radix128tree_delete(ctx->tree6, + cidr->u.in6.addr.s6_addr, + cidr->u.in6.mask.s6_addr); + + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree"); + return NGX_CONF_ERROR; + } + + rc = ngx_radix128tree_insert(ctx->tree6, cidr->u.in6.addr.s6_addr, + cidr->u.in6.mask.s6_addr, + (uintptr_t) val); + + break; +#endif + + default: /* AF_INET */ + rc = ngx_radix32tree_insert(ctx->tree, cidr->u.in.addr, + cidr->u.in.mask, (uintptr_t) val); + + if (rc == NGX_OK) { + return NGX_CONF_OK; + } + + if (rc == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + /* rc == NGX_BUSY */ + + old = (ngx_stream_variable_value_t *) + ngx_radix32tree_find(ctx->tree, cidr->u.in.addr); + + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "duplicate network \"%V\", value: \"%v\", old value: \"%v\"", + net, val, old); + + rc = ngx_radix32tree_delete(ctx->tree, + cidr->u.in.addr, cidr->u.in.mask); + + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree"); + return NGX_CONF_ERROR; + } + + rc = ngx_radix32tree_insert(ctx->tree, cidr->u.in.addr, + cidr->u.in.mask, (uintptr_t) val); + + break; + } + + if (rc == NGX_OK) { + return NGX_CONF_OK; + } + + return NGX_CONF_ERROR; +} + + +static ngx_stream_variable_value_t * +ngx_stream_geo_value(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx, + ngx_str_t *value) +{ + uint32_t hash; + ngx_stream_variable_value_t *val; + ngx_stream_geo_variable_value_node_t *gvvn; + + hash = ngx_crc32_long(value->data, value->len); + + gvvn = (ngx_stream_geo_variable_value_node_t *) + ngx_str_rbtree_lookup(&ctx->rbtree, value, hash); + + if (gvvn) { + return gvvn->value; + } + + val = ngx_palloc(ctx->pool, sizeof(ngx_stream_variable_value_t)); + if (val == NULL) { + return NULL; + } + + val->len = value->len; + val->data = ngx_pstrdup(ctx->pool, value); + if (val->data == NULL) { + return NULL; + } + + val->valid = 1; + val->no_cacheable = 0; + val->not_found = 0; + + gvvn = ngx_palloc(ctx->temp_pool, + sizeof(ngx_stream_geo_variable_value_node_t)); + if (gvvn == NULL) { + return NULL; + } + + gvvn->sn.node.key = hash; + gvvn->sn.str.len = val->len; + gvvn->sn.str.data = val->data; + gvvn->value = val; + gvvn->offset = 0; + + ngx_rbtree_insert(&ctx->rbtree, &gvvn->sn.node); + + ctx->data_size += ngx_align(sizeof(ngx_stream_variable_value_t) + + value->len, sizeof(void *)); + + return val; +} + + +static ngx_int_t +ngx_stream_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net, ngx_cidr_t *cidr) +{ + ngx_int_t rc; + + if (ngx_strcmp(net->data, "255.255.255.255") == 0) { + cidr->family = AF_INET; + cidr->u.in.addr = 0xffffffff; + cidr->u.in.mask = 0xffffffff; + + return NGX_OK; + } + + rc = ngx_ptocidr(net, cidr); + + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid network \"%V\"", net); + return NGX_ERROR; + } + + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", net); + } + + return NGX_OK; +} + + +static char * +ngx_stream_geo_include(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx, + ngx_str_t *name) +{ + char *rv; + ngx_str_t file; + + file.len = name->len + 4; + file.data = ngx_pnalloc(ctx->temp_pool, name->len + 5); + if (file.data == NULL) { + return NGX_CONF_ERROR; + } + + ngx_sprintf(file.data, "%V.bin%Z", name); + + if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (ctx->ranges) { + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); + + switch (ngx_stream_geo_include_binary_base(cf, ctx, &file)) { + case NGX_OK: + return NGX_CONF_OK; + case NGX_ERROR: + return NGX_CONF_ERROR; + default: + break; + } + } + + file.len -= 4; + file.data[file.len] = '\0'; + + ctx->include_name = file; + + if (ctx->outside_entries) { + ctx->allow_binary_include = 0; + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); + + rv = ngx_conf_parse(cf, &file); + + ctx->includes++; + ctx->outside_entries = 0; + + return rv; +} + + +static ngx_int_t +ngx_stream_geo_include_binary_base(ngx_conf_t *cf, + ngx_stream_geo_conf_ctx_t *ctx, ngx_str_t *name) +{ + u_char *base, ch; + time_t mtime; + size_t size, len; + ssize_t n; + uint32_t crc32; + ngx_err_t err; + ngx_int_t rc; + ngx_uint_t i; + ngx_file_t file; + ngx_file_info_t fi; + ngx_stream_geo_range_t *range, **ranges; + ngx_stream_geo_header_t *header; + ngx_stream_variable_value_t *vv; + + ngx_memzero(&file, sizeof(ngx_file_t)); + file.name = *name; + file.log = cf->log; + + file.fd = ngx_open_file(name->data, NGX_FILE_RDONLY, 0, 0); + if (file.fd == NGX_INVALID_FILE) { + err = ngx_errno; + if (err != NGX_ENOENT) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, err, + ngx_open_file_n " \"%s\" failed", name->data); + } + return NGX_DECLINED; + } + + if (ctx->outside_entries) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "binary geo range base \"%s\" cannot be mixed with usual entries", + name->data); + rc = NGX_ERROR; + goto done; + } + + if (ctx->binary_include) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "second binary geo range base \"%s\" cannot be mixed with \"%s\"", + name->data, ctx->include_name.data); + rc = NGX_ERROR; + goto done; + } + + if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, + ngx_fd_info_n " \"%s\" failed", name->data); + goto failed; + } + + size = (size_t) ngx_file_size(&fi); + mtime = ngx_file_mtime(&fi); + + ch = name->data[name->len - 4]; + name->data[name->len - 4] = '\0'; + + if (ngx_file_info(name->data, &fi) == NGX_FILE_ERROR) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, + ngx_file_info_n " \"%s\" failed", name->data); + goto failed; + } + + name->data[name->len - 4] = ch; + + if (mtime < ngx_file_mtime(&fi)) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "stale binary geo range base \"%s\"", name->data); + goto failed; + } + + base = ngx_palloc(ctx->pool, size); + if (base == NULL) { + goto failed; + } + + n = ngx_read_file(&file, base, size, 0); + + if (n == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, + ngx_read_file_n " \"%s\" failed", name->data); + goto failed; + } + + if ((size_t) n != size) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, 0, + ngx_read_file_n " \"%s\" returned only %z bytes instead of %z", + name->data, n, size); + goto failed; + } + + header = (ngx_stream_geo_header_t *) base; + + if (size < 16 || ngx_memcmp(&ngx_stream_geo_header, header, 12) != 0) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "incompatible binary geo range base \"%s\"", name->data); + goto failed; + } + + ngx_crc32_init(crc32); + + vv = (ngx_stream_variable_value_t *) + (base + sizeof(ngx_stream_geo_header_t)); + + while (vv->data) { + len = ngx_align(sizeof(ngx_stream_variable_value_t) + vv->len, + sizeof(void *)); + ngx_crc32_update(&crc32, (u_char *) vv, len); + vv->data += (size_t) base; + vv = (ngx_stream_variable_value_t *) ((u_char *) vv + len); + } + ngx_crc32_update(&crc32, (u_char *) vv, + sizeof(ngx_stream_variable_value_t)); + vv++; + + ranges = (ngx_stream_geo_range_t **) vv; + + for (i = 0; i < 0x10000; i++) { + ngx_crc32_update(&crc32, (u_char *) &ranges[i], sizeof(void *)); + if (ranges[i]) { + ranges[i] = (ngx_stream_geo_range_t *) + ((u_char *) ranges[i] + (size_t) base); + } + } + + range = (ngx_stream_geo_range_t *) &ranges[0x10000]; + + while ((u_char *) range < base + size) { + while (range->value) { + ngx_crc32_update(&crc32, (u_char *) range, + sizeof(ngx_stream_geo_range_t)); + range->value = (ngx_stream_variable_value_t *) + ((u_char *) range->value + (size_t) base); + range++; + } + ngx_crc32_update(&crc32, (u_char *) range, sizeof(void *)); + range = (ngx_stream_geo_range_t *) ((u_char *) range + sizeof(void *)); + } + + ngx_crc32_final(crc32); + + if (crc32 != header->crc32) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "CRC32 mismatch in binary geo range base \"%s\"", name->data); + goto failed; + } + + ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, + "using binary geo range base \"%s\"", name->data); + + ctx->include_name = *name; + ctx->binary_include = 1; + ctx->high.low = ranges; + rc = NGX_OK; + + goto done; + +failed: + + rc = NGX_DECLINED; + +done: + + if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", name->data); + } + + return rc; +} + + +static void +ngx_stream_geo_create_binary_base(ngx_stream_geo_conf_ctx_t *ctx) +{ + u_char *p; + uint32_t hash; + ngx_str_t s; + ngx_uint_t i; + ngx_file_mapping_t fm; + ngx_stream_geo_range_t *r, *range, **ranges; + ngx_stream_geo_header_t *header; + ngx_stream_geo_variable_value_node_t *gvvn; + + fm.name = ngx_pnalloc(ctx->temp_pool, ctx->include_name.len + 5); + if (fm.name == NULL) { + return; + } + + ngx_sprintf(fm.name, "%V.bin%Z", &ctx->include_name); + + fm.size = ctx->data_size; + fm.log = ctx->pool->log; + + ngx_log_error(NGX_LOG_NOTICE, fm.log, 0, + "creating binary geo range base \"%s\"", fm.name); + + if (ngx_create_file_mapping(&fm) != NGX_OK) { + return; + } + + p = ngx_cpymem(fm.addr, &ngx_stream_geo_header, + sizeof(ngx_stream_geo_header_t)); + + p = ngx_stream_geo_copy_values(fm.addr, p, ctx->rbtree.root, + ctx->rbtree.sentinel); + + p += sizeof(ngx_stream_variable_value_t); + + ranges = (ngx_stream_geo_range_t **) p; + + p += 0x10000 * sizeof(ngx_stream_geo_range_t *); + + for (i = 0; i < 0x10000; i++) { + r = ctx->high.low[i]; + if (r == NULL) { + continue; + } + + range = (ngx_stream_geo_range_t *) p; + ranges[i] = (ngx_stream_geo_range_t *) (p - (u_char *) fm.addr); + + do { + s.len = r->value->len; + s.data = r->value->data; + hash = ngx_crc32_long(s.data, s.len); + gvvn = (ngx_stream_geo_variable_value_node_t *) + ngx_str_rbtree_lookup(&ctx->rbtree, &s, hash); + + range->value = (ngx_stream_variable_value_t *) gvvn->offset; + range->start = r->start; + range->end = r->end; + range++; + + } while ((++r)->value); + + range->value = NULL; + + p = (u_char *) range + sizeof(void *); + } + + header = fm.addr; + header->crc32 = ngx_crc32_long((u_char *) fm.addr + + sizeof(ngx_stream_geo_header_t), + fm.size - sizeof(ngx_stream_geo_header_t)); + + ngx_close_file_mapping(&fm); +} + + +static u_char * +ngx_stream_geo_copy_values(u_char *base, u_char *p, ngx_rbtree_node_t *node, + ngx_rbtree_node_t *sentinel) +{ + ngx_stream_variable_value_t *vv; + ngx_stream_geo_variable_value_node_t *gvvn; + + if (node == sentinel) { + return p; + } + + gvvn = (ngx_stream_geo_variable_value_node_t *) node; + gvvn->offset = p - base; + + vv = (ngx_stream_variable_value_t *) p; + *vv = *gvvn->value; + p += sizeof(ngx_stream_variable_value_t); + vv->data = (u_char *) (p - base); + + p = ngx_cpymem(p, gvvn->sn.str.data, gvvn->sn.str.len); + + p = ngx_align_ptr(p, sizeof(void *)); + + p = ngx_stream_geo_copy_values(base, p, node->left, sentinel); + + return ngx_stream_geo_copy_values(base, p, node->right, sentinel); +} diff --git a/src/stream/ngx_stream_geoip_module.c b/src/stream/ngx_stream_geoip_module.c new file mode 100644 index 0000000..f694033 --- /dev/null +++ b/src/stream/ngx_stream_geoip_module.c @@ -0,0 +1,814 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + +#include +#include + + +#define NGX_GEOIP_COUNTRY_CODE 0 +#define NGX_GEOIP_COUNTRY_CODE3 1 +#define NGX_GEOIP_COUNTRY_NAME 2 + + +typedef struct { + GeoIP *country; + GeoIP *org; + GeoIP *city; +#if (NGX_HAVE_GEOIP_V6) + unsigned country_v6:1; + unsigned org_v6:1; + unsigned city_v6:1; +#endif +} ngx_stream_geoip_conf_t; + + +typedef struct { + ngx_str_t *name; + uintptr_t data; +} ngx_stream_geoip_var_t; + + +typedef const char *(*ngx_stream_geoip_variable_handler_pt)(GeoIP *, + u_long addr); + + +ngx_stream_geoip_variable_handler_pt ngx_stream_geoip_country_functions[] = { + GeoIP_country_code_by_ipnum, + GeoIP_country_code3_by_ipnum, + GeoIP_country_name_by_ipnum, +}; + + +#if (NGX_HAVE_GEOIP_V6) + +typedef const char *(*ngx_stream_geoip_variable_handler_v6_pt)(GeoIP *, + geoipv6_t addr); + + +ngx_stream_geoip_variable_handler_v6_pt + ngx_stream_geoip_country_v6_functions[] = +{ + GeoIP_country_code_by_ipnum_v6, + GeoIP_country_code3_by_ipnum_v6, + GeoIP_country_name_by_ipnum_v6, +}; + +#endif + + +static ngx_int_t ngx_stream_geoip_country_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_geoip_org_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_geoip_city_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_geoip_region_name_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_geoip_city_float_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_geoip_city_int_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static GeoIPRecord *ngx_stream_geoip_get_city_record(ngx_stream_session_t *s); + +static ngx_int_t ngx_stream_geoip_add_variables(ngx_conf_t *cf); +static void *ngx_stream_geoip_create_conf(ngx_conf_t *cf); +static char *ngx_stream_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void ngx_stream_geoip_cleanup(void *data); + + +static ngx_command_t ngx_stream_geoip_commands[] = { + + { ngx_string("geoip_country"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE12, + ngx_stream_geoip_country, + NGX_STREAM_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("geoip_org"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE12, + ngx_stream_geoip_org, + NGX_STREAM_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("geoip_city"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE12, + ngx_stream_geoip_city, + NGX_STREAM_MAIN_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_geoip_module_ctx = { + ngx_stream_geoip_add_variables, /* preconfiguration */ + NULL, /* postconfiguration */ + + ngx_stream_geoip_create_conf, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_geoip_module = { + NGX_MODULE_V1, + &ngx_stream_geoip_module_ctx, /* module context */ + ngx_stream_geoip_commands, /* module directives */ + NGX_STREAM_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_stream_variable_t ngx_stream_geoip_vars[] = { + + { ngx_string("geoip_country_code"), NULL, + ngx_stream_geoip_country_variable, + NGX_GEOIP_COUNTRY_CODE, 0, 0 }, + + { ngx_string("geoip_country_code3"), NULL, + ngx_stream_geoip_country_variable, + NGX_GEOIP_COUNTRY_CODE3, 0, 0 }, + + { ngx_string("geoip_country_name"), NULL, + ngx_stream_geoip_country_variable, + NGX_GEOIP_COUNTRY_NAME, 0, 0 }, + + { ngx_string("geoip_org"), NULL, + ngx_stream_geoip_org_variable, + 0, 0, 0 }, + + { ngx_string("geoip_city_continent_code"), NULL, + ngx_stream_geoip_city_variable, + offsetof(GeoIPRecord, continent_code), 0, 0 }, + + { ngx_string("geoip_city_country_code"), NULL, + ngx_stream_geoip_city_variable, + offsetof(GeoIPRecord, country_code), 0, 0 }, + + { ngx_string("geoip_city_country_code3"), NULL, + ngx_stream_geoip_city_variable, + offsetof(GeoIPRecord, country_code3), 0, 0 }, + + { ngx_string("geoip_city_country_name"), NULL, + ngx_stream_geoip_city_variable, + offsetof(GeoIPRecord, country_name), 0, 0 }, + + { ngx_string("geoip_region"), NULL, + ngx_stream_geoip_city_variable, + offsetof(GeoIPRecord, region), 0, 0 }, + + { ngx_string("geoip_region_name"), NULL, + ngx_stream_geoip_region_name_variable, + 0, 0, 0 }, + + { ngx_string("geoip_city"), NULL, + ngx_stream_geoip_city_variable, + offsetof(GeoIPRecord, city), 0, 0 }, + + { ngx_string("geoip_postal_code"), NULL, + ngx_stream_geoip_city_variable, + offsetof(GeoIPRecord, postal_code), 0, 0 }, + + { ngx_string("geoip_latitude"), NULL, + ngx_stream_geoip_city_float_variable, + offsetof(GeoIPRecord, latitude), 0, 0 }, + + { ngx_string("geoip_longitude"), NULL, + ngx_stream_geoip_city_float_variable, + offsetof(GeoIPRecord, longitude), 0, 0 }, + + { ngx_string("geoip_dma_code"), NULL, + ngx_stream_geoip_city_int_variable, + offsetof(GeoIPRecord, dma_code), 0, 0 }, + + { ngx_string("geoip_area_code"), NULL, + ngx_stream_geoip_city_int_variable, + offsetof(GeoIPRecord, area_code), 0, 0 }, + + { ngx_null_string, NULL, NULL, 0, 0, 0 } +}; + + +static u_long +ngx_stream_geoip_addr(ngx_stream_session_t *s, ngx_stream_geoip_conf_t *gcf) +{ + ngx_addr_t addr; + struct sockaddr_in *sin; + + addr.sockaddr = s->connection->sockaddr; + addr.socklen = s->connection->socklen; + /* addr.name = s->connection->addr_text; */ + +#if (NGX_HAVE_INET6) + + if (addr.sockaddr->sa_family == AF_INET6) { + u_char *p; + in_addr_t inaddr; + struct in6_addr *inaddr6; + + inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr; + + if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { + p = inaddr6->s6_addr; + + inaddr = p[12] << 24; + inaddr += p[13] << 16; + inaddr += p[14] << 8; + inaddr += p[15]; + + return inaddr; + } + } + +#endif + + if (addr.sockaddr->sa_family != AF_INET) { + return INADDR_NONE; + } + + sin = (struct sockaddr_in *) addr.sockaddr; + return ntohl(sin->sin_addr.s_addr); +} + + +#if (NGX_HAVE_GEOIP_V6) + +static geoipv6_t +ngx_stream_geoip_addr_v6(ngx_stream_session_t *s, ngx_stream_geoip_conf_t *gcf) +{ + ngx_addr_t addr; + in_addr_t addr4; + struct in6_addr addr6; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + + addr.sockaddr = s->connection->sockaddr; + addr.socklen = s->connection->socklen; + /* addr.name = s->connection->addr_text; */ + + switch (addr.sockaddr->sa_family) { + + case AF_INET: + /* Produce IPv4-mapped IPv6 address. */ + sin = (struct sockaddr_in *) addr.sockaddr; + addr4 = ntohl(sin->sin_addr.s_addr); + + ngx_memzero(&addr6, sizeof(struct in6_addr)); + addr6.s6_addr[10] = 0xff; + addr6.s6_addr[11] = 0xff; + addr6.s6_addr[12] = addr4 >> 24; + addr6.s6_addr[13] = addr4 >> 16; + addr6.s6_addr[14] = addr4 >> 8; + addr6.s6_addr[15] = addr4; + return addr6; + + case AF_INET6: + sin6 = (struct sockaddr_in6 *) addr.sockaddr; + return sin6->sin6_addr; + + default: + return in6addr_any; + } +} + +#endif + + +static ngx_int_t +ngx_stream_geoip_country_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_stream_geoip_variable_handler_pt handler = + ngx_stream_geoip_country_functions[data]; +#if (NGX_HAVE_GEOIP_V6) + ngx_stream_geoip_variable_handler_v6_pt handler_v6 = + ngx_stream_geoip_country_v6_functions[data]; +#endif + + const char *val; + ngx_stream_geoip_conf_t *gcf; + + gcf = ngx_stream_get_module_main_conf(s, ngx_stream_geoip_module); + + if (gcf->country == NULL) { + goto not_found; + } + +#if (NGX_HAVE_GEOIP_V6) + val = gcf->country_v6 + ? handler_v6(gcf->country, ngx_stream_geoip_addr_v6(s, gcf)) + : handler(gcf->country, ngx_stream_geoip_addr(s, gcf)); +#else + val = handler(gcf->country, ngx_stream_geoip_addr(s, gcf)); +#endif + + if (val == NULL) { + goto not_found; + } + + v->len = ngx_strlen(val); + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = (u_char *) val; + + return NGX_OK; + +not_found: + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geoip_org_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + size_t len; + char *val; + ngx_stream_geoip_conf_t *gcf; + + gcf = ngx_stream_get_module_main_conf(s, ngx_stream_geoip_module); + + if (gcf->org == NULL) { + goto not_found; + } + +#if (NGX_HAVE_GEOIP_V6) + val = gcf->org_v6 + ? GeoIP_name_by_ipnum_v6(gcf->org, + ngx_stream_geoip_addr_v6(s, gcf)) + : GeoIP_name_by_ipnum(gcf->org, + ngx_stream_geoip_addr(s, gcf)); +#else + val = GeoIP_name_by_ipnum(gcf->org, ngx_stream_geoip_addr(s, gcf)); +#endif + + if (val == NULL) { + goto not_found; + } + + len = ngx_strlen(val); + v->data = ngx_pnalloc(s->connection->pool, len); + if (v->data == NULL) { + ngx_free(val); + return NGX_ERROR; + } + + ngx_memcpy(v->data, val, len); + + v->len = len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + ngx_free(val); + + return NGX_OK; + +not_found: + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geoip_city_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + char *val; + size_t len; + GeoIPRecord *gr; + + gr = ngx_stream_geoip_get_city_record(s); + if (gr == NULL) { + goto not_found; + } + + val = *(char **) ((char *) gr + data); + if (val == NULL) { + goto no_value; + } + + len = ngx_strlen(val); + v->data = ngx_pnalloc(s->connection->pool, len); + if (v->data == NULL) { + GeoIPRecord_delete(gr); + return NGX_ERROR; + } + + ngx_memcpy(v->data, val, len); + + v->len = len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + GeoIPRecord_delete(gr); + + return NGX_OK; + +no_value: + + GeoIPRecord_delete(gr); + +not_found: + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geoip_region_name_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + size_t len; + const char *val; + GeoIPRecord *gr; + + gr = ngx_stream_geoip_get_city_record(s); + if (gr == NULL) { + goto not_found; + } + + val = GeoIP_region_name_by_code(gr->country_code, gr->region); + + GeoIPRecord_delete(gr); + + if (val == NULL) { + goto not_found; + } + + len = ngx_strlen(val); + v->data = ngx_pnalloc(s->connection->pool, len); + if (v->data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(v->data, val, len); + + v->len = len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; + +not_found: + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geoip_city_float_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + float val; + GeoIPRecord *gr; + + gr = ngx_stream_geoip_get_city_record(s); + if (gr == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->data = ngx_pnalloc(s->connection->pool, NGX_INT64_LEN + 5); + if (v->data == NULL) { + GeoIPRecord_delete(gr); + return NGX_ERROR; + } + + val = *(float *) ((char *) gr + data); + + v->len = ngx_sprintf(v->data, "%.4f", val) - v->data; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + GeoIPRecord_delete(gr); + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geoip_city_int_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + int val; + GeoIPRecord *gr; + + gr = ngx_stream_geoip_get_city_record(s); + if (gr == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->data = ngx_pnalloc(s->connection->pool, NGX_INT64_LEN); + if (v->data == NULL) { + GeoIPRecord_delete(gr); + return NGX_ERROR; + } + + val = *(int *) ((char *) gr + data); + + v->len = ngx_sprintf(v->data, "%d", val) - v->data; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + GeoIPRecord_delete(gr); + + return NGX_OK; +} + + +static GeoIPRecord * +ngx_stream_geoip_get_city_record(ngx_stream_session_t *s) +{ + ngx_stream_geoip_conf_t *gcf; + + gcf = ngx_stream_get_module_main_conf(s, ngx_stream_geoip_module); + + if (gcf->city) { +#if (NGX_HAVE_GEOIP_V6) + return gcf->city_v6 + ? GeoIP_record_by_ipnum_v6(gcf->city, + ngx_stream_geoip_addr_v6(s, gcf)) + : GeoIP_record_by_ipnum(gcf->city, + ngx_stream_geoip_addr(s, gcf)); +#else + return GeoIP_record_by_ipnum(gcf->city, ngx_stream_geoip_addr(s, gcf)); +#endif + } + + return NULL; +} + + +static ngx_int_t +ngx_stream_geoip_add_variables(ngx_conf_t *cf) +{ + ngx_stream_variable_t *var, *v; + + for (v = ngx_stream_geoip_vars; v->name.len; v++) { + var = ngx_stream_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = v->get_handler; + var->data = v->data; + } + + return NGX_OK; +} + + +static void * +ngx_stream_geoip_create_conf(ngx_conf_t *cf) +{ + ngx_pool_cleanup_t *cln; + ngx_stream_geoip_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_geoip_conf_t)); + if (conf == NULL) { + return NULL; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NULL; + } + + cln->handler = ngx_stream_geoip_cleanup; + cln->data = conf; + + return conf; +} + + +static char * +ngx_stream_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_geoip_conf_t *gcf = conf; + + ngx_str_t *value; + + if (gcf->country) { + return "is duplicate"; + } + + value = cf->args->elts; + + gcf->country = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE); + + if (gcf->country == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "GeoIP_open(\"%V\") failed", &value[1]); + + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 3) { + if (ngx_strcmp(value[2].data, "utf8") == 0) { + GeoIP_set_charset(gcf->country, GEOIP_CHARSET_UTF8); + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + } + + switch (gcf->country->databaseType) { + + case GEOIP_COUNTRY_EDITION: + + return NGX_CONF_OK; + +#if (NGX_HAVE_GEOIP_V6) + case GEOIP_COUNTRY_EDITION_V6: + + gcf->country_v6 = 1; + return NGX_CONF_OK; +#endif + + default: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid GeoIP database \"%V\" type:%d", + &value[1], gcf->country->databaseType); + return NGX_CONF_ERROR; + } +} + + +static char * +ngx_stream_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_geoip_conf_t *gcf = conf; + + ngx_str_t *value; + + if (gcf->org) { + return "is duplicate"; + } + + value = cf->args->elts; + + gcf->org = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE); + + if (gcf->org == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "GeoIP_open(\"%V\") failed", &value[1]); + + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 3) { + if (ngx_strcmp(value[2].data, "utf8") == 0) { + GeoIP_set_charset(gcf->org, GEOIP_CHARSET_UTF8); + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + } + + switch (gcf->org->databaseType) { + + case GEOIP_ISP_EDITION: + case GEOIP_ORG_EDITION: + case GEOIP_DOMAIN_EDITION: + case GEOIP_ASNUM_EDITION: + + return NGX_CONF_OK; + +#if (NGX_HAVE_GEOIP_V6) + case GEOIP_ISP_EDITION_V6: + case GEOIP_ORG_EDITION_V6: + case GEOIP_DOMAIN_EDITION_V6: + case GEOIP_ASNUM_EDITION_V6: + + gcf->org_v6 = 1; + return NGX_CONF_OK; +#endif + + default: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid GeoIP database \"%V\" type:%d", + &value[1], gcf->org->databaseType); + return NGX_CONF_ERROR; + } +} + + +static char * +ngx_stream_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_geoip_conf_t *gcf = conf; + + ngx_str_t *value; + + if (gcf->city) { + return "is duplicate"; + } + + value = cf->args->elts; + + gcf->city = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE); + + if (gcf->city == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "GeoIP_open(\"%V\") failed", &value[1]); + + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 3) { + if (ngx_strcmp(value[2].data, "utf8") == 0) { + GeoIP_set_charset(gcf->city, GEOIP_CHARSET_UTF8); + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + } + + switch (gcf->city->databaseType) { + + case GEOIP_CITY_EDITION_REV0: + case GEOIP_CITY_EDITION_REV1: + + return NGX_CONF_OK; + +#if (NGX_HAVE_GEOIP_V6) + case GEOIP_CITY_EDITION_REV0_V6: + case GEOIP_CITY_EDITION_REV1_V6: + + gcf->city_v6 = 1; + return NGX_CONF_OK; +#endif + + default: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid GeoIP City database \"%V\" type:%d", + &value[1], gcf->city->databaseType); + return NGX_CONF_ERROR; + } +} + + +static void +ngx_stream_geoip_cleanup(void *data) +{ + ngx_stream_geoip_conf_t *gcf = data; + + if (gcf->country) { + GeoIP_delete(gcf->country); + } + + if (gcf->org) { + GeoIP_delete(gcf->org); + } + + if (gcf->city) { + GeoIP_delete(gcf->city); + } +} diff --git a/src/stream/ngx_stream_handler.c b/src/stream/ngx_stream_handler.c index aa69e44..61169e1 100644 --- a/src/stream/ngx_stream_handler.c +++ b/src/stream/ngx_stream_handler.c @@ -149,6 +149,15 @@ ngx_stream_init_connection(ngx_connection_t *c) cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); + s->variables = ngx_pcalloc(s->connection->pool, + cmcf->variables.nelts + * sizeof(ngx_stream_variable_value_t)); + + if (s->variables == NULL) { + ngx_stream_close_connection(c); + return; + } + if (cmcf->limit_conn_handler) { rc = cmcf->limit_conn_handler(s); diff --git a/src/stream/ngx_stream_limit_conn_module.c b/src/stream/ngx_stream_limit_conn_module.c index f1d8a37..40eca94 100644 --- a/src/stream/ngx_stream_limit_conn_module.c +++ b/src/stream/ngx_stream_limit_conn_module.c @@ -11,33 +11,34 @@ typedef struct { - u_char color; - u_char len; - u_short conn; - u_char data[1]; + u_char color; + u_char len; + u_short conn; + u_char data[1]; } ngx_stream_limit_conn_node_t; typedef struct { - ngx_shm_zone_t *shm_zone; - ngx_rbtree_node_t *node; + ngx_shm_zone_t *shm_zone; + ngx_rbtree_node_t *node; } ngx_stream_limit_conn_cleanup_t; typedef struct { - ngx_rbtree_t *rbtree; + ngx_rbtree_t *rbtree; + ngx_stream_complex_value_t key; } ngx_stream_limit_conn_ctx_t; typedef struct { - ngx_shm_zone_t *shm_zone; - ngx_uint_t conn; + ngx_shm_zone_t *shm_zone; + ngx_uint_t conn; } ngx_stream_limit_conn_limit_t; typedef struct { - ngx_array_t limits; - ngx_uint_t log_level; + ngx_array_t limits; + ngx_uint_t log_level; } ngx_stream_limit_conn_conf_t; @@ -93,28 +94,29 @@ static ngx_command_t ngx_stream_limit_conn_commands[] = { static ngx_stream_module_t ngx_stream_limit_conn_module_ctx = { + NULL, /* preconfiguration */ ngx_stream_limit_conn_init, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ ngx_stream_limit_conn_create_conf, /* create server configuration */ - ngx_stream_limit_conn_merge_conf, /* merge server configuration */ + ngx_stream_limit_conn_merge_conf /* merge server configuration */ }; ngx_module_t ngx_stream_limit_conn_module = { NGX_MODULE_V1, - &ngx_stream_limit_conn_module_ctx, /* module context */ - ngx_stream_limit_conn_commands, /* module directives */ - NGX_STREAM_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_stream_limit_conn_module_ctx, /* module context */ + ngx_stream_limit_conn_commands, /* module directives */ + NGX_STREAM_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 }; @@ -129,48 +131,36 @@ ngx_stream_limit_conn_handler(ngx_stream_session_t *s) ngx_slab_pool_t *shpool; ngx_rbtree_node_t *node; ngx_pool_cleanup_t *cln; - struct sockaddr_in *sin; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif ngx_stream_limit_conn_ctx_t *ctx; ngx_stream_limit_conn_node_t *lc; ngx_stream_limit_conn_conf_t *lccf; ngx_stream_limit_conn_limit_t *limits; ngx_stream_limit_conn_cleanup_t *lccln; - switch (s->connection->sockaddr->sa_family) { - - case AF_INET: - sin = (struct sockaddr_in *) s->connection->sockaddr; - - key.len = sizeof(in_addr_t); - key.data = (u_char *) &sin->sin_addr; - - break; - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) s->connection->sockaddr; - - key.len = sizeof(struct in6_addr); - key.data = sin6->sin6_addr.s6_addr; - - break; -#endif - - default: - return NGX_DECLINED; - } - - hash = ngx_crc32_short(key.data, key.len); - lccf = ngx_stream_get_module_srv_conf(s, ngx_stream_limit_conn_module); limits = lccf->limits.elts; for (i = 0; i < lccf->limits.nelts; i++) { ctx = limits[i].shm_zone->data; + if (ngx_stream_complex_value(s, &ctx->key, &key) != NGX_OK) { + return NGX_ERROR; + } + + if (key.len == 0) { + continue; + } + + if (key.len > 255) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "the value of the \"%V\" key " + "is more than 255 bytes: \"%V\"", + &ctx->key.value, &key); + continue; + } + + hash = ngx_crc32_short(key.data, key.len); + shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr; ngx_shmtx_lock(&shpool->mutex); @@ -382,6 +372,19 @@ ngx_stream_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data) ctx = shm_zone->data; if (octx) { + if (ctx->key.value.len != octx->key.value.len + || ngx_strncmp(ctx->key.value.data, octx->key.value.data, + ctx->key.value.len) + != 0) + { + ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, + "limit_conn_zone \"%V\" uses the \"%V\" key " + "while previously it used the \"%V\" key", + &shm_zone->shm.name, &ctx->key.value, + &octx->key.value); + return NGX_ERROR; + } + ctx->rbtree = octx->rbtree; return NGX_OK; @@ -465,12 +468,13 @@ ngx_stream_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, void *child) static char * ngx_stream_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_stream_limit_conn_ctx_t *ctx; + u_char *p; + ssize_t size; + ngx_str_t *value, name, s; + ngx_uint_t i; + ngx_shm_zone_t *shm_zone; + ngx_stream_limit_conn_ctx_t *ctx; + ngx_stream_compile_complex_value_t ccv; value = cf->args->elts; @@ -479,6 +483,16 @@ ngx_stream_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &ctx->key; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + size = 0; name.len = 0; @@ -537,17 +551,11 @@ ngx_stream_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } if (shm_zone->data) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "%V \"%V\" is already bound to key " - "\"$binary_remote_addr\"", - &cmd->name, &name); - return NGX_CONF_ERROR; - } + ctx = shm_zone->data; - if (ngx_strcmp(value[1].data, "$binary_remote_addr") != 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "unsupported key \"%V\", use " - "$binary_remote_addr", &value[1]); + "%V \"%V\" is already bound to key \"%V\"", + &cmd->name, &name, &ctx->key.value); return NGX_CONF_ERROR; } diff --git a/src/stream/ngx_stream_map_module.c b/src/stream/ngx_stream_map_module.c new file mode 100644 index 0000000..47a15be --- /dev/null +++ b/src/stream/ngx_stream_map_module.c @@ -0,0 +1,574 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_uint_t hash_max_size; + ngx_uint_t hash_bucket_size; +} ngx_stream_map_conf_t; + + +typedef struct { + ngx_hash_keys_arrays_t keys; + + ngx_array_t *values_hash; +#if (NGX_PCRE) + ngx_array_t regexes; +#endif + + ngx_stream_variable_value_t *default_value; + ngx_conf_t *cf; + ngx_uint_t hostnames; /* unsigned hostnames:1 */ +} ngx_stream_map_conf_ctx_t; + + +typedef struct { + ngx_stream_map_t map; + ngx_stream_complex_value_t value; + ngx_stream_variable_value_t *default_value; + ngx_uint_t hostnames; /* unsigned hostnames:1 */ +} ngx_stream_map_ctx_t; + + +static int ngx_libc_cdecl ngx_stream_map_cmp_dns_wildcards(const void *one, + const void *two); +static void *ngx_stream_map_create_conf(ngx_conf_t *cf); +static char *ngx_stream_map_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); + + +static ngx_command_t ngx_stream_map_commands[] = { + + { ngx_string("map"), + NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2, + ngx_stream_map_block, + NGX_STREAM_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("map_hash_max_size"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_STREAM_MAIN_CONF_OFFSET, + offsetof(ngx_stream_map_conf_t, hash_max_size), + NULL }, + + { ngx_string("map_hash_bucket_size"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_STREAM_MAIN_CONF_OFFSET, + offsetof(ngx_stream_map_conf_t, hash_bucket_size), + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_map_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + ngx_stream_map_create_conf, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_map_module = { + NGX_MODULE_V1, + &ngx_stream_map_module_ctx, /* module context */ + ngx_stream_map_commands, /* module directives */ + NGX_STREAM_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_stream_map_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, + uintptr_t data) +{ + ngx_stream_map_ctx_t *map = (ngx_stream_map_ctx_t *) data; + + ngx_str_t val, str; + ngx_stream_complex_value_t *cv; + ngx_stream_variable_value_t *value; + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream map started"); + + if (ngx_stream_complex_value(s, &map->value, &val) != NGX_OK) { + return NGX_ERROR; + } + + if (map->hostnames && val.len > 0 && val.data[val.len - 1] == '.') { + val.len--; + } + + value = ngx_stream_map_find(s, &map->map, &val); + + if (value == NULL) { + value = map->default_value; + } + + if (!value->valid) { + cv = (ngx_stream_complex_value_t *) value->data; + + if (ngx_stream_complex_value(s, cv, &str) != NGX_OK) { + return NGX_ERROR; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->len = str.len; + v->data = str.data; + + } else { + *v = *value; + } + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream map: \"%V\" \"%v\"", &val, v); + + return NGX_OK; +} + + +static void * +ngx_stream_map_create_conf(ngx_conf_t *cf) +{ + ngx_stream_map_conf_t *mcf; + + mcf = ngx_palloc(cf->pool, sizeof(ngx_stream_map_conf_t)); + if (mcf == NULL) { + return NULL; + } + + mcf->hash_max_size = NGX_CONF_UNSET_UINT; + mcf->hash_bucket_size = NGX_CONF_UNSET_UINT; + + return mcf; +} + + +static char * +ngx_stream_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_map_conf_t *mcf = conf; + + char *rv; + ngx_str_t *value, name; + ngx_conf_t save; + ngx_pool_t *pool; + ngx_hash_init_t hash; + ngx_stream_map_ctx_t *map; + ngx_stream_variable_t *var; + ngx_stream_map_conf_ctx_t ctx; + ngx_stream_compile_complex_value_t ccv; + + if (mcf->hash_max_size == NGX_CONF_UNSET_UINT) { + mcf->hash_max_size = 2048; + } + + if (mcf->hash_bucket_size == NGX_CONF_UNSET_UINT) { + mcf->hash_bucket_size = ngx_cacheline_size; + + } else { + mcf->hash_bucket_size = ngx_align(mcf->hash_bucket_size, + ngx_cacheline_size); + } + + map = ngx_pcalloc(cf->pool, sizeof(ngx_stream_map_ctx_t)); + if (map == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &map->value; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + name = value[2]; + + if (name.data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &name); + return NGX_CONF_ERROR; + } + + name.len--; + name.data++; + + var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + var->get_handler = ngx_stream_map_variable; + var->data = (uintptr_t) map; + + pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log); + if (pool == NULL) { + return NGX_CONF_ERROR; + } + + ctx.keys.pool = cf->pool; + ctx.keys.temp_pool = pool; + + if (ngx_hash_keys_array_init(&ctx.keys, NGX_HASH_LARGE) != NGX_OK) { + ngx_destroy_pool(pool); + return NGX_CONF_ERROR; + } + + ctx.values_hash = ngx_pcalloc(pool, sizeof(ngx_array_t) * ctx.keys.hsize); + if (ctx.values_hash == NULL) { + ngx_destroy_pool(pool); + return NGX_CONF_ERROR; + } + +#if (NGX_PCRE) + if (ngx_array_init(&ctx.regexes, cf->pool, 2, + sizeof(ngx_stream_map_regex_t)) + != NGX_OK) + { + ngx_destroy_pool(pool); + return NGX_CONF_ERROR; + } +#endif + + ctx.default_value = NULL; + ctx.cf = &save; + ctx.hostnames = 0; + + save = *cf; + cf->pool = pool; + cf->ctx = &ctx; + cf->handler = ngx_stream_map; + cf->handler_conf = conf; + + rv = ngx_conf_parse(cf, NULL); + + *cf = save; + + if (rv != NGX_CONF_OK) { + ngx_destroy_pool(pool); + return rv; + } + + map->default_value = ctx.default_value ? ctx.default_value: + &ngx_stream_variable_null_value; + + map->hostnames = ctx.hostnames; + + hash.key = ngx_hash_key_lc; + hash.max_size = mcf->hash_max_size; + hash.bucket_size = mcf->hash_bucket_size; + hash.name = "map_hash"; + hash.pool = cf->pool; + + if (ctx.keys.keys.nelts) { + hash.hash = &map->map.hash.hash; + hash.temp_pool = NULL; + + if (ngx_hash_init(&hash, ctx.keys.keys.elts, ctx.keys.keys.nelts) + != NGX_OK) + { + ngx_destroy_pool(pool); + return NGX_CONF_ERROR; + } + } + + if (ctx.keys.dns_wc_head.nelts) { + + ngx_qsort(ctx.keys.dns_wc_head.elts, + (size_t) ctx.keys.dns_wc_head.nelts, + sizeof(ngx_hash_key_t), ngx_stream_map_cmp_dns_wildcards); + + hash.hash = NULL; + hash.temp_pool = pool; + + if (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wc_head.elts, + ctx.keys.dns_wc_head.nelts) + != NGX_OK) + { + ngx_destroy_pool(pool); + return NGX_CONF_ERROR; + } + + map->map.hash.wc_head = (ngx_hash_wildcard_t *) hash.hash; + } + + if (ctx.keys.dns_wc_tail.nelts) { + + ngx_qsort(ctx.keys.dns_wc_tail.elts, + (size_t) ctx.keys.dns_wc_tail.nelts, + sizeof(ngx_hash_key_t), ngx_stream_map_cmp_dns_wildcards); + + hash.hash = NULL; + hash.temp_pool = pool; + + if (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wc_tail.elts, + ctx.keys.dns_wc_tail.nelts) + != NGX_OK) + { + ngx_destroy_pool(pool); + return NGX_CONF_ERROR; + } + + map->map.hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash; + } + +#if (NGX_PCRE) + + if (ctx.regexes.nelts) { + map->map.regex = ctx.regexes.elts; + map->map.nregex = ctx.regexes.nelts; + } + +#endif + + ngx_destroy_pool(pool); + + return rv; +} + + +static int ngx_libc_cdecl +ngx_stream_map_cmp_dns_wildcards(const void *one, const void *two) +{ + ngx_hash_key_t *first, *second; + + first = (ngx_hash_key_t *) one; + second = (ngx_hash_key_t *) two; + + return ngx_dns_strcmp(first->key.data, second->key.data); +} + + +static char * +ngx_stream_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +{ + u_char *data; + size_t len; + ngx_int_t rv; + ngx_str_t *value, v; + ngx_uint_t i, key; + ngx_stream_map_conf_ctx_t *ctx; + ngx_stream_complex_value_t cv, *cvp; + ngx_stream_variable_value_t *var, **vp; + ngx_stream_compile_complex_value_t ccv; + + ctx = cf->ctx; + + value = cf->args->elts; + + if (cf->args->nelts == 1 + && ngx_strcmp(value[0].data, "hostnames") == 0) + { + ctx->hostnames = 1; + return NGX_CONF_OK; + + } else if (cf->args->nelts != 2) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid number of the map parameters"); + return NGX_CONF_ERROR; + } + + if (ngx_strcmp(value[0].data, "include") == 0) { + return ngx_conf_include(cf, dummy, conf); + } + + key = 0; + + for (i = 0; i < value[1].len; i++) { + key = ngx_hash(key, value[1].data[i]); + } + + key %= ctx->keys.hsize; + + vp = ctx->values_hash[key].elts; + + if (vp) { + for (i = 0; i < ctx->values_hash[key].nelts; i++) { + + if (vp[i]->valid) { + data = vp[i]->data; + len = vp[i]->len; + + } else { + cvp = (ngx_stream_complex_value_t *) vp[i]->data; + data = cvp->value.data; + len = cvp->value.len; + } + + if (value[1].len != len) { + continue; + } + + if (ngx_strncmp(value[1].data, data, len) == 0) { + var = vp[i]; + goto found; + } + } + + } else { + if (ngx_array_init(&ctx->values_hash[key], cf->pool, 4, + sizeof(ngx_stream_variable_value_t *)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + } + + var = ngx_palloc(ctx->keys.pool, sizeof(ngx_stream_variable_value_t)); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + v.len = value[1].len; + v.data = ngx_pstrdup(ctx->keys.pool, &value[1]); + if (v.data == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = ctx->cf; + ccv.value = &v; + ccv.complex_value = &cv; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + cvp = ngx_palloc(ctx->keys.pool, sizeof(ngx_stream_complex_value_t)); + if (cvp == NULL) { + return NGX_CONF_ERROR; + } + + *cvp = cv; + + var->len = 0; + var->data = (u_char *) cvp; + var->valid = 0; + + } else { + var->len = v.len; + var->data = v.data; + var->valid = 1; + } + + var->no_cacheable = 0; + var->not_found = 0; + + vp = ngx_array_push(&ctx->values_hash[key]); + if (vp == NULL) { + return NGX_CONF_ERROR; + } + + *vp = var; + +found: + + if (ngx_strcmp(value[0].data, "default") == 0) { + + if (ctx->default_value) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate default map parameter"); + return NGX_CONF_ERROR; + } + + ctx->default_value = var; + + return NGX_CONF_OK; + } + +#if (NGX_PCRE) + + if (value[0].len && value[0].data[0] == '~') { + ngx_regex_compile_t rc; + ngx_stream_map_regex_t *regex; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + + regex = ngx_array_push(&ctx->regexes); + if (regex == NULL) { + return NGX_CONF_ERROR; + } + + value[0].len--; + value[0].data++; + + ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); + + if (value[0].data[0] == '*') { + value[0].len--; + value[0].data++; + rc.options = NGX_REGEX_CASELESS; + } + + rc.pattern = value[0]; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; + + regex->regex = ngx_stream_regex_compile(ctx->cf, &rc); + if (regex->regex == NULL) { + return NGX_CONF_ERROR; + } + + regex->value = var; + + return NGX_CONF_OK; + } + +#endif + + if (value[0].len && value[0].data[0] == '\\') { + value[0].len--; + value[0].data++; + } + + rv = ngx_hash_add_key(&ctx->keys, &value[0], var, + (ctx->hostnames) ? NGX_HASH_WILDCARD_KEY : 0); + + if (rv == NGX_OK) { + return NGX_CONF_OK; + } + + if (rv == NGX_DECLINED) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid hostname or wildcard \"%V\"", &value[0]); + } + + if (rv == NGX_BUSY) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "conflicting parameter \"%V\"", &value[0]); + } + + return NGX_CONF_ERROR; +} diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 6c535fd..9d43109 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -10,6 +10,15 @@ #include +typedef struct { + ngx_addr_t *addr; + ngx_stream_complex_value_t *value; +#if (NGX_HAVE_TRANSPARENT_PROXY) + ngx_uint_t transparent; /* unsigned transparent:1; */ +#endif +} ngx_stream_upstream_local_t; + + typedef struct { ngx_msec_t connect_timeout; ngx_msec_t timeout; @@ -21,14 +30,14 @@ typedef struct { ngx_uint_t next_upstream_tries; ngx_flag_t next_upstream; ngx_flag_t proxy_protocol; - ngx_addr_t *local; + ngx_stream_upstream_local_t *local; #if (NGX_STREAM_SSL) ngx_flag_t ssl_enable; ngx_flag_t ssl_session_reuse; ngx_uint_t ssl_protocols; ngx_str_t ssl_ciphers; - ngx_str_t ssl_name; + ngx_stream_complex_value_t *ssl_name; ngx_flag_t ssl_server_name; ngx_flag_t ssl_verify; @@ -43,12 +52,18 @@ typedef struct { #endif ngx_stream_upstream_srv_conf_t *upstream; + ngx_stream_complex_value_t *upstream_value; } ngx_stream_proxy_srv_conf_t; static void ngx_stream_proxy_handler(ngx_stream_session_t *s); +static ngx_int_t ngx_stream_proxy_eval(ngx_stream_session_t *s, + ngx_stream_proxy_srv_conf_t *pscf); +static ngx_int_t ngx_stream_proxy_set_local(ngx_stream_session_t *s, + ngx_stream_upstream_t *u, ngx_stream_upstream_local_t *local); static void ngx_stream_proxy_connect(ngx_stream_session_t *s); static void ngx_stream_proxy_init_upstream(ngx_stream_session_t *s); +static void ngx_stream_proxy_resolve_handler(ngx_resolver_ctx_t *ctx); static void ngx_stream_proxy_upstream_handler(ngx_event_t *ev); static void ngx_stream_proxy_downstream_handler(ngx_event_t *ev); static void ngx_stream_proxy_process_connection(ngx_event_t *ev, @@ -113,7 +128,7 @@ static ngx_command_t ngx_stream_proxy_commands[] = { NULL }, { ngx_string("proxy_bind"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE12, ngx_stream_proxy_bind, NGX_STREAM_SRV_CONF_OFFSET, 0, @@ -235,7 +250,7 @@ static ngx_command_t ngx_stream_proxy_commands[] = { { ngx_string("proxy_ssl_name"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_stream_set_complex_value_slot, NGX_STREAM_SRV_CONF_OFFSET, offsetof(ngx_stream_proxy_srv_conf_t, ssl_name), NULL }, @@ -303,6 +318,7 @@ static ngx_command_t ngx_stream_proxy_commands[] = { static ngx_stream_module_t ngx_stream_proxy_module_ctx = { + NULL, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ @@ -332,11 +348,16 @@ ngx_module_t ngx_stream_proxy_module = { static void ngx_stream_proxy_handler(ngx_stream_session_t *s) { - u_char *p; - ngx_connection_t *c; - ngx_stream_upstream_t *u; - ngx_stream_proxy_srv_conf_t *pscf; - ngx_stream_upstream_srv_conf_t *uscf; + u_char *p; + ngx_str_t *host; + ngx_uint_t i; + ngx_connection_t *c; + ngx_resolver_ctx_t *ctx, temp; + ngx_stream_upstream_t *u; + ngx_stream_core_srv_conf_t *cscf; + ngx_stream_proxy_srv_conf_t *pscf; + ngx_stream_upstream_srv_conf_t *uscf, **uscfp; + ngx_stream_upstream_main_conf_t *umcf; c = s->connection; @@ -358,10 +379,168 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) u->peer.log = c->log; u->peer.log_error = NGX_ERROR_ERR; - u->peer.local = pscf->local; + if (ngx_stream_proxy_set_local(s, u, pscf->local) != NGX_OK) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + u->peer.type = c->type; - uscf = pscf->upstream; + u->proxy_protocol = pscf->proxy_protocol; + u->start_sec = ngx_time(); + + c->write->handler = ngx_stream_proxy_downstream_handler; + c->read->handler = ngx_stream_proxy_downstream_handler; + + if (c->type == SOCK_STREAM) { + p = ngx_pnalloc(c->pool, pscf->buffer_size); + if (p == NULL) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + u->downstream_buf.start = p; + u->downstream_buf.end = p + pscf->buffer_size; + u->downstream_buf.pos = p; + u->downstream_buf.last = p; + + if (u->proxy_protocol +#if (NGX_STREAM_SSL) + && pscf->ssl == NULL +#endif + && pscf->buffer_size >= NGX_PROXY_PROTOCOL_MAX_HEADER) + { + /* optimization for a typical case */ + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream proxy send PROXY protocol header"); + + p = ngx_proxy_protocol_write(c, u->downstream_buf.last, + u->downstream_buf.end); + if (p == NULL) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + u->downstream_buf.last = p; + u->proxy_protocol = 0; + } + + if (c->read->ready) { + ngx_post_event(c->read, &ngx_posted_events); + } + } + + if (pscf->upstream_value) { + if (ngx_stream_proxy_eval(s, pscf) != NGX_OK) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + } + + if (u->resolved == NULL) { + + uscf = pscf->upstream; + + } else { + +#if (NGX_STREAM_SSL) + u->ssl_name = u->resolved->host; +#endif + + host = &u->resolved->host; + + if (u->resolved->sockaddr) { + + if (u->resolved->port == 0 + && u->resolved->sockaddr->sa_family != AF_UNIX) + { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no port in upstream \"%V\"", host); + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + if (ngx_stream_upstream_create_round_robin_peer(s, u->resolved) + != NGX_OK) + { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + ngx_stream_proxy_connect(s); + + return; + } + + umcf = ngx_stream_get_module_main_conf(s, ngx_stream_upstream_module); + + uscfp = umcf->upstreams.elts; + + for (i = 0; i < umcf->upstreams.nelts; i++) { + + uscf = uscfp[i]; + + if (uscf->host.len == host->len + && ((uscf->port == 0 && u->resolved->no_port) + || uscf->port == u->resolved->port) + && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0) + { + goto found; + } + } + + if (u->resolved->port == 0) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no port in upstream \"%V\"", host); + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + temp.name = *host; + + cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); + + ctx = ngx_resolve_start(cscf->resolver, &temp); + if (ctx == NULL) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + if (ctx == NGX_NO_RESOLVER) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no resolver defined to resolve %V", host); + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + ctx->name = *host; + ctx->handler = ngx_stream_proxy_resolve_handler; + ctx->data = s; + ctx->timeout = cscf->resolver_timeout; + + u->resolved->ctx = ctx; + + if (ngx_resolve_name(ctx) != NGX_OK) { + u->resolved->ctx = NULL; + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + return; + } + +found: + + if (uscf == NULL) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, "no upstream configuration"); + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + +#if (NGX_HTTP_SSL) + u->ssl_name = uscf->host; +#endif if (uscf->peer.init(s, uscf) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_ERROR); @@ -376,55 +555,111 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) u->peer.tries = pscf->next_upstream_tries; } - u->proxy_protocol = pscf->proxy_protocol; - u->start_sec = ngx_time(); + ngx_stream_proxy_connect(s); +} - c->write->handler = ngx_stream_proxy_downstream_handler; - c->read->handler = ngx_stream_proxy_downstream_handler; - if (c->type == SOCK_DGRAM) { - ngx_stream_proxy_connect(s); - return; +static ngx_int_t +ngx_stream_proxy_eval(ngx_stream_session_t *s, + ngx_stream_proxy_srv_conf_t *pscf) +{ + ngx_str_t host; + ngx_url_t url; + ngx_stream_upstream_t *u; + + if (ngx_stream_complex_value(s, pscf->upstream_value, &host) != NGX_OK) { + return NGX_ERROR; } - p = ngx_pnalloc(c->pool, pscf->buffer_size); - if (p == NULL) { - ngx_stream_proxy_finalize(s, NGX_ERROR); - return; - } + ngx_memzero(&url, sizeof(ngx_url_t)); - u->downstream_buf.start = p; - u->downstream_buf.end = p + pscf->buffer_size; - u->downstream_buf.pos = p; - u->downstream_buf.last = p; + url.url = host; + url.no_resolve = 1; - if (u->proxy_protocol -#if (NGX_STREAM_SSL) - && pscf->ssl == NULL -#endif - && pscf->buffer_size >= NGX_PROXY_PROTOCOL_MAX_HEADER) - { - /* optimization for a typical case */ - - ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, - "stream proxy send PROXY protocol header"); - - p = ngx_proxy_protocol_write(c, u->downstream_buf.last, - u->downstream_buf.end); - if (p == NULL) { - ngx_stream_proxy_finalize(s, NGX_ERROR); - return; + if (ngx_parse_url(s->connection->pool, &url) != NGX_OK) { + if (url.err) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "%s in upstream \"%V\"", url.err, &url.url); } - u->downstream_buf.last = p; - u->proxy_protocol = 0; + return NGX_ERROR; } - if (c->read->ready) { - ngx_post_event(c->read, &ngx_posted_events); + u = s->upstream; + + u->resolved = ngx_pcalloc(s->connection->pool, + sizeof(ngx_stream_upstream_resolved_t)); + if (u->resolved == NULL) { + return NGX_ERROR; } - ngx_stream_proxy_connect(s); + if (url.addrs && url.addrs[0].sockaddr) { + u->resolved->sockaddr = url.addrs[0].sockaddr; + u->resolved->socklen = url.addrs[0].socklen; + u->resolved->naddrs = 1; + u->resolved->host = url.addrs[0].name; + + } else { + u->resolved->host = url.host; + } + + u->resolved->port = url.port; + u->resolved->no_port = url.no_port; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_proxy_set_local(ngx_stream_session_t *s, ngx_stream_upstream_t *u, + ngx_stream_upstream_local_t *local) +{ + ngx_int_t rc; + ngx_str_t val; + ngx_addr_t *addr; + + if (local == NULL) { + u->peer.local = NULL; + return NGX_OK; + } + +#if (NGX_HAVE_TRANSPARENT_PROXY) + u->peer.transparent = local->transparent; +#endif + + if (local->value == NULL) { + u->peer.local = local->addr; + return NGX_OK; + } + + if (ngx_stream_complex_value(s, local->value, &val) != NGX_OK) { + return NGX_ERROR; + } + + if (val.len == 0) { + return NGX_OK; + } + + addr = ngx_palloc(s->connection->pool, sizeof(ngx_addr_t)); + if (addr == NULL) { + return NGX_ERROR; + } + + rc = ngx_parse_addr_port(s->connection->pool, addr, val.data, val.len); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "invalid local address \"%V\"", &val); + return NGX_OK; + } + + addr->name = val; + u->peer.local = addr; + + return NGX_OK; } @@ -814,10 +1049,13 @@ ngx_stream_proxy_ssl_name(ngx_stream_session_t *s) u = s->upstream; - name = pscf->ssl_name; + if (pscf->ssl_name) { + if (ngx_stream_complex_value(s, pscf->ssl_name, &name) != NGX_OK) { + return NGX_ERROR; + } - if (name.len == 0) { - name = pscf->upstream->host; + } else { + name = u->ssl_name; } if (name.len == 0) { @@ -906,6 +1144,75 @@ ngx_stream_proxy_downstream_handler(ngx_event_t *ev) } +static void +ngx_stream_proxy_resolve_handler(ngx_resolver_ctx_t *ctx) +{ + ngx_stream_session_t *s; + ngx_stream_upstream_t *u; + ngx_stream_proxy_srv_conf_t *pscf; + ngx_stream_upstream_resolved_t *ur; + + s = ctx->data; + + u = s->upstream; + ur = u->resolved; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, s->connection->log, 0, + "stream upstream resolve"); + + if (ctx->state) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "%V could not be resolved (%i: %s)", + &ctx->name, ctx->state, + ngx_resolver_strerror(ctx->state)); + + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + ur->naddrs = ctx->naddrs; + ur->addrs = ctx->addrs; + +#if (NGX_DEBUG) + { + u_char text[NGX_SOCKADDR_STRLEN]; + ngx_str_t addr; + ngx_uint_t i; + + addr.data = text; + + for (i = 0; i < ctx->naddrs; i++) { + addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen, + text, NGX_SOCKADDR_STRLEN, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "name was resolved to %V", &addr); + } + } +#endif + + if (ngx_stream_upstream_create_round_robin_peer(s, ur) != NGX_OK) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + ngx_resolve_name_done(ctx); + ur->ctx = NULL; + + u->peer.start_time = ngx_current_msec; + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + + if (pscf->next_upstream_tries + && u->peer.tries > pscf->next_upstream_tries) + { + u->peer.tries = pscf->next_upstream_tries; + } + + ngx_stream_proxy_connect(s); +} + + static void ngx_stream_proxy_upstream_handler(ngx_event_t *ev) { @@ -1328,6 +1635,11 @@ ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_int_t rc) goto noupstream; } + if (u->resolved && u->resolved->ctx) { + ngx_resolve_name_done(u->resolved->ctx); + u->resolved->ctx = NULL; + } + if (u->peer.free && u->peer.sockaddr) { u->peer.free(&u->peer, u->peer.data, 0); u->peer.sockaddr = NULL; @@ -1402,7 +1714,7 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) * * conf->ssl_protocols = 0; * conf->ssl_ciphers = { 0, NULL }; - * conf->ssl_name = { 0, NULL }; + * conf->ssl_name = NULL; * conf->ssl_trusted_certificate = { 0, NULL }; * conf->ssl_crl = { 0, NULL }; * conf->ssl_certificate = { 0, NULL }; @@ -1410,6 +1722,7 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) * * conf->ssl = NULL; * conf->upstream = NULL; + * conf->upstream_value = NULL; */ conf->connect_timeout = NGX_CONF_UNSET_MSEC; @@ -1486,7 +1799,9 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); - ngx_conf_merge_str_value(conf->ssl_name, prev->ssl_name, ""); + if (conf->ssl_name == NULL) { + conf->ssl_name = prev->ssl_name; + } ngx_conf_merge_value(conf->ssl_server_name, prev->ssl_server_name, 0); @@ -1561,13 +1876,7 @@ ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf) } } - if (SSL_CTX_set_cipher_list(pscf->ssl->ctx, - (const char *) pscf->ssl_ciphers.data) - == 0) - { - ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, - "SSL_CTX_set_cipher_list(\"%V\") failed", - &pscf->ssl_ciphers); + if (ngx_ssl_ciphers(cf, pscf->ssl, &pscf->ssl_ciphers, 0) != NGX_OK) { return NGX_ERROR; } @@ -1602,11 +1911,13 @@ ngx_stream_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_stream_proxy_srv_conf_t *pscf = conf; - ngx_url_t u; - ngx_str_t *value, *url; - ngx_stream_core_srv_conf_t *cscf; + ngx_url_t u; + ngx_str_t *value, *url; + ngx_stream_complex_value_t cv; + ngx_stream_core_srv_conf_t *cscf; + ngx_stream_compile_complex_value_t ccv; - if (pscf->upstream) { + if (pscf->upstream || pscf->upstream_value) { return "is duplicate"; } @@ -1618,6 +1929,28 @@ ngx_stream_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) url = &value[1]; + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = url; + ccv.complex_value = &cv; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths) { + pscf->upstream_value = ngx_palloc(cf->pool, + sizeof(ngx_stream_complex_value_t)); + if (pscf->upstream_value == NULL) { + return NGX_CONF_ERROR; + } + + *pscf->upstream_value = cv; + + return NGX_CONF_OK; + } + ngx_memzero(&u, sizeof(ngx_url_t)); u.url = *url; @@ -1637,8 +1970,11 @@ ngx_stream_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_stream_proxy_srv_conf_t *pscf = conf; - ngx_int_t rc; - ngx_str_t *value; + ngx_int_t rc; + ngx_str_t *value; + ngx_stream_complex_value_t cv; + ngx_stream_upstream_local_t *local; + ngx_stream_compile_complex_value_t ccv; if (pscf->local != NGX_CONF_UNSET_PTR) { return "is duplicate"; @@ -1646,29 +1982,75 @@ ngx_stream_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) value = cf->args->elts; - if (ngx_strcmp(value[1].data, "off") == 0) { + if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "off") == 0) { pscf->local = NULL; return NGX_CONF_OK; } - pscf->local = ngx_palloc(cf->pool, sizeof(ngx_addr_t)); - if (pscf->local == NULL) { + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { return NGX_CONF_ERROR; } - rc = ngx_parse_addr(cf->pool, pscf->local, value[1].data, value[1].len); - - switch (rc) { - case NGX_OK: - pscf->local->name = value[1]; - return NGX_CONF_OK; - - case NGX_DECLINED: - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid address \"%V\"", &value[1]); - /* fall through */ - - default: + local = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_local_t)); + if (local == NULL) { return NGX_CONF_ERROR; } + + pscf->local = local; + + if (cv.lengths) { + local->value = ngx_palloc(cf->pool, sizeof(ngx_stream_complex_value_t)); + if (local->value == NULL) { + return NGX_CONF_ERROR; + } + + *local->value = cv; + + } else { + local->addr = ngx_palloc(cf->pool, sizeof(ngx_addr_t)); + if (local->addr == NULL) { + return NGX_CONF_ERROR; + } + + rc = ngx_parse_addr_port(cf->pool, local->addr, value[1].data, + value[1].len); + + switch (rc) { + case NGX_OK: + local->addr->name = value[1]; + break; + + case NGX_DECLINED: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid address \"%V\"", &value[1]); + /* fall through */ + + default: + return NGX_CONF_ERROR; + } + } + + if (cf->args->nelts > 2) { + if (ngx_strcmp(value[2].data, "transparent") == 0) { +#if (NGX_HAVE_TRANSPARENT_PROXY) + local->transparent = 1; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "transparent proxying is not supported " + "on this platform, ignored"); +#endif + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + } + + return NGX_CONF_OK; } diff --git a/src/stream/ngx_stream_return_module.c b/src/stream/ngx_stream_return_module.c new file mode 100644 index 0000000..3ab9bdf --- /dev/null +++ b/src/stream/ngx_stream_return_module.c @@ -0,0 +1,207 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_stream_complex_value_t text; +} ngx_stream_return_srv_conf_t; + + +typedef struct { + ngx_buf_t buf; +} ngx_stream_return_ctx_t; + + +static void ngx_stream_return_handler(ngx_stream_session_t *s); +static void ngx_stream_return_write_handler(ngx_event_t *ev); + +static void *ngx_stream_return_create_srv_conf(ngx_conf_t *cf); +static char *ngx_stream_return(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + + +static ngx_command_t ngx_stream_return_commands[] = { + + { ngx_string("return"), + NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_stream_return, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_return_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_stream_return_create_srv_conf, /* create server configuration */ + NULL /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_return_module = { + NGX_MODULE_V1, + &ngx_stream_return_module_ctx, /* module context */ + ngx_stream_return_commands, /* module directives */ + NGX_STREAM_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 void +ngx_stream_return_handler(ngx_stream_session_t *s) +{ + ngx_str_t text; + ngx_connection_t *c; + ngx_stream_return_ctx_t *ctx; + ngx_stream_return_srv_conf_t *rscf; + + c = s->connection; + + c->log->action = "returning text"; + + rscf = ngx_stream_get_module_srv_conf(s, ngx_stream_return_module); + + if (ngx_stream_complex_value(s, &rscf->text, &text) != NGX_OK) { + ngx_stream_close_connection(c); + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream return text: \"%V\"", &text); + + if (text.len == 0) { + ngx_stream_close_connection(c); + return; + } + + ctx = ngx_pcalloc(c->pool, sizeof(ngx_stream_return_ctx_t)); + if (ctx == NULL) { + ngx_stream_close_connection(c); + return; + } + + ngx_stream_set_ctx(s, ctx, ngx_stream_return_module); + + ctx->buf.pos = text.data; + ctx->buf.last = text.data + text.len; + + c->write->handler = ngx_stream_return_write_handler; + + ngx_stream_return_write_handler(c->write); +} + + +static void +ngx_stream_return_write_handler(ngx_event_t *ev) +{ + ssize_t n; + ngx_buf_t *b; + ngx_connection_t *c; + ngx_stream_session_t *s; + ngx_stream_return_ctx_t *ctx; + + c = ev->data; + s = c->data; + + if (ev->timedout) { + ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); + ngx_stream_close_connection(c); + return; + } + + if (ev->ready) { + ctx = ngx_stream_get_module_ctx(s, ngx_stream_return_module); + + b = &ctx->buf; + + n = c->send(c, b->pos, b->last - b->pos); + if (n == NGX_ERROR) { + ngx_stream_close_connection(c); + return; + } + + if (n > 0) { + b->pos += n; + + if (b->pos == b->last) { + ngx_stream_close_connection(c); + return; + } + } + } + + if (ngx_handle_write_event(ev, 0) != NGX_OK) { + ngx_stream_close_connection(c); + return; + } + + ngx_add_timer(ev, 5000); +} + + +static void * +ngx_stream_return_create_srv_conf(ngx_conf_t *cf) +{ + ngx_stream_return_srv_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_return_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + return conf; +} + + +static char * +ngx_stream_return(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_return_srv_conf_t *rscf = conf; + + ngx_str_t *value; + ngx_stream_core_srv_conf_t *cscf; + ngx_stream_compile_complex_value_t ccv; + + if (rscf->text.value.data) { + return "is duplicate"; + } + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &rscf->text; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + cscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_core_module); + + cscf->handler = ngx_stream_return_handler; + + return NGX_CONF_OK; +} diff --git a/src/stream/ngx_stream_script.c b/src/stream/ngx_stream_script.c new file mode 100644 index 0000000..8130f92 --- /dev/null +++ b/src/stream/ngx_stream_script.c @@ -0,0 +1,854 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +static ngx_int_t ngx_stream_script_init_arrays( + ngx_stream_script_compile_t *sc); +static ngx_int_t ngx_stream_script_done(ngx_stream_script_compile_t *sc); +static ngx_int_t ngx_stream_script_add_copy_code( + ngx_stream_script_compile_t *sc, ngx_str_t *value, ngx_uint_t last); +static ngx_int_t ngx_stream_script_add_var_code( + ngx_stream_script_compile_t *sc, ngx_str_t *name); +#if (NGX_PCRE) +static ngx_int_t ngx_stream_script_add_capture_code( + ngx_stream_script_compile_t *sc, ngx_uint_t n); +#endif +static ngx_int_t ngx_stream_script_add_full_name_code( + ngx_stream_script_compile_t *sc); +static size_t ngx_stream_script_full_name_len_code( + ngx_stream_script_engine_t *e); +static void ngx_stream_script_full_name_code(ngx_stream_script_engine_t *e); + + +#define ngx_stream_script_exit (u_char *) &ngx_stream_script_exit_code + +static uintptr_t ngx_stream_script_exit_code = (uintptr_t) NULL; + + +void +ngx_stream_script_flush_complex_value(ngx_stream_session_t *s, + ngx_stream_complex_value_t *val) +{ + ngx_uint_t *index; + + index = val->flushes; + + if (index) { + while (*index != (ngx_uint_t) -1) { + + if (s->variables[*index].no_cacheable) { + s->variables[*index].valid = 0; + s->variables[*index].not_found = 0; + } + + index++; + } + } +} + + +ngx_int_t +ngx_stream_complex_value(ngx_stream_session_t *s, + ngx_stream_complex_value_t *val, ngx_str_t *value) +{ + size_t len; + ngx_stream_script_code_pt code; + ngx_stream_script_engine_t e; + ngx_stream_script_len_code_pt lcode; + + if (val->lengths == NULL) { + *value = val->value; + return NGX_OK; + } + + ngx_stream_script_flush_complex_value(s, val); + + ngx_memzero(&e, sizeof(ngx_stream_script_engine_t)); + + e.ip = val->lengths; + e.session = s; + e.flushed = 1; + + len = 0; + + while (*(uintptr_t *) e.ip) { + lcode = *(ngx_stream_script_len_code_pt *) e.ip; + len += lcode(&e); + } + + value->len = len; + value->data = ngx_pnalloc(s->connection->pool, len); + if (value->data == NULL) { + return NGX_ERROR; + } + + e.ip = val->values; + e.pos = value->data; + e.buf = *value; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_stream_script_code_pt *) e.ip; + code((ngx_stream_script_engine_t *) &e); + } + + *value = e.buf; + + return NGX_OK; +} + + +ngx_int_t +ngx_stream_compile_complex_value(ngx_stream_compile_complex_value_t *ccv) +{ + ngx_str_t *v; + ngx_uint_t i, n, nv, nc; + ngx_array_t flushes, lengths, values, *pf, *pl, *pv; + ngx_stream_script_compile_t sc; + + v = ccv->value; + + nv = 0; + nc = 0; + + for (i = 0; i < v->len; i++) { + if (v->data[i] == '$') { + if (v->data[i + 1] >= '1' && v->data[i + 1] <= '9') { + nc++; + + } else { + nv++; + } + } + } + + if ((v->len == 0 || v->data[0] != '$') + && (ccv->conf_prefix || ccv->root_prefix)) + { + if (ngx_conf_full_name(ccv->cf->cycle, v, ccv->conf_prefix) != NGX_OK) { + return NGX_ERROR; + } + + ccv->conf_prefix = 0; + ccv->root_prefix = 0; + } + + ccv->complex_value->value = *v; + ccv->complex_value->flushes = NULL; + ccv->complex_value->lengths = NULL; + ccv->complex_value->values = NULL; + + if (nv == 0 && nc == 0) { + return NGX_OK; + } + + n = nv + 1; + + if (ngx_array_init(&flushes, ccv->cf->pool, n, sizeof(ngx_uint_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + n = nv * (2 * sizeof(ngx_stream_script_copy_code_t) + + sizeof(ngx_stream_script_var_code_t)) + + sizeof(uintptr_t); + + if (ngx_array_init(&lengths, ccv->cf->pool, n, 1) != NGX_OK) { + return NGX_ERROR; + } + + n = (nv * (2 * sizeof(ngx_stream_script_copy_code_t) + + sizeof(ngx_stream_script_var_code_t)) + + sizeof(uintptr_t) + + v->len + + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); + + if (ngx_array_init(&values, ccv->cf->pool, n, 1) != NGX_OK) { + return NGX_ERROR; + } + + pf = &flushes; + pl = &lengths; + pv = &values; + + ngx_memzero(&sc, sizeof(ngx_stream_script_compile_t)); + + sc.cf = ccv->cf; + sc.source = v; + sc.flushes = &pf; + sc.lengths = &pl; + sc.values = &pv; + sc.complete_lengths = 1; + sc.complete_values = 1; + sc.zero = ccv->zero; + sc.conf_prefix = ccv->conf_prefix; + sc.root_prefix = ccv->root_prefix; + + if (ngx_stream_script_compile(&sc) != NGX_OK) { + return NGX_ERROR; + } + + if (flushes.nelts) { + ccv->complex_value->flushes = flushes.elts; + ccv->complex_value->flushes[flushes.nelts] = (ngx_uint_t) -1; + } + + ccv->complex_value->lengths = lengths.elts; + ccv->complex_value->values = values.elts; + + return NGX_OK; +} + + +char * +ngx_stream_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *p = conf; + + ngx_str_t *value; + ngx_stream_complex_value_t **cv; + ngx_stream_compile_complex_value_t ccv; + + cv = (ngx_stream_complex_value_t **) (p + cmd->offset); + + if (*cv != NULL) { + return "duplicate"; + } + + *cv = ngx_palloc(cf->pool, sizeof(ngx_stream_complex_value_t)); + if (*cv == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = *cv; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +ngx_uint_t +ngx_stream_script_variables_count(ngx_str_t *value) +{ + ngx_uint_t i, n; + + for (n = 0, i = 0; i < value->len; i++) { + if (value->data[i] == '$') { + n++; + } + } + + return n; +} + + +ngx_int_t +ngx_stream_script_compile(ngx_stream_script_compile_t *sc) +{ + u_char ch; + ngx_str_t name; + ngx_uint_t i, bracket; + + if (ngx_stream_script_init_arrays(sc) != NGX_OK) { + return NGX_ERROR; + } + + for (i = 0; i < sc->source->len; /* void */ ) { + + name.len = 0; + + if (sc->source->data[i] == '$') { + + if (++i == sc->source->len) { + goto invalid_variable; + } + + if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') { +#if (NGX_PCRE) + ngx_uint_t n; + + n = sc->source->data[i] - '0'; + + if (ngx_stream_script_add_capture_code(sc, n) != NGX_OK) { + return NGX_ERROR; + } + + i++; + + continue; +#else + ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, + "using variable \"$%c\" requires " + "PCRE library", sc->source->data[i]); + return NGX_ERROR; +#endif + } + + if (sc->source->data[i] == '{') { + bracket = 1; + + if (++i == sc->source->len) { + goto invalid_variable; + } + + name.data = &sc->source->data[i]; + + } else { + bracket = 0; + name.data = &sc->source->data[i]; + } + + for ( /* void */ ; i < sc->source->len; i++, name.len++) { + ch = sc->source->data[i]; + + if (ch == '}' && bracket) { + i++; + bracket = 0; + break; + } + + if ((ch >= 'A' && ch <= 'Z') + || (ch >= 'a' && ch <= 'z') + || (ch >= '0' && ch <= '9') + || ch == '_') + { + continue; + } + + break; + } + + if (bracket) { + ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, + "the closing bracket in \"%V\" " + "variable is missing", &name); + return NGX_ERROR; + } + + if (name.len == 0) { + goto invalid_variable; + } + + sc->variables++; + + if (ngx_stream_script_add_var_code(sc, &name) != NGX_OK) { + return NGX_ERROR; + } + + continue; + } + + name.data = &sc->source->data[i]; + + while (i < sc->source->len) { + + if (sc->source->data[i] == '$') { + break; + } + + i++; + name.len++; + } + + sc->size += name.len; + + if (ngx_stream_script_add_copy_code(sc, &name, (i == sc->source->len)) + != NGX_OK) + { + return NGX_ERROR; + } + } + + return ngx_stream_script_done(sc); + +invalid_variable: + + ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, "invalid variable name"); + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_stream_script_init_arrays(ngx_stream_script_compile_t *sc) +{ + ngx_uint_t n; + + if (sc->flushes && *sc->flushes == NULL) { + n = sc->variables ? sc->variables : 1; + *sc->flushes = ngx_array_create(sc->cf->pool, n, sizeof(ngx_uint_t)); + if (*sc->flushes == NULL) { + return NGX_ERROR; + } + } + + if (*sc->lengths == NULL) { + n = sc->variables * (2 * sizeof(ngx_stream_script_copy_code_t) + + sizeof(ngx_stream_script_var_code_t)) + + sizeof(uintptr_t); + + *sc->lengths = ngx_array_create(sc->cf->pool, n, 1); + if (*sc->lengths == NULL) { + return NGX_ERROR; + } + } + + if (*sc->values == NULL) { + n = (sc->variables * (2 * sizeof(ngx_stream_script_copy_code_t) + + sizeof(ngx_stream_script_var_code_t)) + + sizeof(uintptr_t) + + sc->source->len + + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); + + *sc->values = ngx_array_create(sc->cf->pool, n, 1); + if (*sc->values == NULL) { + return NGX_ERROR; + } + } + + sc->variables = 0; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_script_done(ngx_stream_script_compile_t *sc) +{ + ngx_str_t zero; + uintptr_t *code; + + if (sc->zero) { + + zero.len = 1; + zero.data = (u_char *) "\0"; + + if (ngx_stream_script_add_copy_code(sc, &zero, 0) != NGX_OK) { + return NGX_ERROR; + } + } + + if (sc->conf_prefix || sc->root_prefix) { + if (ngx_stream_script_add_full_name_code(sc) != NGX_OK) { + return NGX_ERROR; + } + } + + if (sc->complete_lengths) { + code = ngx_stream_script_add_code(*sc->lengths, sizeof(uintptr_t), + NULL); + if (code == NULL) { + return NGX_ERROR; + } + + *code = (uintptr_t) NULL; + } + + if (sc->complete_values) { + code = ngx_stream_script_add_code(*sc->values, sizeof(uintptr_t), + &sc->main); + if (code == NULL) { + return NGX_ERROR; + } + + *code = (uintptr_t) NULL; + } + + return NGX_OK; +} + + +void * +ngx_stream_script_add_code(ngx_array_t *codes, size_t size, void *code) +{ + u_char *elts, **p; + void *new; + + elts = codes->elts; + + new = ngx_array_push_n(codes, size); + if (new == NULL) { + return NULL; + } + + if (code) { + if (elts != codes->elts) { + p = code; + *p += (u_char *) codes->elts - elts; + } + } + + return new; +} + + +static ngx_int_t +ngx_stream_script_add_copy_code(ngx_stream_script_compile_t *sc, + ngx_str_t *value, ngx_uint_t last) +{ + u_char *p; + size_t size, len, zero; + ngx_stream_script_copy_code_t *code; + + zero = (sc->zero && last); + len = value->len + zero; + + code = ngx_stream_script_add_code(*sc->lengths, + sizeof(ngx_stream_script_copy_code_t), + NULL); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_stream_script_code_pt) ngx_stream_script_copy_len_code; + code->len = len; + + size = (sizeof(ngx_stream_script_copy_code_t) + len + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); + + code = ngx_stream_script_add_code(*sc->values, size, &sc->main); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = ngx_stream_script_copy_code; + code->len = len; + + p = ngx_cpymem((u_char *) code + sizeof(ngx_stream_script_copy_code_t), + value->data, value->len); + + if (zero) { + *p = '\0'; + sc->zero = 0; + } + + return NGX_OK; +} + + +size_t +ngx_stream_script_copy_len_code(ngx_stream_script_engine_t *e) +{ + ngx_stream_script_copy_code_t *code; + + code = (ngx_stream_script_copy_code_t *) e->ip; + + e->ip += sizeof(ngx_stream_script_copy_code_t); + + return code->len; +} + + +void +ngx_stream_script_copy_code(ngx_stream_script_engine_t *e) +{ + u_char *p; + ngx_stream_script_copy_code_t *code; + + code = (ngx_stream_script_copy_code_t *) e->ip; + + p = e->pos; + + if (!e->skip) { + e->pos = ngx_copy(p, e->ip + sizeof(ngx_stream_script_copy_code_t), + code->len); + } + + e->ip += sizeof(ngx_stream_script_copy_code_t) + + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1)); + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, e->session->connection->log, 0, + "stream script copy: \"%*s\"", e->pos - p, p); +} + + +static ngx_int_t +ngx_stream_script_add_var_code(ngx_stream_script_compile_t *sc, ngx_str_t *name) +{ + ngx_int_t index, *p; + ngx_stream_script_var_code_t *code; + + index = ngx_stream_get_variable_index(sc->cf, name); + + if (index == NGX_ERROR) { + return NGX_ERROR; + } + + if (sc->flushes) { + p = ngx_array_push(*sc->flushes); + if (p == NULL) { + return NGX_ERROR; + } + + *p = index; + } + + code = ngx_stream_script_add_code(*sc->lengths, + sizeof(ngx_stream_script_var_code_t), + NULL); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_stream_script_code_pt) + ngx_stream_script_copy_var_len_code; + code->index = (uintptr_t) index; + + code = ngx_stream_script_add_code(*sc->values, + sizeof(ngx_stream_script_var_code_t), + &sc->main); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = ngx_stream_script_copy_var_code; + code->index = (uintptr_t) index; + + return NGX_OK; +} + + +size_t +ngx_stream_script_copy_var_len_code(ngx_stream_script_engine_t *e) +{ + ngx_stream_variable_value_t *value; + ngx_stream_script_var_code_t *code; + + code = (ngx_stream_script_var_code_t *) e->ip; + + e->ip += sizeof(ngx_stream_script_var_code_t); + + if (e->flushed) { + value = ngx_stream_get_indexed_variable(e->session, code->index); + + } else { + value = ngx_stream_get_flushed_variable(e->session, code->index); + } + + if (value && !value->not_found) { + return value->len; + } + + return 0; +} + + +void +ngx_stream_script_copy_var_code(ngx_stream_script_engine_t *e) +{ + u_char *p; + ngx_stream_variable_value_t *value; + ngx_stream_script_var_code_t *code; + + code = (ngx_stream_script_var_code_t *) e->ip; + + e->ip += sizeof(ngx_stream_script_var_code_t); + + if (!e->skip) { + + if (e->flushed) { + value = ngx_stream_get_indexed_variable(e->session, code->index); + + } else { + value = ngx_stream_get_flushed_variable(e->session, code->index); + } + + if (value && !value->not_found) { + p = e->pos; + e->pos = ngx_copy(p, value->data, value->len); + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, + e->session->connection->log, 0, + "stream script var: \"%*s\"", e->pos - p, p); + } + } +} + + +#if (NGX_PCRE) + +static ngx_int_t +ngx_stream_script_add_capture_code(ngx_stream_script_compile_t *sc, + ngx_uint_t n) +{ + ngx_stream_script_copy_capture_code_t *code; + + code = ngx_stream_script_add_code(*sc->lengths, + sizeof(ngx_stream_script_copy_capture_code_t), + NULL); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_stream_script_code_pt) + ngx_stream_script_copy_capture_len_code; + code->n = 2 * n; + + + code = ngx_stream_script_add_code(*sc->values, + sizeof(ngx_stream_script_copy_capture_code_t), + &sc->main); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = ngx_stream_script_copy_capture_code; + code->n = 2 * n; + + if (sc->ncaptures < n) { + sc->ncaptures = n; + } + + return NGX_OK; +} + + +size_t +ngx_stream_script_copy_capture_len_code(ngx_stream_script_engine_t *e) +{ + int *cap; + ngx_uint_t n; + ngx_stream_session_t *s; + ngx_stream_script_copy_capture_code_t *code; + + s = e->session; + + code = (ngx_stream_script_copy_capture_code_t *) e->ip; + + e->ip += sizeof(ngx_stream_script_copy_capture_code_t); + + n = code->n; + + if (n < s->ncaptures) { + cap = s->captures; + return cap[n + 1] - cap[n]; + } + + return 0; +} + + +void +ngx_stream_script_copy_capture_code(ngx_stream_script_engine_t *e) +{ + int *cap; + u_char *p, *pos; + ngx_uint_t n; + ngx_stream_session_t *s; + ngx_stream_script_copy_capture_code_t *code; + + s = e->session; + + code = (ngx_stream_script_copy_capture_code_t *) e->ip; + + e->ip += sizeof(ngx_stream_script_copy_capture_code_t); + + n = code->n; + + pos = e->pos; + + if (n < s->ncaptures) { + cap = s->captures; + p = s->captures_data; + e->pos = ngx_copy(pos, &p[cap[n]], cap[n + 1] - cap[n]); + } + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, e->session->connection->log, 0, + "stream script capture: \"%*s\"", e->pos - pos, pos); +} + +#endif + + +static ngx_int_t +ngx_stream_script_add_full_name_code(ngx_stream_script_compile_t *sc) +{ + ngx_stream_script_full_name_code_t *code; + + code = ngx_stream_script_add_code(*sc->lengths, + sizeof(ngx_stream_script_full_name_code_t), + NULL); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_stream_script_code_pt) + ngx_stream_script_full_name_len_code; + code->conf_prefix = sc->conf_prefix; + + code = ngx_stream_script_add_code(*sc->values, + sizeof(ngx_stream_script_full_name_code_t), &sc->main); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = ngx_stream_script_full_name_code; + code->conf_prefix = sc->conf_prefix; + + return NGX_OK; +} + + +static size_t +ngx_stream_script_full_name_len_code(ngx_stream_script_engine_t *e) +{ + ngx_stream_script_full_name_code_t *code; + + code = (ngx_stream_script_full_name_code_t *) e->ip; + + e->ip += sizeof(ngx_stream_script_full_name_code_t); + + return code->conf_prefix ? ngx_cycle->conf_prefix.len: + ngx_cycle->prefix.len; +} + + +static void +ngx_stream_script_full_name_code(ngx_stream_script_engine_t *e) +{ + ngx_stream_script_full_name_code_t *code; + + ngx_str_t value, *prefix; + + code = (ngx_stream_script_full_name_code_t *) e->ip; + + value.data = e->buf.data; + value.len = e->pos - e->buf.data; + + prefix = code->conf_prefix ? (ngx_str_t *) &ngx_cycle->conf_prefix: + (ngx_str_t *) &ngx_cycle->prefix; + + if (ngx_get_full_name(e->session->connection->pool, prefix, &value) + != NGX_OK) + { + e->ip = ngx_stream_script_exit; + return; + } + + e->buf = value; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, e->session->connection->log, 0, + "stream script fullname: \"%V\"", &value); + + e->ip += sizeof(ngx_stream_script_full_name_code_t); +} diff --git a/src/stream/ngx_stream_script.h b/src/stream/ngx_stream_script.h new file mode 100644 index 0000000..0abe50e --- /dev/null +++ b/src/stream/ngx_stream_script.h @@ -0,0 +1,123 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_STREAM_SCRIPT_H_INCLUDED_ +#define _NGX_STREAM_SCRIPT_H_INCLUDED_ + + +#include +#include +#include + + +typedef struct { + u_char *ip; + u_char *pos; + ngx_stream_variable_value_t *sp; + + ngx_str_t buf; + ngx_str_t line; + + unsigned flushed:1; + unsigned skip:1; + + ngx_stream_session_t *session; +} ngx_stream_script_engine_t; + + +typedef struct { + ngx_conf_t *cf; + ngx_str_t *source; + + ngx_array_t **flushes; + ngx_array_t **lengths; + ngx_array_t **values; + + ngx_uint_t variables; + ngx_uint_t ncaptures; + ngx_uint_t size; + + void *main; + + unsigned complete_lengths:1; + unsigned complete_values:1; + unsigned zero:1; + unsigned conf_prefix:1; + unsigned root_prefix:1; +} ngx_stream_script_compile_t; + + +typedef struct { + ngx_str_t value; + ngx_uint_t *flushes; + void *lengths; + void *values; +} ngx_stream_complex_value_t; + + +typedef struct { + ngx_conf_t *cf; + ngx_str_t *value; + ngx_stream_complex_value_t *complex_value; + + unsigned zero:1; + unsigned conf_prefix:1; + unsigned root_prefix:1; +} ngx_stream_compile_complex_value_t; + + +typedef void (*ngx_stream_script_code_pt) (ngx_stream_script_engine_t *e); +typedef size_t (*ngx_stream_script_len_code_pt) (ngx_stream_script_engine_t *e); + + +typedef struct { + ngx_stream_script_code_pt code; + uintptr_t len; +} ngx_stream_script_copy_code_t; + + +typedef struct { + ngx_stream_script_code_pt code; + uintptr_t index; +} ngx_stream_script_var_code_t; + + +typedef struct { + ngx_stream_script_code_pt code; + uintptr_t n; +} ngx_stream_script_copy_capture_code_t; + + +typedef struct { + ngx_stream_script_code_pt code; + uintptr_t conf_prefix; +} ngx_stream_script_full_name_code_t; + + +void ngx_stream_script_flush_complex_value(ngx_stream_session_t *s, + ngx_stream_complex_value_t *val); +ngx_int_t ngx_stream_complex_value(ngx_stream_session_t *s, + ngx_stream_complex_value_t *val, ngx_str_t *value); +ngx_int_t ngx_stream_compile_complex_value( + ngx_stream_compile_complex_value_t *ccv); +char *ngx_stream_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +ngx_uint_t ngx_stream_script_variables_count(ngx_str_t *value); +ngx_int_t ngx_stream_script_compile(ngx_stream_script_compile_t *sc); + +void *ngx_stream_script_add_code(ngx_array_t *codes, size_t size, void *code); + +size_t ngx_stream_script_copy_len_code(ngx_stream_script_engine_t *e); +void ngx_stream_script_copy_code(ngx_stream_script_engine_t *e); +size_t ngx_stream_script_copy_var_len_code(ngx_stream_script_engine_t *e); +void ngx_stream_script_copy_var_code(ngx_stream_script_engine_t *e); +size_t ngx_stream_script_copy_capture_len_code(ngx_stream_script_engine_t *e); +void ngx_stream_script_copy_capture_code(ngx_stream_script_engine_t *e); + +#endif /* _NGX_STREAM_SCRIPT_H_INCLUDED_ */ diff --git a/src/stream/ngx_stream_split_clients_module.c b/src/stream/ngx_stream_split_clients_module.c new file mode 100644 index 0000000..af6c8a1 --- /dev/null +++ b/src/stream/ngx_stream_split_clients_module.c @@ -0,0 +1,244 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + uint32_t percent; + ngx_stream_variable_value_t value; +} ngx_stream_split_clients_part_t; + + +typedef struct { + ngx_stream_complex_value_t value; + ngx_array_t parts; +} ngx_stream_split_clients_ctx_t; + + +static char *ngx_conf_split_clients_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_split_clients(ngx_conf_t *cf, ngx_command_t *dummy, + void *conf); + +static ngx_command_t ngx_stream_split_clients_commands[] = { + + { ngx_string("split_clients"), + NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2, + ngx_conf_split_clients_block, + NGX_STREAM_MAIN_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_split_clients_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_split_clients_module = { + NGX_MODULE_V1, + &ngx_stream_split_clients_module_ctx, /* module context */ + ngx_stream_split_clients_commands, /* module directives */ + NGX_STREAM_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_stream_split_clients_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_stream_split_clients_ctx_t *ctx = + (ngx_stream_split_clients_ctx_t *) data; + + uint32_t hash; + ngx_str_t val; + ngx_uint_t i; + ngx_stream_split_clients_part_t *part; + + *v = ngx_stream_variable_null_value; + + if (ngx_stream_complex_value(s, &ctx->value, &val) != NGX_OK) { + return NGX_OK; + } + + hash = ngx_murmur_hash2(val.data, val.len); + + part = ctx->parts.elts; + + for (i = 0; i < ctx->parts.nelts; i++) { + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream split: %uD %uD", hash, part[i].percent); + + if (hash < part[i].percent || part[i].percent == 0) { + *v = part[i].value; + return NGX_OK; + } + } + + return NGX_OK; +} + + +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; + ngx_conf_t save; + ngx_stream_variable_t *var; + ngx_stream_split_clients_ctx_t *ctx; + ngx_stream_split_clients_part_t *part; + ngx_stream_compile_complex_value_t ccv; + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_stream_split_clients_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &ctx->value; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + name = value[2]; + + if (name.data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &name); + return NGX_CONF_ERROR; + } + + name.len--; + name.data++; + + var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + var->get_handler = ngx_stream_split_clients_variable; + var->data = (uintptr_t) ctx; + + if (ngx_array_init(&ctx->parts, cf->pool, 2, + sizeof(ngx_stream_split_clients_part_t)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + save = *cf; + cf->ctx = ctx; + cf->handler = ngx_stream_split_clients; + cf->handler_conf = conf; + + rv = ngx_conf_parse(cf, NULL); + + *cf = save; + + if (rv != NGX_CONF_OK) { + return rv; + } + + sum = 0; + last = 0; + part = ctx->parts.elts; + + 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 total is greater than 100%%"); + return NGX_CONF_ERROR; + } + + if (part[i].percent) { + last += part[i].percent * (uint64_t) 0xffffffff / 10000; + part[i].percent = last; + } + } + + return rv; +} + + +static char * +ngx_stream_split_clients(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +{ + ngx_int_t n; + ngx_str_t *value; + ngx_stream_split_clients_ctx_t *ctx; + ngx_stream_split_clients_part_t *part; + + ctx = cf->ctx; + value = cf->args->elts; + + part = ngx_array_push(&ctx->parts); + if (part == NULL) { + return NGX_CONF_ERROR; + } + + if (value[0].len == 1 && value[0].data[0] == '*') { + part->percent = 0; + + } else { + if (value[0].len == 0 || value[0].data[value[0].len - 1] != '%') { + goto invalid; + } + + n = ngx_atofp(value[0].data, value[0].len - 1, 2); + if (n == NGX_ERROR || n == 0) { + goto invalid; + } + + part->percent = (uint32_t) n; + } + + part->value.len = value[1].len; + part->value.valid = 1; + part->value.no_cacheable = 0; + part->value.not_found = 0; + part->value.data = value[1].data; + + return NGX_CONF_OK; + +invalid: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid percent value \"%V\"", &value[0]); + return NGX_CONF_ERROR; +} diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index e12da1b..2661220 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -10,10 +10,20 @@ #include +typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c, + ngx_pool_t *pool, ngx_str_t *s); + + #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" -#define NGX_DEFAULT_ECDH_CURVE "prime256v1" +#define NGX_DEFAULT_ECDH_CURVE "auto" +static ngx_int_t ngx_stream_ssl_static_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_ssl_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); + +static ngx_int_t ngx_stream_ssl_add_variables(ngx_conf_t *cf); static void *ngx_stream_ssl_create_conf(ngx_conf_t *cf); static char *ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child); @@ -45,16 +55,16 @@ static ngx_command_t ngx_stream_ssl_commands[] = { { ngx_string("ssl_certificate"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_conf_set_str_array_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, certificate), + offsetof(ngx_stream_ssl_conf_t, certificates), NULL }, { ngx_string("ssl_certificate_key"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_conf_set_str_array_slot, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_ssl_conf_t, certificate_key), + offsetof(ngx_stream_ssl_conf_t, certificate_keys), NULL }, { ngx_string("ssl_password_file"), @@ -132,6 +142,7 @@ static ngx_command_t ngx_stream_ssl_commands[] = { static ngx_stream_module_t ngx_stream_ssl_module_ctx = { + ngx_stream_ssl_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ @@ -158,9 +169,112 @@ ngx_module_t ngx_stream_ssl_module = { }; +static ngx_stream_variable_t ngx_stream_ssl_vars[] = { + + { ngx_string("ssl_protocol"), NULL, ngx_stream_ssl_static_variable, + (uintptr_t) ngx_ssl_get_protocol, NGX_STREAM_VAR_CHANGEABLE, 0 }, + + { ngx_string("ssl_cipher"), NULL, ngx_stream_ssl_static_variable, + (uintptr_t) ngx_ssl_get_cipher_name, NGX_STREAM_VAR_CHANGEABLE, 0 }, + + { ngx_string("ssl_session_id"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_session_id, NGX_STREAM_VAR_CHANGEABLE, 0 }, + + { ngx_string("ssl_session_reused"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_session_reused, NGX_STREAM_VAR_CHANGEABLE, 0 }, + + { ngx_string("ssl_server_name"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_server_name, NGX_STREAM_VAR_CHANGEABLE, 0 }, + + { ngx_null_string, NULL, NULL, 0, 0, 0 } +}; + + static ngx_str_t ngx_stream_ssl_sess_id_ctx = ngx_string("STREAM"); +static ngx_int_t +ngx_stream_ssl_static_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_ssl_variable_handler_pt handler = (ngx_ssl_variable_handler_pt) data; + + size_t len; + ngx_str_t str; + + if (s->connection->ssl) { + + (void) handler(s->connection, NULL, &str); + + v->data = str.data; + + for (len = 0; v->data[len]; len++) { /* void */ } + + v->len = len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; + } + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_ssl_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_ssl_variable_handler_pt handler = (ngx_ssl_variable_handler_pt) data; + + ngx_str_t str; + + if (s->connection->ssl) { + + if (handler(s->connection, s->connection->pool, &str) != NGX_OK) { + return NGX_ERROR; + } + + v->len = str.len; + v->data = str.data; + + if (v->len) { + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; + } + } + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_ssl_add_variables(ngx_conf_t *cf) +{ + ngx_stream_variable_t *var, *v; + + for (v = ngx_stream_ssl_vars; v->name.len; v++) { + var = ngx_stream_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = v->get_handler; + var->data = v->data; + } + + return NGX_OK; +} + + static void * ngx_stream_ssl_create_conf(ngx_conf_t *cf) { @@ -175,8 +289,6 @@ ngx_stream_ssl_create_conf(ngx_conf_t *cf) * set by ngx_pcalloc(): * * scf->protocols = 0; - * scf->certificate = { 0, NULL }; - * scf->certificate_key = { 0, NULL }; * scf->dhparam = { 0, NULL }; * scf->ecdh_curve = { 0, NULL }; * scf->ciphers = { 0, NULL }; @@ -184,6 +296,8 @@ ngx_stream_ssl_create_conf(ngx_conf_t *cf) */ scf->handshake_timeout = NGX_CONF_UNSET_MSEC; + scf->certificates = NGX_CONF_UNSET_PTR; + scf->certificate_keys = NGX_CONF_UNSET_PTR; scf->passwords = NGX_CONF_UNSET_PTR; scf->prefer_server_ciphers = NGX_CONF_UNSET; scf->builtin_session_cache = NGX_CONF_UNSET; @@ -216,8 +330,9 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); - ngx_conf_merge_str_value(conf->certificate, prev->certificate, ""); - ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, ""); + ngx_conf_merge_ptr_value(conf->certificates, prev->certificates, NULL); + ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys, + NULL); ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL); @@ -231,15 +346,18 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) conf->ssl.log = cf->log; - if (conf->certificate.len == 0) { + if (conf->certificates == NULL) { return NGX_CONF_OK; } - if (conf->certificate_key.len == 0) { + if (conf->certificate_keys == NULL + || conf->certificate_keys->nelts < conf->certificates->nelts) + { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no \"ssl_certificate_key\" is defined " "for certificate \"%V\"", - &conf->certificate); + ((ngx_str_t *) conf->certificates->elts) + + conf->certificates->nelts - 1); return NGX_CONF_ERROR; } @@ -255,31 +373,20 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) cln->handler = ngx_ssl_cleanup_ctx; cln->data = &conf->ssl; - if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate, - &conf->certificate_key, conf->passwords) + if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates, + conf->certificate_keys, conf->passwords) != NGX_OK) { return NGX_CONF_ERROR; } - if (SSL_CTX_set_cipher_list(conf->ssl.ctx, - (const char *) conf->ciphers.data) - == 0) + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, + conf->prefer_server_ciphers) + != NGX_OK) { - ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, - "SSL_CTX_set_cipher_list(\"%V\") failed", - &conf->ciphers); return NGX_CONF_ERROR; } - if (conf->prefer_server_ciphers) { - SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); - } - -#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) - SSL_CTX_set_tmp_rsa_callback(conf->ssl.ctx, ngx_ssl_rsa512_key_callback); -#endif - if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { return NGX_CONF_ERROR; } diff --git a/src/stream/ngx_stream_ssl_module.h b/src/stream/ngx_stream_ssl_module.h index 85e8b6e..9b1c41a 100644 --- a/src/stream/ngx_stream_ssl_module.h +++ b/src/stream/ngx_stream_ssl_module.h @@ -27,8 +27,9 @@ typedef struct { time_t session_timeout; - ngx_str_t certificate; - ngx_str_t certificate_key; + ngx_array_t *certificates; + ngx_array_t *certificate_keys; + ngx_str_t dhparam; ngx_str_t ecdh_curve; diff --git a/src/stream/ngx_stream_upstream.c b/src/stream/ngx_stream_upstream.c index 69dddc5..2ea5eeb 100644 --- a/src/stream/ngx_stream_upstream.c +++ b/src/stream/ngx_stream_upstream.c @@ -39,13 +39,14 @@ static ngx_command_t ngx_stream_upstream_commands[] = { static ngx_stream_module_t ngx_stream_upstream_module_ctx = { + NULL, /* preconfiguration */ NULL, /* postconfiguration */ ngx_stream_upstream_create_main_conf, /* create main configuration */ ngx_stream_upstream_init_main_conf, /* init main configuration */ NULL, /* create server configuration */ - NULL, /* merge server configuration */ + NULL /* merge server configuration */ }; diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h index 1f4810c..5f067c0 100644 --- a/src/stream/ngx_stream_upstream.h +++ b/src/stream/ngx_stream_upstream.h @@ -78,6 +78,21 @@ struct ngx_stream_upstream_srv_conf_s { }; +typedef struct { + ngx_str_t host; + in_port_t port; + ngx_uint_t no_port; /* unsigned no_port:1 */ + + ngx_uint_t naddrs; + ngx_resolver_addr_t *addrs; + + struct sockaddr *sockaddr; + socklen_t socklen; + + ngx_resolver_ctx_t *ctx; +} ngx_stream_upstream_resolved_t; + + typedef struct { ngx_peer_connection_t peer; ngx_buf_t downstream_buf; @@ -88,6 +103,7 @@ typedef struct { #if (NGX_STREAM_SSL) ngx_str_t ssl_name; #endif + ngx_stream_upstream_resolved_t *resolved; unsigned connected:1; unsigned proxy_protocol:1; } ngx_stream_upstream_t; diff --git a/src/stream/ngx_stream_upstream_hash_module.c b/src/stream/ngx_stream_upstream_hash_module.c index 56ff7d6..88185eb 100644 --- a/src/stream/ngx_stream_upstream_hash_module.c +++ b/src/stream/ngx_stream_upstream_hash_module.c @@ -23,6 +23,7 @@ typedef struct { typedef struct { + ngx_stream_complex_value_t key; ngx_stream_upstream_chash_points_t *points; } ngx_stream_upstream_hash_srv_conf_t; @@ -76,13 +77,14 @@ static ngx_command_t ngx_stream_upstream_hash_commands[] = { static ngx_stream_module_t ngx_stream_upstream_hash_module_ctx = { + NULL, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ ngx_stream_upstream_hash_create_conf, /* create server configuration */ - NULL, /* merge server configuration */ + NULL /* merge server configuration */ }; @@ -140,7 +142,9 @@ ngx_stream_upstream_init_hash_peer(ngx_stream_session_t *s, hcf = ngx_stream_conf_upstream_srv_conf(us, ngx_stream_upstream_hash_module); - hp->key = s->connection->addr_text; + if (ngx_stream_complex_value(s, &hcf->key, &hp->key) != NGX_OK) { + return NGX_ERROR; + } ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "upstream hash key:\"%V\"", &hp->key); @@ -615,15 +619,21 @@ ngx_stream_upstream_hash_create_conf(ngx_conf_t *cf) static char * ngx_stream_upstream_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_str_t *value; - ngx_stream_upstream_srv_conf_t *uscf; + ngx_stream_upstream_hash_srv_conf_t *hcf = conf; + + ngx_str_t *value; + ngx_stream_upstream_srv_conf_t *uscf; + ngx_stream_compile_complex_value_t ccv; value = cf->args->elts; - if (ngx_strcmp(value[1].data, "$remote_addr")) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "unsupported hash key \"%V\", use $remote_addr", - &value[1]); + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &hcf->key; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { return NGX_CONF_ERROR; } diff --git a/src/stream/ngx_stream_upstream_least_conn_module.c b/src/stream/ngx_stream_upstream_least_conn_module.c index c9719f9..e884975 100644 --- a/src/stream/ngx_stream_upstream_least_conn_module.c +++ b/src/stream/ngx_stream_upstream_least_conn_module.c @@ -32,13 +32,14 @@ static ngx_command_t ngx_stream_upstream_least_conn_commands[] = { static ngx_stream_module_t ngx_stream_upstream_least_conn_module_ctx = { + NULL, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ - NULL, /* merge server configuration */ + NULL /* merge server configuration */ }; diff --git a/src/stream/ngx_stream_upstream_round_robin.c b/src/stream/ngx_stream_upstream_round_robin.c index e1ab592..7aced0f 100644 --- a/src/stream/ngx_stream_upstream_round_robin.c +++ b/src/stream/ngx_stream_upstream_round_robin.c @@ -23,6 +23,10 @@ static ngx_int_t ngx_stream_upstream_set_round_robin_peer_session( ngx_peer_connection_t *pc, void *data); static void ngx_stream_upstream_save_round_robin_peer_session( ngx_peer_connection_t *pc, void *data); +static ngx_int_t ngx_stream_upstream_empty_set_session( + ngx_peer_connection_t *pc, void *data); +static void ngx_stream_upstream_empty_save_session(ngx_peer_connection_t *pc, + void *data); #endif @@ -292,6 +296,123 @@ ngx_stream_upstream_init_round_robin_peer(ngx_stream_session_t *s, } +ngx_int_t +ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, + ngx_stream_upstream_resolved_t *ur) +{ + u_char *p; + size_t len; + socklen_t socklen; + ngx_uint_t i, n; + struct sockaddr *sockaddr; + ngx_stream_upstream_rr_peer_t *peer, **peerp; + ngx_stream_upstream_rr_peers_t *peers; + ngx_stream_upstream_rr_peer_data_t *rrp; + + rrp = s->upstream->peer.data; + + if (rrp == NULL) { + rrp = ngx_palloc(s->connection->pool, + sizeof(ngx_stream_upstream_rr_peer_data_t)); + if (rrp == NULL) { + return NGX_ERROR; + } + + s->upstream->peer.data = rrp; + } + + peers = ngx_pcalloc(s->connection->pool, + sizeof(ngx_stream_upstream_rr_peers_t)); + if (peers == NULL) { + return NGX_ERROR; + } + + peer = ngx_pcalloc(s->connection->pool, + sizeof(ngx_stream_upstream_rr_peer_t) * ur->naddrs); + if (peer == NULL) { + return NGX_ERROR; + } + + peers->single = (ur->naddrs == 1); + peers->number = ur->naddrs; + peers->name = &ur->host; + + if (ur->sockaddr) { + peer[0].sockaddr = ur->sockaddr; + peer[0].socklen = ur->socklen; + peer[0].name = ur->host; + peer[0].weight = 1; + peer[0].effective_weight = 1; + peer[0].current_weight = 0; + peer[0].max_fails = 1; + peer[0].fail_timeout = 10; + peers->peer = peer; + + } else { + peerp = &peers->peer; + + for (i = 0; i < ur->naddrs; i++) { + + socklen = ur->addrs[i].socklen; + + sockaddr = ngx_palloc(s->connection->pool, socklen); + if (sockaddr == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(sockaddr, ur->addrs[i].sockaddr, socklen); + ngx_inet_set_port(sockaddr, ur->port); + + p = ngx_pnalloc(s->connection->pool, NGX_SOCKADDR_STRLEN); + if (p == NULL) { + return NGX_ERROR; + } + + len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1); + + peer[i].sockaddr = sockaddr; + peer[i].socklen = socklen; + peer[i].name.len = len; + peer[i].name.data = p; + peer[i].weight = 1; + peer[i].effective_weight = 1; + peer[i].current_weight = 0; + peer[i].max_fails = 1; + peer[i].fail_timeout = 10; + *peerp = &peer[i]; + peerp = &peer[i].next; + } + } + + rrp->peers = peers; + rrp->current = NULL; + + if (rrp->peers->number <= 8 * sizeof(uintptr_t)) { + rrp->tried = &rrp->data; + rrp->data = 0; + + } else { + n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1)) + / (8 * sizeof(uintptr_t)); + + rrp->tried = ngx_pcalloc(s->connection->pool, n * sizeof(uintptr_t)); + if (rrp->tried == NULL) { + return NGX_ERROR; + } + } + + s->upstream->peer.get = ngx_stream_upstream_get_round_robin_peer; + s->upstream->peer.free = ngx_stream_upstream_free_round_robin_peer; + s->upstream->peer.tries = ngx_stream_upstream_tries(rrp->peers); +#if (NGX_STREAM_SSL) + s->upstream->peer.set_session = ngx_stream_upstream_empty_set_session; + s->upstream->peer.save_session = ngx_stream_upstream_empty_save_session; +#endif + + return NGX_OK; +} + + ngx_int_t ngx_stream_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) { @@ -699,4 +820,18 @@ ngx_stream_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc, } } + +static ngx_int_t +ngx_stream_upstream_empty_set_session(ngx_peer_connection_t *pc, void *data) +{ + return NGX_OK; +} + + +static void +ngx_stream_upstream_empty_save_session(ngx_peer_connection_t *pc, void *data) +{ + return; +} + #endif diff --git a/src/stream/ngx_stream_upstream_round_robin.h b/src/stream/ngx_stream_upstream_round_robin.h index 77ee0ab..452c2e9 100644 --- a/src/stream/ngx_stream_upstream_round_robin.h +++ b/src/stream/ngx_stream_upstream_round_robin.h @@ -130,6 +130,8 @@ ngx_int_t ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, ngx_stream_upstream_srv_conf_t *us); ngx_int_t ngx_stream_upstream_init_round_robin_peer(ngx_stream_session_t *s, ngx_stream_upstream_srv_conf_t *us); +ngx_int_t ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, + ngx_stream_upstream_resolved_t *ur); ngx_int_t ngx_stream_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data); void ngx_stream_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, diff --git a/src/stream/ngx_stream_upstream_zone_module.c b/src/stream/ngx_stream_upstream_zone_module.c index ffc9e8a..07ab88d 100644 --- a/src/stream/ngx_stream_upstream_zone_module.c +++ b/src/stream/ngx_stream_upstream_zone_module.c @@ -32,13 +32,14 @@ static ngx_command_t ngx_stream_upstream_zone_commands[] = { static ngx_stream_module_t ngx_stream_upstream_zone_module_ctx = { + NULL, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ - NULL, /* merge server configuration */ + NULL /* merge server configuration */ }; diff --git a/src/stream/ngx_stream_variables.c b/src/stream/ngx_stream_variables.c new file mode 100644 index 0000000..10f9c7e --- /dev/null +++ b/src/stream/ngx_stream_variables.c @@ -0,0 +1,971 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include +#include + + +static ngx_int_t ngx_stream_variable_binary_remote_addr( + ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_remote_addr(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_remote_port(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_server_addr(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_server_port(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_bytes_sent(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_connection(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); + +static ngx_int_t ngx_stream_variable_nginx_version(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_hostname(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_pid(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_msec(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_time_iso8601(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_time_local(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); + + +static ngx_stream_variable_t ngx_stream_core_variables[] = { + + { ngx_string("binary_remote_addr"), NULL, + ngx_stream_variable_binary_remote_addr, 0, 0, 0 }, + + { ngx_string("remote_addr"), NULL, + ngx_stream_variable_remote_addr, 0, 0, 0 }, + + { ngx_string("remote_port"), NULL, + ngx_stream_variable_remote_port, 0, 0, 0 }, + + { ngx_string("server_addr"), NULL, + ngx_stream_variable_server_addr, 0, 0, 0 }, + + { ngx_string("server_port"), NULL, + ngx_stream_variable_server_port, 0, 0, 0 }, + + { ngx_string("bytes_sent"), NULL, ngx_stream_variable_bytes_sent, + 0, 0, 0 }, + + { ngx_string("connection"), NULL, + ngx_stream_variable_connection, 0, 0, 0 }, + + { ngx_string("nginx_version"), NULL, ngx_stream_variable_nginx_version, + 0, 0, 0 }, + + { ngx_string("hostname"), NULL, ngx_stream_variable_hostname, + 0, 0, 0 }, + + { ngx_string("pid"), NULL, ngx_stream_variable_pid, + 0, 0, 0 }, + + { ngx_string("msec"), NULL, ngx_stream_variable_msec, + 0, NGX_STREAM_VAR_NOCACHEABLE, 0 }, + + { ngx_string("time_iso8601"), NULL, ngx_stream_variable_time_iso8601, + 0, NGX_STREAM_VAR_NOCACHEABLE, 0 }, + + { ngx_string("time_local"), NULL, ngx_stream_variable_time_local, + 0, NGX_STREAM_VAR_NOCACHEABLE, 0 }, + + { ngx_null_string, NULL, NULL, 0, 0, 0 } +}; + + +ngx_stream_variable_value_t ngx_stream_variable_null_value = + ngx_stream_variable(""); +ngx_stream_variable_value_t ngx_stream_variable_true_value = + ngx_stream_variable("1"); + + +ngx_stream_variable_t * +ngx_stream_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags) +{ + ngx_int_t rc; + ngx_uint_t i; + ngx_hash_key_t *key; + ngx_stream_variable_t *v; + ngx_stream_core_main_conf_t *cmcf; + + if (name->len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"$\""); + return NULL; + } + + cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); + + key = cmcf->variables_keys->keys.elts; + for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) { + if (name->len != key[i].key.len + || ngx_strncasecmp(name->data, key[i].key.data, name->len) != 0) + { + continue; + } + + v = key[i].value; + + if (!(v->flags & NGX_STREAM_VAR_CHANGEABLE)) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the duplicate \"%V\" variable", name); + return NULL; + } + + return v; + } + + v = ngx_palloc(cf->pool, sizeof(ngx_stream_variable_t)); + if (v == NULL) { + return NULL; + } + + v->name.len = name->len; + v->name.data = ngx_pnalloc(cf->pool, name->len); + if (v->name.data == NULL) { + return NULL; + } + + ngx_strlow(v->name.data, name->data, name->len); + + v->set_handler = NULL; + v->get_handler = NULL; + v->data = 0; + v->flags = flags; + v->index = 0; + + rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0); + + if (rc == NGX_ERROR) { + return NULL; + } + + if (rc == NGX_BUSY) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "conflicting variable name \"%V\"", name); + return NULL; + } + + return v; +} + + +ngx_int_t +ngx_stream_get_variable_index(ngx_conf_t *cf, ngx_str_t *name) +{ + ngx_uint_t i; + ngx_stream_variable_t *v; + ngx_stream_core_main_conf_t *cmcf; + + if (name->len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"$\""); + return NGX_ERROR; + } + + cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); + + v = cmcf->variables.elts; + + if (v == NULL) { + if (ngx_array_init(&cmcf->variables, cf->pool, 4, + sizeof(ngx_stream_variable_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + } else { + for (i = 0; i < cmcf->variables.nelts; i++) { + if (name->len != v[i].name.len + || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0) + { + continue; + } + + return i; + } + } + + v = ngx_array_push(&cmcf->variables); + if (v == NULL) { + return NGX_ERROR; + } + + v->name.len = name->len; + v->name.data = ngx_pnalloc(cf->pool, name->len); + if (v->name.data == NULL) { + return NGX_ERROR; + } + + ngx_strlow(v->name.data, name->data, name->len); + + v->set_handler = NULL; + v->get_handler = NULL; + v->data = 0; + v->flags = 0; + v->index = cmcf->variables.nelts - 1; + + return v->index; +} + + +ngx_stream_variable_value_t * +ngx_stream_get_indexed_variable(ngx_stream_session_t *s, ngx_uint_t index) +{ + ngx_stream_variable_t *v; + ngx_stream_core_main_conf_t *cmcf; + + cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); + + if (cmcf->variables.nelts <= index) { + ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0, + "unknown variable index: %ui", index); + return NULL; + } + + if (s->variables[index].not_found || s->variables[index].valid) { + return &s->variables[index]; + } + + v = cmcf->variables.elts; + + if (v[index].get_handler(s, &s->variables[index], v[index].data) + == NGX_OK) + { + if (v[index].flags & NGX_STREAM_VAR_NOCACHEABLE) { + s->variables[index].no_cacheable = 1; + } + + return &s->variables[index]; + } + + s->variables[index].valid = 0; + s->variables[index].not_found = 1; + + return NULL; +} + + +ngx_stream_variable_value_t * +ngx_stream_get_flushed_variable(ngx_stream_session_t *s, ngx_uint_t index) +{ + ngx_stream_variable_value_t *v; + + v = &s->variables[index]; + + if (v->valid || v->not_found) { + if (!v->no_cacheable) { + return v; + } + + v->valid = 0; + v->not_found = 0; + } + + return ngx_stream_get_indexed_variable(s, index); +} + + +ngx_stream_variable_value_t * +ngx_stream_get_variable(ngx_stream_session_t *s, ngx_str_t *name, + ngx_uint_t key) +{ + ngx_stream_variable_t *v; + ngx_stream_variable_value_t *vv; + ngx_stream_core_main_conf_t *cmcf; + + cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); + + v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len); + + if (v) { + if (v->flags & NGX_STREAM_VAR_INDEXED) { + return ngx_stream_get_flushed_variable(s, v->index); + + } else { + + vv = ngx_palloc(s->connection->pool, + sizeof(ngx_stream_variable_value_t)); + + if (vv && v->get_handler(s, vv, v->data) == NGX_OK) { + return vv; + } + + return NULL; + } + } + + vv = ngx_palloc(s->connection->pool, sizeof(ngx_stream_variable_value_t)); + if (vv == NULL) { + return NULL; + } + + vv->not_found = 1; + + return vv; +} + + +static ngx_int_t +ngx_stream_variable_binary_remote_addr(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) + { + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + switch (s->connection->sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) s->connection->sockaddr; + + v->len = sizeof(struct in6_addr); + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = sin6->sin6_addr.s6_addr; + + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) s->connection->sockaddr; + + v->len = sizeof(in_addr_t); + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = (u_char *) &sin->sin_addr; + + break; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_remote_addr(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + v->len = s->connection->addr_text.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = s->connection->addr_text.data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_remote_port(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_uint_t port; + + v->len = 0; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1); + if (v->data == NULL) { + return NGX_ERROR; + } + + port = ngx_inet_get_port(s->connection->sockaddr); + + if (port > 0 && port < 65536) { + v->len = ngx_sprintf(v->data, "%ui", port) - v->data; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_server_addr(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_str_t str; + u_char addr[NGX_SOCKADDR_STRLEN]; + + str.len = NGX_SOCKADDR_STRLEN; + str.data = addr; + + if (ngx_connection_local_sockaddr(s->connection, &str, 0) != NGX_OK) { + return NGX_ERROR; + } + + str.data = ngx_pnalloc(s->connection->pool, str.len); + if (str.data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(str.data, addr, str.len); + + v->len = str.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = str.data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_server_port(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_uint_t port; + + v->len = 0; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + if (ngx_connection_local_sockaddr(s->connection, NULL, 0) != NGX_OK) { + return NGX_ERROR; + } + + v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1); + if (v->data == NULL) { + return NGX_ERROR; + } + + port = ngx_inet_get_port(s->connection->local_sockaddr); + + if (port > 0 && port < 65536) { + v->len = ngx_sprintf(v->data, "%ui", port) - v->data; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_bytes_sent(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + + p = ngx_pnalloc(s->connection->pool, NGX_OFF_T_LEN); + if (p == NULL) { + return NGX_ERROR; + } + + v->len = ngx_sprintf(p, "%O", s->connection->sent) - p; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_connection(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + + p = ngx_pnalloc(s->connection->pool, NGX_ATOMIC_T_LEN); + if (p == NULL) { + return NGX_ERROR; + } + + v->len = ngx_sprintf(p, "%uA", s->connection->number) - p; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_nginx_version(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + v->len = sizeof(NGINX_VERSION) - 1; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = (u_char *) NGINX_VERSION; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_hostname(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + v->len = ngx_cycle->hostname.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = ngx_cycle->hostname.data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_pid(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + + p = ngx_pnalloc(s->connection->pool, NGX_INT64_LEN); + if (p == NULL) { + return NGX_ERROR; + } + + v->len = ngx_sprintf(p, "%P", ngx_pid) - p; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_msec(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + ngx_time_t *tp; + + p = ngx_pnalloc(s->connection->pool, NGX_TIME_T_LEN + 4); + if (p == NULL) { + return NGX_ERROR; + } + + tp = ngx_timeofday(); + + v->len = ngx_sprintf(p, "%T.%03M", tp->sec, tp->msec) - p; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_time_iso8601(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + + p = ngx_pnalloc(s->connection->pool, ngx_cached_http_log_iso8601.len); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, ngx_cached_http_log_iso8601.data, + ngx_cached_http_log_iso8601.len); + + v->len = ngx_cached_http_log_iso8601.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_time_local(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + + p = ngx_pnalloc(s->connection->pool, ngx_cached_http_log_time.len); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, ngx_cached_http_log_time.data, ngx_cached_http_log_time.len); + + v->len = ngx_cached_http_log_time.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + +void * +ngx_stream_map_find(ngx_stream_session_t *s, ngx_stream_map_t *map, + ngx_str_t *match) +{ + void *value; + u_char *low; + size_t len; + ngx_uint_t key; + + len = match->len; + + if (len) { + low = ngx_pnalloc(s->connection->pool, len); + if (low == NULL) { + return NULL; + } + + } else { + low = NULL; + } + + key = ngx_hash_strlow(low, match->data, len); + + value = ngx_hash_find_combined(&map->hash, key, low, len); + if (value) { + return value; + } + +#if (NGX_PCRE) + + if (len && map->nregex) { + ngx_int_t n; + ngx_uint_t i; + ngx_stream_map_regex_t *reg; + + reg = map->regex; + + for (i = 0; i < map->nregex; i++) { + + n = ngx_stream_regex_exec(s, reg[i].regex, match); + + if (n == NGX_OK) { + return reg[i].value; + } + + if (n == NGX_DECLINED) { + continue; + } + + /* NGX_ERROR */ + + return NULL; + } + } + +#endif + + return NULL; +} + + +#if (NGX_PCRE) + +static ngx_int_t +ngx_stream_variable_not_found(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + v->not_found = 1; + return NGX_OK; +} + + +ngx_stream_regex_t * +ngx_stream_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc) +{ + u_char *p; + size_t size; + ngx_str_t name; + ngx_uint_t i, n; + ngx_stream_variable_t *v; + ngx_stream_regex_t *re; + ngx_stream_regex_variable_t *rv; + ngx_stream_core_main_conf_t *cmcf; + + rc->pool = cf->pool; + + if (ngx_regex_compile(rc) != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc->err); + return NULL; + } + + re = ngx_pcalloc(cf->pool, sizeof(ngx_stream_regex_t)); + if (re == NULL) { + return NULL; + } + + re->regex = rc->regex; + re->ncaptures = rc->captures; + re->name = rc->pattern; + + cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); + cmcf->ncaptures = ngx_max(cmcf->ncaptures, re->ncaptures); + + n = (ngx_uint_t) rc->named_captures; + + if (n == 0) { + return re; + } + + rv = ngx_palloc(rc->pool, n * sizeof(ngx_stream_regex_variable_t)); + if (rv == NULL) { + return NULL; + } + + re->variables = rv; + re->nvariables = n; + + size = rc->name_size; + p = rc->names; + + for (i = 0; i < n; i++) { + rv[i].capture = 2 * ((p[0] << 8) + p[1]); + + name.data = &p[2]; + name.len = ngx_strlen(name.data); + + v = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE); + if (v == NULL) { + return NULL; + } + + rv[i].index = ngx_stream_get_variable_index(cf, &name); + if (rv[i].index == NGX_ERROR) { + return NULL; + } + + v->get_handler = ngx_stream_variable_not_found; + + p += size; + } + + return re; +} + + +ngx_int_t +ngx_stream_regex_exec(ngx_stream_session_t *s, ngx_stream_regex_t *re, + ngx_str_t *str) +{ + ngx_int_t rc, index; + ngx_uint_t i, n, len; + ngx_stream_variable_value_t *vv; + ngx_stream_core_main_conf_t *cmcf; + + cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); + + if (re->ncaptures) { + len = cmcf->ncaptures; + + if (s->captures == NULL) { + s->captures = ngx_palloc(s->connection->pool, len * sizeof(int)); + if (s->captures == NULL) { + return NGX_ERROR; + } + } + + } else { + len = 0; + } + + rc = ngx_regex_exec(re->regex, str, s->captures, len); + + if (rc == NGX_REGEX_NO_MATCHED) { + return NGX_DECLINED; + } + + if (rc < 0) { + ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0, + ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"", + rc, str, &re->name); + return NGX_ERROR; + } + + for (i = 0; i < re->nvariables; i++) { + + n = re->variables[i].capture; + index = re->variables[i].index; + vv = &s->variables[index]; + + vv->len = s->captures[n + 1] - s->captures[n]; + vv->valid = 1; + vv->no_cacheable = 0; + vv->not_found = 0; + vv->data = &str->data[s->captures[n]]; + +#if (NGX_DEBUG) + { + ngx_stream_variable_t *v; + + v = cmcf->variables.elts; + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream regex set $%V to \"%v\"", &v[index].name, vv); + } +#endif + } + + s->ncaptures = rc * 2; + s->captures_data = str->data; + + return NGX_OK; +} + +#endif + + +ngx_int_t +ngx_stream_variables_add_core_vars(ngx_conf_t *cf) +{ + ngx_int_t rc; + ngx_stream_variable_t *cv, *v; + ngx_stream_core_main_conf_t *cmcf; + + cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); + + cmcf->variables_keys = ngx_pcalloc(cf->temp_pool, + sizeof(ngx_hash_keys_arrays_t)); + if (cmcf->variables_keys == NULL) { + return NGX_ERROR; + } + + cmcf->variables_keys->pool = cf->pool; + cmcf->variables_keys->temp_pool = cf->pool; + + if (ngx_hash_keys_array_init(cmcf->variables_keys, NGX_HASH_SMALL) + != NGX_OK) + { + return NGX_ERROR; + } + + for (cv = ngx_stream_core_variables; cv->name.len; cv++) { + v = ngx_palloc(cf->pool, sizeof(ngx_stream_variable_t)); + if (v == NULL) { + return NGX_ERROR; + } + + *v = *cv; + + rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, + NGX_HASH_READONLY_KEY); + + if (rc == NGX_OK) { + continue; + } + + if (rc == NGX_BUSY) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "conflicting variable name \"%V\"", &v->name); + } + + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_stream_variables_init_vars(ngx_conf_t *cf) +{ + ngx_uint_t i, n; + ngx_hash_key_t *key; + ngx_hash_init_t hash; + ngx_stream_variable_t *v, *av; + ngx_stream_core_main_conf_t *cmcf; + + /* set the handlers for the indexed stream variables */ + + cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); + + v = cmcf->variables.elts; + key = cmcf->variables_keys->keys.elts; + + for (i = 0; i < cmcf->variables.nelts; i++) { + + for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) { + + av = key[n].value; + + if (v[i].name.len == key[n].key.len + && ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len) + == 0) + { + v[i].get_handler = av->get_handler; + v[i].data = av->data; + + av->flags |= NGX_STREAM_VAR_INDEXED; + v[i].flags = av->flags; + + av->index = i; + + if (av->get_handler == NULL) { + break; + } + + goto next; + } + } + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "unknown \"%V\" variable", &v[i].name); + + return NGX_ERROR; + + next: + continue; + } + + + for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) { + av = key[n].value; + + if (av->flags & NGX_STREAM_VAR_NOHASH) { + key[n].key.data = NULL; + } + } + + + hash.hash = &cmcf->variables_hash; + hash.key = ngx_hash_key; + hash.max_size = cmcf->variables_hash_max_size; + hash.bucket_size = cmcf->variables_hash_bucket_size; + hash.name = "variables_hash"; + hash.pool = cf->pool; + hash.temp_pool = NULL; + + if (ngx_hash_init(&hash, cmcf->variables_keys->keys.elts, + cmcf->variables_keys->keys.nelts) + != NGX_OK) + { + return NGX_ERROR; + } + + cmcf->variables_keys = NULL; + + return NGX_OK; +} diff --git a/src/stream/ngx_stream_variables.h b/src/stream/ngx_stream_variables.h new file mode 100644 index 0000000..e4151e2 --- /dev/null +++ b/src/stream/ngx_stream_variables.h @@ -0,0 +1,109 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_STREAM_VARIABLES_H_INCLUDED_ +#define _NGX_STREAM_VARIABLES_H_INCLUDED_ + + +#include +#include +#include + + +typedef ngx_variable_value_t ngx_stream_variable_value_t; + +#define ngx_stream_variable(v) { sizeof(v) - 1, 1, 0, 0, 0, (u_char *) v } + +typedef struct ngx_stream_variable_s ngx_stream_variable_t; + +typedef void (*ngx_stream_set_variable_pt) (ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +typedef ngx_int_t (*ngx_stream_get_variable_pt) (ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); + + +#define NGX_STREAM_VAR_CHANGEABLE 1 +#define NGX_STREAM_VAR_NOCACHEABLE 2 +#define NGX_STREAM_VAR_INDEXED 4 +#define NGX_STREAM_VAR_NOHASH 8 + + +struct ngx_stream_variable_s { + ngx_str_t name; /* must be first to build the hash */ + ngx_stream_set_variable_pt set_handler; + ngx_stream_get_variable_pt get_handler; + uintptr_t data; + ngx_uint_t flags; + ngx_uint_t index; +}; + + +ngx_stream_variable_t *ngx_stream_add_variable(ngx_conf_t *cf, ngx_str_t *name, + ngx_uint_t flags); +ngx_int_t ngx_stream_get_variable_index(ngx_conf_t *cf, ngx_str_t *name); +ngx_stream_variable_value_t *ngx_stream_get_indexed_variable( + ngx_stream_session_t *s, ngx_uint_t index); +ngx_stream_variable_value_t *ngx_stream_get_flushed_variable( + ngx_stream_session_t *s, ngx_uint_t index); + +ngx_stream_variable_value_t *ngx_stream_get_variable(ngx_stream_session_t *s, + ngx_str_t *name, ngx_uint_t key); + + +#if (NGX_PCRE) + +typedef struct { + ngx_uint_t capture; + ngx_int_t index; +} ngx_stream_regex_variable_t; + + +typedef struct { + ngx_regex_t *regex; + ngx_uint_t ncaptures; + ngx_stream_regex_variable_t *variables; + ngx_uint_t nvariables; + ngx_str_t name; +} ngx_stream_regex_t; + + +typedef struct { + ngx_stream_regex_t *regex; + void *value; +} ngx_stream_map_regex_t; + + +ngx_stream_regex_t *ngx_stream_regex_compile(ngx_conf_t *cf, + ngx_regex_compile_t *rc); +ngx_int_t ngx_stream_regex_exec(ngx_stream_session_t *s, ngx_stream_regex_t *re, + ngx_str_t *str); + +#endif + + +typedef struct { + ngx_hash_combined_t hash; +#if (NGX_PCRE) + ngx_stream_map_regex_t *regex; + ngx_uint_t nregex; +#endif +} ngx_stream_map_t; + + +void *ngx_stream_map_find(ngx_stream_session_t *s, ngx_stream_map_t *map, + ngx_str_t *match); + + +ngx_int_t ngx_stream_variables_add_core_vars(ngx_conf_t *cf); +ngx_int_t ngx_stream_variables_init_vars(ngx_conf_t *cf); + + +extern ngx_stream_variable_value_t ngx_stream_variable_null_value; +extern ngx_stream_variable_value_t ngx_stream_variable_true_value; + + +#endif /* _NGX_STREAM_VARIABLES_H_INCLUDED_ */ From 561cc605190ba0f0d851af4073320c0607372ad2 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 1 Aug 2016 10:38:39 +0300 Subject: [PATCH 134/651] Add pointers to track modules not yet ready for migration --- debian/modules/README.Modules-versions | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index b71b1e0..02e38b8 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -27,6 +27,7 @@ README for Modules versions nginx-upstream-fair Homepage: https://github.com/gnosek/nginx-upstream-fair Version: a18b409 + Dynamic: No, https://github.com/gnosek/nginx-upstream-fair/pull/21 nginx-push Homepage: https://github.com/slact/nginx_http_push_module @@ -36,14 +37,17 @@ README for Modules versions Homepage: https://github.com/masterzen/nginx-upload-progress-module rm -r debian/nginx-upload-progress/test Version: v0.9.1 + Dynamic: No, https://github.com/masterzen/nginx-upload-progress-module/issues/46 nginx-cache-purge Homepage: https://github.com/FRiCKLE/ngx_cache_purge/ Version: 2.3 + Dynamic: No, https://github.com/FRiCKLE/ngx_cache_purge/pull/45 nginx-dav-ext-module Homepage: https://github.com/arut/nginx-dav-ext-module Version: v0.0.3 + Dynamic: No, https://github.com/arut/nginx-dav-ext-module/issues/21 ngx-fancyindex Homepage: https://github.com/aperezdc/ngx-fancyindex @@ -52,3 +56,4 @@ README for Modules versions ngx_http_substitutions_filter_module Homepage: https://github.com/yaoweibin/ngx_http_substitutions_filter_module Version: v0.6.4 + Dynamic: No, https://github.com/yaoweibin/ngx_http_substitutions_filter_module/pull/19 From c06d35b10321f5906788672f9516a0e5afe01997 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 26 Aug 2016 12:40:48 +0300 Subject: [PATCH 135/651] Enable slice module on all flavors --- debian/changelog | 1 + debian/control | 12 ++++++------ debian/rules | 1 + 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/debian/changelog b/debian/changelog index a0528da..b505145 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,7 @@ nginx (1.10.1-2) UNRELEASED; urgency=medium * debian/control: Don't allow building against liblua5.1-0-dev on architectures that libluajit is available. + + Enable slice module on all flavors. (Closes: #815080) * debian/modules/nginx-lua: + Update nginx-lua to v0.10.5 diff --git a/debian/control b/debian/control index 0c7f2cb..5badc14 100644 --- a/debian/control +++ b/debian/control @@ -110,8 +110,8 @@ Description: nginx web/proxy server (standard version) . OPTIONAL HTTP MODULES: Addition, Auth Request, Charset, WebDAV, GeoIP, Gunzip, Gzip, Gzip Precompression, Headers, HTTP/2, Image Filter, Index, Log, Real IP, - SSI, SSL, Stream, Stub Status, Substitution, Thread Pool, Upstream, User ID, - XSLT. + Slice, SSI, SSL, Stream, Stub Status, Substitution, Thread Pool, Upstream, + User ID, XSLT. . MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. . @@ -152,8 +152,8 @@ Description: nginx web/proxy server (basic version) FastCGI, Map, Proxy, Rewrite. . OPTIONAL HTTP MODULES: Auth Request, Charset, Gzip, Gzip Precompression, - Headers, HTTP/2, Index, Log, Real IP, SSI, SSL, Stub Status, Thread Pool, - WebDAV, Upstream. + Headers, HTTP/2, Index, Log, Real IP, Slice, SSI, SSL, Stub Status, Thread + Pool, WebDAV, Upstream. . THIRD PARTY MODULES: Echo. @@ -205,8 +205,8 @@ Description: nginx web/proxy server (extended version) . OPTIONAL HTTP MODULES: Addition, Auth Request, Charset, WebDAV, FLV, GeoIP, Gunzip, Gzip, Gzip Precompression, Headers, HTTP/2, Image Filter, Index, Log, - MP4, Embedded Perl, Random Index, Real IP, Secure Link, SSI, SSL, Stream, - Stub Status, Substitution, Thread Pool, Upstream, User ID, XSLT. + MP4, Embedded Perl, Random Index, Real IP, Slice, Secure Link, SSI, SSL, + Stream, Stub Status, Substitution, Thread Pool, Upstream, User ID, XSLT. . MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. . diff --git a/debian/rules b/debian/rules index c21c307..39eb71a 100755 --- a/debian/rules +++ b/debian/rules @@ -52,6 +52,7 @@ common_configure_flags := \ --with-http_auth_request_module \ --with-http_v2_module \ --with-http_dav_module \ + --with-http_slice_module \ --with-threads light_configure_flags := \ From 6cdcbed1f9080da5d03af903822db5d6ade7c92d Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 26 Aug 2016 13:15:12 +0300 Subject: [PATCH 136/651] mod: Upgrade nginx-lua to v0.10.6 --- debian/changelog | 2 +- debian/modules/README.Modules-versions | 2 +- debian/modules/nginx-lua/Changes | 51 - debian/modules/nginx-lua/README.markdown | 416 ++++-- debian/modules/nginx-lua/config | 6 + .../modules/nginx-lua/doc/HttpLuaModule.wiki | 380 ++++-- .../nginx-lua/src/api/ngx_http_lua_api.h | 2 +- .../nginx-lua/src/ngx_http_lua_accessby.c | 8 + .../nginx-lua/src/ngx_http_lua_balancer.c | 103 +- .../nginx-lua/src/ngx_http_lua_bodyfilterby.c | 2 +- .../nginx-lua/src/ngx_http_lua_cache.c | 4 +- .../nginx-lua/src/ngx_http_lua_clfactory.c | 8 +- .../nginx-lua/src/ngx_http_lua_common.h | 47 +- .../nginx-lua/src/ngx_http_lua_contentby.c | 8 + .../nginx-lua/src/ngx_http_lua_control.c | 26 +- .../nginx-lua/src/ngx_http_lua_coroutine.c | 12 +- .../nginx-lua/src/ngx_http_lua_directive.c | 16 +- .../src/ngx_http_lua_headerfilterby.c | 2 +- .../nginx-lua/src/ngx_http_lua_headers.c | 6 + .../nginx-lua/src/ngx_http_lua_headers_in.c | 5 + .../nginx-lua/src/ngx_http_lua_logby.c | 2 +- .../nginx-lua/src/ngx_http_lua_module.c | 112 +- .../nginx-lua/src/ngx_http_lua_phase.c | 10 +- .../nginx-lua/src/ngx_http_lua_rewriteby.c | 8 + .../nginx-lua/src/ngx_http_lua_setby.c | 2 +- .../nginx-lua/src/ngx_http_lua_shdict.c | 1133 +++++++++++++++-- .../nginx-lua/src/ngx_http_lua_shdict.h | 10 +- .../nginx-lua/src/ngx_http_lua_sleep.c | 3 +- .../nginx-lua/src/ngx_http_lua_socket_tcp.c | 12 +- .../modules/nginx-lua/src/ngx_http_lua_ssl.c | 37 + .../modules/nginx-lua/src/ngx_http_lua_ssl.h | 43 + .../nginx-lua/src/ngx_http_lua_ssl_certby.c | 362 +++++- .../nginx-lua/src/ngx_http_lua_ssl_certby.h | 10 - .../nginx-lua/src/ngx_http_lua_ssl_ocsp.c | 4 +- .../src/ngx_http_lua_ssl_session_fetchby.c | 592 +++++++++ .../src/ngx_http_lua_ssl_session_fetchby.h | 34 + .../src/ngx_http_lua_ssl_session_storeby.c | 602 +++++++++ .../src/ngx_http_lua_ssl_session_storeby.h | 34 + .../nginx-lua/src/ngx_http_lua_string.c | 4 +- .../nginx-lua/src/ngx_http_lua_subrequest.c | 2 +- .../nginx-lua/src/ngx_http_lua_timer.c | 2 +- .../modules/nginx-lua/src/ngx_http_lua_util.c | 48 +- .../modules/nginx-lua/src/ngx_http_lua_util.h | 5 +- debian/modules/nginx-lua/t/009-log.t | 2 +- debian/modules/nginx-lua/t/010-request_body.t | 2 +- debian/modules/nginx-lua/t/016-resp-header.t | 4 +- debian/modules/nginx-lua/t/020-subrequest.t | 2 +- .../nginx-lua/t/023-rewrite/request_body.t | 2 +- .../nginx-lua/t/023-rewrite/subrequest.t | 2 +- .../nginx-lua/t/024-access/request_body.t | 2 +- .../nginx-lua/t/024-access/subrequest.t | 2 +- debian/modules/nginx-lua/t/028-req-header.t | 42 +- debian/modules/nginx-lua/t/030-uri-args.t | 4 +- debian/modules/nginx-lua/t/031-post-args.t | 2 +- debian/modules/nginx-lua/t/043-shdict.t | 6 +- debian/modules/nginx-lua/t/062-count.t | 2 +- .../nginx-lua/t/068-socket-keepalive.t | 77 +- debian/modules/nginx-lua/t/070-sha1.t | 9 +- debian/modules/nginx-lua/t/129-ssl-socket.t | 48 +- debian/modules/nginx-lua/t/132-lua-blocks.t | 16 + debian/modules/nginx-lua/t/133-worker-count.t | 20 + debian/modules/nginx-lua/t/138-balancer.t | 28 +- debian/modules/nginx-lua/t/139-ssl-cert-by.t | 115 +- debian/modules/nginx-lua/t/140-ssl-c-api.t | 402 +++++- .../nginx-lua/t/142-ssl-session-store.t | 750 +++++++++++ .../nginx-lua/t/143-ssl-session-fetch.t | 1027 +++++++++++++++ .../nginx-lua/t/144-shdict-incr-init.t | 226 ++++ debian/modules/nginx-lua/t/145-shdict-list.t | 745 +++++++++++ debian/modules/nginx-lua/t/lib/CRC32.lua | 2 +- debian/modules/nginx-lua/util/build.sh | 2 +- debian/modules/nginx-lua/util/ngx-links | 2 +- 71 files changed, 7164 insertions(+), 556 deletions(-) delete mode 100644 debian/modules/nginx-lua/Changes create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_ssl.c create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_ssl.h create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.c create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.h create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.c create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.h create mode 100644 debian/modules/nginx-lua/t/142-ssl-session-store.t create mode 100644 debian/modules/nginx-lua/t/143-ssl-session-fetch.t create mode 100644 debian/modules/nginx-lua/t/144-shdict-incr-init.t create mode 100644 debian/modules/nginx-lua/t/145-shdict-list.t diff --git a/debian/changelog b/debian/changelog index b505145..1c253a7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -6,7 +6,7 @@ nginx (1.10.1-2) UNRELEASED; urgency=medium that libluajit is available. + Enable slice module on all flavors. (Closes: #815080) * debian/modules/nginx-lua: - + Update nginx-lua to v0.10.5 + + Update nginx-lua to v0.10.6 [ Michael Lustfield ] * debian/patches/0003-*.patch: diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index 02e38b8..1ad980c 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -22,7 +22,7 @@ README for Modules versions nginx-lua Homepage: https://github.com/openresty/lua-nginx-module - Version: v0.10.5 + Version: v0.10.6 nginx-upstream-fair Homepage: https://github.com/gnosek/nginx-upstream-fair diff --git a/debian/modules/nginx-lua/Changes b/debian/modules/nginx-lua/Changes deleted file mode 100644 index 703f73d..0000000 --- a/debian/modules/nginx-lua/Changes +++ /dev/null @@ -1,51 +0,0 @@ -0.2.0 - 5 July 2011 -* now we support ngx.var[1], ngx.var[2], and etc to refer to the nginx regex capturing variables \$1, \$2, and etc in Lua. this resolved github issue #43. thanks Tobia Conforto for reporting it. - -* now we use the same value overriding mechanism as ngx_rewrite's set command for ngx.var.VAR = new_value. Assigning values to special variables like $limit_rate and $args should now work; also writing to built-in variables that are not changeable (like $arg_PARAMETER) will result in a 500 error page, as expected, now. thanks Richard Kearsley for reporting it. - -* fixed the lua_code_cache off warning when the lua_code_cache is explicitly on. thanks Feng Xingguo. - -* applied the patch from cyberty to add ngx.http_time() function to expose the nginx core function ngx_http_time to the Lua land. - -* fixed an issue on i386: we now use off_t consistently. mixing it with size_t on 32-bit systems can cause Bad Things. this fixed github issue #42. thanks moodydeath. - -* fixed an issue on i386: fixed a formatter mismatch issue in ngx_http_echo_adjust_subrequest. thanks Wang Bin. This caused incorrect subrequest Content-Length header when a body is specified. - -* now in the subrequest capturing processor, we worked around an issue in ngx_http_static_module that when it issues 301 redirect for directory access w/o a trailing slash, it does not inject r->headers_out.location into the r->headers_out.headers list. thanks moodydeath for reporting it in the discussion of github issue #41. - -* fixed a bug in ngx.location.capture() and ngx.location.capture_multi() that we could not capture locations with internal redirections in them. thanks moodydeath for reporting it in github issue #41. - -* fixed redundant last chunk issue for ngx.exec() invocation at rewrite and access phases: we should quit the current core_run_phases cycle; this also fixed github issue #40: 2 Subrequest calls when using access_by_lua, ngx.exec and echo_location. - -* fixed ngx.exit(status) where status >= 200 and status < 300 for access_by_lua* and rewrite_by_lua*: it should quit the whole request altegother and skip all those subsequent phase handlers (if any). thanks moodydeath for reporting it. - -* fixed github issue #39: setting differnt response headers in Lua with common prefix might interfere with each other. thanks moodydeath. - -* fixed GitHub issue #38: request headers did not forward to subrequests when the "method" or "body" option is explicitly specified by a non-nil value for ngx.location.capture(). thanks Richard Kearsley. - -* fixed a bug in output header set; we should always set the header->hash to 1. thanks moodydeath for reporting it. - -* fixed spots that trigger the "variable set but not used" warning issued by gcc 4.6.0. - -* now we turn the ngx.req.header table into an ngx.req.get_headers() function; we also added ngx.req.set_header(name, value) and ngx.req.clear_header(name). thanks moodydeath. - -* now we make ngx_devel_kit (NDK) optional. thanks Kirill A. Korinskiy. - -* removed a duplicate definition of the ngx_str_set macro caught by ctags; also fixed a warning thrown by gcc -O3 on Mac OS X 10.6. - -* added patch to use PCRE related Lua extensions in ngx_lua (chaoslawful) - -* now we change the way we process HTTP 1.0 requests by automatically buffering all the user outputs generated by ngx.print()/ngx.say() calls, which is much more natural than the old broken way. - -* fixed the "ngx.exec() after ngx.location.capture() hanging" bug for rewrite_by_lua* and access_by_lua* as well. thanks Wendal Chen. - -* applied a patch from moodydeath to introduce the "ngx.is_subrequest" attribute. - -* now we encourage use of the client_body_in_single_buffer directive instead of big client_body_buffer_size when lua_need_request_body is turned on. - -* fixed the config script and added extra linking options needed by LuaJIT in 64-bit Mac OS X. - -* fixed the zero size alert caused by ngx.print("") in Lua. - -* now we always allocate r->request_body for subrequests when the method option is specified for ngx.location.capture*. this prevents accidental inheritance of parent request's request body when client_body_buffer_size < client_max_body_size. - diff --git a/debian/modules/nginx-lua/README.markdown b/debian/modules/nginx-lua/README.markdown index 14e9ecc..8065060 100644 --- a/debian/modules/nginx-lua/README.markdown +++ b/debian/modules/nginx-lua/README.markdown @@ -62,7 +62,7 @@ Production ready. Version ======= -This document describes ngx_lua [v0.10.5](https://github.com/openresty/lua-nginx-module/tags) released on 25 May 2016. +This document describes ngx_lua [v0.10.6](https://github.com/openresty/lua-nginx-module/tags) released on 15 August 2016. Synopsis ======== @@ -249,6 +249,8 @@ Nginx Compatibility The latest version of this module is compatible with the following versions of Nginx: +* 1.11.x (last tested: 1.11.2) +* 1.10.x * 1.9.x (last tested: 1.9.15) * 1.8.x * 1.7.x (last tested: 1.7.10) @@ -274,9 +276,9 @@ Build the source with this module: ```bash - wget 'http://nginx.org/download/nginx-1.9.15.tar.gz' - tar -xzvf nginx-1.9.15.tar.gz - cd nginx-1.9.15/ + wget 'http://nginx.org/download/nginx-1.11.2.tar.gz' + tar -xzvf nginx-1.11.2.tar.gz + cd nginx-1.11.2/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib @@ -1037,6 +1039,10 @@ Directives * [lua_need_request_body](#lua_need_request_body) * [ssl_certificate_by_lua_block](#ssl_certificate_by_lua_block) * [ssl_certificate_by_lua_file](#ssl_certificate_by_lua_file) +* [ssl_session_fetch_by_lua_block](#ssl_session_fetch_by_lua_block) +* [ssl_session_fetch_by_lua_file](#ssl_session_fetch_by_lua_file) +* [ssl_session_store_by_lua_block](#ssl_session_store_by_lua_block) +* [ssl_session_store_by_lua_file](#ssl_session_store_by_lua_file) * [lua_shared_dict](#lua_shared_dict) * [lua_socket_connect_timeout](#lua_socket_connect_timeout) * [lua_socket_send_timeout](#lua_socket_send_timeout) @@ -2320,7 +2326,7 @@ lua_need_request_body Determines whether to force the request body data to be read before running rewrite/access/access_by_lua* or not. The Nginx core does not read the client request body by default and if request body data is required, then this directive should be turned `on` or the [ngx.req.read_body](#ngxreqread_body) function should be called within the Lua code. -To read the request body data within the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable, +To read the request body data within the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable, [client_body_buffer_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size) must have the same value as [client_max_body_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size). Because when the content length exceeds [client_body_buffer_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size) but less than [client_max_body_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size), Nginx will buffer the data into a temporary file on the disk, which will lead to empty value in the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable. If the current location includes [rewrite_by_lua](#rewrite_by_lua) or [rewrite_by_lua_file](#rewrite_by_lua_file) directives, @@ -2441,6 +2447,123 @@ This directive was first introduced in the `v0.10.0` release. [Back to TOC](#directives) +ssl_session_fetch_by_lua_block +------------------------------ + +**syntax:** *ssl_session_fetch_by_lua_block { lua-script }* + +**context:** *server* + +**phase:** *right-before-SSL-handshake* + +This directive runs Lua code to look up and load the SSL session (if any) according to the session ID +provided by the current SSL handshake request for the downstream. + +The Lua API for obtaining the current session ID and loading a cached SSL session data +is provided in the [ngx.ssl.session](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl/session.md) +Lua module shipped with the [lua-resty-core](https://github.com/openresty/lua-resty-core#readme) +library. + +Lua APIs that may yield, like [ngx.sleep](#ngxsleep) and [cosockets](#ngxsockettcp), +are enabled in this context. + +This hook, together with the [ssl_session_store_by_lua*](#ssl_session_store_by_lua_block) hook, +can be used to implement distributed caching mechanisms in pure Lua (based +on the [cosocket](#ngxsockettcp) API, for example). If a cached SSL session is found +and loaded into the current SSL connection context, +SSL session resumption can then get immediately initiated and bypass the full SSL handshake process which is very expensive in terms of CPU time. + +Please note that TLS session tickets are very different and it is the clients' responsibility +to cache the SSL session state when session tickets are used. SSL session resumptions based on +TLS session tickets would happen automatically without going through this hook (nor the +[ssl_session_store_by_lua_block](#ssl_session_store_by_lua) hook). This hook is mainly +for older or less capable SSL clients that can only do SSL sessions by session IDs. + +When [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) is specified at the same time, +this hook usually runs before [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block). +When the SSL session is found and successfully loaded for the current SSL connection, +SSL session resumption will happen and thus bypass the [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) +hook completely. In this case, NGINX also bypasses the [ssl_session_store_by_lua_block](#ssl_session_store_by_lua) +hook, for obvious reasons. + +If you are using the [official pre-built packages](http://openresty.org/en/linux-packages.html) for [OpenResty](https://openresty.org/) +1.11.2.1 or later, then everything should work out of the box. + +If you are using OpenSSL libraries not provided by [OpenResty](https://openresty.org), +then you need to apply the following patch for OpenSSL 1.0.2h or later: + + + +If you are not using the NGINX core shipped with [OpenResty](https://openresty.org) 1.11.2.1 or later, then you need to +apply the following patch to the standard NGINX core 1.11.2 or later: + + + +This directive was first introduced in the `v0.10.6` release. + +[Back to TOC](#directives) + +ssl_session_fetch_by_lua_file +----------------------------- + +**syntax:** *ssl_session_fetch_by_lua_file <path-to-lua-script-file>* + +**context:** *server* + +**phase:** *right-before-SSL-handshake* + +Equivalent to [ssl_session_fetch_by_lua_block](#ssl_session_fetch_by_lua_block), except that the file specified by `` contains the Lua code, or rather, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. + +When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. + +This directive was first introduced in the `v0.10.6` release. + +[Back to TOC](#directives) + +ssl_session_store_by_lua_block +------------------------------ + +**syntax:** *ssl_session_store_by_lua_block { lua-script }* + +**context:** *server* + +**phase:** *right-after-SSL-handshake* + +This directive runs Lua code to fetch and save the SSL session (if any) according to the session ID +provided by the current SSL handshake request for the downstream. The saved or cached SSL +session data can be used for future SSL connections to resume SSL sessions without going +through the full SSL handshake process (which is very expensive in terms of CPU time). + +Lua APIs that may yield, like [ngx.sleep](#ngxsleep) and [cosockets](#ngxsockettcp), +are *disabled* in this context. You can still, however, use the [ngx.timer.at](#ngxtimerat) API +to create 0-delay timers to save the SSL session data asynchronously to external services (like `redis` or `memcached`). + +The Lua API for obtaining the current session ID and the associated session state data +is provided in the [ngx.ssl.session](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl/session.md#readme) +Lua module shipped with the [lua-resty-core](https://github.com/openresty/lua-resty-core#readme) +library. + +This directive was first introduced in the `v0.10.6` release. + +[Back to TOC](#directives) + +ssl_session_store_by_lua_file +----------------------------- + +**syntax:** *ssl_session_store_by_lua_file <path-to-lua-script-file>* + +**context:** *server* + +**phase:** *right-before-SSL-handshake* + +Equivalent to [ssl_session_store_by_lua_block](#ssl_session_store_by_lua_block), except that the file specified by `` contains the Lua code, or rather, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. + +When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. + +This directive was first introduced in the `v0.10.6` release. + +[Back to TOC](#directives) + lua_shared_dict --------------- @@ -2920,6 +3043,11 @@ Nginx API for Lua * [ngx.shared.DICT.replace](#ngxshareddictreplace) * [ngx.shared.DICT.delete](#ngxshareddictdelete) * [ngx.shared.DICT.incr](#ngxshareddictincr) +* [ngx.shared.DICT.lpush](#ngxshareddictlpush) +* [ngx.shared.DICT.rpush](#ngxshareddictrpush) +* [ngx.shared.DICT.lpop](#ngxshareddictlpop) +* [ngx.shared.DICT.rpop](#ngxshareddictrpop) +* [ngx.shared.DICT.llen](#ngxshareddictllen) * [ngx.shared.DICT.flush_all](#ngxshareddictflush_all) * [ngx.shared.DICT.flush_expired](#ngxshareddictflush_expired) * [ngx.shared.DICT.get_keys](#ngxshareddictget_keys) @@ -3110,7 +3238,7 @@ This API requires a relatively expensive metamethod call and it is recommended t Core constants -------------- -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, *log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, *log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** ```lua @@ -3136,7 +3264,7 @@ The `ngx.DECLINED` constant was first introduced in the `v0.5.0rc19` release. HTTP method constants --------------------- -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** ngx.HTTP_GET @@ -3162,7 +3290,7 @@ These constants are usually used in [ngx.location.capture](#ngxlocationcapture) HTTP status constants --------------------- -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** ```nginx @@ -3206,7 +3334,7 @@ HTTP status constants Nginx log level constants ------------------------- -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** ```lua @@ -3229,7 +3357,7 @@ print ----- **syntax:** *print(...)* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, certificate_by_lua** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Writes argument values into the nginx `error.log` file with the `ngx.NOTICE` log level. @@ -3998,6 +4126,8 @@ outputs something like this: This method was first introduced in the `v0.7.17` release. +This method does not work in HTTP/2 requests yet. + [Back to TOC](#nginx-api-for-lua) ngx.req.get_method @@ -4961,7 +5091,7 @@ ngx.log ------- **syntax:** *ngx.log(log_level, ...)* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Log arguments concatenated to error.log with the given logging level. @@ -4979,9 +5109,9 @@ ngx.flush **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** -Flushes response output to the client. +Flushes response output to the client. -`ngx.flush` accepts an optional boolean `wait` argument (Default: `false`) first introduced in the `v0.3.1rc34` release. When called with the default argument, it issues an asynchronous call (Returns immediately without waiting for output data to be written into the system send buffer). Calling the function with the `wait` argument set to `true` switches to synchronous mode. +`ngx.flush` accepts an optional boolean `wait` argument (Default: `false`) first introduced in the `v0.3.1rc34` release. When called with the default argument, it issues an asynchronous call (Returns immediately without waiting for output data to be written into the system send buffer). Calling the function with the `wait` argument set to `true` switches to synchronous mode. In synchronous mode, the function will not return until all output data has been written into the system send buffer or until the [send_timeout](http://nginx.org/en/docs/http/ngx_http_core_module.html#send_timeout) setting has expired. Note that using the Lua coroutine mechanism means that this function does not block the Nginx event loop even in the synchronous mode. @@ -4997,7 +5127,7 @@ ngx.exit -------- **syntax:** *ngx.exit(status)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** When `status >= 200` (i.e., `ngx.HTTP_OK` and above), it will interrupt the execution of the current request and return status code to nginx. @@ -5042,7 +5172,9 @@ Note that while this method accepts all [HTTP status constants](#http-status-con Also note that this method call terminates the processing of the current request and that it is recommended that a coding style that combines this method call with the `return` statement, i.e., `return ngx.exit(...)` be used to reinforce the fact that the request processing is being terminated. -When being used in the context of [header_filter_by_lua](#header_filter_by_lua), `ngx.exit()` is an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use `return` in combination as suggested above. +When being used in the contexts of [header_filter_by_lua](#header_filter_by_lua) and +[ssl_session_store_by_lua*](#ssl_session_store_by_lua_block), `ngx.exit()` is +an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use `return` in combination as suggested above. [Back to TOC](#nginx-api-for-lua) @@ -5085,7 +5217,7 @@ ngx.sleep --------- **syntax:** *ngx.sleep(seconds)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Sleeps for the specified seconds without blocking. One can specify time resolution up to 0.001 seconds (i.e., one milliseconds). @@ -5101,7 +5233,7 @@ ngx.escape_uri -------------- **syntax:** *newstr = ngx.escape_uri(str)* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Escape `str` as a URI component. @@ -5191,7 +5323,7 @@ ngx.decode_args --------------- **syntax:** *table = ngx.decode_args(str, max_args?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Decodes a URI encoded query-string into a Lua table. This is the inverse function of [ngx.encode_args](#ngxencode_args). @@ -5214,7 +5346,7 @@ ngx.encode_base64 ----------------- **syntax:** *newstr = ngx.encode_base64(str, no_padding?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Encodes `str` to a base64 digest. @@ -5226,7 +5358,7 @@ ngx.decode_base64 ----------------- **syntax:** *newstr = ngx.decode_base64(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Decodes the `str` argument as a base64 digest to the raw form. Returns `nil` if `str` is not well formed. @@ -5236,7 +5368,7 @@ ngx.crc32_short --------------- **syntax:** *intval = ngx.crc32_short(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Calculates the CRC-32 (Cyclic Redundancy Code) digest for the `str` argument. @@ -5252,7 +5384,7 @@ ngx.crc32_long -------------- **syntax:** *intval = ngx.crc32_long(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Calculates the CRC-32 (Cyclic Redundancy Code) digest for the `str` argument. @@ -5268,7 +5400,7 @@ ngx.hmac_sha1 ------------- **syntax:** *digest = ngx.hmac_sha1(secret_key, str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Computes the [HMAC-SHA1](http://en.wikipedia.org/wiki/HMAC) digest of the argument `str` and turns the result using the secret key ``. @@ -5300,7 +5432,7 @@ ngx.md5 ------- **syntax:** *digest = ngx.md5(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns the hexadecimal representation of the MD5 digest of the `str` argument. @@ -5327,7 +5459,7 @@ ngx.md5_bin ----------- **syntax:** *digest = ngx.md5_bin(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns the binary form of the MD5 digest of the `str` argument. @@ -5339,7 +5471,7 @@ ngx.sha1_bin ------------ **syntax:** *digest = ngx.sha1_bin(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns the binary form of the SHA-1 digest of the `str` argument. @@ -5353,7 +5485,7 @@ ngx.quote_sql_str ----------------- **syntax:** *quoted_value = ngx.quote_sql_str(raw_value)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns a quoted SQL string literal according to the MySQL quoting rules. @@ -5363,7 +5495,7 @@ ngx.today --------- **syntax:** *str = ngx.today()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns current date (in the format `yyyy-mm-dd`) from the nginx cached time (no syscall involved unlike Lua's date library). @@ -5375,7 +5507,7 @@ ngx.time -------- **syntax:** *secs = ngx.time()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns the elapsed seconds from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -5387,7 +5519,7 @@ ngx.now ------- **syntax:** *secs = ngx.now()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns a floating-point number for the elapsed time in seconds (including milliseconds as the decimal part) from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -5401,7 +5533,7 @@ ngx.update_time --------------- **syntax:** *ngx.update_time()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Forcibly updates the Nginx current time cache. This call involves a syscall and thus has some overhead, so do not abuse it. @@ -5413,7 +5545,7 @@ ngx.localtime ------------- **syntax:** *str = ngx.localtime()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns the current time stamp (in the format `yyyy-mm-dd hh:mm:ss`) of the nginx cached time (no syscall involved unlike Lua's [os.date](http://www.lua.org/manual/5.1/manual.html#pdf-os.date) function). @@ -5425,7 +5557,7 @@ ngx.utctime ----------- **syntax:** *str = ngx.utctime()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns the current time stamp (in the format `yyyy-mm-dd hh:mm:ss`) of the nginx cached time (no syscall involved unlike Lua's [os.date](http://www.lua.org/manual/5.1/manual.html#pdf-os.date) function). @@ -5437,7 +5569,7 @@ ngx.cookie_time --------------- **syntax:** *str = ngx.cookie_time(sec)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns a formatted string can be used as the cookie expiration time. The parameter `sec` is the time stamp in seconds (like those returned from [ngx.time](#ngxtime)). @@ -5453,7 +5585,7 @@ ngx.http_time ------------- **syntax:** *str = ngx.http_time(sec)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns a formated string can be used as the http header time (for example, being used in `Last-Modified` header). The parameter `sec` is the time stamp in seconds (like those returned from [ngx.time](#ngxtime)). @@ -5469,7 +5601,7 @@ ngx.parse_http_time ------------------- **syntax:** *sec = ngx.parse_http_time(str)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Parse the http time string (as returned by [ngx.http_time](#ngxhttp_time)) into seconds. Returns the seconds or `nil` if the input string is in bad forms. @@ -5497,7 +5629,7 @@ ngx.re.match ------------ **syntax:** *captures, err = ngx.re.match(subject, regex, options?, ctx?, res_table?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Matches the `subject` string using the Perl compatible regular expression `regex` with the optional `options`. @@ -5655,9 +5787,9 @@ ngx.re.find ----------- **syntax:** *from, to, err = ngx.re.find(subject, regex, options?, ctx?, nth?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** -Similar to [ngx.re.match](#ngxrematch) but only returns the begining index (`from`) and end index (`to`) of the matched substring. The returned indexes are 1-based and can be fed directly into the [string.sub](http://www.lua.org/manual/5.1/manual.html#pdf-string.sub) API function to obtain the matched substring. +Similar to [ngx.re.match](#ngxrematch) but only returns the beginning index (`from`) and end index (`to`) of the matched substring. The returned indexes are 1-based and can be fed directly into the [string.sub](http://www.lua.org/manual/5.1/manual.html#pdf-string.sub) API function to obtain the matched substring. In case of errors (like bad regexes or any PCRE runtime errors), this API function returns two `nil` values followed by a string describing the error. @@ -5709,7 +5841,7 @@ ngx.re.gmatch ------------- **syntax:** *iterator, err = ngx.re.gmatch(subject, regex, options?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Similar to [ngx.re.match](#ngxrematch), but returns a Lua iterator instead, so as to let the user programmer iterate all the matches over the `` string argument with the PCRE `regex`. @@ -5787,7 +5919,7 @@ ngx.re.sub ---------- **syntax:** *newstr, n, err = ngx.re.sub(subject, regex, replace, options?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Substitutes the first match of the Perl compatible regular expression `regex` on the `subject` argument string with the string or function argument `replace`. The optional `options` argument has exactly the same meaning as in [ngx.re.match](#ngxrematch). @@ -5853,7 +5985,7 @@ ngx.re.gsub ----------- **syntax:** *newstr, n, err = ngx.re.gsub(subject, regex, replace, options?)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Just like [ngx.re.sub](#ngxresub), but does global substitution. @@ -5893,7 +6025,7 @@ ngx.shared.DICT **syntax:** *dict = ngx.shared\[name_var\]* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Fetching the shm-based Lua dictionary object for the shared memory zone named `DICT` defined by the [lua_shared_dict](#lua_shared_dict) directive. @@ -5910,6 +6042,11 @@ The resulting object `dict` has the following methods: * [replace](#ngxshareddictreplace) * [delete](#ngxshareddictdelete) * [incr](#ngxshareddictincr) +* [lpush](#ngxshareddictlpush) +* [rpush](#ngxshareddictrpush) +* [lpop](#ngxshareddictlpop) +* [rpop](#ngxshareddictrpop) +* [llen](#ngxshareddictllen) * [flush_all](#ngxshareddictflush_all) * [flush_expired](#ngxshareddictflush_expired) * [get_keys](#ngxshareddictget_keys) @@ -5966,9 +6103,9 @@ ngx.shared.DICT.get ------------------- **syntax:** *value, flags = ngx.shared.DICT:get(key)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** -Retrieving the value in the dictionary [ngx.shared.DICT](#ngxshareddict) for the key `key`. If the key does not exist or has been expired, then `nil` will be returned. +Retrieving the value in the dictionary [ngx.shared.DICT](#ngxshareddict) for the key `key`. If the key does not exist or has expired, then `nil` will be returned. In case of errors, `nil` and a string describing the error will be returned. @@ -6004,7 +6141,7 @@ ngx.shared.DICT.get_stale ------------------------- **syntax:** *value, flags, stale = ngx.shared.DICT:get_stale(key)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Similar to the [get](#ngxshareddictget) method but returns the value even if the key has already expired. @@ -6022,7 +6159,7 @@ ngx.shared.DICT.set ------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:set(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Unconditionally sets a key-value pair into the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). Returns three values: @@ -6070,7 +6207,7 @@ ngx.shared.DICT.safe_set ------------------------ **syntax:** *ok, err = ngx.shared.DICT:safe_set(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Similar to the [set](#ngxshareddictset) method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return `nil` and the string "no memory". @@ -6084,7 +6221,7 @@ ngx.shared.DICT.add ------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:add(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Just like the [set](#ngxshareddictset) method, but only stores the key-value pair into the dictionary [ngx.shared.DICT](#ngxshareddict) if the key does *not* exist. @@ -6100,7 +6237,7 @@ ngx.shared.DICT.safe_add ------------------------ **syntax:** *ok, err = ngx.shared.DICT:safe_add(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Similar to the [add](#ngxshareddictadd) method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return `nil` and the string "no memory". @@ -6114,7 +6251,7 @@ ngx.shared.DICT.replace ----------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:replace(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Just like the [set](#ngxshareddictset) method, but only stores the key-value pair into the dictionary [ngx.shared.DICT](#ngxshareddict) if the key *does* exist. @@ -6130,7 +6267,7 @@ ngx.shared.DICT.delete ---------------------- **syntax:** *ngx.shared.DICT:delete(key)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Unconditionally removes the key-value pair from the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). @@ -6144,19 +6281,110 @@ See also [ngx.shared.DICT](#ngxshareddict). ngx.shared.DICT.incr -------------------- -**syntax:** *newval, err = ngx.shared.DICT:incr(key, value)* +**syntax:** *newval, err, forcible? = ngx.shared.DICT:incr(key, value, init?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Increments the (numerical) value for `key` in the shm-based dictionary [ngx.shared.DICT](#ngxshareddict) by the step value `value`. Returns the new resulting number if the operation is successfully completed or `nil` and an error message otherwise. -The key must already exist in the dictionary, otherwise it will return `nil` and `"not found"`. +When the key does not exist or has already expired in the shared dictionary, + +1. if the `init` argument is not specified or takes the value `nil`, this method will return `nil` and the error string `"not found"`, or +1. if the `init` argument takes a number value, this method will create a new `key` with the value `init + value`. + +Like the [add](#ngxshareddictadd) method, it also overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. + +The `forcible` return value will always be `nil` when the `init` argument is not specified. + +If this method succeeds in storing the current item by forcibly removing other not-yet-expired items in the dictionary via LRU, the `forcible` return value will be `true`. If it stores the item without forcibly removing other valid items, then the return value `forcible` will be `false`. If the original value is not a valid Lua number in the dictionary, it will return `nil` and `"not a number"`. -The `value` argument can be any valid Lua numbers, like negative numbers or floating-point numbers. +The `value` argument and `init` argument can be any valid Lua numbers, like negative numbers or floating-point numbers. -This feature was first introduced in the `v0.3.1rc22` release. +This method was first introduced in the `v0.3.1rc22` release. + +The optional `init` parameter was first added in the `v0.10.6` release. + +See also [ngx.shared.DICT](#ngxshareddict). + +[Back to TOC](#nginx-api-for-lua) + +ngx.shared.DICT.lpush +--------------------- +**syntax:** *length, err = ngx.shared.DICT:lpush(key, value)* + +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** + +Inserts the specified (numerical or string) `value` at the head of the list named `key` in the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). Returns the number of elements in the list after the push operation. + +If `key` does not exist, it is created as an empty list before performing the push operation. When the `key` already takes a value that is not a list, it will return `nil` and `"value not a list"`. + +It never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return `nil` and the string "no memory". + +This feature was first introduced in the `v0.10.6` release. + +See also [ngx.shared.DICT](#ngxshareddict). + +[Back to TOC](#nginx-api-for-lua) + +ngx.shared.DICT.rpush +--------------------- +**syntax:** *length, err = ngx.shared.DICT:rpush(key, value)* + +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** + +Similar to the [lpush](#ngxshareddictlpush) method, but inserts the specified (numerical or string) `value` at the tail of the list named `key`. + +This feature was first introduced in the `v0.10.6` release. + +See also [ngx.shared.DICT](#ngxshareddict). + +[Back to TOC](#nginx-api-for-lua) + +ngx.shared.DICT.lpop +-------------------- +**syntax:** *val, err = ngx.shared.DICT:lpop(key)* + +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** + +Removes and returns the first element of the list named `key` in the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). + +If `key` does not exist, it will return `nil`. When the `key` already takes a value that is not a list, it will return `nil` and `"value not a list"`. + +This feature was first introduced in the `v0.10.6` release. + +See also [ngx.shared.DICT](#ngxshareddict). + +[Back to TOC](#nginx-api-for-lua) + +ngx.shared.DICT.rpop +-------------------- +**syntax:** *val, err = ngx.shared.DICT:rpop(key)* + +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** + +Removes and returns the last element of the list named `key` in the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). + +If `key` does not exist, it will return `nil`. When the `key` already takes a value that is not a list, it will return `nil` and `"value not a list"`. + +This feature was first introduced in the `v0.10.6` release. + +See also [ngx.shared.DICT](#ngxshareddict). + +[Back to TOC](#nginx-api-for-lua) + +ngx.shared.DICT.llen +-------------------- +**syntax:** *len, err = ngx.shared.DICT:llen(key)* + +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** + +Returns the number of elements in the list named `key` in the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). + +If key does not exist, it is interpreted as an empty list and 0 is returned. When the `key` already takes a value that is not a list, it will return `nil` and `"value not a list"`. + +This feature was first introduced in the `v0.10.6` release. See also [ngx.shared.DICT](#ngxshareddict). @@ -6166,7 +6394,7 @@ ngx.shared.DICT.flush_all ------------------------- **syntax:** *ngx.shared.DICT:flush_all()* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Flushes out all the items in the dictionary. This method does not actuall free up all the memory blocks in the dictionary but just marks all the existing items as expired. @@ -6180,7 +6408,7 @@ ngx.shared.DICT.flush_expired ----------------------------- **syntax:** *flushed = ngx.shared.DICT:flush_expired(max_count?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Flushes out the expired items in the dictionary, up to the maximal number specified by the optional `max_count` argument. When the `max_count` argument is given `0` or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. @@ -6196,7 +6424,7 @@ ngx.shared.DICT.get_keys ------------------------ **syntax:** *keys = ngx.shared.DICT:get_keys(max_count?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Fetch a list of the keys from the dictionary, up to ``. @@ -6212,7 +6440,7 @@ ngx.socket.udp -------------- **syntax:** *udpsock = ngx.socket.udp()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Creates and returns a UDP or datagram-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: @@ -6236,7 +6464,7 @@ udpsock:setpeername **syntax:** *ok, err = udpsock:setpeername("unix:/path/to/unix-domain.socket")* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Attempts to connect a UDP socket object to a remote server or to a datagram unix domain socket file. Because the datagram protocol is actually connection-less, this method does not really establish a "connection", but only just set the name of the remote peer for subsequent read/write operations. @@ -6295,7 +6523,7 @@ udpsock:send ------------ **syntax:** *ok, err = udpsock:send(data)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Sends data on the current UDP or datagram unix domain socket object. @@ -6311,7 +6539,7 @@ udpsock:receive --------------- **syntax:** *data, err = udpsock:receive(size?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Receives data from the UDP or datagram unix domain socket object with an optional receive buffer size argument, `size`. @@ -6346,7 +6574,7 @@ udpsock:close ------------- **syntax:** *ok, err = udpsock:close()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Closes the current UDP or datagram unix domain socket. It returns the `1` in case of success and returns `nil` with a string describing the error otherwise. @@ -6360,7 +6588,7 @@ udpsock:settimeout ------------------ **syntax:** *udpsock:settimeout(time)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Set the timeout value in milliseconds for subsequent socket operations (like [receive](#udpsockreceive)). @@ -6384,7 +6612,7 @@ ngx.socket.tcp -------------- **syntax:** *tcpsock = ngx.socket.tcp()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: @@ -6430,7 +6658,7 @@ tcpsock:connect **syntax:** *ok, err = tcpsock:connect("unix:/path/to/unix-domain.socket", options_table?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Attempts to connect a TCP socket object to a remote server or to a stream unix domain socket file without blocking. @@ -6509,7 +6737,7 @@ tcpsock:sslhandshake -------------------- **syntax:** *session, err = tcpsock:sslhandshake(reused_session?, server_name?, ssl_verify?, send_status_req?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Does SSL/TLS handshake on the currently established connection. @@ -6554,7 +6782,7 @@ tcpsock:send ------------ **syntax:** *bytes, err = tcpsock:send(data)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Sends data without blocking on the current TCP or Unix Domain Socket connection. @@ -6586,7 +6814,7 @@ tcpsock:receive **syntax:** *data, err, partial = tcpsock:receive(pattern?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Receives data from the connected socket according to the reading pattern or size. @@ -6628,7 +6856,7 @@ tcpsock:receiveuntil -------------------- **syntax:** *iterator = tcpsock:receiveuntil(pattern, options?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** This method returns an iterator Lua function that can be called to read the data stream until it sees the specified pattern or an error occurs. @@ -6727,7 +6955,7 @@ tcpsock:close ------------- **syntax:** *ok, err = tcpsock:close()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Closes the current TCP or stream unix domain socket. It returns the `1` in case of success and returns `nil` with a string describing the error otherwise. @@ -6743,7 +6971,7 @@ tcpsock:settimeout ------------------ **syntax:** *tcpsock:settimeout(time)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Set the timeout value in milliseconds for subsequent socket operations ([connect](#tcpsockconnect), [receive](#tcpsockreceive), and iterators returned from [receiveuntil](#tcpsockreceiveuntil)). @@ -6759,7 +6987,7 @@ tcpsock:setoption ----------------- **syntax:** *tcpsock:setoption(option, value?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** This function is added for [LuaSocket](http://w3.impa.br/~diego/software/luasocket/tcp.html) API compatibility and does nothing for now. Its functionality will be implemented in future. @@ -6771,7 +6999,7 @@ tcpsock:setkeepalive -------------------- **syntax:** *ok, err = tcpsock:setkeepalive(timeout?, size?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Puts the current socket's connection immediately into the cosocket built-in connection pool and keep it alive until other [connect](#tcpsockconnect) method calls request it or the associated maximal idle timeout is expired. @@ -6799,7 +7027,7 @@ tcpsock:getreusedtimes ---------------------- **syntax:** *count, err = tcpsock:getreusedtimes()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** This method returns the (successfully) reused times for the current connection. In case of error, it returns `nil` and a string describing the error. @@ -6839,7 +7067,7 @@ ngx.get_phase ------------- **syntax:** *str = ngx.get_phase()* -**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Retrieves the current running phase name. Possible return values are @@ -6849,6 +7077,10 @@ Retrieves the current running phase name. Possible return values are for the context of [init_worker_by_lua](#init_worker_by_lua) or [init_worker_by_lua_file](#init_worker_by_lua_file). * `ssl_cert` for the context of [ssl_certificate_by_lua_block](#ssl_certificate_by_lua_block) or [ssl_certificate_by_lua_file](#ssl_certificate_by_lua_file). +* `ssl_session_fetch` + for the context of [ssl_session_fetch_by_lua*](#ssl_session_fetch_by_lua_block). +* `ssl_session_store` + for the context of [ssl_session_store_by_lua*](#ssl_session_store_by_lua_block). * `set` for the context of [set_by_lua](#set_by_lua) or [set_by_lua_file](#set_by_lua_file). * `rewrite` @@ -6876,7 +7108,7 @@ ngx.thread.spawn ---------------- **syntax:** *co = ngx.thread.spawn(func, arg1, arg2, ...)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Spawns a new user "light thread" with the Lua function `func` as well as those optional arguments `arg1`, `arg2`, and etc. Returns a Lua thread (or Lua coroutine) object represents this "light thread". @@ -7014,7 +7246,7 @@ ngx.thread.wait --------------- **syntax:** *ok, res1, res2, ... = ngx.thread.wait(thread1, thread2, ...)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** Waits on one or more child "light threads" and returns the results of the first "light thread" that terminates (either successfully or with an error). @@ -7171,7 +7403,7 @@ ngx.timer.at ------------ **syntax:** *ok, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Creates an Nginx timer with a user callback function as well as optional user arguments. @@ -7229,7 +7461,7 @@ Here is a simple example: } ``` -One can also create infinite re-occuring timers, for instance, a timer getting triggered every `5` seconds, by calling `ngx.timer.at` recursively in the timer callback function. Here is such an example, +One can also create infinite re-occurring timers, for instance, a timer getting triggered every `5` seconds, by calling `ngx.timer.at` recursively in the timer callback function. Here is such an example, ```lua @@ -7297,7 +7529,7 @@ ngx.timer.running_count ----------------------- **syntax:** *count = ngx.timer.running_count()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns the number of timers currently running. @@ -7309,7 +7541,7 @@ ngx.timer.pending_count ----------------------- **syntax:** *count = ngx.timer.pending_count()* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Returns the number of pending timers. @@ -7425,7 +7657,7 @@ ngx.worker.count **syntax:** *count = ngx.worker.count()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua** Returns the total number of the Nginx worker processes (i.e., the value configured by the [worker_processes](http://nginx.org/en/docs/ngx_core_module.html#worker_processes) @@ -7540,7 +7772,7 @@ ndk.set_var.DIRECTIVE --------------------- **syntax:** *res = ndk.set_var.DIRECTIVE_NAME* -**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua** +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** This mechanism allows calling other nginx C modules' directives that are implemented by [Nginx Devel Kit](https://github.com/simpl/ngx_devel_kit) (NDK)'s set_var submodule's `ndk_set_var_value`. @@ -7581,7 +7813,7 @@ coroutine.create ---------------- **syntax:** *co = coroutine.create(f)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Creates a user Lua coroutines with a Lua function, and returns a coroutine object. @@ -7597,7 +7829,7 @@ coroutine.resume ---------------- **syntax:** *ok, ... = coroutine.resume(co, ...)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Resumes the executation of a user Lua coroutine object previously yielded or just created. @@ -7613,7 +7845,7 @@ coroutine.yield --------------- **syntax:** *... = coroutine.yield(...)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Yields the execution of the current user Lua coroutine. @@ -7629,7 +7861,7 @@ coroutine.wrap -------------- **syntax:** *co = coroutine.wrap(f)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Similar to the standard Lua [coroutine.wrap](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.wrap) API, but works in the context of the Lua coroutines created by ngx_lua. @@ -7643,7 +7875,7 @@ coroutine.running ----------------- **syntax:** *co = coroutine.running()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Identical to the standard Lua [coroutine.running](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.running) API. @@ -7657,7 +7889,7 @@ coroutine.status ---------------- **syntax:** *status = coroutine.status(co)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Identical to the standard Lua [coroutine.status](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.status) API. diff --git a/debian/modules/nginx-lua/config b/debian/modules/nginx-lua/config index c91a07e..0f2749d 100644 --- a/debian/modules/nginx-lua/config +++ b/debian/modules/nginx-lua/config @@ -357,6 +357,9 @@ HTTP_LUA_SRCS=" \ $ngx_addon_dir/src/ngx_http_lua_ssl_ocsp.c \ $ngx_addon_dir/src/ngx_http_lua_lex.c \ $ngx_addon_dir/src/ngx_http_lua_balancer.c \ + $ngx_addon_dir/src/ngx_http_lua_ssl_session_storeby.c \ + $ngx_addon_dir/src/ngx_http_lua_ssl_session_fetchby.c \ + $ngx_addon_dir/src/ngx_http_lua_ssl.c \ " HTTP_LUA_DEPS=" \ @@ -414,6 +417,9 @@ HTTP_LUA_DEPS=" \ $ngx_addon_dir/src/ngx_http_lua_ssl_certby.h \ $ngx_addon_dir/src/ngx_http_lua_lex.h \ $ngx_addon_dir/src/ngx_http_lua_balancer.h \ + $ngx_addon_dir/src/ngx_http_lua_ssl_session_storeby.h \ + $ngx_addon_dir/src/ngx_http_lua_ssl_session_fetchby.h \ + $ngx_addon_dir/src/ngx_http_lua_ssl.h \ " CFLAGS="$CFLAGS -DNDK_SET_VAR" diff --git a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki index 78ce13c..2a5b0d2 100644 --- a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.5] released on 25 May 2016. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.6] released on 15 August 2016. = Synopsis = @@ -186,6 +186,8 @@ The Lua state (Lua VM instance) is shared across all the requests handled by a s The latest version of this module is compatible with the following versions of Nginx: +* 1.11.x (last tested: 1.11.2) +* 1.10.x * 1.9.x (last tested: 1.9.15) * 1.8.x * 1.7.x (last tested: 1.7.10) @@ -207,9 +209,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.9.15.tar.gz' - tar -xzvf nginx-1.9.15.tar.gz - cd nginx-1.9.15/ + wget 'http://nginx.org/download/nginx-1.11.2.tar.gz' + tar -xzvf nginx-1.11.2.tar.gz + cd nginx-1.11.2/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib @@ -1941,7 +1943,7 @@ This directive was first introduced in the v0.10.0 release. Determines whether to force the request body data to be read before running rewrite/access/access_by_lua* or not. The Nginx core does not read the client request body by default and if request body data is required, then this directive should be turned on or the [[#ngx.req.read_body|ngx.req.read_body]] function should be called within the Lua code. -To read the request body data within the [[HttpCoreModule#$request_body|$request_body]] variable, +To read the request body data within the [[HttpCoreModule#$request_body|$request_body]] variable, [[HttpCoreModule#client_body_buffer_size|client_body_buffer_size]] must have the same value as [[HttpCoreModule#client_max_body_size|client_max_body_size]]. Because when the content length exceeds [[HttpCoreModule#client_body_buffer_size|client_body_buffer_size]] but less than [[HttpCoreModule#client_max_body_size|client_max_body_size]], Nginx will buffer the data into a temporary file on the disk, which will lead to empty value in the [[HttpCoreModule#$request_body|$request_body]] variable. If the current location includes [[#rewrite_by_lua|rewrite_by_lua]] or [[#rewrite_by_lua_file|rewrite_by_lua_file]] directives, @@ -2053,6 +2055,111 @@ When a relative path like foo/bar.lua is given, they will be turned This directive was first introduced in the v0.10.0 release. +== ssl_session_fetch_by_lua_block == + +'''syntax:''' ''ssl_session_fetch_by_lua_block { lua-script }'' + +'''context:''' ''server'' + +'''phase:''' ''right-before-SSL-handshake'' + +This directive runs Lua code to look up and load the SSL session (if any) according to the session ID +provided by the current SSL handshake request for the downstream. + +The Lua API for obtaining the current session ID and loading a cached SSL session data +is provided in the [ngx.ssl.session](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl/session.md) +Lua module shipped with the [lua-resty-core](https://github.com/openresty/lua-resty-core#readme) +library. + +Lua APIs that may yield, like [[#ngx.sleep|ngx.sleep]] and [[#ngx.socket.tcp|cosockets]], +are enabled in this context. + +This hook, together with the [[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]] hook, +can be used to implement distributed caching mechanisms in pure Lua (based +on the [[#ngx.socket.tcp|cosocket]] API, for example). If a cached SSL session is found +and loaded into the current SSL connection context, +SSL session resumption can then get immediately initiated and bypass the full SSL handshake process which is very expensive in terms of CPU time. + +Please note that TLS session tickets are very different and it is the clients' responsibility +to cache the SSL session state when session tickets are used. SSL session resumptions based on +TLS session tickets would happen automatically without going through this hook (nor the +[[#ssl_session_store_by_lua*|ssl_session_store_by_lua_block]] hook). This hook is mainly +for older or less capable SSL clients that can only do SSL sessions by session IDs. + +When [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]] is specified at the same time, +this hook usually runs before [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]]. +When the SSL session is found and successfully loaded for the current SSL connection, +SSL session resumption will happen and thus bypass the [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]] +hook completely. In this case, NGINX also bypasses the [[#ssl_session_store_by_lua*|ssl_session_store_by_lua_block]] +hook, for obvious reasons. + +If you are using the [official pre-built packages](http://openresty.org/en/linux-packages.html) for [OpenResty](https://openresty.org/) +1.11.2.1 or later, then everything should work out of the box. + +If you are using OpenSSL libraries not provided by [OpenResty](https://openresty.org), +then you need to apply the following patch for OpenSSL 1.0.2h or later: + +https://github.com/openresty/openresty/blob/master/patches/openssl-1.0.2h-sess_set_get_cb_yield.patch + +If you are not using the NGINX core shipped with [OpenResty](https://openresty.org) 1.11.2.1 or later, then you need to +apply the following patch to the standard NGINX core 1.11.2 or later: + +http://openresty.org/download/nginx-1.11.2-nonblocking_ssl_handshake_hooks.patch + +This directive was first introduced in the v0.10.6 release. + +== ssl_session_fetch_by_lua_file == + +'''syntax:''' ''ssl_session_fetch_by_lua_file '' + +'''context:''' ''server'' + +'''phase:''' ''right-before-SSL-handshake'' + +Equivalent to [[#ssl_session_fetch_by_lua_block|ssl_session_fetch_by_lua_block]], except that the file specified by contains the Lua code, or rather, the [[#Lua/LuaJIT bytecode support|Lua/LuaJIT bytecode]] to be executed. + +When a relative path like foo/bar.lua is given, they will be turned into the absolute path relative to the server prefix path determined by the -p PATH command-line option while starting the Nginx server. + +This directive was first introduced in the v0.10.6 release. + +== ssl_session_store_by_lua_block == + +'''syntax:''' ''ssl_session_store_by_lua_block { lua-script }'' + +'''context:''' ''server'' + +'''phase:''' ''right-after-SSL-handshake'' + +This directive runs Lua code to fetch and save the SSL session (if any) according to the session ID +provided by the current SSL handshake request for the downstream. The saved or cached SSL +session data can be used for future SSL connections to resume SSL sessions without going +through the full SSL handshake process (which is very expensive in terms of CPU time). + +Lua APIs that may yield, like [[#ngx.sleep|ngx.sleep]] and [[#ngx.socket.tcp|cosockets]], +are *disabled* in this context. You can still, however, use the [[#ngx.timer.at|ngx.timer.at]] API +to create 0-delay timers to save the SSL session data asynchronously to external services (like redis or memcached). + +The Lua API for obtaining the current session ID and the associated session state data +is provided in the [ngx.ssl.session](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl/session.md#readme) +Lua module shipped with the [lua-resty-core](https://github.com/openresty/lua-resty-core#readme) +library. + +This directive was first introduced in the v0.10.6 release. + +== ssl_session_store_by_lua_file == + +'''syntax:''' ''ssl_session_store_by_lua_file '' + +'''context:''' ''server'' + +'''phase:''' ''right-before-SSL-handshake'' + +Equivalent to [[#ssl_session_store_by_lua_block|ssl_session_store_by_lua_block]], except that the file specified by contains the Lua code, or rather, the [[#Lua/LuaJIT bytecode support|Lua/LuaJIT bytecode]] to be executed. + +When a relative path like foo/bar.lua is given, they will be turned into the absolute path relative to the server prefix path determined by the -p PATH command-line option while starting the Nginx server. + +This directive was first introduced in the v0.10.6 release. + == lua_shared_dict == '''syntax:''' ''lua_shared_dict '' @@ -2499,7 +2606,7 @@ Undefined NGINX variables are evaluated to `nil` while uninitialized (but define This API requires a relatively expensive metamethod call and it is recommended to avoid using it on hot code paths. == Core constants == -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, *log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, *log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' ngx.OK (0) @@ -2520,7 +2627,7 @@ The ngx.null constant is a NULL light userdata usually The ngx.DECLINED constant was first introduced in the v0.5.0rc19 release. == HTTP method constants == -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' ngx.HTTP_GET @@ -2543,7 +2650,7 @@ The ngx.DECLINED constant was first introduced in the v0.5.0r These constants are usually used in [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] method calls. == HTTP status constants == -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' value = ngx.HTTP_CONTINUE (100) (first added in the v0.9.20 release) @@ -2583,7 +2690,7 @@ These constants are usually used in [[#ngx.location.capture|ngx.location.capture == Nginx log level constants == -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' ngx.STDERR @@ -2602,7 +2709,7 @@ These constants are usually used by the [[#ngx.log|ngx.log]] method. == print == '''syntax:''' ''print(...)'' -'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, certificate_by_lua*'' +'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Writes argument values into the nginx error.log file with the ngx.NOTICE log level. @@ -3302,6 +3409,8 @@ outputs something like this: This method was first introduced in the v0.7.17 release. +This method does not work in HTTP/2 requests yet. + == ngx.req.get_method == '''syntax:''' ''method_name = ngx.req.get_method()'' @@ -4127,7 +4236,7 @@ Just as [[#ngx.print|ngx.print]] but also emit a trailing newline. == ngx.log == '''syntax:''' ''ngx.log(log_level, ...)'' -'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Log arguments concatenated to error.log with the given logging level. @@ -4142,9 +4251,9 @@ There is a hard coded 2048 byte limitation on error message lengths '''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' -Flushes response output to the client. +Flushes response output to the client. -ngx.flush accepts an optional boolean wait argument (Default: false) first introduced in the v0.3.1rc34 release. When called with the default argument, it issues an asynchronous call (Returns immediately without waiting for output data to be written into the system send buffer). Calling the function with the wait argument set to true switches to synchronous mode. +ngx.flush accepts an optional boolean wait argument (Default: false) first introduced in the v0.3.1rc34 release. When called with the default argument, it issues an asynchronous call (Returns immediately without waiting for output data to be written into the system send buffer). Calling the function with the wait argument set to true switches to synchronous mode. In synchronous mode, the function will not return until all output data has been written into the system send buffer or until the [[HttpCoreModule#send_timeout|send_timeout]] setting has expired. Note that using the Lua coroutine mechanism means that this function does not block the Nginx event loop even in the synchronous mode. @@ -4157,7 +4266,7 @@ Since v0.8.3 this function returns 1 on success, or re == ngx.exit == '''syntax:''' ''ngx.exit(status)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' When status >= 200 (i.e., ngx.HTTP_OK and above), it will interrupt the execution of the current request and return status code to nginx. @@ -4199,7 +4308,9 @@ Note that while this method accepts all [[#HTTP status constants|HTTP status con Also note that this method call terminates the processing of the current request and that it is recommended that a coding style that combines this method call with the return statement, i.e., return ngx.exit(...) be used to reinforce the fact that the request processing is being terminated. -When being used in the context of [[#header_filter_by_lua|header_filter_by_lua]], ngx.exit() is an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use return in combination as suggested above. +When being used in the contexts of [[#header_filter_by_lua|header_filter_by_lua]] and +[[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]], ngx.exit() is +an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use return in combination as suggested above. == ngx.eof == '''syntax:''' ''ok, err = ngx.eof()'' @@ -4234,7 +4345,7 @@ Since v0.8.3 this function returns 1 on success, or re == ngx.sleep == '''syntax:''' ''ngx.sleep(seconds)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Sleeps for the specified seconds without blocking. One can specify time resolution up to 0.001 seconds (i.e., one milliseconds). @@ -4247,7 +4358,7 @@ This method was introduced in the 0.5.0rc30 release. == ngx.escape_uri == '''syntax:''' ''newstr = ngx.escape_uri(str)'' -'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Escape str as a URI component. @@ -4324,7 +4435,7 @@ This method was first introduced in the v0.3.1rc27 release. == ngx.decode_args == '''syntax:''' ''table = ngx.decode_args(str, max_args?)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Decodes a URI encoded query-string into a Lua table. This is the inverse function of [[#ngx.encode_args|ngx.encode_args]]. @@ -4343,7 +4454,7 @@ This method was introduced in the v0.5.0rc29. == ngx.encode_base64 == '''syntax:''' ''newstr = ngx.encode_base64(str, no_padding?)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Encodes str to a base64 digest. @@ -4352,14 +4463,14 @@ Since the 0.9.16 release, an optional boolean-typed no_paddin == ngx.decode_base64 == '''syntax:''' ''newstr = ngx.decode_base64(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Decodes the str argument as a base64 digest to the raw form. Returns nil if str is not well formed. == ngx.crc32_short == '''syntax:''' ''intval = ngx.crc32_short(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Calculates the CRC-32 (Cyclic Redundancy Code) digest for the str argument. @@ -4372,7 +4483,7 @@ This API was first introduced in the v0.3.1rc8 release. == ngx.crc32_long == '''syntax:''' ''intval = ngx.crc32_long(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Calculates the CRC-32 (Cyclic Redundancy Code) digest for the str argument. @@ -4385,7 +4496,7 @@ This API was first introduced in the v0.3.1rc8 release. == ngx.hmac_sha1 == '''syntax:''' ''digest = ngx.hmac_sha1(secret_key, str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Computes the [http://en.wikipedia.org/wiki/HMAC HMAC-SHA1] digest of the argument str and turns the result using the secret key . @@ -4413,7 +4524,7 @@ This function was first introduced in the v0.3.1rc29 release. == ngx.md5 == '''syntax:''' ''digest = ngx.md5(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns the hexadecimal representation of the MD5 digest of the str argument. @@ -4436,7 +4547,7 @@ See [[#ngx.md5_bin|ngx.md5_bin]] if the raw binary MD5 digest is required. == ngx.md5_bin == '''syntax:''' ''digest = ngx.md5_bin(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns the binary form of the MD5 digest of the str argument. @@ -4445,7 +4556,7 @@ See [[#ngx.md5|ngx.md5]] if the hexadecimal form of the MD5 digest is required. == ngx.sha1_bin == '''syntax:''' ''digest = ngx.sha1_bin(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns the binary form of the SHA-1 digest of the str argument. @@ -4456,14 +4567,14 @@ This function was first introduced in the v0.5.0rc6. == ngx.quote_sql_str == '''syntax:''' ''quoted_value = ngx.quote_sql_str(raw_value)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns a quoted SQL string literal according to the MySQL quoting rules. == ngx.today == '''syntax:''' ''str = ngx.today()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns current date (in the format yyyy-mm-dd) from the nginx cached time (no syscall involved unlike Lua's date library). @@ -4472,7 +4583,7 @@ This is the local time. == ngx.time == '''syntax:''' ''secs = ngx.time()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns the elapsed seconds from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -4481,7 +4592,7 @@ Updates of the Nginx time cache an be forced by calling [[#ngx.update_time|ngx.u == ngx.now == '''syntax:''' ''secs = ngx.now()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns a floating-point number for the elapsed time in seconds (including milliseconds as the decimal part) from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -4492,7 +4603,7 @@ This API was first introduced in v0.3.1rc32. == ngx.update_time == '''syntax:''' ''ngx.update_time()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Forcibly updates the Nginx current time cache. This call involves a syscall and thus has some overhead, so do not abuse it. @@ -4501,7 +4612,7 @@ This API was first introduced in v0.3.1rc32. == ngx.localtime == '''syntax:''' ''str = ngx.localtime()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns the current time stamp (in the format yyyy-mm-dd hh:mm:ss) of the nginx cached time (no syscall involved unlike Lua's [http://www.lua.org/manual/5.1/manual.html#pdf-os.date os.date] function). @@ -4510,7 +4621,7 @@ This is the local time. == ngx.utctime == '''syntax:''' ''str = ngx.utctime()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns the current time stamp (in the format yyyy-mm-dd hh:mm:ss) of the nginx cached time (no syscall involved unlike Lua's [http://www.lua.org/manual/5.1/manual.html#pdf-os.date os.date] function). @@ -4519,7 +4630,7 @@ This is the UTC time. == ngx.cookie_time == '''syntax:''' ''str = ngx.cookie_time(sec)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns a formatted string can be used as the cookie expiration time. The parameter sec is the time stamp in seconds (like those returned from [[#ngx.time|ngx.time]]). @@ -4531,7 +4642,7 @@ Returns a formatted string can be used as the cookie expiration time. The parame == ngx.http_time == '''syntax:''' ''str = ngx.http_time(sec)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns a formated string can be used as the http header time (for example, being used in Last-Modified header). The parameter sec is the time stamp in seconds (like those returned from [[#ngx.time|ngx.time]]). @@ -4543,7 +4654,7 @@ Returns a formated string can be used as the http header time (for example, bein == ngx.parse_http_time == '''syntax:''' ''sec = ngx.parse_http_time(str)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Parse the http time string (as returned by [[#ngx.http_time|ngx.http_time]]) into seconds. Returns the seconds or nil if the input string is in bad forms. @@ -4564,7 +4675,7 @@ Returns true if the current request is an nginx subrequest, or subject string using the Perl compatible regular expression regex with the optional options. @@ -4711,9 +4822,9 @@ This feature was introduced in the v0.2.1rc11 release. == ngx.re.find == '''syntax:''' ''from, to, err = ngx.re.find(subject, regex, options?, ctx?, nth?)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' -Similar to [[#ngx.re.match|ngx.re.match]] but only returns the begining index (from) and end index (to) of the matched substring. The returned indexes are 1-based and can be fed directly into the [http://www.lua.org/manual/5.1/manual.html#pdf-string.sub string.sub] API function to obtain the matched substring. +Similar to [[#ngx.re.match|ngx.re.match]] but only returns the beginning index (from) and end index (to) of the matched substring. The returned indexes are 1-based and can be fed directly into the [http://www.lua.org/manual/5.1/manual.html#pdf-string.sub string.sub] API function to obtain the matched substring. In case of errors (like bad regexes or any PCRE runtime errors), this API function returns two nil values followed by a string describing the error. @@ -4760,7 +4871,7 @@ This API function was first introduced in the v0.9.2 release. == ngx.re.gmatch == '''syntax:''' ''iterator, err = ngx.re.gmatch(subject, regex, options?)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Similar to [[#ngx.re.match|ngx.re.match]], but returns a Lua iterator instead, so as to let the user programmer iterate all the matches over the string argument with the PCRE regex. @@ -4833,7 +4944,7 @@ This feature was first introduced in the v0.2.1rc12 release. == ngx.re.sub == '''syntax:''' ''newstr, n, err = ngx.re.sub(subject, regex, replace, options?)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Substitutes the first match of the Perl compatible regular expression regex on the subject argument string with the string or function argument replace. The optional options argument has exactly the same meaning as in [[#ngx.re.match|ngx.re.match]]. @@ -4892,7 +5003,7 @@ This feature was first introduced in the v0.2.1rc13 release. == ngx.re.gsub == '''syntax:''' ''newstr, n, err = ngx.re.gsub(subject, regex, replace, options?)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Just like [[#ngx.re.sub|ngx.re.sub]], but does global substitution. @@ -4927,7 +5038,7 @@ This feature was first introduced in the v0.2.1rc15 release. '''syntax:''' ''dict = ngx.shared[name_var]'' -'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Fetching the shm-based Lua dictionary object for the shared memory zone named DICT defined by the [[#lua_shared_dict|lua_shared_dict]] directive. @@ -4944,6 +5055,11 @@ The resulting object dict has the following methods: * [[#ngx.shared.DICT.replace|replace]] * [[#ngx.shared.DICT.delete|delete]] * [[#ngx.shared.DICT.incr|incr]] +* [[#ngx.shared.DICT.lpush|lpush]] +* [[#ngx.shared.DICT.rpush|rpush]] +* [[#ngx.shared.DICT.lpop|lpop]] +* [[#ngx.shared.DICT.rpop|rpop]] +* [[#ngx.shared.DICT.llen|llen]] * [[#ngx.shared.DICT.flush_all|flush_all]] * [[#ngx.shared.DICT.flush_expired|flush_expired]] * [[#ngx.shared.DICT.get_keys|get_keys]] @@ -4995,9 +5111,9 @@ This feature was first introduced in the v0.3.1rc22 release. == ngx.shared.DICT.get == '''syntax:''' ''value, flags = ngx.shared.DICT:get(key)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' -Retrieving the value in the dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] for the key key. If the key does not exist or has been expired, then nil will be returned. +Retrieving the value in the dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] for the key key. If the key does not exist or has expired, then nil will be returned. In case of errors, nil and a string describing the error will be returned. @@ -5028,7 +5144,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.get_stale == '''syntax:''' ''value, flags, stale = ngx.shared.DICT:get_stale(key)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Similar to the [[#ngx.shared.DICT.get|get]] method but returns the value even if the key has already expired. @@ -5043,7 +5159,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.set == '''syntax:''' ''success, err, forcible = ngx.shared.DICT:set(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Unconditionally sets a key-value pair into the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. Returns three values: @@ -5086,7 +5202,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.safe_set == '''syntax:''' ''ok, err = ngx.shared.DICT:safe_set(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Similar to the [[#ngx.shared.DICT.set|set]] method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return nil and the string "no memory". @@ -5097,7 +5213,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.add == '''syntax:''' ''success, err, forcible = ngx.shared.DICT:add(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Just like the [[#ngx.shared.DICT.set|set]] method, but only stores the key-value pair into the dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] if the key does ''not'' exist. @@ -5110,7 +5226,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.safe_add == '''syntax:''' ''ok, err = ngx.shared.DICT:safe_add(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Similar to the [[#ngx.shared.DICT.add|add]] method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return nil and the string "no memory". @@ -5121,7 +5237,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.replace == '''syntax:''' ''success, err, forcible = ngx.shared.DICT:replace(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Just like the [[#ngx.shared.DICT.set|set]] method, but only stores the key-value pair into the dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] if the key ''does'' exist. @@ -5134,7 +5250,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.delete == '''syntax:''' ''ngx.shared.DICT:delete(key)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Unconditionally removes the key-value pair from the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. @@ -5145,26 +5261,102 @@ This feature was first introduced in the v0.3.1rc22 release. See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.incr == -'''syntax:''' ''newval, err = ngx.shared.DICT:incr(key, value)'' +'''syntax:''' ''newval, err, forcible? = ngx.shared.DICT:incr(key, value, init?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Increments the (numerical) value for key in the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] by the step value value. Returns the new resulting number if the operation is successfully completed or nil and an error message otherwise. -The key must already exist in the dictionary, otherwise it will return nil and "not found". +When the key does not exist or has already expired in the shared dictionary, + +# if the init argument is not specified or takes the value nil, this method will return nil and the error string "not found", or +# if the init argument takes a number value, this method will create a new key with the value init + value. + +Like the [[#ngx.shared.DICT.add|add]] method, it also overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. + +The forcible return value will always be nil when the init argument is not specified. + +If this method succeeds in storing the current item by forcibly removing other not-yet-expired items in the dictionary via LRU, the forcible return value will be true. If it stores the item without forcibly removing other valid items, then the return value forcible will be false. If the original value is not a valid Lua number in the dictionary, it will return nil and "not a number". -The value argument can be any valid Lua numbers, like negative numbers or floating-point numbers. +The value argument and init argument can be any valid Lua numbers, like negative numbers or floating-point numbers. -This feature was first introduced in the v0.3.1rc22 release. +This method was first introduced in the v0.3.1rc22 release. + +The optional `init` parameter was first added in the v0.10.6 release. + +See also [[#ngx.shared.DICT|ngx.shared.DICT]]. + +== ngx.shared.DICT.lpush == +'''syntax:''' ''length, err = ngx.shared.DICT:lpush(key, value)'' + +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' + +Inserts the specified (numerical or string) value at the head of the list named key in the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. Returns the number of elements in the list after the push operation. + +If key does not exist, it is created as an empty list before performing the push operation. When the key already takes a value that is not a list, it will return nil and "value not a list". + +It never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return nil and the string "no memory". + +This feature was first introduced in the v0.10.6 release. + +See also [[#ngx.shared.DICT|ngx.shared.DICT]]. + +== ngx.shared.DICT.rpush == +'''syntax:''' ''length, err = ngx.shared.DICT:rpush(key, value)'' + +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' + +Similar to the [[#ngx.shared.DICT.lpush|lpush]] method, but inserts the specified (numerical or string) value at the tail of the list named key. + +This feature was first introduced in the v0.10.6 release. + +See also [[#ngx.shared.DICT|ngx.shared.DICT]]. + +== ngx.shared.DICT.lpop == +'''syntax:''' ''val, err = ngx.shared.DICT:lpop(key)'' + +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' + +Removes and returns the first element of the list named key in the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. + +If key does not exist, it will return nil. When the key already takes a value that is not a list, it will return nil and "value not a list". + +This feature was first introduced in the v0.10.6 release. + +See also [[#ngx.shared.DICT|ngx.shared.DICT]]. + +== ngx.shared.DICT.rpop == +'''syntax:''' ''val, err = ngx.shared.DICT:rpop(key)'' + +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' + +Removes and returns the last element of the list named key in the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. + +If key does not exist, it will return nil. When the key already takes a value that is not a list, it will return nil and "value not a list". + +This feature was first introduced in the v0.10.6 release. + +See also [[#ngx.shared.DICT|ngx.shared.DICT]]. + +== ngx.shared.DICT.llen == +'''syntax:''' ''len, err = ngx.shared.DICT:llen(key)'' + +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' + +Returns the number of elements in the list named key in the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. + +If key does not exist, it is interpreted as an empty list and 0 is returned. When the key already takes a value that is not a list, it will return nil and "value not a list". + +This feature was first introduced in the v0.10.6 release. See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.flush_all == '''syntax:''' ''ngx.shared.DICT:flush_all()'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Flushes out all the items in the dictionary. This method does not actuall free up all the memory blocks in the dictionary but just marks all the existing items as expired. @@ -5175,7 +5367,7 @@ See also [[#ngx.shared.DICT.flush_expired|ngx.shared.DICT.flush_expired]] and [[ == ngx.shared.DICT.flush_expired == '''syntax:''' ''flushed = ngx.shared.DICT:flush_expired(max_count?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Flushes out the expired items in the dictionary, up to the maximal number specified by the optional max_count argument. When the max_count argument is given 0 or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. @@ -5188,7 +5380,7 @@ See also [[#ngx.shared.DICT.flush_all|ngx.shared.DICT.flush_all]] and [[#ngx.sha == ngx.shared.DICT.get_keys == '''syntax:''' ''keys = ngx.shared.DICT:get_keys(max_count?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Fetch a list of the keys from the dictionary, up to . @@ -5201,7 +5393,7 @@ This feature was first introduced in the v0.7.3 release. == ngx.socket.udp == '''syntax:''' ''udpsock = ngx.socket.udp()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Creates and returns a UDP or datagram-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: @@ -5222,7 +5414,7 @@ See also [[#ngx.socket.tcp|ngx.socket.tcp]]. '''syntax:''' ''ok, err = udpsock:setpeername("unix:/path/to/unix-domain.socket")'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Attempts to connect a UDP socket object to a remote server or to a datagram unix domain socket file. Because the datagram protocol is actually connection-less, this method does not really establish a "connection", but only just set the name of the remote peer for subsequent read/write operations. @@ -5275,7 +5467,7 @@ This method was first introduced in the v0.5.7 release. == udpsock:send == '''syntax:''' ''ok, err = udpsock:send(data)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Sends data on the current UDP or datagram unix domain socket object. @@ -5288,7 +5480,7 @@ This feature was first introduced in the v0.5.7 release. == udpsock:receive == '''syntax:''' ''data, err = udpsock:receive(size?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Receives data from the UDP or datagram unix domain socket object with an optional receive buffer size argument, size. @@ -5319,7 +5511,7 @@ This feature was first introduced in the v0.5.7 release. == udpsock:close == '''syntax:''' ''ok, err = udpsock:close()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Closes the current UDP or datagram unix domain socket. It returns the 1 in case of success and returns nil with a string describing the error otherwise. @@ -5330,7 +5522,7 @@ This feature was first introduced in the v0.5.7 release. == udpsock:settimeout == '''syntax:''' ''udpsock:settimeout(time)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Set the timeout value in milliseconds for subsequent socket operations (like [[#udpsock:receive|receive]]). @@ -5348,7 +5540,7 @@ This API function was first added to the v0.10.1 release. == ngx.socket.tcp == '''syntax:''' ''tcpsock = ngx.socket.tcp()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: @@ -5391,7 +5583,7 @@ See also [[#ngx.socket.udp|ngx.socket.udp]]. '''syntax:''' ''ok, err = tcpsock:connect("unix:/path/to/unix-domain.socket", options_table?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Attempts to connect a TCP socket object to a remote server or to a stream unix domain socket file without blocking. @@ -5463,7 +5655,7 @@ This method was first introduced in the v0.5.0rc1 release. == tcpsock:sslhandshake == '''syntax:''' ''session, err = tcpsock:sslhandshake(reused_session?, server_name?, ssl_verify?, send_status_req?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Does SSL/TLS handshake on the currently established connection. @@ -5505,7 +5697,7 @@ This method was first introduced in the v0.9.11 release. == tcpsock:send == '''syntax:''' ''bytes, err = tcpsock:send(data)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Sends data without blocking on the current TCP or Unix Domain Socket connection. @@ -5533,7 +5725,7 @@ This feature was first introduced in the v0.5.0rc1 release. '''syntax:''' ''data, err, partial = tcpsock:receive(pattern?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Receives data from the connected socket according to the reading pattern or size. @@ -5571,7 +5763,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:receiveuntil == '''syntax:''' ''iterator = tcpsock:receiveuntil(pattern, options?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' This method returns an iterator Lua function that can be called to read the data stream until it sees the specified pattern or an error occurs. @@ -5663,7 +5855,7 @@ This method was first introduced in the v0.5.0rc1 release. == tcpsock:close == '''syntax:''' ''ok, err = tcpsock:close()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Closes the current TCP or stream unix domain socket. It returns the 1 in case of success and returns nil with a string describing the error otherwise. @@ -5676,7 +5868,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:settimeout == '''syntax:''' ''tcpsock:settimeout(time)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Set the timeout value in milliseconds for subsequent socket operations ([[#tcpsock:connect|connect]], [[#tcpsock:receive|receive]], and iterators returned from [[#tcpsock:receiveuntil|receiveuntil]]). @@ -5689,7 +5881,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:setoption == '''syntax:''' ''tcpsock:setoption(option, value?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' This function is added for [http://w3.impa.br/~diego/software/luasocket/tcp.html LuaSocket] API compatibility and does nothing for now. Its functionality will be implemented in future. @@ -5698,7 +5890,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:setkeepalive == '''syntax:''' ''ok, err = tcpsock:setkeepalive(timeout?, size?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Puts the current socket's connection immediately into the cosocket built-in connection pool and keep it alive until other [[#tcpsock:connect|connect]] method calls request it or the associated maximal idle timeout is expired. @@ -5723,7 +5915,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:getreusedtimes == '''syntax:''' ''count, err = tcpsock:getreusedtimes()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' This method returns the (successfully) reused times for the current connection. In case of error, it returns nil and a string describing the error. @@ -5756,7 +5948,7 @@ This feature was first introduced in the v0.5.0rc1 release. == ngx.get_phase == '''syntax:''' ''str = ngx.get_phase()'' -'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Retrieves the current running phase name. Possible return values are @@ -5766,6 +5958,10 @@ Retrieves the current running phase name. Possible return values are : for the context of [[#init_worker_by_lua|init_worker_by_lua]] or [[#init_worker_by_lua_file|init_worker_by_lua_file]]. * ssl_cert : for the context of [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua_block]] or [[#ssl_certificate_by_lua_file|ssl_certificate_by_lua_file]]. +* ssl_session_fetch +: for the context of [[#ssl_session_fetch_by_lua_block|ssl_session_fetch_by_lua*]]. +* ssl_session_store +: for the context of [[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]]. * set : for the context of [[#set_by_lua|set_by_lua]] or [[#set_by_lua_file|set_by_lua_file]]. * rewrite @@ -5790,7 +5986,7 @@ This API was first introduced in the v0.5.10 release. == ngx.thread.spawn == '''syntax:''' ''co = ngx.thread.spawn(func, arg1, arg2, ...)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Spawns a new user "light thread" with the Lua function func as well as those optional arguments arg1, arg2, and etc. Returns a Lua thread (or Lua coroutine) object represents this "light thread". @@ -5923,7 +6119,7 @@ This API was first enabled in the v0.7.0 release. == ngx.thread.wait == '''syntax:''' ''ok, res1, res2, ... = ngx.thread.wait(thread1, thread2, ...)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' Waits on one or more child "light threads" and returns the results of the first "light thread" that terminates (either successfully or with an error). @@ -6068,7 +6264,7 @@ See also [[#lua_check_client_abort|lua_check_client_abort]]. == ngx.timer.at == '''syntax:''' ''ok, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Creates an Nginx timer with a user callback function as well as optional user arguments. @@ -6125,7 +6321,7 @@ Here is a simple example: } -One can also create infinite re-occuring timers, for instance, a timer getting triggered every 5 seconds, by calling ngx.timer.at recursively in the timer callback function. Here is such an example, +One can also create infinite re-occurring timers, for instance, a timer getting triggered every 5 seconds, by calling ngx.timer.at recursively in the timer callback function. Here is such an example, local delay = 5 @@ -6189,7 +6385,7 @@ This API was first introduced in the v0.8.0 release. == ngx.timer.running_count == '''syntax:''' ''count = ngx.timer.running_count()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns the number of timers currently running. @@ -6198,7 +6394,7 @@ This directive was first introduced in the v0.9.20 release. == ngx.timer.pending_count == '''syntax:''' ''count = ngx.timer.pending_count()'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Returns the number of pending timers. @@ -6287,7 +6483,7 @@ This API was first introduced in the 0.9.5 release. '''syntax:''' ''count = ngx.worker.count()'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua*'' Returns the total number of the Nginx worker processes (i.e., the value configured by the [http://nginx.org/en/docs/ngx_core_module.html#worker_processes worker_processes] @@ -6384,7 +6580,7 @@ This feature requires at least ngx_lua v0.10.0. == ndk.set_var.DIRECTIVE == '''syntax:''' ''res = ndk.set_var.DIRECTIVE_NAME'' -'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' This mechanism allows calling other nginx C modules' directives that are implemented by [https://github.com/simpl/ngx_devel_kit Nginx Devel Kit] (NDK)'s set_var submodule's ndk_set_var_value. @@ -6421,7 +6617,7 @@ This feature requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_kit] == coroutine.create == '''syntax:''' ''co = coroutine.create(f)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Creates a user Lua coroutines with a Lua function, and returns a coroutine object. @@ -6434,7 +6630,7 @@ This API was first introduced in the v0.6.0 release. == coroutine.resume == '''syntax:''' ''ok, ... = coroutine.resume(co, ...)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Resumes the executation of a user Lua coroutine object previously yielded or just created. @@ -6447,7 +6643,7 @@ This API was first introduced in the v0.6.0 release. == coroutine.yield == '''syntax:''' ''... = coroutine.yield(...)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Yields the execution of the current user Lua coroutine. @@ -6460,7 +6656,7 @@ This API was first introduced in the v0.6.0 release. == coroutine.wrap == '''syntax:''' ''co = coroutine.wrap(f)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Similar to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.wrap coroutine.wrap] API, but works in the context of the Lua coroutines created by ngx_lua. @@ -6471,7 +6667,7 @@ This API was first introduced in the v0.6.0 release. == coroutine.running == '''syntax:''' ''co = coroutine.running()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Identical to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.running coroutine.running] API. @@ -6482,7 +6678,7 @@ This API was first enabled in the v0.6.0 release. == coroutine.status == '''syntax:''' ''status = coroutine.status(co)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' Identical to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.status coroutine.status] API. diff --git a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h index 4bac0f6..88b41ad 100644 --- a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10005 +#define ngx_http_lua_version 10006 typedef struct { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c b/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c index bd09def..1a4ba6d 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c @@ -309,6 +309,10 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) if (llcf->check_client_abort) { r->read_event_handler = ngx_http_lua_rd_check_broken_connection; +#if (NGX_HTTP_V2) + if (!r->stream) { +#endif + rev = r->connection->read; if (!rev->active) { @@ -317,6 +321,10 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) } } +#if (NGX_HTTP_V2) + } +#endif + } else { r->read_event_handler = ngx_http_block_reading; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c b/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c index 5fa289b..0adf787 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c @@ -33,6 +33,10 @@ struct ngx_http_lua_balancer_peer_data_s { in_port_t port; int last_peer_state; + +#if !(HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS) + unsigned cloned_upstream_conf; /* :1 */ +#endif }; @@ -128,7 +132,7 @@ ngx_http_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, dd("enter"); - /* must specifiy a content handler */ + /* must specify a content handler */ if (cmd->post == NULL) { return NGX_CONF_ERROR; } @@ -372,7 +376,7 @@ ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r) dd("rc == %d", (int) rc); if (rc != 0) { - /* error occured when running loaded code */ + /* error occurred when running loaded code */ err_msg = (u_char *) lua_tolstring(L, -1, &len); if (err_msg == NULL) { @@ -536,6 +540,101 @@ ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r, } +int +ngx_http_lua_ffi_balancer_set_timeouts(ngx_http_request_t *r, + long connect_timeout, long send_timeout, long read_timeout, + char **err) +{ + ngx_http_lua_ctx_t *ctx; + ngx_http_upstream_t *u; + +#if !(HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS) + ngx_http_upstream_conf_t *ucf; +#endif + ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_balancer_peer_data_t *bp; + + if (r == NULL) { + *err = "no request found"; + return NGX_ERROR; + } + + u = r->upstream; + + if (u == NULL) { + *err = "no upstream found"; + return NGX_ERROR; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + *err = "no ctx found"; + return NGX_ERROR; + } + + if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) { + *err = "API disabled in the current context"; + return NGX_ERROR; + } + + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + + bp = lmcf->balancer_peer_data; + if (bp == NULL) { + *err = "no upstream peer data found"; + return NGX_ERROR; + } + +#if !(HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS) + if (!bp->cloned_upstream_conf) { + /* we clone the upstream conf for the current request so that + * we do not affect other requests at all. */ + + ucf = ngx_palloc(r->pool, sizeof(ngx_http_upstream_conf_t)); + + if (ucf == NULL) { + *err = "no memory"; + return NGX_ERROR; + } + + ngx_memcpy(ucf, u->conf, sizeof(ngx_http_upstream_conf_t)); + + u->conf = ucf; + bp->cloned_upstream_conf = 1; + + } else { + ucf = u->conf; + } +#endif + + if (connect_timeout > 0) { +#if (HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS) + u->connect_timeout = (ngx_msec_t) connect_timeout; +#else + ucf->connect_timeout = (ngx_msec_t) connect_timeout; +#endif + } + + if (send_timeout > 0) { +#if (HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS) + u->send_timeout = (ngx_msec_t) send_timeout; +#else + ucf->send_timeout = (ngx_msec_t) send_timeout; +#endif + } + + if (read_timeout > 0) { +#if (HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS) + u->read_timeout = (ngx_msec_t) read_timeout; +#else + ucf->read_timeout = (ngx_msec_t) read_timeout; +#endif + } + + return NGX_OK; +} + + int ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r, int count, char **err) diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_bodyfilterby.c b/debian/modules/nginx-lua/src/ngx_http_lua_bodyfilterby.c index 86e347e..2b3c38f 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_bodyfilterby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_bodyfilterby.c @@ -116,7 +116,7 @@ ngx_http_lua_body_filter_by_chunk(lua_State *L, ngx_http_request_t *r, if (rc != 0) { - /* error occured */ + /* error occurred */ err_msg = (u_char *) lua_tolstring(L, -1, &len); if (err_msg == NULL) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_cache.c b/debian/modules/nginx-lua/src/ngx_http_lua_cache.c index e8a132e..5ea3069 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_cache.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_cache.c @@ -166,7 +166,7 @@ ngx_http_lua_cache_loadbuffer(ngx_log_t *log, lua_State *L, rc = ngx_http_lua_clfactory_loadbuffer(L, (char *) src, src_len, name); if (rc != 0) { - /* Oops! error occured when loading Lua script */ + /* Oops! error occurred when loading Lua script */ if (rc == LUA_ERRMEM) { err = "memory allocation error"; @@ -252,7 +252,7 @@ ngx_http_lua_cache_loadfile(ngx_log_t *log, lua_State *L, dd("loadfile returns %d (%d)", (int) rc, LUA_ERRFILE); if (rc != 0) { - /* Oops! error occured when loading Lua script */ + /* Oops! error occurred when loading Lua script */ switch (rc) { case LUA_ERRMEM: err = "memory allocation error"; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_clfactory.c b/debian/modules/nginx-lua/src/ngx_http_lua_clfactory.c index 86885bb..89698c7 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_clfactory.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_clfactory.c @@ -93,14 +93,14 @@ * | Char | Number of upvalues referenced by this function * | [nups] | * --------------------- - * | Char | Number of paramters of this function + * | Char | Number of parameters of this function * | [numparams] | * --------------------- * | Char | Does this function has variable number of arguments? * | [is_var_arg] | main function always set to VARARG_ISVARARG (2) * --------------------- * | Char | Maximum stack size this function used - * | [maxstacksize] | Intially set to 2 + * | [maxstacksize] | Initially set to 2 * --------------------- * | Vector(instr) | Code instructions of this function * | [code] | @@ -177,7 +177,7 @@ * | Char | F(ffi) | V(vararg)| C(has internal funcs) * | [func flag] | * --------------------- - * | Char | Number of paramters of this function + * | Char | Number of parameters of this function * | [numparams] | * --------------------- * | Char | @@ -498,7 +498,7 @@ ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, sizeof(size_t) + sizeof(int) * 2); /* number of upvalues */ *(lf->begin_code.str + POS_NUM_OF_UPVS) = 0; - /* number of paramters */ + /* number of parameters */ *(lf->begin_code.str + POS_NUM_OF_PARA) = 0; /* is var-argument function? */ *(lf->begin_code.str + POS_IS_VAR_ARG) = 2; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_common.h b/debian/modules/nginx-lua/src/ngx_http_lua_common.h index 758c42a..d5e0dc8 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_common.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_common.h @@ -42,6 +42,13 @@ #endif +#ifndef NGX_HAVE_SHA1 +# if (nginx_version >= 1011002) +# define NGX_HAVE_SHA1 1 +# endif +#endif + + #ifndef MD5_DIGEST_LENGTH #define MD5_DIGEST_LENGTH 16 #endif @@ -96,17 +103,19 @@ typedef struct { /* must be within 16 bit */ -#define NGX_HTTP_LUA_CONTEXT_SET 0x001 -#define NGX_HTTP_LUA_CONTEXT_REWRITE 0x002 -#define NGX_HTTP_LUA_CONTEXT_ACCESS 0x004 -#define NGX_HTTP_LUA_CONTEXT_CONTENT 0x008 -#define NGX_HTTP_LUA_CONTEXT_LOG 0x010 -#define NGX_HTTP_LUA_CONTEXT_HEADER_FILTER 0x020 -#define NGX_HTTP_LUA_CONTEXT_BODY_FILTER 0x040 -#define NGX_HTTP_LUA_CONTEXT_TIMER 0x080 -#define NGX_HTTP_LUA_CONTEXT_INIT_WORKER 0x100 -#define NGX_HTTP_LUA_CONTEXT_BALANCER 0x200 -#define NGX_HTTP_LUA_CONTEXT_SSL_CERT 0x400 +#define NGX_HTTP_LUA_CONTEXT_SET 0x0001 +#define NGX_HTTP_LUA_CONTEXT_REWRITE 0x0002 +#define NGX_HTTP_LUA_CONTEXT_ACCESS 0x0004 +#define NGX_HTTP_LUA_CONTEXT_CONTENT 0x0008 +#define NGX_HTTP_LUA_CONTEXT_LOG 0x0010 +#define NGX_HTTP_LUA_CONTEXT_HEADER_FILTER 0x0020 +#define NGX_HTTP_LUA_CONTEXT_BODY_FILTER 0x0040 +#define NGX_HTTP_LUA_CONTEXT_TIMER 0x0080 +#define NGX_HTTP_LUA_CONTEXT_INIT_WORKER 0x0100 +#define NGX_HTTP_LUA_CONTEXT_BALANCER 0x0200 +#define NGX_HTTP_LUA_CONTEXT_SSL_CERT 0x0400 +#define NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE 0x0800 +#define NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH 0x1000 #ifndef NGX_LUA_NO_FFI_API @@ -197,10 +206,18 @@ struct ngx_http_lua_main_conf_s { union ngx_http_lua_srv_conf_u { #if (NGX_HTTP_SSL) struct { - ngx_http_lua_srv_conf_handler_pt cert_handler; - ngx_str_t cert_src; - u_char *cert_src_key; - } ssl; + ngx_http_lua_srv_conf_handler_pt ssl_cert_handler; + ngx_str_t ssl_cert_src; + u_char *ssl_cert_src_key; + + ngx_http_lua_srv_conf_handler_pt ssl_sess_store_handler; + ngx_str_t ssl_sess_store_src; + u_char *ssl_sess_store_src_key; + + ngx_http_lua_srv_conf_handler_pt ssl_sess_fetch_handler; + ngx_str_t ssl_sess_fetch_src; + u_char *ssl_sess_fetch_src_key; + } srv; #endif struct { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c b/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c index 6718885..ecd6c0e 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c @@ -97,6 +97,10 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) if (llcf->check_client_abort) { r->read_event_handler = ngx_http_lua_rd_check_broken_connection; +#if (NGX_HTTP_V2) + if (!r->stream) { +#endif + rev = r->connection->read; if (!rev->active) { @@ -105,6 +109,10 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) } } +#if (NGX_HTTP_V2) + } +#endif + } else { r->read_event_handler = ngx_http_block_reading; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_control.c b/debian/modules/nginx-lua/src/ngx_http_lua_control.c index 4c5f65e..9e78bec 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_control.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_control.c @@ -318,11 +318,16 @@ ngx_http_lua_ngx_exit(lua_State *L) | NGX_HTTP_LUA_CONTEXT_TIMER | NGX_HTTP_LUA_CONTEXT_HEADER_FILTER | NGX_HTTP_LUA_CONTEXT_BALANCER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); rc = (ngx_int_t) luaL_checkinteger(L, 1); - if (ctx->context == NGX_HTTP_LUA_CONTEXT_SSL_CERT) { + if (ctx->context & (NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH)) + { #if (NGX_HTTP_SSL) @@ -332,6 +337,10 @@ ngx_http_lua_ngx_exit(lua_State *L) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua exit with code %i", rc); + if (ctx->context == NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE) { + return 0; + } + return lua_yield(L, 0); #else @@ -460,14 +469,19 @@ ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, u_char *err, | NGX_HTTP_LUA_CONTEXT_TIMER | NGX_HTTP_LUA_CONTEXT_HEADER_FILTER | NGX_HTTP_LUA_CONTEXT_BALANCER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT, + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH, err, errlen) != NGX_OK) { return NGX_ERROR; } - if (ctx->context == NGX_HTTP_LUA_CONTEXT_SSL_CERT) { + if (ctx->context & (NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH)) + { #if (NGX_HTTP_SSL) @@ -477,6 +491,10 @@ ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, u_char *err, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua exit with code %d", status); + if (ctx->context == NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE) { + return NGX_DONE; + } + return NGX_OK; #else diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_coroutine.c b/debian/modules/nginx-lua/src/ngx_http_lua_coroutine.c index cb819c6..b790814 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_coroutine.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_coroutine.c @@ -77,7 +77,8 @@ ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r, | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); vm = ngx_http_lua_get_lua_vm(r, ctx); @@ -153,7 +154,8 @@ ngx_http_lua_coroutine_resume(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); p_coctx = ctx->cur_co_ctx; if (p_coctx == NULL) { @@ -213,7 +215,8 @@ ngx_http_lua_coroutine_yield(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); coctx = ctx->cur_co_ctx; @@ -362,7 +365,8 @@ ngx_http_lua_coroutine_status(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); coctx = ngx_http_lua_get_co_ctx(co, ctx); if (coctx == NULL) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c b/debian/modules/nginx-lua/src/ngx_http_lua_directive.c index e6bc339..e9313db 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_directive.c @@ -459,7 +459,7 @@ ngx_http_lua_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return "does not work with " NGINX_VER; #endif - /* must specifiy a content handler */ + /* must specify a content handler */ if (cmd->post == NULL) { return NGX_CONF_ERROR; } @@ -569,7 +569,7 @@ ngx_http_lua_access_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) dd("enter"); - /* must specifiy a content handler */ + /* must specify a content handler */ if (cmd->post == NULL) { return NGX_CONF_ERROR; } @@ -681,7 +681,7 @@ ngx_http_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) dd("enter"); - /* must specifiy a content handler */ + /* must specify a content handler */ if (cmd->post == NULL) { return NGX_CONF_ERROR; } @@ -802,7 +802,7 @@ ngx_http_lua_log_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) dd("enter"); - /* must specifiy a content handler */ + /* must specify a content handler */ if (cmd->post == NULL) { return NGX_CONF_ERROR; } @@ -912,7 +912,7 @@ ngx_http_lua_header_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, dd("enter"); - /* must specifiy a content handler */ + /* must specify a content handler */ if (cmd->post == NULL) { return NGX_CONF_ERROR; } @@ -1012,7 +1012,7 @@ ngx_http_lua_body_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, dd("enter"); - /* must specifiy a content handler */ + /* must specify a content handler */ if (cmd->post == NULL) { return NGX_CONF_ERROR; } @@ -1110,7 +1110,7 @@ ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, dd("enter"); - /* must specifiy a content handler */ + /* must specify a content handler */ if (cmd->post == NULL) { return NGX_CONF_ERROR; } @@ -1177,7 +1177,7 @@ ngx_http_lua_init_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, dd("enter"); - /* must specifiy a content handler */ + /* must specify a content handler */ if (cmd->post == NULL) { return NGX_CONF_ERROR; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c b/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c index 75ce324..b504530 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c @@ -112,7 +112,7 @@ ngx_http_lua_header_filter_by_chunk(lua_State *L, ngx_http_request_t *r) dd("rc == %d", (int) rc); if (rc != 0) { - /* error occured when running loaded code */ + /* error occurred when running loaded code */ err_msg = (u_char *) lua_tolstring(L, -1, &len); if (err_msg == NULL) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers.c b/debian/modules/nginx-lua/src/ngx_http_lua_headers.c index 45be168..0af56f6 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headers.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headers.c @@ -99,6 +99,12 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) hc = mr->http_connection; c = mr->connection; +#if (NGX_HTTP_V2) + if (mr->stream) { + return luaL_error(L, "http v2 not supported yet"); + } +#endif + #if 1 dd("hc->nbusy: %d", (int) hc->nbusy); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers_in.c b/debian/modules/nginx-lua/src/ngx_http_lua_headers_in.c index 82b4331..b0c28d5 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headers_in.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headers_in.c @@ -263,6 +263,11 @@ retry: new_header: + if (r->headers_in.headers.last == NULL) { + /* must be 400 bad request */ + return NGX_OK; + } + h = ngx_list_push(&r->headers_in.headers); if (h == NULL) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_logby.c b/debian/modules/nginx-lua/src/ngx_http_lua_logby.c index 0a79acd..49fcd08 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_logby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_logby.c @@ -198,7 +198,7 @@ ngx_http_lua_log_by_chunk(lua_State *L, ngx_http_request_t *r) #endif if (rc != 0) { - /* error occured when running loaded code */ + /* error occurred when running loaded code */ err_msg = (u_char *) lua_tolstring(L, -1, &len); if (err_msg == NULL) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_module.c b/debian/modules/nginx-lua/src/ngx_http_lua_module.c index 867661c..c5e10f9 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_module.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_module.c @@ -26,6 +26,8 @@ #include "ngx_http_lua_semaphore.h" #include "ngx_http_lua_balancer.h" #include "ngx_http_lua_ssl_certby.h" +#include "ngx_http_lua_ssl_session_storeby.h" +#include "ngx_http_lua_ssl_session_fetchby.h" static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf); @@ -525,6 +527,34 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, (void *) ngx_http_lua_ssl_cert_handler_file }, + { ngx_string("ssl_session_store_by_lua_block"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_http_lua_ssl_sess_store_by_lua_block, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + (void *) ngx_http_lua_ssl_sess_store_handler_inline }, + + { ngx_string("ssl_session_store_by_lua_file"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_lua_ssl_sess_store_by_lua, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + (void *) ngx_http_lua_ssl_sess_store_handler_file }, + + { ngx_string("ssl_session_fetch_by_lua_block"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_http_lua_ssl_sess_fetch_by_lua_block, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + (void *) ngx_http_lua_ssl_sess_fetch_handler_inline }, + + { ngx_string("ssl_session_fetch_by_lua_file"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_lua_ssl_sess_fetch_by_lua, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + (void *) ngx_http_lua_ssl_sess_fetch_handler_file }, + { ngx_string("lua_ssl_verify_depth"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, @@ -681,7 +711,6 @@ ngx_http_lua_init(ngx_conf_t *cf) } #ifndef NGX_LUA_NO_FFI_API - /* add the cleanup of semaphores after the lua_close */ cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { @@ -690,7 +719,6 @@ ngx_http_lua_init(ngx_conf_t *cf) cln->data = lmcf; cln->handler = ngx_http_lua_sema_mm_cleanup; - #endif if (lmcf->lua == NULL) { @@ -761,7 +789,9 @@ ngx_http_lua_lowat_check(ngx_conf_t *cf, void *post, void *data) static void * ngx_http_lua_create_main_conf(ngx_conf_t *cf) { +#ifndef NGX_LUA_NO_FFI_API ngx_int_t rc; +#endif ngx_http_lua_main_conf_t *lmcf; @@ -802,11 +832,14 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) lmcf->postponed_to_rewrite_phase_end = NGX_CONF_UNSET; lmcf->postponed_to_access_phase_end = NGX_CONF_UNSET; +#ifndef NGX_LUA_NO_FFI_API rc = ngx_http_lua_sema_mm_init(cf, lmcf); if (rc != NGX_OK) { return NULL; } + dd("nginx Lua module main config structure initialized!"); +#endif return lmcf; } @@ -852,9 +885,18 @@ ngx_http_lua_create_srv_conf(ngx_conf_t *cf) } /* set by ngx_pcalloc: - * lscf->ssl.cert_handler = NULL; - * lscf->ssl.cert_src = { 0, NULL }; - * lscf->ssl.cert_src_key = NULL; + * lscf->srv.ssl_cert_handler = NULL; + * lscf->srv.ssl_cert_src = { 0, NULL }; + * lscf->srv.ssl_cert_src_key = NULL; + * + * lscf->srv.ssl_session_store_handler = NULL; + * lscf->srv.ssl_session_store_src = { 0, NULL }; + * lscf->srv.ssl_session_store_src_key = NULL; + * + * lscf->srv.ssl_session_fetch_handler = NULL; + * lscf->srv.ssl_session_fetch_src = { 0, NULL }; + * lscf->srv.ssl_session_fetch_src_key = NULL; + * * lscf->balancer.handler = NULL; * lscf->balancer.src = { 0, NULL }; * lscf->balancer.src_key = NULL; @@ -875,13 +917,13 @@ ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) dd("merge srv conf"); - if (conf->ssl.cert_src.len == 0) { - conf->ssl.cert_src = prev->ssl.cert_src; - conf->ssl.cert_src_key = prev->ssl.cert_src_key; - conf->ssl.cert_handler = prev->ssl.cert_handler; + if (conf->srv.ssl_cert_src.len == 0) { + conf->srv.ssl_cert_src = prev->srv.ssl_cert_src; + conf->srv.ssl_cert_src_key = prev->srv.ssl_cert_src_key; + conf->srv.ssl_cert_handler = prev->srv.ssl_cert_handler; } - if (conf->ssl.cert_src.len) { + if (conf->srv.ssl_cert_src.len) { sscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_ssl_module); if (sscf == NULL || sscf->ssl.ctx == NULL) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, @@ -910,6 +952,56 @@ ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) # endif +#endif + } + + if (conf->srv.ssl_sess_store_src.len == 0) { + conf->srv.ssl_sess_store_src = prev->srv.ssl_sess_store_src; + conf->srv.ssl_sess_store_src_key = prev->srv.ssl_sess_store_src_key; + conf->srv.ssl_sess_store_handler = prev->srv.ssl_sess_store_handler; + } + + if (conf->srv.ssl_sess_store_src.len) { + sscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_ssl_module); + if (sscf == NULL || sscf->ssl.ctx == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no ssl configured for the server"); + + return NGX_CONF_ERROR; + } + +#ifdef LIBRESSL_VERSION_NUMBER + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "LibreSSL does not support ssl_session_store_by_lua*"); + return NGX_CONF_ERROR; +#else + SSL_CTX_sess_set_new_cb(sscf->ssl.ctx, + ngx_http_lua_ssl_sess_store_handler); +#endif + } + + if (conf->srv.ssl_sess_fetch_src.len == 0) { + conf->srv.ssl_sess_fetch_src = prev->srv.ssl_sess_fetch_src; + conf->srv.ssl_sess_fetch_src_key = prev->srv.ssl_sess_fetch_src_key; + conf->srv.ssl_sess_fetch_handler = prev->srv.ssl_sess_fetch_handler; + } + + if (conf->srv.ssl_sess_fetch_src.len) { + sscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_ssl_module); + if (sscf == NULL || sscf->ssl.ctx == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no ssl configured for the server"); + + return NGX_CONF_ERROR; + } + +#ifdef LIBRESSL_VERSION_NUMBER + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "LibreSSL does not support ssl_session_fetch_by_lua*"); + return NGX_CONF_ERROR; +#else + SSL_CTX_sess_set_get_cb(sscf->ssl.ctx, + ngx_http_lua_ssl_sess_fetch_handler); #endif } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_phase.c b/debian/modules/nginx-lua/src/ngx_http_lua_phase.c index b8e936a..50c5311 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_phase.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_phase.c @@ -84,8 +84,16 @@ ngx_http_lua_ngx_get_phase(lua_State *L) lua_pushliteral(L, "ssl_cert"); break; + case NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE: + lua_pushliteral(L, "ssl_session_store"); + break; + + case NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH: + lua_pushliteral(L, "ssl_session_fetch"); + break; + default: - return luaL_error(L, "unknown phase: %d", (int) ctx->context); + return luaL_error(L, "unknown phase: %#x", (int) ctx->context); } return 1; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c b/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c index 2ef59c5..44d8941 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c @@ -304,6 +304,10 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) if (llcf->check_client_abort) { r->read_event_handler = ngx_http_lua_rd_check_broken_connection; +#if (NGX_HTTP_V2) + if (!r->stream) { +#endif + rev = r->connection->read; if (!rev->active) { @@ -312,6 +316,10 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) } } +#if (NGX_HTTP_V2) + } +#endif + } else { r->read_event_handler = ngx_http_block_reading; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_setby.c b/debian/modules/nginx-lua/src/ngx_http_lua_setby.c index ed9ccc4..2e8762a 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_setby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_setby.c @@ -88,7 +88,7 @@ ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val, #endif if (rc != 0) { - /* error occured when running loaded code */ + /* error occurred when running loaded code */ err_msg = (u_char *) lua_tolstring(L, -1, &len); if (err_msg == NULL) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c b/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c index 43f5f9e..ac7f6f1 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c @@ -34,6 +34,13 @@ static int ngx_http_lua_shdict_delete(lua_State *L); static int ngx_http_lua_shdict_flush_all(lua_State *L); static int ngx_http_lua_shdict_flush_expired(lua_State *L); static int ngx_http_lua_shdict_get_keys(lua_State *L); +static int ngx_http_lua_shdict_lpush(lua_State *L); +static int ngx_http_lua_shdict_rpush(lua_State *L); +static int ngx_http_lua_shdict_push_helper(lua_State *L, int flags); +static int ngx_http_lua_shdict_lpop(lua_State *L); +static int ngx_http_lua_shdict_rpop(lua_State *L); +static int ngx_http_lua_shdict_pop_helper(lua_State *L, int flags); +static int ngx_http_lua_shdict_llen(lua_State *L); static ngx_inline ngx_shm_zone_t *ngx_http_lua_shdict_get_zone(lua_State *L, @@ -45,11 +52,32 @@ static ngx_inline ngx_shm_zone_t *ngx_http_lua_shdict_get_zone(lua_State *L, #define NGX_HTTP_LUA_SHDICT_SAFE_STORE 0x0004 +#define NGX_HTTP_LUA_SHDICT_LEFT 0x0001 +#define NGX_HTTP_LUA_SHDICT_RIGHT 0x0002 + + enum { SHDICT_USERDATA_INDEX = 1, }; +enum { + SHDICT_TNIL = 0, /* same as LUA_TNIL */ + SHDICT_TBOOLEAN = 1, /* same as LUA_TBOOLEAN */ + SHDICT_TNUMBER = 3, /* same as LUA_TNUMBER */ + SHDICT_TSTRING = 4, /* same as LUA_TSTRING */ + SHDICT_TLIST = 5, +}; + + +static ngx_inline ngx_queue_t * +ngx_http_lua_shdict_get_list_head(ngx_http_lua_shdict_node_t *sd, size_t len) +{ + return (ngx_queue_t *) ngx_align_ptr(((u_char *) &sd->data + len), + NGX_ALIGNMENT); +} + + ngx_int_t ngx_http_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data) { @@ -90,7 +118,7 @@ ngx_http_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data) ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel, ngx_http_lua_shdict_rbtree_insert_value); - ngx_queue_init(&ctx->sh->queue); + ngx_queue_init(&ctx->sh->lru_queue); len = sizeof(" in lua_shared_dict zone \"\"") + shm_zone->shm.name.len; @@ -214,7 +242,7 @@ ngx_http_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, if (rc == 0) { ngx_queue_remove(&sd->queue); - ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); *sdp = sd; @@ -249,13 +277,14 @@ ngx_http_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, static int ngx_http_lua_shdict_expire(ngx_http_lua_shdict_ctx_t *ctx, ngx_uint_t n) { - ngx_time_t *tp; - uint64_t now; - ngx_queue_t *q; - int64_t ms; - ngx_rbtree_node_t *node; - ngx_http_lua_shdict_node_t *sd; - int freed = 0; + ngx_time_t *tp; + uint64_t now; + ngx_queue_t *q, *list_queue, *lq; + int64_t ms; + ngx_rbtree_node_t *node; + ngx_http_lua_shdict_node_t *sd; + int freed = 0; + ngx_http_lua_shdict_list_node_t *lnode; tp = ngx_timeofday(); @@ -269,11 +298,11 @@ ngx_http_lua_shdict_expire(ngx_http_lua_shdict_ctx_t *ctx, ngx_uint_t n) while (n < 3) { - if (ngx_queue_empty(&ctx->sh->queue)) { + if (ngx_queue_empty(&ctx->sh->lru_queue)) { return freed; } - q = ngx_queue_last(&ctx->sh->queue); + q = ngx_queue_last(&ctx->sh->lru_queue); sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue); @@ -289,6 +318,20 @@ ngx_http_lua_shdict_expire(ngx_http_lua_shdict_ctx_t *ctx, ngx_uint_t n) } } + if (sd->value_type == SHDICT_TLIST) { + list_queue = ngx_http_lua_shdict_get_list_head(sd, sd->key_len); + + for (lq = ngx_queue_head(list_queue); + lq != ngx_queue_sentinel(list_queue); + lq = ngx_queue_next(lq)) + { + lnode = ngx_queue_data(lq, ngx_http_lua_shdict_list_node_t, + queue); + + ngx_slab_free_locked(ctx->shpool, lnode); + } + } + ngx_queue_remove(q); node = (ngx_rbtree_node_t *) @@ -316,7 +359,7 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) lua_createtable(L, 0, lmcf->shm_zones->nelts /* nrec */); /* ngx.shared */ - lua_createtable(L, 0 /* narr */, 13 /* nrec */); /* shared mt */ + lua_createtable(L, 0 /* narr */, 18 /* nrec */); /* shared mt */ lua_pushcfunction(L, ngx_http_lua_shdict_get); lua_setfield(L, -2, "get"); @@ -345,6 +388,21 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) lua_pushcfunction(L, ngx_http_lua_shdict_delete); lua_setfield(L, -2, "delete"); + lua_pushcfunction(L, ngx_http_lua_shdict_lpush); + lua_setfield(L, -2, "lpush"); + + lua_pushcfunction(L, ngx_http_lua_shdict_rpush); + lua_setfield(L, -2, "rpush"); + + lua_pushcfunction(L, ngx_http_lua_shdict_lpop); + lua_setfield(L, -2, "lpop"); + + lua_pushcfunction(L, ngx_http_lua_shdict_rpop); + lua_setfield(L, -2, "rpop"); + + lua_pushcfunction(L, ngx_http_lua_shdict_llen); + lua_setfield(L, -2, "llen"); + lua_pushcfunction(L, ngx_http_lua_shdict_flush_all); lua_setfield(L, -2, "flush_all"); @@ -503,12 +561,13 @@ ngx_http_lua_shdict_get_helper(lua_State *L, int get_stale) value.len = (size_t) sd->value_len; switch (value_type) { - case LUA_TSTRING: + + case SHDICT_TSTRING: lua_pushlstring(L, (char *) value.data, value.len); break; - case LUA_TNUMBER: + case SHDICT_TNUMBER: if (value.len != sizeof(double)) { @@ -524,7 +583,7 @@ ngx_http_lua_shdict_get_helper(lua_State *L, int get_stale) lua_pushnumber(L, num); break; - case LUA_TBOOLEAN: + case SHDICT_TBOOLEAN: if (value.len != sizeof(u_char)) { @@ -540,6 +599,14 @@ ngx_http_lua_shdict_get_helper(lua_State *L, int get_stale) lua_pushboolean(L, c ? 1 : 0); break; + case SHDICT_TLIST: + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushnil(L); + lua_pushliteral(L, "value is a list"); + return 2; + default: ngx_shmtx_unlock(&ctx->shpool->mutex); @@ -621,8 +688,8 @@ ngx_http_lua_shdict_flush_all(lua_State *L) ngx_shmtx_lock(&ctx->shpool->mutex); - for (q = ngx_queue_head(&ctx->sh->queue); - q != ngx_queue_sentinel(&ctx->sh->queue); + for (q = ngx_queue_head(&ctx->sh->lru_queue); + q != ngx_queue_sentinel(&ctx->sh->lru_queue); q = ngx_queue_next(q)) { sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue); @@ -640,16 +707,17 @@ ngx_http_lua_shdict_flush_all(lua_State *L) static int ngx_http_lua_shdict_flush_expired(lua_State *L) { - ngx_queue_t *q, *prev; - ngx_http_lua_shdict_node_t *sd; - ngx_http_lua_shdict_ctx_t *ctx; - ngx_shm_zone_t *zone; - ngx_time_t *tp; - int freed = 0; - int attempts = 0; - ngx_rbtree_node_t *node; - uint64_t now; - int n; + ngx_queue_t *q, *prev, *list_queue, *lq; + ngx_http_lua_shdict_node_t *sd; + ngx_http_lua_shdict_ctx_t *ctx; + ngx_shm_zone_t *zone; + ngx_time_t *tp; + int freed = 0; + int attempts = 0; + ngx_rbtree_node_t *node; + uint64_t now; + int n; + ngx_http_lua_shdict_list_node_t *lnode; n = lua_gettop(L); @@ -672,7 +740,7 @@ ngx_http_lua_shdict_flush_expired(lua_State *L) ngx_shmtx_lock(&ctx->shpool->mutex); - if (ngx_queue_empty(&ctx->sh->queue)) { + if (ngx_queue_empty(&ctx->sh->lru_queue)) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushnumber(L, 0); return 1; @@ -682,14 +750,29 @@ ngx_http_lua_shdict_flush_expired(lua_State *L) now = (uint64_t) tp->sec * 1000 + tp->msec; - q = ngx_queue_last(&ctx->sh->queue); + q = ngx_queue_last(&ctx->sh->lru_queue); - while (q != ngx_queue_sentinel(&ctx->sh->queue)) { + while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { prev = ngx_queue_prev(q); sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue); if (sd->expires != 0 && sd->expires <= now) { + + if (sd->value_type == SHDICT_TLIST) { + list_queue = ngx_http_lua_shdict_get_list_head(sd, sd->key_len); + + for (lq = ngx_queue_head(list_queue); + lq != ngx_queue_sentinel(list_queue); + lq = ngx_queue_next(lq)) + { + lnode = ngx_queue_data(lq, ngx_http_lua_shdict_list_node_t, + queue); + + ngx_slab_free_locked(ctx->shpool, lnode); + } + } + ngx_queue_remove(q); node = (ngx_rbtree_node_t *) @@ -753,7 +836,7 @@ ngx_http_lua_shdict_get_keys(lua_State *L) ngx_shmtx_lock(&ctx->shpool->mutex); - if (ngx_queue_empty(&ctx->sh->queue)) { + if (ngx_queue_empty(&ctx->sh->lru_queue)) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_createtable(L, 0, 0); return 1; @@ -765,9 +848,9 @@ ngx_http_lua_shdict_get_keys(lua_State *L) /* first run through: get total number of elements we need to allocate */ - q = ngx_queue_last(&ctx->sh->queue); + q = ngx_queue_last(&ctx->sh->lru_queue); - while (q != ngx_queue_sentinel(&ctx->sh->queue)) { + while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { prev = ngx_queue_prev(q); sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue); @@ -787,9 +870,9 @@ ngx_http_lua_shdict_get_keys(lua_State *L) /* second run through: add keys to table */ total = 0; - q = ngx_queue_last(&ctx->sh->queue); + q = ngx_queue_last(&ctx->sh->lru_queue); - while (q != ngx_queue_sentinel(&ctx->sh->queue)) { + while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { prev = ngx_queue_prev(q); sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue); @@ -870,6 +953,7 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) /* indicates whether to foricibly override other * valid entries */ int32_t user_flags = 0; + ngx_queue_t *queue, *q; n = lua_gettop(L); @@ -914,17 +998,18 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) value_type = lua_type(L, 3); switch (value_type) { - case LUA_TSTRING: + + case SHDICT_TSTRING: value.data = (u_char *) lua_tolstring(L, 3, &value.len); break; - case LUA_TNUMBER: + case SHDICT_TNUMBER: value.len = sizeof(double); num = lua_tonumber(L, 3); value.data = (u_char *) # break; - case LUA_TBOOLEAN: + case SHDICT_TBOOLEAN: value.len = sizeof(u_char); c = lua_toboolean(L, 3) ? 1 : 0; value.data = &c; @@ -1015,14 +1100,17 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) replace: - if (value.data && value.len == (size_t) sd->value_len) { + if (value.data + && value.len == (size_t) sd->value_len + && sd->value_type != SHDICT_TLIST) + { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: found old entry and value " "size matched, reusing it"); ngx_queue_remove(&sd->queue); - ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); sd->key_len = (u_short) key.len; @@ -1060,6 +1148,21 @@ replace: remove: + if (sd->value_type == SHDICT_TLIST) { + queue = ngx_http_lua_shdict_get_list_head(sd, key.len); + + for (q = ngx_queue_head(queue); + q != ngx_queue_sentinel(queue); + q = ngx_queue_next(q)) + { + p = (u_char *) ngx_queue_data(q, + ngx_http_lua_shdict_list_node_t, + queue); + + ngx_slab_free_locked(ctx->shpool, p); + } + } + ngx_queue_remove(&sd->queue); node = (ngx_rbtree_node_t *) @@ -1158,7 +1261,7 @@ allocated: ngx_rbtree_insert(&ctx->sh->rbtree, node); - ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); ngx_shmtx_unlock(&ctx->shpool->mutex); @@ -1172,21 +1275,27 @@ allocated: static int ngx_http_lua_shdict_incr(lua_State *L) { - int n; + int i, n; ngx_str_t key; uint32_t hash; ngx_int_t rc; ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; double num; + double init = 0; u_char *p; ngx_shm_zone_t *zone; double value; + ngx_rbtree_node_t *node; + /* indicates whether to foricibly override other + * valid entries */ + int forcible = 0; + ngx_queue_t *queue, *q; n = lua_gettop(L); - if (n != 3) { - return luaL_error(L, "expecting 3 arguments, but only seen %d", n); + if (n != 3 && n != 4) { + return luaL_error(L, "expecting 3 or 4 arguments, but only seen %d", n); } if (lua_type(L, 1) != LUA_TTABLE) { @@ -1224,6 +1333,10 @@ ngx_http_lua_shdict_incr(lua_State *L) value = luaL_checknumber(L, 3); + if (n == 4) { + init = luaL_checknumber(L, 4); + } + dd("looking up key %.*s in shared dict %.*s", (int) key.len, key.data, (int) ctx->name.len, ctx->name.data); @@ -1238,16 +1351,47 @@ ngx_http_lua_shdict_incr(lua_State *L) dd("shdict lookup returned %d", (int) rc); if (rc == NGX_DECLINED || rc == NGX_DONE) { - ngx_shmtx_unlock(&ctx->shpool->mutex); - lua_pushnil(L); - lua_pushliteral(L, "not found"); - return 2; + if (n == 3) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushnil(L); + lua_pushliteral(L, "not found"); + return 2; + } + + /* add value */ + num = value + init; + + if (rc == NGX_DONE) { + + /* found an expired item */ + + if ((size_t) sd->value_len == sizeof(double) + && sd->value_type != SHDICT_TLIST) + { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "lua shared dict incr: found old entry and " + "value size matched, reusing it"); + + ngx_queue_remove(&sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + + dd("go to setvalue"); + goto setvalue; + } + + dd("go to remove"); + goto remove; + } + + dd("go to insert"); + goto insert; } /* rc == NGX_OK */ - if (sd->value_type != LUA_TNUMBER || sd->value_len != sizeof(double)) { + if (sd->value_type != SHDICT_TNUMBER || sd->value_len != sizeof(double)) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushnil(L); @@ -1256,7 +1400,7 @@ ngx_http_lua_shdict_incr(lua_State *L) } ngx_queue_remove(&sd->queue); - ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); dd("setting value type to %d", (int) sd->value_type); @@ -1272,6 +1416,109 @@ ngx_http_lua_shdict_incr(lua_State *L) lua_pushnumber(L, num); lua_pushnil(L); return 2; + +remove: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "lua shared dict incr: found old entry but value size " + "NOT matched, removing it first"); + + if (sd->value_type == SHDICT_TLIST) { + queue = ngx_http_lua_shdict_get_list_head(sd, key.len); + + for (q = ngx_queue_head(queue); + q != ngx_queue_sentinel(queue); + q = ngx_queue_next(q)) + { + p = (u_char *) ngx_queue_data(q, + ngx_http_lua_shdict_list_node_t, + queue); + + ngx_slab_free_locked(ctx->shpool, p); + } + } + + ngx_queue_remove(&sd->queue); + + node = (ngx_rbtree_node_t *) + ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); + + ngx_rbtree_delete(&ctx->sh->rbtree, node); + + ngx_slab_free_locked(ctx->shpool, node); + +insert: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "lua shared dict incr: creating a new entry"); + + n = offsetof(ngx_rbtree_node_t, color) + + offsetof(ngx_http_lua_shdict_node_t, data) + + key.len + + sizeof(double); + + node = ngx_slab_alloc_locked(ctx->shpool, n); + + if (node == NULL) { + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "lua shared dict incr: overriding non-expired items " + "due to memory shortage for entry \"%V\"", &key); + + for (i = 0; i < 30; i++) { + if (ngx_http_lua_shdict_expire(ctx, 0) == 0) { + break; + } + + forcible = 1; + + node = ngx_slab_alloc_locked(ctx->shpool, n); + if (node != NULL) { + goto allocated; + } + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushboolean(L, 0); + lua_pushliteral(L, "no memory"); + lua_pushboolean(L, forcible); + return 3; + } + +allocated: + + sd = (ngx_http_lua_shdict_node_t *) &node->color; + + node->key = hash; + + sd->key_len = (u_short) key.len; + + sd->value_len = (uint32_t) sizeof(double); + + ngx_rbtree_insert(&ctx->sh->rbtree, node); + + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + +setvalue: + + sd->user_flags = 0; + + sd->expires = 0; + + dd("setting value type to %d", LUA_TNUMBER); + + sd->value_type = (uint8_t) LUA_TNUMBER; + + p = ngx_copy(sd->data, key.data, key.len); + ngx_memcpy(p, (double *) &num, sizeof(double)); + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushnumber(L, num); + lua_pushnil(L); + lua_pushboolean(L, forcible); + return 3; } @@ -1316,7 +1563,8 @@ ngx_http_lua_shared_dict_get(ngx_shm_zone_t *zone, u_char *key_data, len = (size_t) sd->value_len; switch (value->type) { - case LUA_TSTRING: + + case SHDICT_TSTRING: if (value->value.s.data == NULL || value->value.s.len == 0) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "no string buffer " @@ -1335,7 +1583,7 @@ ngx_http_lua_shared_dict_get(ngx_shm_zone_t *zone, u_char *key_data, ngx_memcpy(value->value.s.data, data, len); break; - case LUA_TNUMBER: + case SHDICT_TNUMBER: if (len != sizeof(double)) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua number " @@ -1349,7 +1597,7 @@ ngx_http_lua_shared_dict_get(ngx_shm_zone_t *zone, u_char *key_data, ngx_memcpy(&value->value.b, data, len); break; - case LUA_TBOOLEAN: + case SHDICT_TBOOLEAN: if (len != sizeof(u_char)) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua boolean " @@ -1377,6 +1625,574 @@ ngx_http_lua_shared_dict_get(ngx_shm_zone_t *zone, u_char *key_data, } +static int +ngx_http_lua_shdict_lpush(lua_State *L) +{ + return ngx_http_lua_shdict_push_helper(L, NGX_HTTP_LUA_SHDICT_LEFT); +} + + +static int +ngx_http_lua_shdict_rpush(lua_State *L) +{ + return ngx_http_lua_shdict_push_helper(L, NGX_HTTP_LUA_SHDICT_RIGHT); +} + + +static int +ngx_http_lua_shdict_push_helper(lua_State *L, int flags) +{ + int n; + ngx_str_t key; + uint32_t hash; + ngx_int_t rc; + ngx_http_lua_shdict_ctx_t *ctx; + ngx_http_lua_shdict_node_t *sd; + ngx_str_t value; + int value_type; + double num; + ngx_rbtree_node_t *node; + ngx_shm_zone_t *zone; + ngx_queue_t *queue, *q; + ngx_http_lua_shdict_list_node_t *lnode; + + n = lua_gettop(L); + + if (n != 3) { + return luaL_error(L, "expecting 3 arguments, " + "but only seen %d", n); + } + + if (lua_type(L, 1) != LUA_TTABLE) { + return luaL_error(L, "bad \"zone\" argument"); + } + + zone = ngx_http_lua_shdict_get_zone(L, 1); + if (zone == NULL) { + return luaL_error(L, "bad \"zone\" argument"); + } + + ctx = zone->data; + + if (lua_isnil(L, 2)) { + lua_pushnil(L); + lua_pushliteral(L, "nil key"); + return 2; + } + + key.data = (u_char *) luaL_checklstring(L, 2, &key.len); + + if (key.len == 0) { + lua_pushnil(L); + lua_pushliteral(L, "empty key"); + return 2; + } + + if (key.len > 65535) { + lua_pushnil(L); + lua_pushliteral(L, "key too long"); + return 2; + } + + hash = ngx_crc32_short(key.data, key.len); + + value_type = lua_type(L, 3); + + switch (value_type) { + + case SHDICT_TSTRING: + value.data = (u_char *) lua_tolstring(L, 3, &value.len); + break; + + case SHDICT_TNUMBER: + value.len = sizeof(double); + num = lua_tonumber(L, 3); + value.data = (u_char *) # + break; + + default: + lua_pushnil(L); + lua_pushliteral(L, "bad value type"); + return 2; + } + + ngx_shmtx_lock(&ctx->shpool->mutex); + +#if 1 + ngx_http_lua_shdict_expire(ctx, 1); +#endif + + rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); + + dd("shdict lookup returned %d", (int) rc); + + /* exists but expired */ + + if (rc == NGX_DONE) { + + if (sd->value_type != SHDICT_TLIST) { + /* TODO: reuse when length matched */ + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "lua shared dict push: found old entry and value " + "type not matched, remove it first"); + + ngx_queue_remove(&sd->queue); + + node = (ngx_rbtree_node_t *) + ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); + + ngx_rbtree_delete(&ctx->sh->rbtree, node); + + ngx_slab_free_locked(ctx->shpool, node); + + dd("go to init_list"); + goto init_list; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "lua shared dict push: found old entry and value " + "type matched, reusing it"); + + sd->expires = 0; + + /* free list nodes */ + + queue = ngx_http_lua_shdict_get_list_head(sd, key.len); + + for (q = ngx_queue_head(queue); + q != ngx_queue_sentinel(queue); + q = ngx_queue_next(q)) + { + /* TODO: reuse matched size list node */ + lnode = ngx_queue_data(q, ngx_http_lua_shdict_list_node_t, queue); + ngx_slab_free_locked(ctx->shpool, lnode); + } + + ngx_queue_init(queue); + + ngx_queue_remove(&sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + + dd("go to push_node"); + goto push_node; + } + + /* exists and not expired */ + + if (rc == NGX_OK) { + + if (sd->value_type != SHDICT_TLIST) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushnil(L); + lua_pushliteral(L, "value not a list"); + return 2; + } + + queue = ngx_http_lua_shdict_get_list_head(sd, key.len); + + ngx_queue_remove(&sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + + dd("go to push_node"); + goto push_node; + } + + /* rc == NGX_DECLINED, not found */ + +init_list: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "lua shared dict list: creating a new entry"); + + /* NOTICE: we assume the begin point aligned in slab, be careful */ + n = offsetof(ngx_rbtree_node_t, color) + + offsetof(ngx_http_lua_shdict_node_t, data) + + key.len + + sizeof(ngx_queue_t); + + dd("length before aligned: %d", n); + + n = (int) (uintptr_t) ngx_align_ptr(n, NGX_ALIGNMENT); + + dd("length after aligned: %d", n); + + node = ngx_slab_alloc_locked(ctx->shpool, n); + + if (node == NULL) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushboolean(L, 0); + lua_pushliteral(L, "no memory"); + return 2; + } + + sd = (ngx_http_lua_shdict_node_t *) &node->color; + + queue = ngx_http_lua_shdict_get_list_head(sd, key.len); + + node->key = hash; + sd->key_len = (u_short) key.len; + + sd->expires = 0; + + sd->value_len = 0; + + dd("setting value type to %d", (int) SHDICT_TLIST); + + sd->value_type = (uint8_t) SHDICT_TLIST; + + ngx_memcpy(sd->data, key.data, key.len); + + ngx_queue_init(queue); + + ngx_rbtree_insert(&ctx->sh->rbtree, node); + + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + +push_node: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "lua shared dict list: creating a new list node"); + + n = offsetof(ngx_http_lua_shdict_list_node_t, data) + + value.len; + + dd("list node length: %d", n); + + lnode = ngx_slab_alloc_locked(ctx->shpool, n); + + if (lnode == NULL) { + + if (sd->value_len == 0) { + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "lua shared dict list: no memory for create" + " list node and list empty, remove it"); + + ngx_queue_remove(&sd->queue); + + node = (ngx_rbtree_node_t *) + ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); + + ngx_rbtree_delete(&ctx->sh->rbtree, node); + + ngx_slab_free_locked(ctx->shpool, node); + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushboolean(L, 0); + lua_pushliteral(L, "no memory"); + return 2; + } + + dd("setting list length to %d", sd->value_len + 1); + + sd->value_len = sd->value_len + 1; + + dd("setting list node value length to %d", (int) value.len); + + lnode->value_len = (uint32_t) value.len; + + dd("setting list node value type to %d", value_type); + + lnode->value_type = (uint8_t) value_type; + + ngx_memcpy(lnode->data, value.data, value.len); + + if (flags == NGX_HTTP_LUA_SHDICT_LEFT) { + ngx_queue_insert_head(queue, &lnode->queue); + + } else { + ngx_queue_insert_tail(queue, &lnode->queue); + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushnumber(L, sd->value_len); + return 1; +} + + +static int +ngx_http_lua_shdict_lpop(lua_State *L) +{ + return ngx_http_lua_shdict_pop_helper(L, NGX_HTTP_LUA_SHDICT_LEFT); +} + + +static int +ngx_http_lua_shdict_rpop(lua_State *L) +{ + return ngx_http_lua_shdict_pop_helper(L, NGX_HTTP_LUA_SHDICT_RIGHT); +} + + +static int +ngx_http_lua_shdict_pop_helper(lua_State *L, int flags) +{ + int n; + ngx_str_t name; + ngx_str_t key; + uint32_t hash; + ngx_int_t rc; + ngx_http_lua_shdict_ctx_t *ctx; + ngx_http_lua_shdict_node_t *sd; + ngx_str_t value; + int value_type; + double num; + ngx_rbtree_node_t *node; + ngx_shm_zone_t *zone; + ngx_queue_t *queue; + ngx_http_lua_shdict_list_node_t *lnode; + + n = lua_gettop(L); + + if (n != 2) { + return luaL_error(L, "expecting 2 arguments, " + "but only seen %d", n); + } + + if (lua_type(L, 1) != LUA_TTABLE) { + return luaL_error(L, "bad \"zone\" argument"); + } + + zone = ngx_http_lua_shdict_get_zone(L, 1); + if (zone == NULL) { + return luaL_error(L, "bad \"zone\" argument"); + } + + ctx = zone->data; + name = ctx->name; + + if (lua_isnil(L, 2)) { + lua_pushnil(L); + lua_pushliteral(L, "nil key"); + return 2; + } + + key.data = (u_char *) luaL_checklstring(L, 2, &key.len); + + if (key.len == 0) { + lua_pushnil(L); + lua_pushliteral(L, "empty key"); + return 2; + } + + if (key.len > 65535) { + lua_pushnil(L); + lua_pushliteral(L, "key too long"); + return 2; + } + + hash = ngx_crc32_short(key.data, key.len); + + ngx_shmtx_lock(&ctx->shpool->mutex); + +#if 1 + ngx_http_lua_shdict_expire(ctx, 1); +#endif + + rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); + + dd("shdict lookup returned %d", (int) rc); + + if (rc == NGX_DECLINED || rc == NGX_DONE) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + lua_pushnil(L); + return 1; + } + + /* rc == NGX_OK */ + + if (sd->value_type != SHDICT_TLIST) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushnil(L); + lua_pushliteral(L, "value not a list"); + return 2; + } + + if (sd->value_len <= 0) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return luaL_error(L, "bad lua list length found for key %s " + "in shared_dict %s: %lu", key.data, name.data, + (unsigned long) sd->value_len); + } + + queue = ngx_http_lua_shdict_get_list_head(sd, key.len); + + if (flags == NGX_HTTP_LUA_SHDICT_LEFT) { + queue = ngx_queue_head(queue); + + } else { + queue = ngx_queue_last(queue); + } + + lnode = ngx_queue_data(queue, ngx_http_lua_shdict_list_node_t, queue); + + value_type = lnode->value_type; + + dd("data: %p", lnode->data); + dd("value len: %d", (int) sd->value_len); + + value.data = lnode->data; + value.len = (size_t) lnode->value_len; + + switch (value_type) { + + case SHDICT_TSTRING: + + lua_pushlstring(L, (char *) value.data, value.len); + break; + + case SHDICT_TNUMBER: + + if (value.len != sizeof(double)) { + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return luaL_error(L, "bad lua list node number value size found " + "for key %s in shared_dict %s: %lu", key.data, + name.data, (unsigned long) value.len); + } + + ngx_memcpy(&num, value.data, sizeof(double)); + + lua_pushnumber(L, num); + break; + + default: + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return luaL_error(L, "bad list node value type found for key %s in " + "shared_dict %s: %d", key.data, name.data, + value_type); + } + + ngx_queue_remove(queue); + + ngx_slab_free_locked(ctx->shpool, lnode); + + if (sd->value_len == 1) { + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "lua shared dict list: empty node after pop, " + "remove it"); + + ngx_queue_remove(&sd->queue); + + node = (ngx_rbtree_node_t *) + ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); + + ngx_rbtree_delete(&ctx->sh->rbtree, node); + + ngx_slab_free_locked(ctx->shpool, node); + + } else { + sd->value_len = sd->value_len - 1; + + ngx_queue_remove(&sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return 1; +} + + +static int +ngx_http_lua_shdict_llen(lua_State *L) +{ + int n; + ngx_str_t key; + uint32_t hash; + ngx_int_t rc; + ngx_http_lua_shdict_ctx_t *ctx; + ngx_http_lua_shdict_node_t *sd; + ngx_shm_zone_t *zone; + + n = lua_gettop(L); + + if (n != 2) { + return luaL_error(L, "expecting 2 arguments, " + "but only seen %d", n); + } + + if (lua_type(L, 1) != LUA_TTABLE) { + return luaL_error(L, "bad \"zone\" argument"); + } + + zone = ngx_http_lua_shdict_get_zone(L, 1); + if (zone == NULL) { + return luaL_error(L, "bad \"zone\" argument"); + } + + ctx = zone->data; + + if (lua_isnil(L, 2)) { + lua_pushnil(L); + lua_pushliteral(L, "nil key"); + return 2; + } + + key.data = (u_char *) luaL_checklstring(L, 2, &key.len); + + if (key.len == 0) { + lua_pushnil(L); + lua_pushliteral(L, "empty key"); + return 2; + } + + if (key.len > 65535) { + lua_pushnil(L); + lua_pushliteral(L, "key too long"); + return 2; + } + + hash = ngx_crc32_short(key.data, key.len); + + ngx_shmtx_lock(&ctx->shpool->mutex); + +#if 1 + ngx_http_lua_shdict_expire(ctx, 1); +#endif + + rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); + + dd("shdict lookup returned %d", (int) rc); + + if (rc == NGX_OK) { + + if (sd->value_type != SHDICT_TLIST) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushnil(L); + lua_pushliteral(L, "value not a list"); + return 2; + } + + ngx_queue_remove(&sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushnumber(L, (lua_Number) sd->value_len); + return 1; + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushnumber(L, 0); + return 1; +} + + ngx_shm_zone_t * ngx_http_lua_find_zone(u_char *name_data, size_t name_len) { @@ -1428,6 +2244,7 @@ ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, uint32_t hash; ngx_int_t rc; ngx_time_t *tp; + ngx_queue_t *queue, *q; ngx_rbtree_node_t *node; ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; @@ -1445,17 +2262,18 @@ ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, hash = ngx_crc32_short(key, key_len); switch (value_type) { - case LUA_TSTRING: + + case SHDICT_TSTRING: /* do nothing */ break; - case LUA_TNUMBER: + case SHDICT_TNUMBER: dd("num value: %lf", num_value); str_value_buf = (u_char *) &num_value; str_value_len = sizeof(double); break; - case LUA_TBOOLEAN: + case SHDICT_TBOOLEAN: c = num_value ? 1 : 0; str_value_buf = &c; str_value_len = sizeof(u_char); @@ -1493,6 +2311,7 @@ ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, *errmsg = "not found"; return NGX_DECLINED; } + /* rc == NGX_OK */ goto replace; @@ -1527,14 +2346,17 @@ ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, replace: - if (str_value_buf && str_value_len == (size_t) sd->value_len) { + if (str_value_buf + && str_value_len == (size_t) sd->value_len + && sd->value_type != SHDICT_TLIST) + { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: found old entry and value " "size matched, reusing it"); ngx_queue_remove(&sd->queue); - ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); sd->key_len = (u_short) key_len; @@ -1569,6 +2391,21 @@ replace: remove: + if (sd->value_type == SHDICT_TLIST) { + queue = ngx_http_lua_shdict_get_list_head(sd, key_len); + + for (q = ngx_queue_head(queue); + q != ngx_queue_sentinel(queue); + q = ngx_queue_next(q)) + { + p = (u_char *) ngx_queue_data(q, + ngx_http_lua_shdict_list_node_t, + queue); + + ngx_slab_free_locked(ctx->shpool, p); + } + } + ngx_queue_remove(&sd->queue); node = (ngx_rbtree_node_t *) @@ -1657,7 +2494,7 @@ allocated: ngx_memcpy(p, str_value_buf, str_value_len); ngx_rbtree_insert(&ctx->sh->rbtree, node); - ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_OK; @@ -1668,7 +2505,7 @@ int ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, size_t key_len, int *value_type, u_char **str_value_buf, size_t *str_value_len, double *num_value, int *user_flags, - int get_stale, int *is_stale) + int get_stale, int *is_stale, char **err) { ngx_str_t name; uint32_t hash; @@ -1681,6 +2518,8 @@ ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, return NGX_ERROR; } + *err = NULL; + ctx = zone->data; name = ctx->name; @@ -1721,12 +2560,12 @@ ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, value.len = (size_t) sd->value_len; if (*str_value_len < (size_t) value.len) { - if (*value_type == LUA_TBOOLEAN) { + if (*value_type == SHDICT_TBOOLEAN) { ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_ERROR; } - if (*value_type == LUA_TSTRING) { + if (*value_type == SHDICT_TSTRING) { *str_value_buf = malloc(value.len); if (*str_value_buf == NULL) { ngx_shmtx_unlock(&ctx->shpool->mutex); @@ -1736,12 +2575,13 @@ ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, } switch (*value_type) { - case LUA_TSTRING: + + case SHDICT_TSTRING: *str_value_len = value.len; ngx_memcpy(*str_value_buf, value.data, value.len); break; - case LUA_TNUMBER: + case SHDICT_TNUMBER: if (value.len != sizeof(double)) { ngx_shmtx_unlock(&ctx->shpool->mutex); @@ -1756,7 +2596,7 @@ ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, ngx_memcpy(num_value, value.data, sizeof(double)); break; - case LUA_TBOOLEAN: + case SHDICT_TBOOLEAN: if (value.len != sizeof(u_char)) { ngx_shmtx_unlock(&ctx->shpool->mutex); @@ -1770,6 +2610,13 @@ ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, ngx_memcpy(*str_value_buf, value.data, value.len); break; + case SHDICT_TLIST: + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + *err = "value is a list"; + return NGX_ERROR; + default: ngx_shmtx_unlock(&ctx->shpool->mutex); @@ -1799,16 +2646,27 @@ ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, int ngx_http_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, - size_t key_len, double *value, char **err) + size_t key_len, double *value, char **err, int has_init, double init, + int *forcible) { + int i, n; uint32_t hash; ngx_int_t rc; ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; double num; + ngx_rbtree_node_t *node; u_char *p; + ngx_queue_t *queue, *q; + + if (zone == NULL) { + return NGX_ERROR; + } ctx = zone->data; + + *forcible = 0; + hash = ngx_crc32_short(key, key_len); dd("looking up key %.*s in shared dict %.*s", (int) key_len, key, @@ -1823,21 +2681,51 @@ ngx_http_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, dd("shdict lookup returned %d", (int) rc); if (rc == NGX_DECLINED || rc == NGX_DONE) { - ngx_shmtx_unlock(&ctx->shpool->mutex); - *err = "not found"; - return NGX_ERROR; + if (!has_init) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + *err = "not found"; + return NGX_ERROR; + } + + /* add value */ + num = *value + init; + + if (rc == NGX_DONE) { + + /* found an expired item */ + + if ((size_t) sd->value_len == sizeof(double) + && sd->value_type != SHDICT_TLIST) + { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "lua shared dict incr: found old entry and " + "value size matched, reusing it"); + + ngx_queue_remove(&sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + + dd("go to setvalue"); + goto setvalue; + } + + dd("go to remove"); + goto remove; + } + + dd("go to insert"); + goto insert; } /* rc == NGX_OK */ - if (sd->value_type != LUA_TNUMBER || sd->value_len != sizeof(double)) { + if (sd->value_type != SHDICT_TNUMBER || sd->value_len != sizeof(double)) { ngx_shmtx_unlock(&ctx->shpool->mutex); *err = "not a number"; return NGX_ERROR; } ngx_queue_remove(&sd->queue); - ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); dd("setting value type to %d", (int) sd->value_type); @@ -1850,6 +2738,105 @@ ngx_http_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, ngx_shmtx_unlock(&ctx->shpool->mutex); + *value = num; + return NGX_OK; + +remove: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "lua shared dict incr: found old entry but value size " + "NOT matched, removing it first"); + + if (sd->value_type == SHDICT_TLIST) { + queue = ngx_http_lua_shdict_get_list_head(sd, key_len); + + for (q = ngx_queue_head(queue); + q != ngx_queue_sentinel(queue); + q = ngx_queue_next(q)) + { + p = (u_char *) ngx_queue_data(q, ngx_http_lua_shdict_list_node_t, + queue); + + ngx_slab_free_locked(ctx->shpool, p); + } + } + + ngx_queue_remove(&sd->queue); + + node = (ngx_rbtree_node_t *) + ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); + + ngx_rbtree_delete(&ctx->sh->rbtree, node); + + ngx_slab_free_locked(ctx->shpool, node); + +insert: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "lua shared dict incr: creating a new entry"); + + n = offsetof(ngx_rbtree_node_t, color) + + offsetof(ngx_http_lua_shdict_node_t, data) + + key_len + + sizeof(double); + + node = ngx_slab_alloc_locked(ctx->shpool, n); + + if (node == NULL) { + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "lua shared dict incr: overriding non-expired items " + "due to memory shortage for entry \"%*s\"", key_len, + key); + + for (i = 0; i < 30; i++) { + if (ngx_http_lua_shdict_expire(ctx, 0) == 0) { + break; + } + + *forcible = 1; + + node = ngx_slab_alloc_locked(ctx->shpool, n); + if (node != NULL) { + goto allocated; + } + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + *err = "no memory"; + return NGX_ERROR; + } + +allocated: + + sd = (ngx_http_lua_shdict_node_t *) &node->color; + + node->key = hash; + + sd->key_len = (u_short) key_len; + + sd->value_len = (uint32_t) sizeof(double); + + ngx_rbtree_insert(&ctx->sh->rbtree, node); + + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + +setvalue: + + sd->user_flags = 0; + + sd->expires = 0; + + dd("setting value type to %d", LUA_TNUMBER); + + sd->value_type = (uint8_t) LUA_TNUMBER; + + p = ngx_copy(sd->data, key, key_len); + ngx_memcpy(p, (double *) &num, sizeof(double)); + + ngx_shmtx_unlock(&ctx->shpool->mutex); + *value = num; return NGX_OK; } @@ -1866,8 +2853,8 @@ ngx_http_lua_ffi_shdict_flush_all(ngx_shm_zone_t *zone) ngx_shmtx_lock(&ctx->shpool->mutex); - for (q = ngx_queue_head(&ctx->sh->queue); - q != ngx_queue_sentinel(&ctx->sh->queue); + for (q = ngx_queue_head(&ctx->sh->lru_queue); + q != ngx_queue_sentinel(&ctx->sh->lru_queue); q = ngx_queue_next(q)) { sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.h b/debian/modules/nginx-lua/src/ngx_http_lua_shdict.h index aa1bb58..5c4ff36 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_shdict.h @@ -24,10 +24,18 @@ typedef struct { } ngx_http_lua_shdict_node_t; +typedef struct { + ngx_queue_t queue; + uint32_t value_len; + uint8_t value_type; + u_char data[1]; +} ngx_http_lua_shdict_list_node_t; + + typedef struct { ngx_rbtree_t rbtree; ngx_rbtree_node_t sentinel; - ngx_queue_t queue; + ngx_queue_t lru_queue; } ngx_http_lua_shdict_shctx_t; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c b/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c index a887c3a..4c0d016 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c @@ -56,7 +56,8 @@ ngx_http_lua_ngx_sleep(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); coctx = ctx->cur_co_ctx; if (coctx == NULL) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c index 2bfdbd3..fe6001f 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c @@ -386,7 +386,8 @@ ngx_http_lua_socket_tcp(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); lua_createtable(L, 3 /* narr */, 1 /* nrec */); lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key); @@ -444,7 +445,8 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); luaL_checktype(L, 1, LUA_TTABLE); @@ -4486,7 +4488,7 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) if (spool == NULL) { /* create a new socket pool for the current peer key */ - if (n == 3) { + if (n >= 3 && !lua_isnil(L, 3)) { pool_size = luaL_checkinteger(L, 3); } else { @@ -4589,7 +4591,7 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) ngx_del_timer(c->write); } - if (n >= 2) { + if (n >= 2 && !lua_isnil(L, 2)) { timeout = (ngx_msec_t) luaL_checkinteger(L, 2); } else { @@ -4902,7 +4904,7 @@ ngx_http_lua_socket_downstream_destroy(lua_State *L) { ngx_http_lua_socket_tcp_upstream_t *u; - dd("downstream destory"); + dd("downstream destroy"); u = lua_touserdata(L, 1); if (u == NULL) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl.c new file mode 100644 index 0000000..8ed7b95 --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl.c @@ -0,0 +1,37 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#if (NGX_HTTP_SSL) + + +int ngx_http_lua_ssl_ctx_index = -1; + + +ngx_int_t +ngx_http_lua_ssl_init(ngx_log_t *log) +{ + if (ngx_http_lua_ssl_ctx_index == -1) { + ngx_http_lua_ssl_ctx_index = SSL_get_ex_new_index(0, NULL, NULL, + NULL, NULL); + + if (ngx_http_lua_ssl_ctx_index == -1) { + ngx_ssl_error(NGX_LOG_ALERT, log, 0, + "lua: SSL_get_ex_new_index() for ctx failed"); + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +#endif /* NGX_HTTP_SSL */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl.h b/debian/modules/nginx-lua/src/ngx_http_lua_ssl.h new file mode 100644 index 0000000..7a245ff --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl.h @@ -0,0 +1,43 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_SSL_H_INCLUDED_ +#define _NGX_HTTP_LUA_SSL_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +#if (NGX_HTTP_SSL) +typedef struct { + ngx_connection_t *connection; /* original true connection */ + ngx_http_request_t *request; /* fake request */ + ngx_pool_cleanup_pt *cleanup; + + ngx_ssl_session_t *session; /* retrurn value for openssl's + * session_get_cb */ + + ngx_str_t session_id; + + int exit_code; /* exit code for openssl's + set_cert_cb callback */ + + unsigned done:1; + unsigned aborted:1; + + unsigned entered_cert_handler:1; + unsigned entered_sess_fetch_handler:1; +} ngx_http_lua_ssl_ctx_t; +#endif + + +ngx_int_t ngx_http_lua_ssl_init(ngx_log_t *log); + + +extern int ngx_http_lua_ssl_ctx_index; + + +#endif /* _NGX_HTTP_LUA_SSL_H_INCLUDED_ */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c index c06bc8e..aca4735 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c @@ -20,6 +20,7 @@ #include "ngx_http_lua_contentby.h" #include "ngx_http_lua_ssl_certby.h" #include "ngx_http_lua_directive.h" +#include "ngx_http_lua_ssl.h" enum { @@ -37,9 +38,6 @@ static ngx_int_t ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r); -int ngx_http_lua_ssl_ctx_index = -1; - - ngx_int_t ngx_http_lua_ssl_cert_handler_file(ngx_http_request_t *r, ngx_http_lua_srv_conf_t *lscf, lua_State *L) @@ -47,8 +45,8 @@ ngx_http_lua_ssl_cert_handler_file(ngx_http_request_t *r, ngx_int_t rc; rc = ngx_http_lua_cache_loadfile(r->connection->log, L, - lscf->ssl.cert_src.data, - lscf->ssl.cert_src_key); + lscf->srv.ssl_cert_src.data, + lscf->srv.ssl_cert_src_key); if (rc != NGX_OK) { return rc; } @@ -67,9 +65,9 @@ ngx_http_lua_ssl_cert_handler_inline(ngx_http_request_t *r, ngx_int_t rc; rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, - lscf->ssl.cert_src.data, - lscf->ssl.cert_src.len, - lscf->ssl.cert_src_key, + lscf->srv.ssl_cert_src.data, + lscf->srv.ssl_cert_src.len, + lscf->srv.ssl_cert_src_key, "=ssl_certificate_by_lua"); if (rc != NGX_OK) { return rc; @@ -120,29 +118,22 @@ ngx_http_lua_ssl_cert_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, ngx_str_t *value; ngx_http_lua_srv_conf_t *lscf = conf; - /* must specifiy a concrete handler */ + /* must specify a concrete handler */ if (cmd->post == NULL) { return NGX_CONF_ERROR; } - if (lscf->ssl.cert_handler) { + if (lscf->srv.ssl_cert_handler) { return "is duplicate"; } - if (ngx_http_lua_ssl_ctx_index == -1) { - ngx_http_lua_ssl_ctx_index = SSL_get_ex_new_index(0, NULL, NULL, - NULL, NULL); - - if (ngx_ssl_connection_index == -1) { - ngx_ssl_error(NGX_LOG_ALERT, cf->log, 0, - "lua: SSL_get_ex_new_index() failed"); - return NGX_CONF_ERROR; - } + if (ngx_http_lua_ssl_init(cf->log) != NGX_OK) { + return NGX_CONF_ERROR; } value = cf->args->elts; - lscf->ssl.cert_handler = (ngx_http_lua_srv_conf_handler_pt) cmd->post; + lscf->srv.ssl_cert_handler = (ngx_http_lua_srv_conf_handler_pt) cmd->post; if (cmd->post == ngx_http_lua_ssl_cert_handler_file) { /* Lua code in an external file */ @@ -153,15 +144,15 @@ ngx_http_lua_ssl_cert_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, return NGX_CONF_ERROR; } - lscf->ssl.cert_src.data = name; - lscf->ssl.cert_src.len = ngx_strlen(name); + lscf->srv.ssl_cert_src.data = name; + lscf->srv.ssl_cert_src.len = ngx_strlen(name); p = ngx_palloc(cf->pool, NGX_HTTP_LUA_FILE_KEY_LEN + 1); if (p == NULL) { return NGX_CONF_ERROR; } - lscf->ssl.cert_src_key = p; + lscf->srv.ssl_cert_src_key = p; p = ngx_copy(p, NGX_HTTP_LUA_FILE_TAG, NGX_HTTP_LUA_FILE_TAG_LEN); p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); @@ -170,14 +161,14 @@ ngx_http_lua_ssl_cert_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, } else { /* inlined Lua code */ - lscf->ssl.cert_src = value[1]; + lscf->srv.ssl_cert_src = value[1]; p = ngx_palloc(cf->pool, NGX_HTTP_LUA_INLINE_KEY_LEN + 1); if (p == NULL) { return NGX_CONF_ERROR; } - lscf->ssl.cert_src_key = p; + lscf->srv.ssl_cert_src_key = p; p = ngx_copy(p, NGX_HTTP_LUA_INLINE_TAG, NGX_HTTP_LUA_INLINE_TAG_LEN); p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); @@ -200,7 +191,8 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) ngx_pool_cleanup_t *cln; ngx_http_connection_t *hc; ngx_http_lua_srv_conf_t *lscf; - ngx_http_lua_ssl_cert_ctx_t *cctx; + ngx_http_core_loc_conf_t *clcf; + ngx_http_lua_ssl_ctx_t *cctx; c = ngx_ssl_get_connection(ssl_conn); @@ -210,7 +202,7 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) dd("ssl cert handler, cert-ctx=%p", cctx); - if (cctx) { + if (cctx && cctx->entered_cert_handler) { /* not the first time */ if (cctx->done) { @@ -225,8 +217,6 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) return -1; } - /* cctx == NULL */ - dd("first time"); hc = c->data; @@ -255,14 +245,42 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) fc->log->log_level = c->log->log_level; fc->ssl = c->ssl; - cctx = ngx_pcalloc(c->pool, sizeof(ngx_http_lua_ssl_cert_ctx_t)); + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + +#if defined(nginx_version) && nginx_version >= 1003014 + +# if nginx_version >= 1009000 + + ngx_set_connection_log(fc, clcf->error_log); + +# else + + ngx_http_set_connection_log(fc, clcf->error_log); + +# endif + +#else + + fc->log->file = clcf->error_log->file; + + if (!(fc->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { + fc->log->log_level = clcf->error_log->log_level; + } + +#endif + if (cctx == NULL) { - goto failed; /* error */ + cctx = ngx_pcalloc(c->pool, sizeof(ngx_http_lua_ssl_ctx_t)); + if (cctx == NULL) { + goto failed; /* error */ + } } cctx->exit_code = 1; /* successful by default */ cctx->connection = c; cctx->request = r; + cctx->entered_cert_handler = 1; + cctx->done = 0; dd("setting cctx"); @@ -280,11 +298,15 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) c->log->action = "loading SSL certificate by lua"; - rc = lscf->ssl.cert_handler(r, lscf, L); + rc = lscf->srv.ssl_cert_handler(r, lscf, L); if (rc >= NGX_OK || rc == NGX_ERROR) { cctx->done = 1; + if (cctx->cleanup) { + *cctx->cleanup = NULL; + } + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua_certificate_by_lua: handler return value: %i, " "cert cb exit code: %d", rc, cctx->exit_code); @@ -303,13 +325,17 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) cln->handler = ngx_http_lua_ssl_cert_done; cln->data = cctx; - cln = ngx_pool_cleanup_add(c->pool, 0); - if (cln == NULL) { - goto failed; + if (cctx->cleanup == NULL) { + cln = ngx_pool_cleanup_add(c->pool, 0); + if (cln == NULL) { + goto failed; + } + + cln->data = cctx; + cctx->cleanup = &cln->handler; } - cln->handler = ngx_http_lua_ssl_cert_aborted; - cln->data = cctx; + *cctx->cleanup = ngx_http_lua_ssl_cert_aborted; return -1; @@ -333,7 +359,7 @@ static void ngx_http_lua_ssl_cert_done(void *data) { ngx_connection_t *c; - ngx_http_lua_ssl_cert_ctx_t *cctx = data; + ngx_http_lua_ssl_ctx_t *cctx = data; dd("lua ssl cert done"); @@ -345,6 +371,10 @@ ngx_http_lua_ssl_cert_done(void *data) cctx->done = 1; + if (cctx->cleanup) { + *cctx->cleanup = NULL; + } + c = cctx->connection; c->log->action = "SSL handshaking"; @@ -356,7 +386,7 @@ ngx_http_lua_ssl_cert_done(void *data) static void ngx_http_lua_ssl_cert_aborted(void *data) { - ngx_http_lua_ssl_cert_ctx_t *cctx = data; + ngx_http_lua_ssl_ctx_t *cctx = data; dd("lua ssl cert done"); @@ -931,7 +961,7 @@ ngx_http_lua_ffi_priv_key_pem_to_der(const u_char *pem, size_t pem_len, pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); if (pkey == NULL) { BIO_free(in); - *err = "PEM_read_bio_PrivateKey failed"; + *err = "PEM_read_bio_PrivateKey() failed"; ERR_clear_error(); return NGX_ERROR; } @@ -941,7 +971,7 @@ ngx_http_lua_ffi_priv_key_pem_to_der(const u_char *pem, size_t pem_len, len = i2d_PrivateKey(pkey, &der); if (len < 0) { EVP_PKEY_free(pkey); - *err = "i2d_PrivateKey failed"; + *err = "i2d_PrivateKey() failed"; ERR_clear_error(); return NGX_ERROR; } @@ -952,6 +982,256 @@ ngx_http_lua_ffi_priv_key_pem_to_der(const u_char *pem, size_t pem_len, } +void * +ngx_http_lua_ffi_parse_pem_cert(const u_char *pem, size_t pem_len, + char **err) +{ + BIO *bio; + X509 *x509; + u_long n; + STACK_OF(X509) *chain; + + bio = BIO_new_mem_buf((char *) pem, (int) pem_len); + if (bio == NULL) { + *err = "BIO_new_mem_buf() failed"; + ERR_clear_error(); + return NULL; + } + + x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); + if (x509 == NULL) { + *err = "PEM_read_bio_X509_AUX() failed"; + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + chain = sk_X509_new_null(); + if (chain == NULL) { + *err = "sk_X509_new_null() failed"; + X509_free(x509); + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + if (sk_X509_push(chain, x509) == 0) { + *err = "sk_X509_push() failed"; + sk_X509_free(chain); + X509_free(x509); + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + /* read rest of the chain */ + + for ( ;; ) { + + x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); + if (x509 == NULL) { + n = ERR_peek_last_error(); + + if (ERR_GET_LIB(n) == ERR_LIB_PEM + && ERR_GET_REASON(n) == PEM_R_NO_START_LINE) + { + /* end of file */ + ERR_clear_error(); + break; + } + + /* some real error */ + + *err = "PEM_read_bio_X509() failed"; + sk_X509_pop_free(chain, X509_free); + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + if (sk_X509_push(chain, x509) == 0) { + *err = "sk_X509_push() failed"; + sk_X509_pop_free(chain, X509_free); + X509_free(x509); + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + } + + BIO_free(bio); + + return chain; +} + + +void +ngx_http_lua_ffi_free_cert(void *cdata) +{ + STACK_OF(X509) *chain = cdata; + + sk_X509_pop_free(chain, X509_free); +} + + +void * +ngx_http_lua_ffi_parse_pem_priv_key(const u_char *pem, size_t pem_len, + char **err) +{ + BIO *in; + EVP_PKEY *pkey; + + in = BIO_new_mem_buf((char *) pem, (int) pem_len); + if (in == NULL) { + *err = "BIO_new_mem_buf() failed"; + ERR_clear_error(); + return NULL; + } + + pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); + if (pkey == NULL) { + *err = "PEM_read_bio_PrivateKey() failed"; + BIO_free(in); + ERR_clear_error(); + return NULL; + } + + BIO_free(in); + + return pkey; +} + + +void +ngx_http_lua_ffi_free_priv_key(void *cdata) +{ + EVP_PKEY *pkey = cdata; + + EVP_PKEY_free(pkey); +} + + +int +ngx_http_lua_ffi_set_cert(ngx_http_request_t *r, + void *cdata, char **err) +{ +#ifdef LIBRESSL_VERSION_NUMBER + + *err = "LibreSSL not supported"; + return NGX_ERROR; + +#else + +# if OPENSSL_VERSION_NUMBER < 0x1000205fL + + *err = "at least OpenSSL 1.0.2e required but found " OPENSSL_VERSION_TEXT; + return NGX_ERROR; + +# else + + int i; + X509 *x509 = NULL; + ngx_ssl_conn_t *ssl_conn; + STACK_OF(X509) *chain = cdata; + + if (r->connection == NULL || r->connection->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = r->connection->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + if (sk_X509_num(chain) < 1) { + *err = "invalid certificate chain"; + goto failed; + } + + x509 = sk_X509_value(chain, 0); + if (x509 == NULL) { + *err = "sk_X509_value() failed"; + goto failed; + } + + if (SSL_use_certificate(ssl_conn, x509) == 0) { + *err = "SSL_use_certificate() failed"; + goto failed; + } + + x509 = NULL; + + /* read rest of the chain */ + + for (i = 1; i < sk_X509_num(chain); i++) { + + x509 = sk_X509_value(chain, i); + if (x509 == NULL) { + *err = "sk_X509_value() failed"; + goto failed; + } + + if (SSL_add1_chain_cert(ssl_conn, x509) == 0) { + *err = "SSL_add1_chain_cert() failed"; + goto failed; + } + } + + *err = NULL; + return NGX_OK; + +failed: + + ERR_clear_error(); + + return NGX_ERROR; + +# endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */ +#endif +} + + +int +ngx_http_lua_ffi_set_priv_key(ngx_http_request_t *r, + void *cdata, char **err) +{ + EVP_PKEY *pkey = NULL; + ngx_ssl_conn_t *ssl_conn; + + if (r->connection == NULL || r->connection->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = r->connection->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + pkey = cdata; + if (pkey == NULL) { + *err = "invalid private key failed"; + goto failed; + } + + if (SSL_use_PrivateKey(ssl_conn, pkey) == 0) { + *err = "SSL_use_PrivateKey() failed"; + goto failed; + } + + return NGX_OK; + +failed: + + ERR_clear_error(); + + return NGX_ERROR; +} + + #endif /* NGX_LUA_NO_FFI_API */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.h b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.h index 11cb963..fb07e01 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.h @@ -14,16 +14,6 @@ #if (NGX_HTTP_SSL) -typedef struct { - ngx_connection_t *connection; /* original true connection */ - ngx_http_request_t *request; /* fake request */ - int exit_code; /* exit code for openssl's - set_cert_cb callback */ - unsigned done; /* :1 */ - unsigned aborted; /* :1 */ -} ngx_http_lua_ssl_cert_ctx_t; - - ngx_int_t ngx_http_lua_ssl_cert_handler_inline(ngx_http_request_t *r, ngx_http_lua_srv_conf_t *lscf, lua_State *L); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c index 1bf4335..3904aa8 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c @@ -233,8 +233,6 @@ ngx_http_lua_ffi_ssl_create_ocsp_request(const char *chain_data, X509_free(cert); BIO_free(bio); - ERR_clear_error(); - return NGX_OK; failed: @@ -255,6 +253,8 @@ failed: BIO_free(bio); } + ERR_clear_error(); + return rc; #endif /* NGX_HTTP_LUA_USE_OCSP */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.c new file mode 100644 index 0000000..4c450b5 --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.c @@ -0,0 +1,592 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#if (NGX_HTTP_SSL) + + +#include "ngx_http_lua_cache.h" +#include "ngx_http_lua_initworkerby.h" +#include "ngx_http_lua_util.h" +#include "ngx_http_ssl_module.h" +#include "ngx_http_lua_contentby.h" +#include "ngx_http_lua_ssl_session_fetchby.h" +#include "ngx_http_lua_ssl.h" +#include "ngx_http_lua_directive.h" + + +/* Lua SSL cached session loading routines */ +static void ngx_http_lua_ssl_sess_fetch_done(void *data); +static void ngx_http_lua_ssl_sess_fetch_aborted(void *data); +static u_char *ngx_http_lua_log_ssl_sess_fetch_error(ngx_log_t *log, + u_char *buf, size_t len); +static ngx_int_t ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, + ngx_http_request_t *r); + + +/* load Lua code from a file for fetching cached SSL session */ +ngx_int_t +ngx_http_lua_ssl_sess_fetch_handler_file(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L) +{ + ngx_int_t rc; + + rc = ngx_http_lua_cache_loadfile(r->connection->log, L, + lscf->srv.ssl_sess_fetch_src.data, + lscf->srv.ssl_sess_fetch_src_key); + if (rc != NGX_OK) { + return rc; + } + + /* make sure we have a valid code chunk */ + ngx_http_lua_assert(lua_isfunction(L, -1)); + + return ngx_http_lua_ssl_sess_fetch_by_chunk(L, r); +} + + +/* load lua code from an inline snippet for fetching cached SSL session */ +ngx_int_t +ngx_http_lua_ssl_sess_fetch_handler_inline(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L) +{ + ngx_int_t rc; + + rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, + lscf->srv.ssl_sess_fetch_src.data, + lscf->srv.ssl_sess_fetch_src.len, + lscf->srv.ssl_sess_fetch_src_key, + "=ssl_session_fetch_by_lua_block"); + if (rc != NGX_OK) { + return rc; + } + + /* make sure we have a valid code chunk */ + ngx_http_lua_assert(lua_isfunction(L, -1)); + + return ngx_http_lua_ssl_sess_fetch_by_chunk(L, r); +} + + +char * +ngx_http_lua_ssl_sess_fetch_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_ssl_sess_fetch_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + +/* conf parser for directive ssl_session_fetch_by_lua */ +char * +ngx_http_lua_ssl_sess_fetch_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + u_char *p; + u_char *name; + ngx_str_t *value; + ngx_http_lua_srv_conf_t *lscf = conf; + + dd("enter"); + + /* must specifiy a content handler */ + if (cmd->post == NULL) { + return NGX_CONF_ERROR; + } + + if (lscf->srv.ssl_sess_fetch_handler) { + return "is duplicate"; + } + + if (ngx_http_lua_ssl_init(cf->log) != NGX_OK) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + lscf->srv.ssl_sess_fetch_handler = + (ngx_http_lua_srv_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_http_lua_ssl_sess_fetch_handler_file) { + /* Lua code in an external file */ + + name = ngx_http_lua_rebase_path(cf->pool, value[1].data, + value[1].len); + if (name == NULL) { + return NGX_CONF_ERROR; + } + + lscf->srv.ssl_sess_fetch_src.data = name; + lscf->srv.ssl_sess_fetch_src.len = ngx_strlen(name); + + p = ngx_palloc(cf->pool, NGX_HTTP_LUA_FILE_KEY_LEN + 1); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + lscf->srv.ssl_sess_fetch_src_key = p; + + p = ngx_copy(p, NGX_HTTP_LUA_FILE_TAG, NGX_HTTP_LUA_FILE_TAG_LEN); + p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); + *p = '\0'; + + } else { + /* inlined Lua code */ + + lscf->srv.ssl_sess_fetch_src = value[1]; + + p = ngx_palloc(cf->pool, NGX_HTTP_LUA_INLINE_KEY_LEN + 1); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + lscf->srv.ssl_sess_fetch_src_key = p; + + p = ngx_copy(p, NGX_HTTP_LUA_INLINE_TAG, NGX_HTTP_LUA_INLINE_TAG_LEN); + p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); + *p = '\0'; + } + + return NGX_CONF_OK; +} + + +/* cached session fetching callback to be set with SSL_CTX_sess_set_get_cb */ +ngx_ssl_session_t * +ngx_http_lua_ssl_sess_fetch_handler(ngx_ssl_conn_t *ssl_conn, u_char *id, + int len, int *copy) +{ + lua_State *L; + ngx_int_t rc; + ngx_connection_t *c, *fc = NULL; + ngx_http_request_t *r = NULL; + ngx_pool_cleanup_t *cln; + ngx_http_connection_t *hc; + ngx_http_lua_ssl_ctx_t *cctx; + ngx_http_lua_srv_conf_t *lscf; + ngx_http_core_loc_conf_t *clcf; + + /* set copy to 0 as we expect OpenSSL to handle + * the memory of returned session */ + + *copy = 0; + + c = ngx_ssl_get_connection(ssl_conn); + + dd("c = %p", c); + + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + + dd("ssl sess_fetch handler, sess_fetch-ctx=%p", cctx); + + if (cctx && cctx->entered_sess_fetch_handler) { + /* not the first time */ + + dd("here: %d", (int) cctx->entered_sess_fetch_handler); + + if (cctx->done) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl_session_fetch_by_lua*: " + "sess get cb exit code: %d", + cctx->exit_code); + + dd("lua ssl sess_fetch done, finally"); + return cctx->session; + } + +#ifdef SSL_ERROR_PENDING_SESSION + return SSL_magic_pending_session_ptr(); +#else + ngx_log_error(NGX_LOG_CRIT, c->log, 0, + "lua: cannot yield in sess get cb: " + "missing async sess get cb support in OpenSSL"); + return NULL; +#endif + } + + dd("first time"); + + hc = c->data; + + fc = ngx_http_lua_create_fake_connection(NULL); + if (fc == NULL) { + goto failed; + } + + fc->log->handler = ngx_http_lua_log_ssl_sess_fetch_error; + fc->log->data = fc; + + fc->addr_text = c->addr_text; + fc->listening = c->listening; + + r = ngx_http_lua_create_fake_request(fc); + if (r == NULL) { + goto failed; + } + + r->main_conf = hc->conf_ctx->main_conf; + r->srv_conf = hc->conf_ctx->srv_conf; + r->loc_conf = hc->conf_ctx->loc_conf; + + fc->log->file = c->log->file; + fc->log->log_level = c->log->log_level; + fc->ssl = c->ssl; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + +#if defined(nginx_version) && nginx_version >= 1003014 + +# if nginx_version >= 1009000 + + ngx_set_connection_log(fc, clcf->error_log); + +# else + + ngx_http_set_connection_log(fc, clcf->error_log); + +# endif + +#else + + fc->log->file = clcf->error_log->file; + + if (!(fc->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { + fc->log->log_level = clcf->error_log->log_level; + } + +#endif + + if (cctx == NULL) { + cctx = ngx_pcalloc(c->pool, sizeof(ngx_http_lua_ssl_ctx_t)); + if (cctx == NULL) { + goto failed; /* error */ + } + } + + cctx->exit_code = 1; /* successful by default */ + cctx->connection = c; + cctx->request = r; + cctx->session_id.data = id; + cctx->session_id.len = len; + cctx->entered_sess_fetch_handler = 1; + cctx->done = 0; + + dd("setting cctx = %p", cctx); + + if (SSL_set_ex_data(c->ssl->connection, ngx_http_lua_ssl_ctx_index, cctx) + == 0) + { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed"); + goto failed; + } + + lscf = ngx_http_get_module_srv_conf(r, ngx_http_lua_module); + + /* TODO honor lua_code_cache off */ + L = ngx_http_lua_get_lua_vm(r, NULL); + + c->log->action = "fetching SSL session by lua"; + + rc = lscf->srv.ssl_sess_fetch_handler(r, lscf, L); + + if (rc >= NGX_OK || rc == NGX_ERROR) { + cctx->done = 1; + + if (cctx->cleanup) { + *cctx->cleanup = NULL; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl_session_fetch_by_lua*: handler return value: %i, " + "sess get cb exit code: %d", rc, cctx->exit_code); + + c->log->action = "SSL handshaking"; + return cctx->session; + } + + /* rc == NGX_DONE */ + + cln = ngx_pool_cleanup_add(fc->pool, 0); + if (cln == NULL) { + goto failed; + } + + cln->handler = ngx_http_lua_ssl_sess_fetch_done; + cln->data = cctx; + + if (cctx->cleanup == NULL) { + /* we only want exactly one cleanup handler to be registered with the + * connection to clean up cctx when connection is aborted */ + cln = ngx_pool_cleanup_add(c->pool, 0); + if (cln == NULL) { + goto failed; + } + + cln->data = cctx; + cctx->cleanup = &cln->handler; + } + + *cctx->cleanup = ngx_http_lua_ssl_sess_fetch_aborted; + +#ifdef SSL_ERROR_PENDING_SESSION + return SSL_magic_pending_session_ptr(); +#else + ngx_log_error(NGX_LOG_CRIT, c->log, 0, + "lua: cannot yield in sess get cb: " + "missing async sess get cb support in OpenSSL"); + + /* fall through to the "failed" label below */ +#endif + +failed: + + if (r && r->pool) { + ngx_http_lua_free_fake_request(r); + } + + if (fc) { + ngx_http_lua_close_fake_connection(fc); + } + + return NULL; +} + + +static void +ngx_http_lua_ssl_sess_fetch_done(void *data) +{ + ngx_connection_t *c; + ngx_http_lua_ssl_ctx_t *cctx = data; + + dd("lua ssl sess_fetch done"); + + if (cctx->aborted) { + return; + } + + ngx_http_lua_assert(cctx->done == 0); + + cctx->done = 1; + + if (cctx->cleanup) { + *cctx->cleanup = NULL; + } + + c = cctx->connection; + + c->log->action = "SSL handshaking"; + + ngx_post_event(c->write, &ngx_posted_events); +} + + +static void +ngx_http_lua_ssl_sess_fetch_aborted(void *data) +{ + ngx_http_lua_ssl_ctx_t *cctx = data; + + dd("lua ssl sess_fetch done"); + + if (cctx->done) { + /* completed successfully already */ + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cctx->connection->log, 0, + "ssl_session_fetch_by_lua*: sess_fetch cb aborted"); + + cctx->aborted = 1; + cctx->request->connection->ssl = NULL; + + ngx_http_lua_finalize_fake_request(cctx->request, NGX_ERROR); +} + + +static u_char * +ngx_http_lua_log_ssl_sess_fetch_error(ngx_log_t *log, u_char *buf, size_t len) +{ + u_char *p; + ngx_connection_t *c; + + if (log->action) { + p = ngx_snprintf(buf, len, " while %s", log->action); + len -= p - buf; + buf = p; + } + + p = ngx_snprintf(buf, len, ", context: ssl_session_fetch_by_lua*"); + len -= p - buf; + buf = p; + + c = log->data; + + if (c->addr_text.len) { + p = ngx_snprintf(buf, len, ", client: %V", &c->addr_text); + len -= p - buf; + buf = p; + } + + if (c && c->listening && c->listening->addr_text.len) { + p = ngx_snprintf(buf, len, ", server: %V", &c->listening->addr_text); + buf = p; + } + + return buf; +} + + +/* initialize lua coroutine for fetching cached session */ +static ngx_int_t +ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) +{ + int co_ref; + ngx_int_t rc; + lua_State *co; + ngx_http_lua_ctx_t *ctx; + ngx_http_cleanup_t *cln; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + if (ctx == NULL) { + ctx = ngx_http_lua_create_ctx(r); + if (ctx == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + } else { + dd("reset ctx"); + ngx_http_lua_reset_ctx(r, L, ctx); + } + + ctx->entered_content_phase = 1; + + /* {{{ new coroutine to handle request */ + co = ngx_http_lua_new_thread(r, L, &co_ref); + + if (co == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "lua: failed to create new coroutine to handle request"); + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + /* move code closure to new coroutine */ + lua_xmove(L, co, 1); + + /* set closure's env table to new coroutine's globals table */ + ngx_http_lua_get_globals_table(co); + lua_setfenv(co, -2); + + /* save nginx request in coroutine globals table */ + ngx_http_lua_set_req(co, r); + + ctx->cur_co_ctx = &ctx->entry_co_ctx; + ctx->cur_co_ctx->co = co; + ctx->cur_co_ctx->co_ref = co_ref; +#ifdef NGX_LUA_USE_ASSERT + ctx->cur_co_ctx->co_top = 1; +#endif + + /* register request cleanup hooks */ + if (ctx->cleanup == NULL) { + cln = ngx_http_cleanup_add(r, 0); + if (cln == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + cln->handler = ngx_http_lua_request_cleanup_handler; + cln->data = ctx; + ctx->cleanup = &cln->handler; + } + + ctx->context = NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH; + + rc = ngx_http_lua_run_thread(L, r, ctx, 0); + + if (rc == NGX_ERROR || rc >= NGX_OK) { + /* do nothing */ + + } else if (rc == NGX_AGAIN) { + rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 0); + + } else if (rc == NGX_DONE) { + rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 1); + + } else { + rc = NGX_OK; + } + + ngx_http_lua_finalize_request(r, rc); + return rc; +} + + +#ifndef NGX_LUA_NO_FFI_API + +/* de-serialized a SSL session and set it back to the request at lua context */ +int +ngx_http_lua_ffi_ssl_set_serialized_session(ngx_http_request_t *r, + const unsigned char *data, int len, char **err) +{ + u_char *p; + u_char buf[NGX_SSL_MAX_SESSION_SIZE]; + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + ngx_ssl_session_t *session = NULL; + ngx_http_lua_ssl_ctx_t *cctx; + + c = r->connection; + + if (c == NULL || c->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = c->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + ngx_memcpy(buf, data, len); + p = buf; + session = d2i_SSL_SESSION(NULL, (const unsigned char **)&p, len); + if (session == NULL) { + ERR_clear_error(); + *err = "failed to de-serialize session"; + return NGX_ERROR; + } + + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + if (cctx == NULL) { + *err = "bad lua context"; + return NGX_ERROR; + } + + cctx->session = session; + + return NGX_OK; +} + +#endif /* NGX_LUA_NO_FFI_API */ + + +#endif /* NGX_HTTP_SSL */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.h b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.h new file mode 100644 index 0000000..5a6f96f --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.h @@ -0,0 +1,34 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_SSL_SESSION_FETCHBY_H_INCLUDED_ +#define _NGX_HTTP_LUA_SSL_SESSION_FETCHBY_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +#if (NGX_HTTP_SSL) +ngx_int_t ngx_http_lua_ssl_sess_fetch_handler_inline(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L); + +ngx_int_t ngx_http_lua_ssl_sess_fetch_handler_file(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L); + +char *ngx_http_lua_ssl_sess_fetch_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + +char *ngx_http_lua_ssl_sess_fetch_by_lua_block(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + +ngx_ssl_session_t *ngx_http_lua_ssl_sess_fetch_handler( + ngx_ssl_conn_t *ssl_conn, u_char *id, int len, int *copy); +#endif + + +#endif /* _NGX_HTTP_LUA_SSL_SESSION_FETCHBY_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.c new file mode 100644 index 0000000..b5596bc --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.c @@ -0,0 +1,602 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#if (NGX_HTTP_SSL) + + +#include "ngx_http_lua_cache.h" +#include "ngx_http_lua_initworkerby.h" +#include "ngx_http_lua_util.h" +#include "ngx_http_ssl_module.h" +#include "ngx_http_lua_contentby.h" +#include "ngx_http_lua_ssl_session_storeby.h" +#include "ngx_http_lua_ssl.h" +#include "ngx_http_lua_directive.h" + + +/* Lua SSL new session store routines */ +static u_char *ngx_http_lua_log_ssl_sess_store_error(ngx_log_t *log, + u_char *buf, size_t len); +static ngx_int_t ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, + ngx_http_request_t *r); + + +/* load Lua code from a file for caching new SSL session. */ +ngx_int_t +ngx_http_lua_ssl_sess_store_handler_file(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L) +{ + ngx_int_t rc; + + rc = ngx_http_lua_cache_loadfile(r->connection->log, L, + lscf->srv.ssl_sess_store_src.data, + lscf->srv.ssl_sess_store_src_key); + if (rc != NGX_OK) { + return rc; + } + + /* make sure we have a valid code chunk */ + ngx_http_lua_assert(lua_isfunction(L, -1)); + + return ngx_http_lua_ssl_sess_store_by_chunk(L, r); +} + + +/* load lua code from an inline snippet for caching new SSL session */ +ngx_int_t +ngx_http_lua_ssl_sess_store_handler_inline(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L) +{ + ngx_int_t rc; + + rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, + lscf->srv.ssl_sess_store_src.data, + lscf->srv.ssl_sess_store_src.len, + lscf->srv.ssl_sess_store_src_key, + "=ssl_session_store_by_lua_block"); + if (rc != NGX_OK) { + return rc; + } + + /* make sure we have a valid code chunk */ + ngx_http_lua_assert(lua_isfunction(L, -1)); + + return ngx_http_lua_ssl_sess_store_by_chunk(L, r); +} + + +char * +ngx_http_lua_ssl_sess_store_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_ssl_sess_store_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + +/* conf parser for directive ssl_session_store_by_lua */ +char * +ngx_http_lua_ssl_sess_store_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + u_char *p; + u_char *name; + ngx_str_t *value; + ngx_http_lua_srv_conf_t *lscf = conf; + + dd("enter"); + + /* must specifiy a content handler */ + if (cmd->post == NULL) { + return NGX_CONF_ERROR; + } + + if (lscf->srv.ssl_sess_store_handler) { + return "is duplicate"; + } + + if (ngx_http_lua_ssl_init(cf->log) != NGX_OK) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + lscf->srv.ssl_sess_store_handler = + (ngx_http_lua_srv_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_http_lua_ssl_sess_store_handler_file) { + /* Lua code in an external file */ + + name = ngx_http_lua_rebase_path(cf->pool, value[1].data, + value[1].len); + if (name == NULL) { + return NGX_CONF_ERROR; + } + + lscf->srv.ssl_sess_store_src.data = name; + lscf->srv.ssl_sess_store_src.len = ngx_strlen(name); + + p = ngx_palloc(cf->pool, NGX_HTTP_LUA_FILE_KEY_LEN + 1); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + lscf->srv.ssl_sess_store_src_key = p; + + p = ngx_copy(p, NGX_HTTP_LUA_FILE_TAG, NGX_HTTP_LUA_FILE_TAG_LEN); + p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); + *p = '\0'; + + } else { + /* inlined Lua code */ + + lscf->srv.ssl_sess_store_src = value[1]; + + p = ngx_palloc(cf->pool, NGX_HTTP_LUA_INLINE_KEY_LEN + 1); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + lscf->srv.ssl_sess_store_src_key = p; + + p = ngx_copy(p, NGX_HTTP_LUA_INLINE_TAG, NGX_HTTP_LUA_INLINE_TAG_LEN); + p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len); + *p = '\0'; + } + + return NGX_CONF_OK; +} + + +/* callback for new session caching, to be set with SSL_CTX_sess_set_new_cb */ +int +ngx_http_lua_ssl_sess_store_handler(ngx_ssl_conn_t *ssl_conn, + ngx_ssl_session_t *sess) +{ + lua_State *L; + ngx_int_t rc; + ngx_connection_t *c, *fc = NULL; + ngx_http_request_t *r = NULL; + ngx_http_connection_t *hc; + ngx_http_lua_ssl_ctx_t *cctx; + ngx_http_lua_srv_conf_t *lscf; + ngx_http_core_loc_conf_t *clcf; + + c = ngx_ssl_get_connection(ssl_conn); + + dd("c = %p", c); + + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + + dd("ssl sess_store handler, sess_store-ctx=%p", cctx); + + hc = c->data; + + fc = ngx_http_lua_create_fake_connection(NULL); + if (fc == NULL) { + goto failed; + } + + fc->log->handler = ngx_http_lua_log_ssl_sess_store_error; + fc->log->data = fc; + + fc->addr_text = c->addr_text; + fc->listening = c->listening; + + r = ngx_http_lua_create_fake_request(fc); + if (r == NULL) { + goto failed; + } + + r->main_conf = hc->conf_ctx->main_conf; + r->srv_conf = hc->conf_ctx->srv_conf; + r->loc_conf = hc->conf_ctx->loc_conf; + + fc->log->file = c->log->file; + fc->log->log_level = c->log->log_level; + fc->ssl = c->ssl; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + +#if defined(nginx_version) && nginx_version >= 1003014 + +# if nginx_version >= 1009000 + + ngx_set_connection_log(fc, clcf->error_log); + +# else + + ngx_http_set_connection_log(fc, clcf->error_log); + +# endif + +#else + + fc->log->file = clcf->error_log->file; + + if (!(fc->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { + fc->log->log_level = clcf->error_log->log_level; + } + +#endif + + if (cctx == NULL) { + cctx = ngx_pcalloc(c->pool, sizeof(ngx_http_lua_ssl_ctx_t)); + if (cctx == NULL) { + goto failed; /* error */ + } + } + + cctx->connection = c; + cctx->request = r; + cctx->session = sess; + cctx->session_id.data = sess->session_id; + cctx->session_id.len = sess->session_id_length; + cctx->done = 0; + + dd("setting cctx"); + + if (SSL_set_ex_data(c->ssl->connection, ngx_http_lua_ssl_ctx_index, cctx) + == 0) + { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed"); + goto failed; + } + + lscf = ngx_http_get_module_srv_conf(r, ngx_http_lua_module); + + /* TODO honor lua_code_cache off */ + L = ngx_http_lua_get_lua_vm(r, NULL); + + c->log->action = "storing SSL session by lua"; + + rc = lscf->srv.ssl_sess_store_handler(r, lscf, L); + + if (rc >= NGX_OK || rc == NGX_ERROR) { + cctx->done = 1; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl_session_store_by_lua*: handler return value: %i, " + "sess new cb exit code: %d", rc, cctx->exit_code); + + c->log->action = "SSL handshaking"; + + /* Return value is a flag indicating whether the passed-in session + * has been freed by this callback; always return 0 so OpenSSL will + * free the session. Nginx's own session caching logic has the same + * practice. */ + return 0; + } + + /* impossible to reach here */ + ngx_http_lua_assert(0); + +failed: + + if (r && r->pool) { + ngx_http_lua_free_fake_request(r); + } + + if (fc) { + ngx_http_lua_close_fake_connection(fc); + } + + return 0; +} + + +static u_char * +ngx_http_lua_log_ssl_sess_store_error(ngx_log_t *log, u_char *buf, size_t len) +{ + u_char *p; + ngx_connection_t *c; + + if (log->action) { + p = ngx_snprintf(buf, len, " while %s", log->action); + len -= p - buf; + buf = p; + } + + p = ngx_snprintf(buf, len, ", context: ssl_session_store_by_lua*"); + len -= p - buf; + buf = p; + + c = log->data; + + if (c->addr_text.len) { + p = ngx_snprintf(buf, len, ", client: %V", &c->addr_text); + len -= p - buf; + buf = p; + } + + if (c && c->listening && c->listening->addr_text.len) { + p = ngx_snprintf(buf, len, ", server: %V", &c->listening->addr_text); + buf = p; + } + + return buf; +} + + +/* initialize lua coroutine for caching new SSL session */ +static ngx_int_t +ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) +{ + size_t len; + u_char *err_msg; + ngx_int_t rc; + ngx_http_lua_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + if (ctx == NULL) { + ctx = ngx_http_lua_create_ctx(r); + if (ctx == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + } else { + dd("reset ctx"); + ngx_http_lua_reset_ctx(r, L, ctx); + } + + ctx->entered_content_phase = 1; + ctx->context = NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE; + + /* init nginx context in Lua VM */ + ngx_http_lua_set_req(L, r); + ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); + + /* {{{ make new env inheriting main thread's globals table */ + lua_createtable(L, 0, 1 /* nrec */); /* the metatable for the new env */ + ngx_http_lua_get_globals_table(L); + lua_setfield(L, -2, "__index"); + lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */ + /* }}} */ + + lua_setfenv(L, -2); /* set new running env for the code closure */ + + lua_pushcfunction(L, ngx_http_lua_traceback); + lua_insert(L, 1); /* put it under chunk and args */ + + /* protected call user code */ + rc = lua_pcall(L, 0, 1, 1); + + lua_remove(L, 1); /* remove traceback function */ + + dd("rc == %d", (int) rc); + + if (rc != 0) { + /* error occured when running loaded code */ + err_msg = (u_char *) lua_tolstring(L, -1, &len); + + if (err_msg == NULL) { + err_msg = (u_char *) "unknown reason"; + len = sizeof("unknown reason") - 1; + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "failed to run session_store_by_lua*: %*s", len, err_msg); + + lua_settop(L, 0); /* clear remaining elems on stack */ + ngx_http_lua_finalize_request(r, rc); + + return NGX_ERROR; + } + + lua_settop(L, 0); /* clear remaining elems on stack */ + ngx_http_lua_finalize_request(r, rc); + return rc; +} + + +#ifndef NGX_LUA_NO_FFI_API + +/* serialize a session from lua context into buf. + * the memory allocation of buf should be handled externally. */ +int +ngx_http_lua_ffi_ssl_get_serialized_session(ngx_http_request_t *r, + u_char *buf, char **err) +{ + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + ngx_ssl_session_t *session; + ngx_http_lua_ssl_ctx_t *cctx; + + c = r->connection; + + if (c == NULL || c->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = c->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + dd("get cctx session"); + + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + if (cctx == NULL) { + *err = "bad lua context"; + return NGX_ERROR; + } + + session = cctx->session; + if (session == NULL) { + *err = "bad session in lua context"; + return NGX_ERROR; + } + + if (i2d_SSL_SESSION(session, &buf) == 0) { + *err = "i2d_SSL_SESSION() failed"; + return NGX_ERROR; + } + + return NGX_OK; +} + + +/* return the size of serialized session. */ +int +ngx_http_lua_ffi_ssl_get_serialized_session_size(ngx_http_request_t *r, + char **err) +{ + int len; + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + ngx_ssl_session_t *session; + ngx_http_lua_ssl_ctx_t *cctx; + + c = r->connection; + + if (c == NULL || c->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = c->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + dd("get cctx session size"); + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + if (cctx == NULL) { + *err = "bad lua context"; + return NGX_ERROR; + } + + session = cctx->session; + if (session == NULL) { + *err = "bad session in lua context"; + return NGX_ERROR; + } + + len = i2d_SSL_SESSION(session, NULL); + if (len == 0) { + *err = "i2d_SSL_SESSION() failed"; + return NGX_ERROR; + } + + return len; +} + + +/* serialize the session id from lua context into buf. + * the memory allocation of buf should be handled externally. */ +int +ngx_http_lua_ffi_ssl_get_session_id(ngx_http_request_t *r, + u_char *buf, char **err) +{ + int id_len; + u_char *id; + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + ngx_http_lua_ssl_ctx_t *cctx; + + c = r->connection; + + if (c == NULL || c->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = c->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + dd("get cctx session"); + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + if (cctx == NULL) { + *err = "bad lua context"; + return NGX_ERROR; + } + + id = cctx->session_id.data; + if (id == NULL) { + *err = "uninitialized session id in lua context"; + return NGX_ERROR; + } + + id_len = cctx->session_id.len; + if (id_len == 0) { + *err = "uninitialized session id len in lua context"; + return NGX_ERROR; + } + + ngx_hex_dump(buf, id, id_len); + + return NGX_OK; +} + + +/* return the size of serialized session id. */ +int +ngx_http_lua_ffi_ssl_get_session_id_size(ngx_http_request_t *r, + char **err) +{ + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + ngx_http_lua_ssl_ctx_t *cctx; + + c = r->connection; + + if (c == NULL || c->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = c->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + dd("get cctx session"); + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + if (cctx == NULL) { + *err = "bad lua context"; + return NGX_ERROR; + } + + if (cctx->session_id.len == 0) { + *err = "uninitialized session id len in lua context"; + return NGX_ERROR; + } + + /* since the session id will be hex dumped to serialize, the serialized + * session will be twice the size of the session id: each byte will be a + * 2-digit hex value. */ + + return 2 * cctx->session_id.len; +} + +#endif /* NGX_LUA_NO_FFI_API */ + + +#endif /* NGX_HTTP_SSL */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.h b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.h new file mode 100644 index 0000000..9bf25ad --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.h @@ -0,0 +1,34 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_SSL_SESSION_STOREBY_H_INCLUDED_ +#define _NGX_HTTP_LUA_SSL_SESSION_STOREBY_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +#if (NGX_HTTP_SSL) +ngx_int_t ngx_http_lua_ssl_sess_store_handler_inline(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L); + +ngx_int_t ngx_http_lua_ssl_sess_store_handler_file(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L); + +char *ngx_http_lua_ssl_sess_store_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + +char *ngx_http_lua_ssl_sess_store_by_lua_block(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + +int ngx_http_lua_ssl_sess_store_handler(ngx_ssl_conn_t *ssl_conn, + ngx_ssl_session_t *sess); +#endif + + +#endif /* _NGX_HTTP_LUA_SSL_SESSION_STOREBY_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_string.c b/debian/modules/nginx-lua/src/ngx_http_lua_string.c index 241b969..22b4c00 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_string.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_string.c @@ -15,7 +15,7 @@ #include "ngx_http_lua_args.h" #include "ngx_crc32.h" -#if NGX_HAVE_SHA1 +#if (NGX_HAVE_SHA1) #include "ngx_sha1.h" #endif @@ -685,7 +685,7 @@ ngx_http_lua_ffi_md5(const u_char *src, size_t len, u_char *dst) int ngx_http_lua_ffi_sha1_bin(const u_char *src, size_t len, u_char *dst) { -#if NGX_HAVE_SHA1 +#if (NGX_HAVE_SHA1) ngx_sha1_t sha; ngx_sha1_init(&sha); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_subrequest.c b/debian/modules/nginx-lua/src/ngx_http_lua_subrequest.c index 4f8a753..6f7aa97 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_subrequest.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_subrequest.c @@ -375,7 +375,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) always_forward_body = lua_toboolean(L, -1); lua_pop(L, 1); - dd("always foward body: %d", always_forward_body); + dd("always forward body: %d", always_forward_body); /* check the "method" option */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c index 96c0ace..04dc9d0 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c @@ -603,7 +603,7 @@ ngx_http_lua_abort_pending_timers(ngx_event_t *ev) cur = ngx_event_timer_rbtree.root; - /* XXX nginx does not guarentee the parent of root is meaningful, + /* XXX nginx does not guarantee the parent of root is meaningful, * so we temporarily override it to simplify tree traversal. */ temp = cur->parent; cur->parent = NULL; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.c b/debian/modules/nginx-lua/src/ngx_http_lua_util.c index 1bd1388..7f59833 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_util.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_util.c @@ -50,6 +50,7 @@ #include "ngx_http_lua_worker.h" #include "ngx_http_lua_socket_tcp.h" #include "ngx_http_lua_ssl_certby.h" +#include "ngx_http_lua_ssl.h" #if 1 @@ -370,37 +371,26 @@ ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, u_char * ngx_http_lua_rebase_path(ngx_pool_t *pool, u_char *src, size_t len) { - u_char *p, *dst; + u_char *p; + ngx_str_t dst; - if (len == 0) { + dst.data = ngx_palloc(pool, len + 1); + if (dst.data == NULL) { return NULL; } - if (src[0] == '/') { - /* being an absolute path already */ - dst = ngx_palloc(pool, len + 1); - if (dst == NULL) { - return NULL; - } - - p = ngx_copy(dst, src, len); - - *p = '\0'; - - return dst; - } - - dst = ngx_palloc(pool, ngx_cycle->prefix.len + len + 1); - if (dst == NULL) { - return NULL; - } - - p = ngx_copy(dst, ngx_cycle->prefix.data, ngx_cycle->prefix.len); - p = ngx_copy(p, src, len); + dst.len = len; + p = ngx_copy(dst.data, src, len); *p = '\0'; - return dst; + if (ngx_get_full_name(pool, (ngx_str_t *) &ngx_cycle->prefix, &dst) + != NGX_OK) + { + return NULL; + } + + return dst.data; } @@ -3291,6 +3281,12 @@ ngx_http_lua_check_broken_connection(ngx_http_request_t *r, ngx_event_t *ev) return NGX_HTTP_CLIENT_CLOSED_REQUEST; } +#if (NGX_HTTP_V2) + if (r->stream) { + return NGX_OK; + } +#endif + #if (NGX_HAVE_KQUEUE) if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { @@ -3547,8 +3543,7 @@ ngx_http_lua_finalize_fake_request(ngx_http_request_t *r, ngx_int_t rc) ngx_connection_t *c; #if (NGX_HTTP_SSL) ngx_ssl_conn_t *ssl_conn; - - ngx_http_lua_ssl_cert_ctx_t *cctx; + ngx_http_lua_ssl_ctx_t *cctx; #endif c = r->connection; @@ -3823,6 +3818,7 @@ ngx_http_lua_create_fake_connection(ngx_pool_t *pool) } c->fd = (ngx_socket_t) -1; + c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); if (pool) { c->pool = pool; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.h b/debian/modules/nginx-lua/src/ngx_http_lua_util.h index f0e8923..a37852f 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_util.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_util.h @@ -87,6 +87,10 @@ extern char ngx_http_lua_headers_metatable_key; : (c) == NGX_HTTP_LUA_CONTEXT_INIT_WORKER ? "init_worker_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_BALANCER ? "balancer_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_SSL_CERT ? "ssl_certificate_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE ? \ + "ssl_session_store_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH ? \ + "ssl_session_fetch_by_lua*" \ : "(unknown)") @@ -433,7 +437,6 @@ ngx_http_lua_get_flush_chain(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) extern ngx_uint_t ngx_http_lua_location_hash; extern ngx_uint_t ngx_http_lua_content_length_hash; -extern int ngx_http_lua_ssl_ctx_index; #endif /* _NGX_HTTP_LUA_UTIL_H_INCLUDED_ */ diff --git a/debian/modules/nginx-lua/t/009-log.t b/debian/modules/nginx-lua/t/009-log.t index 053dd45..0c6a9a5 100644 --- a/debian/modules/nginx-lua/t/009-log.t +++ b/debian/modules/nginx-lua/t/009-log.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; #worker_connections(1014); #master_process_enabled(1); -log_level('debug'); # to ensure any log-level can be outputed +log_level('debug'); # to ensure any log-level can be outputted repeat_each(2); diff --git a/debian/modules/nginx-lua/t/010-request_body.t b/debian/modules/nginx-lua/t/010-request_body.t index d200495..2640a54 100644 --- a/debian/modules/nginx-lua/t/010-request_body.t +++ b/debian/modules/nginx-lua/t/010-request_body.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; #worker_connections(1014); #master_process_enabled(1); -log_level('debug'); # to ensure any log-level can be outputed +log_level('debug'); # to ensure any log-level can be outputted repeat_each(2); diff --git a/debian/modules/nginx-lua/t/016-resp-header.t b/debian/modules/nginx-lua/t/016-resp-header.t index b1f5e2a..179b411 100644 --- a/debian/modules/nginx-lua/t/016-resp-header.t +++ b/debian/modules/nginx-lua/t/016-resp-header.t @@ -530,7 +530,7 @@ Hellofoo, baz -=== TEST 27: get non-existant header +=== TEST 27: get non-existent header --- config location /lua { content_by_lua ' @@ -546,7 +546,7 @@ nil -=== TEST 28: get non-existant header +=== TEST 28: get non-existent header --- config location /lua { content_by_lua ' diff --git a/debian/modules/nginx-lua/t/020-subrequest.t b/debian/modules/nginx-lua/t/020-subrequest.t index 88ac1b4..3390d64 100644 --- a/debian/modules/nginx-lua/t/020-subrequest.t +++ b/debian/modules/nginx-lua/t/020-subrequest.t @@ -427,7 +427,7 @@ cached: hello -=== TEST 14: emtpy args option table +=== TEST 14: empty args option table --- config location /foo { echo $query_string; diff --git a/debian/modules/nginx-lua/t/023-rewrite/request_body.t b/debian/modules/nginx-lua/t/023-rewrite/request_body.t index 665d6de..0594001 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/request_body.t +++ b/debian/modules/nginx-lua/t/023-rewrite/request_body.t @@ -3,7 +3,7 @@ use Test::Nginx::Socket::Lua; #worker_connections(1014); #master_process_enabled(1); -log_level('debug'); # to ensure any log-level can be outputed +log_level('debug'); # to ensure any log-level can be outputted repeat_each(2); diff --git a/debian/modules/nginx-lua/t/023-rewrite/subrequest.t b/debian/modules/nginx-lua/t/023-rewrite/subrequest.t index 3c206a8..a307388 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/subrequest.t +++ b/debian/modules/nginx-lua/t/023-rewrite/subrequest.t @@ -409,7 +409,7 @@ cached: hello -=== TEST 14: emtpy args option table +=== TEST 14: empty args option table --- config location /foo { echo $query_string; diff --git a/debian/modules/nginx-lua/t/024-access/request_body.t b/debian/modules/nginx-lua/t/024-access/request_body.t index e4ac161..a6fead2 100644 --- a/debian/modules/nginx-lua/t/024-access/request_body.t +++ b/debian/modules/nginx-lua/t/024-access/request_body.t @@ -3,7 +3,7 @@ use Test::Nginx::Socket::Lua; #worker_connections(1014); #master_process_enabled(1); -log_level('debug'); # to ensure any log-level can be outputed +log_level('debug'); # to ensure any log-level can be outputted repeat_each(2); diff --git a/debian/modules/nginx-lua/t/024-access/subrequest.t b/debian/modules/nginx-lua/t/024-access/subrequest.t index 00c56b8..bfe96d6 100644 --- a/debian/modules/nginx-lua/t/024-access/subrequest.t +++ b/debian/modules/nginx-lua/t/024-access/subrequest.t @@ -409,7 +409,7 @@ cached: hello -=== TEST 14: emtpy args option table +=== TEST 14: empty args option table --- config location /foo { echo $query_string; diff --git a/debian/modules/nginx-lua/t/028-req-header.t b/debian/modules/nginx-lua/t/028-req-header.t index fd13cba..498f777 100644 --- a/debian/modules/nginx-lua/t/028-req-header.t +++ b/debian/modules/nginx-lua/t/028-req-header.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (2 * blocks() + 28); +plan tests => repeat_each() * (2 * blocks() + 30); #no_diff(); #no_long_string(); @@ -1582,3 +1582,43 @@ X-Forwarded-For: 8.8.8.8 Foo: 127.0.0.1 --- no_error_log [error] + + + +=== TEST 52: for bad requests (bad request method letter case) +--- config + error_page 400 = /err; + + location = /err { + content_by_lua_block { + ngx.req.set_header("Foo", "bar") + ngx.say("ok") + } + } +--- raw_request +GeT / HTTP/1.1 +--- response_body +ok +--- no_error_log +[error] +--- no_check_leak + + + +=== TEST 53: for bad requests (bad request method names) +--- config + error_page 400 = /err; + + location = /err { + content_by_lua_block { + ngx.req.set_header("Foo", "bar") + ngx.say("ok") + } + } +--- raw_request +GET x HTTP/1.1 +--- response_body +ok +--- no_error_log +[error] +--- no_check_leak diff --git a/debian/modules/nginx-lua/t/030-uri-args.t b/debian/modules/nginx-lua/t/030-uri-args.t index 2f18ba7..8ee8401 100644 --- a/debian/modules/nginx-lua/t/030-uri-args.t +++ b/debian/modules/nginx-lua/t/030-uri-args.t @@ -276,7 +276,7 @@ done -=== TEST 10: empty key, but non-emtpy values +=== TEST 10: empty key, but non-empty values --- config location /lua { content_by_lua ' @@ -818,7 +818,7 @@ lua hit query args limit 2 -=== TEST 36: max args (limited after an empty key, but non-emtpy values) +=== TEST 36: max args (limited after an empty key, but non-empty values) --- config location /lua { content_by_lua ' diff --git a/debian/modules/nginx-lua/t/031-post-args.t b/debian/modules/nginx-lua/t/031-post-args.t index 4f8b9d7..c2b6b8f 100644 --- a/debian/modules/nginx-lua/t/031-post-args.t +++ b/debian/modules/nginx-lua/t/031-post-args.t @@ -152,7 +152,7 @@ lua hit query args limit 2 -=== TEST 6: max args (limited after an empty key, but non-emtpy values) +=== TEST 6: max args (limited after an empty key, but non-empty values) --- config location /lua { content_by_lua ' diff --git a/debian/modules/nginx-lua/t/043-shdict.t b/debian/modules/nginx-lua/t/043-shdict.t index cd160f7..a21a34a 100644 --- a/debian/modules/nginx-lua/t/043-shdict.t +++ b/debian/modules/nginx-lua/t/043-shdict.t @@ -816,7 +816,7 @@ foo = hello -=== TEST 31: incr key (key exists) +=== TEST 31: replace key (key exists) --- http_config lua_shared_dict dogs 1m; --- config @@ -950,7 +950,7 @@ foo = 10534 -=== TEST 36: replace key (key not exists) +=== TEST 36: incr key (key not exists) --- http_config lua_shared_dict dogs 1m; --- config @@ -973,7 +973,7 @@ foo = nil -=== TEST 37: replace key (key expired) +=== TEST 37: incr key (key expired) --- http_config lua_shared_dict dogs 1m; --- config diff --git a/debian/modules/nginx-lua/t/062-count.t b/debian/modules/nginx-lua/t/062-count.t index a24611c..e16291b 100644 --- a/debian/modules/nginx-lua/t/062-count.t +++ b/debian/modules/nginx-lua/t/062-count.t @@ -283,7 +283,7 @@ n = 4 --- request GET /test --- response_body -n = 13 +n = 18 --- no_error_log [error] diff --git a/debian/modules/nginx-lua/t/068-socket-keepalive.t b/debian/modules/nginx-lua/t/068-socket-keepalive.t index a005620..f052e9a 100644 --- a/debian/modules/nginx-lua/t/068-socket-keepalive.t +++ b/debian/modules/nginx-lua/t/068-socket-keepalive.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; #repeat_each(2); -plan tests => repeat_each() * (blocks() * 5 + 7); +plan tests => repeat_each() * (blocks() * 5 + 9); our $HtmlDir = html_dir; @@ -1476,3 +1476,78 @@ done --- no_error_log [error] + + +=== TEST 24: setkeepalive() with explicit nil args +--- config + server_tokens off; + location /t { + lua_socket_keepalive_timeout 100ms; + + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local port = ngx.var.port + + local sock = ngx.socket.tcp() + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local req = "GET /foo HTTP/1.1\r\nHost: localhost\r\nConnection: keepalive\r\n\r\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + ngx.say("request sent: ", bytes) + + local reader = sock:receiveuntil("\r\n0\r\n\r\n") + local data, res = reader() + + if not data then + ngx.say("failed to receive response body: ", err) + return + end + + ngx.say("received response of ", #data, " bytes") + + local ok, err = sock:setkeepalive(nil, nil) + if not ok then + ngx.say("failed to set reusable: ", err) + end + + ngx.location.capture("/sleep") + + ngx.say("done") + } + } + + location /foo { + echo foo; + } + + location /sleep { + echo_sleep 1; + } +--- request +GET /t +--- response_body +connected: 1 +request sent: 61 +received response of 156 bytes +done +--- no_error_log +[error] +--- error_log eval +["lua tcp socket keepalive close handler", +"lua tcp socket keepalive: free connection pool for ", +"lua tcp socket keepalive timeout: 100 ms", +qr/lua tcp socket connection pool size: 30\b/] +--- timeout: 4 diff --git a/debian/modules/nginx-lua/t/070-sha1.t b/debian/modules/nginx-lua/t/070-sha1.t index 8648a8c..62823a9 100644 --- a/debian/modules/nginx-lua/t/070-sha1.t +++ b/debian/modules/nginx-lua/t/070-sha1.t @@ -7,7 +7,7 @@ log_level('warn'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 1); +plan tests => repeat_each() * (blocks() * 3); #no_diff(); #no_long_string(); @@ -24,6 +24,8 @@ __DATA__ GET /sha1 --- response_body qvTGHdzF6KLavt4PO0gs2a6pQ00= +--- no_error_log +[error] @@ -36,6 +38,8 @@ qvTGHdzF6KLavt4PO0gs2a6pQ00= GET /sha1 --- response_body 2jmj7l5rSw0yVb/vlWAYkK/YBwk= +--- no_error_log +[error] @@ -48,6 +52,8 @@ GET /sha1 GET /sha1 --- response_body 2jmj7l5rSw0yVb/vlWAYkK/YBwk= +--- no_error_log +[error] @@ -62,4 +68,3 @@ GET /sha1 zgmxJ9SPg4aKRWReJG07UvS97L4= --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/129-ssl-socket.t b/debian/modules/nginx-lua/t/129-ssl-socket.t index c19853d..9da9a5c 100644 --- a/debian/modules/nginx-lua/t/129-ssl-socket.t +++ b/debian/modules/nginx-lua/t/129-ssl-socket.t @@ -86,7 +86,7 @@ __DATA__ local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -162,7 +162,7 @@ SSL reused session local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -239,7 +239,7 @@ SSL reused session local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -320,7 +320,7 @@ SSL reused session local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -412,7 +412,7 @@ The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.o local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -492,7 +492,7 @@ The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.o local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -569,7 +569,7 @@ SSL reused session local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -650,7 +650,7 @@ SSL reused session local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -734,7 +734,7 @@ SSL reused session local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -813,7 +813,7 @@ SSL reused session local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -902,7 +902,7 @@ SSL reused session local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -995,7 +995,7 @@ SSL reused session local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -1072,7 +1072,7 @@ SSL reused session local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -1156,7 +1156,7 @@ SSL reused session local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -1236,7 +1236,7 @@ SSL reused session local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -1316,7 +1316,7 @@ SSL reused session local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -1396,7 +1396,7 @@ SSL reused session local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -1684,7 +1684,7 @@ attempt to call method 'sslhandshake' (a nil value) while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -1789,7 +1789,7 @@ SSL reused session while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -1893,7 +1893,7 @@ SSL reused session while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -1987,7 +1987,7 @@ SSL reused session while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -2071,7 +2071,7 @@ SSL reused session local line, err = sock:receive() if not line then - ngx.say("failed to recieve response status line: ", err) + ngx.say("failed to receive response status line: ", err) return end @@ -2444,7 +2444,7 @@ SSL reused session while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -2549,7 +2549,7 @@ SSL reused session while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end diff --git a/debian/modules/nginx-lua/t/132-lua-blocks.t b/debian/modules/nginx-lua/t/132-lua-blocks.t index e2933e9..a57d701 100644 --- a/debian/modules/nginx-lua/t/132-lua-blocks.t +++ b/debian/modules/nginx-lua/t/132-lua-blocks.t @@ -588,3 +588,19 @@ GET /test3 "3: " . ("this is just some random filler to cause an error" x 20) . "\n" --- no_error_log [error] + + + +=== TEST 23: lexer should not stop lexing in the middle of a value +--- config + location /t { + content_by_lua_block { + ngx.say("} }") + ngx.say("} }") + } + } +--- request +GET /t +--- response_body_like: } +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/133-worker-count.t b/debian/modules/nginx-lua/t/133-worker-count.t index c97f6b4..3e03ecc 100644 --- a/debian/modules/nginx-lua/t/133-worker-count.t +++ b/debian/modules/nginx-lua/t/133-worker-count.t @@ -50,3 +50,23 @@ GET /lua workers: 1 --- no_error_log [error] + + + +=== TEST 3: init_worker_by_lua +--- http_config + init_worker_by_lua_block { + init_worker_count = ngx.worker.count() + } +--- config + location /lua { + content_by_lua_block { + ngx.say("workers: ", init_worker_count) + } + } +--- request +GET /lua +--- response_body +workers: 1 +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/138-balancer.t b/debian/modules/nginx-lua/t/138-balancer.t index e44cf8e..8d45c24 100644 --- a/debian/modules/nginx-lua/t/138-balancer.t +++ b/debian/modules/nginx-lua/t/138-balancer.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 8); +plan tests => repeat_each() * (blocks() * 4 + 9); #no_diff(); no_long_string(); @@ -405,3 +405,29 @@ ctx counter: nil ctx counter: nil --- no_error_log [error] + + + +=== TEST 14: ngx.log(ngx.ERR, ...) github #816 +--- http_config + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + ngx.log(ngx.ERR, "hello from balancer by lua!") + } + } +--- config + location = /t { + proxy_pass http://backend; + } +--- request + GET /t +--- response_body_like: 502 Bad Gateway +--- error_code: 502 +--- error_log eval +[ +'[lua] balancer_by_lua:2: hello from balancer by lua! while connecting to upstream,', +qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\.0\.1:80/t"}, +] +--- no_error_log +[warn] diff --git a/debian/modules/nginx-lua/t/139-ssl-cert-by.t b/debian/modules/nginx-lua/t/139-ssl-cert-by.t index 9297a0d..b9fd60d 100644 --- a/debian/modules/nginx-lua/t/139-ssl-cert-by.t +++ b/debian/modules/nginx-lua/t/139-ssl-cert-by.t @@ -82,7 +82,7 @@ __DATA__ while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -180,7 +180,7 @@ ssl_certificate_by_lua:1: ssl cert by lua is running! while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -285,7 +285,7 @@ qr/elapsed in ssl cert by lua: 0.(?:09|1[01])\d+,/, while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -403,7 +403,7 @@ my timer run! while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -1108,7 +1108,7 @@ print("ssl cert by lua is running!") while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -1219,7 +1219,7 @@ a.lua:1: ssl cert by lua is running! while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -1343,7 +1343,7 @@ lua ssl server name: "test.com" while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -1439,7 +1439,7 @@ GitHub openresty/lua-resty-core#42 while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -1475,3 +1475,102 @@ ssl_certificate_by_lua:1: ssl cert by lua is running! --- no_error_log [error] [alert] + + + +=== TEST 18: simple logging (syslog) +github issue #723 +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + error_log syslog:server=127.0.0.1:12345 debug; + + ssl_certificate_by_lua_block { print("ssl cert by lua is running!") } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to receive response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- error_log eval +[ +qr/\[error\] .*? send\(\) failed/, +'lua ssl server name: "test.com"', +] +--- no_error_log +[alert] +ssl_certificate_by_lua:1: ssl cert by lua is running! diff --git a/debian/modules/nginx-lua/t/140-ssl-c-api.t b/debian/modules/nginx-lua/t/140-ssl-c-api.t index 4ecc2cd..44ad93d 100644 --- a/debian/modules/nginx-lua/t/140-ssl-c-api.t +++ b/debian/modules/nginx-lua/t/140-ssl-c-api.t @@ -22,6 +22,57 @@ log_level 'debug'; no_long_string(); #no_diff(); +add_block_preprocessor(sub { + my $block = shift; + + if (!defined $block->user_files) { + $block->set_value("user_files", <<'_EOC_'); +>>> defines.lua +local ffi = require "ffi" + +ffi.cdef[[ + int ngx_http_lua_ffi_cert_pem_to_der(const unsigned char *pem, + size_t pem_len, unsigned char *der, char **err); + + int ngx_http_lua_ffi_priv_key_pem_to_der(const unsigned char *pem, + size_t pem_len, unsigned char *der, char **err); + + int ngx_http_lua_ffi_ssl_set_der_certificate(void *r, + const char *data, size_t len, char **err); + + int ngx_http_lua_ffi_ssl_set_der_private_key(void *r, + const char *data, size_t len, char **err); + + int ngx_http_lua_ffi_ssl_clear_certs(void *r, char **err); + + void *ngx_http_lua_ffi_parse_pem_cert(const unsigned char *pem, + size_t pem_len, char **err); + + void *ngx_http_lua_ffi_parse_pem_priv_key(const unsigned char *pem, + size_t pem_len, char **err); + + int ngx_http_lua_ffi_set_cert(void *r, + void *cdata, char **err); + + int ngx_http_lua_ffi_set_priv_key(void *r, + void *cdata, char **err); + + void ngx_http_lua_ffi_free_cert(void *cdata); + + void ngx_http_lua_ffi_free_priv_key(void *cdata); + + int ngx_http_lua_ffi_ssl_clear_certs(void *r, char **err); +]] +_EOC_ + } + + my $http_config = $block->http_config || ''; + $http_config .= <<'_EOC_'; +lua_package_path "$prefix/html/?.lua;;"; +_EOC_ + $block->set_value("http_config", $http_config); +}); + run_tests(); __DATA__ @@ -35,24 +86,9 @@ __DATA__ ssl_certificate_by_lua_block { collectgarbage() + require "defines" local ffi = require "ffi" - ffi.cdef[[ - int ngx_http_lua_ffi_cert_pem_to_der(const unsigned char *pem, - size_t pem_len, unsigned char *der, char **err); - - int ngx_http_lua_ffi_priv_key_pem_to_der(const unsigned char *pem, - size_t pem_len, unsigned char *der, char **err); - - int ngx_http_lua_ffi_ssl_set_der_certificate(void *r, - const char *data, size_t len, char **err); - - int ngx_http_lua_ffi_ssl_set_der_private_key(void *r, - const char *data, size_t len, char **err); - - int ngx_http_lua_ffi_ssl_clear_certs(void *r, char **err); - ]] - local errmsg = ffi.new("char *[1]") local r = getfenv(0).__ngx_req @@ -157,7 +193,7 @@ __DATA__ while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -205,22 +241,7 @@ lua ssl server name: "test.com" collectgarbage() local ffi = require "ffi" - - ffi.cdef[[ - int ngx_http_lua_ffi_cert_pem_to_der(const unsigned char *pem, - size_t pem_len, unsigned char *der, char **err); - - int ngx_http_lua_ffi_priv_key_pem_to_der(const unsigned char *pem, - size_t pem_len, unsigned char *der, char **err); - - int ngx_http_lua_ffi_ssl_set_der_certificate(void *r, - const char *data, size_t len, char **err); - - int ngx_http_lua_ffi_ssl_set_der_private_key(void *r, - const char *data, size_t len, char **err); - - int ngx_http_lua_ffi_ssl_clear_certs(void *r, char **err); - ]] + require "defines" local errmsg = ffi.new("char *[1]") @@ -326,7 +347,7 @@ lua ssl server name: "test.com" while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -374,14 +395,7 @@ lua ssl server name: "test.com" collectgarbage() local ffi = require "ffi" - - ffi.cdef[[ - int ngx_http_lua_ffi_cert_pem_to_der(const unsigned char *pem, - size_t pem_len, unsigned char *der, char **err); - - int ngx_http_lua_ffi_priv_key_pem_to_der(const unsigned char *pem, - size_t pem_len, unsigned char *der, char **err); - ]] + require "defines" local errmsg = ffi.new("char *[1]") @@ -461,7 +475,7 @@ lua ssl server name: "test.com" while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -493,7 +507,307 @@ close: 1 nil --- error_log lua ssl server name: "test.com" failed to parse PEM cert: PEM_read_bio_X509_AUX() -failed to parse PEM priv key: PEM_read_bio_PrivateKey failed +failed to parse PEM priv key: PEM_read_bio_PrivateKey() failed --- no_error_log [alert] + + + +=== TEST 4: simple cert + private key cdata +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate_by_lua_block { + collectgarbage() + + local ffi = require "ffi" + require "defines" + + local errmsg = ffi.new("char *[1]") + + local r = getfenv(0).__ngx_req + if not r then + ngx.log(ngx.ERR, "no request found") + return + end + + ffi.C.ngx_http_lua_ffi_ssl_clear_certs(r, errmsg) + + local f = assert(io.open("t/cert/test.crt", "rb")) + local cert_data = f:read("*all") + f:close() + + local cert = ffi.C.ngx_http_lua_ffi_parse_pem_cert(cert_data, #cert_data, errmsg) + if not cert then + ngx.log(ngx.ERR, "failed to parse PEM cert: ", + ffi.string(errmsg[0])) + return + end + + local rc = ffi.C.ngx_http_lua_ffi_set_cert(r, cert, errmsg) + if rc ~= 0 then + ngx.log(ngx.ERR, "failed to set cdata cert: ", + ffi.string(errmsg[0])) + return + end + + ffi.C.ngx_http_lua_ffi_free_cert(cert) + + f = assert(io.open("t/cert/test.key", "rb")) + local pkey_data = f:read("*all") + f:close() + + local pkey = ffi.C.ngx_http_lua_ffi_parse_pem_priv_key(pkey_data, #pkey_data, errmsg) + if not pkey then + ngx.log(ngx.ERR, "failed to parse PEM priv key: ", + ffi.string(errmsg[0])) + return + end + + local rc = ffi.C.ngx_http_lua_ffi_set_priv_key(r, pkey, errmsg) + if rc ~= 0 then + ngx.log(ngx.ERR, "failed to set cdata priv key: ", + ffi.string(errmsg[0])) + return + end + + ffi.C.ngx_http_lua_ffi_free_priv_key(pkey) + } + + ssl_certificate ../../cert/test2.crt; + ssl_certificate_key ../../cert/test2.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to recieve response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- error_log +lua ssl server name: "test.com" + +--- no_error_log +[error] +[alert] + + + +=== TEST 5: ECDSA cert + private key cdata +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate_by_lua_block { + collectgarbage() + + local ffi = require "ffi" + require "defines" + + local errmsg = ffi.new("char *[1]") + + local r = getfenv(0).__ngx_req + if not r then + ngx.log(ngx.ERR, "no request found") + return + end + + ffi.C.ngx_http_lua_ffi_ssl_clear_certs(r, errmsg) + + local f = assert(io.open("t/cert/test_ecdsa.crt", "rb")) + local cert_data = f:read("*all") + f:close() + + local cert = ffi.C.ngx_http_lua_ffi_parse_pem_cert(cert_data, #cert_data, errmsg) + if not cert then + ngx.log(ngx.ERR, "failed to parse PEM cert: ", + ffi.string(errmsg[0])) + return + end + + local rc = ffi.C.ngx_http_lua_ffi_set_cert(r, cert, errmsg) + if rc ~= 0 then + ngx.log(ngx.ERR, "failed to set cdata cert: ", + ffi.string(errmsg[0])) + return + end + + ffi.C.ngx_http_lua_ffi_free_cert(cert) + + f = assert(io.open("t/cert/test_ecdsa.key", "rb")) + local pkey_data = f:read("*all") + f:close() + + local pkey = ffi.C.ngx_http_lua_ffi_parse_pem_priv_key(pkey_data, #pkey_data, errmsg) + if not pkey then + ngx.log(ngx.ERR, "failed to parse PEM priv key: ", + ffi.string(errmsg[0])) + return + end + + local rc = ffi.C.ngx_http_lua_ffi_set_priv_key(r, pkey, errmsg) + if rc ~= 0 then + ngx.log(ngx.ERR, "failed to set cdata priv key: ", + ffi.string(errmsg[0])) + return + end + + ffi.C.ngx_http_lua_ffi_free_priv_key(pkey) + } + + ssl_certificate ../../cert/test2.crt; + ssl_certificate_key ../../cert/test2.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test_ecdsa.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to recieve response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- error_log +lua ssl server name: "test.com" + +--- no_error_log +[error] +[alert] diff --git a/debian/modules/nginx-lua/t/142-ssl-session-store.t b/debian/modules/nginx-lua/t/142-ssl-session-store.t new file mode 100644 index 0000000..da84a8d --- /dev/null +++ b/debian/modules/nginx-lua/t/142-ssl-session-store.t @@ -0,0 +1,750 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; +use Cwd qw(abs_path realpath); +use File::Basename; + +repeat_each(3); + +plan tests => repeat_each() * (blocks() * 6 + 2); + +$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); + +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_CERT_DIR} ||= dirname(realpath(abs_path(__FILE__))); + +#log_level 'warn'; +log_level 'debug'; + +no_long_string(); +#no_diff(); + +run_tests(); + +__DATA__ + +=== TEST 1: simple logging +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_store_by_lua_block { print("ssl session store by lua is running!") } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +ssl_session_store_by_lua_block:1: ssl session store by lua is running! + +--- no_error_log +[error] +[alert] + + + +=== TEST 2: sleep is not allowed +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_store_by_lua_block { + local begin = ngx.now() + ngx.sleep(0.1) + print("elapsed in ssl store session by lua: ", ngx.now() - begin) + } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +API disabled in the context of ssl_session_store_by_lua* + +--- no_error_log +[alert] +[emerg] + + + +=== TEST 3: timer +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_session_store_by_lua_block { + local function f() + print("my timer run!") + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.log(ngx.ERR, "failed to create timer: ", err) + return + end + } + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +my timer run! + +--- no_error_log +[error] +[alert] + + + +=== TEST 4: cosocket is not allowed +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_store_by_lua_block { + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if not ok then + ngx.log(ngx.ERR, "failed to connect to memc: ", err) + return + end + + local bytes, err = sock:send("flush_all\\r\\n") + if not bytes then + ngx.log(ngx.ERR, "failed to send flush_all command: ", err) + return + end + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "failed to receive memc reply: ", err) + return + end + + print("received memc reply: ", res) + } + + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +API disabled in the context of ssl_session_store_by_lua* + +--- no_error_log +[alert] +[emerg] + + + +=== TEST 5: ngx.exit(0) - no yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_store_by_lua_block { + ngx.exit(0) + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +lua exit with code 0 + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 6: ngx.exit(ngx.ERROR) - no yield +ngx.exit does not yield and the error code is eaten. +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_store_by_lua_block { + ngx.exit(ngx.ERROR) + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +lua exit with code -1 +ssl_session_store_by_lua*: handler return value: 0, sess new cb exit code: 0 + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 7: lua exception - no yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_store_by_lua_block { + error("bad bad bad") + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +failed to run session_store_by_lua*: ssl_session_store_by_lua_block:2: bad bad bad + +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 8: get phase +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_store_by_lua_block { + print("get_phase: ", ngx.get_phase()) + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +get_phase: ssl_session_store + +--- no_error_log +[alert] +[emerg] +[error] + + + +=== TEST 9: inter-operation with ssl_certificate_by_lua +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate_by_lua_block { + local begin = ngx.now() + ngx.sleep(0.1) + print("elapsed in ssl cert by lua: ", ngx.now() - begin) + } + ssl_session_store_by_lua_block { print("ssl store session by lua is running!") } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log eval +[ +'lua ssl server name: "test.com"', +qr/elapsed in ssl cert by lua: 0.(?:09|1[01])\d+,/, +'ssl_session_store_by_lua_block:1: ssl store session by lua is running!', +] + +--- no_error_log +[error] +[alert] + + + +=== TEST 10: simple logging (by file) +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_store_by_lua_file html/a.lua; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- user_files +>>> a.lua +print("ssl store session by lua is running!") + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +a.lua:1: ssl store session by lua is running! + +--- no_error_log +[error] +[alert] diff --git a/debian/modules/nginx-lua/t/143-ssl-session-fetch.t b/debian/modules/nginx-lua/t/143-ssl-session-fetch.t new file mode 100644 index 0000000..686f671 --- /dev/null +++ b/debian/modules/nginx-lua/t/143-ssl-session-fetch.t @@ -0,0 +1,1027 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket::Lua; +use Cwd qw(abs_path realpath); +use File::Basename; + +repeat_each(3); + +plan tests => repeat_each() * (blocks() * 6); + +$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); + +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_CERT_DIR} ||= dirname(realpath(abs_path(__FILE__))); + +#log_level 'warn'; +log_level 'debug'; + +no_long_string(); +#no_diff(); + +run_tests(); + +__DATA__ + +=== TEST 1: simple logging +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { print("ssl fetch sess by lua is running!") } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!/s + +--- grep_error_log_out eval +[ +'', +'ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running! +', +'ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running! +', +] + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 2: sleep +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { + local begin = ngx.now() + ngx.sleep(0.1) + print("elapsed in ssl fetch session by lua: ", ngx.now() - begin) + } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/elapsed in ssl fetch session by lua: 0.(?:09|1[01])\d+,/, + +--- grep_error_log_out eval +[ +'', +qr/elapsed in ssl fetch session by lua: 0.(?:09|1[01])\d+,/, +qr/elapsed in ssl fetch session by lua: 0.(?:09|1[01])\d+,/, +] + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 3: timer +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_session_fetch_by_lua_block { + local function f() + print("my timer run!") + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.log(ngx.ERR, "failed to create timer: ", err) + return + end + } + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/my timer run!/s + +--- grep_error_log_out eval +[ +'', +'my timer run! +', +'my timer run! +', +] + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 4: cosocket +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if not ok then + ngx.log(ngx.ERR, "failed to connect to memc: ", err) + return + end + + local bytes, err = sock:send("flush_all\r\n") + if not bytes then + ngx.log(ngx.ERR, "failed to send flush_all command: ", err) + return + end + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "failed to receive memc reply: ", err) + return + end + + print("received memc reply: ", res) + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/received memc reply: OK/s + +--- grep_error_log_out eval +[ +'', +'received memc reply: OK +', +'received memc reply: OK +', +] + +--- no_error_log +[alert] +[error] +[emerg] + + + +=== TEST 5: ngx.exit(0) - yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { + ngx.exit(0) + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/lua exit with code 0/s + +--- grep_error_log_out eval +[ +'', +'lua exit with code 0 +', +'lua exit with code 0 +', +] + +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 6: ngx.exit(ngx.ERROR) - yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { + ngx.exit(ngx.ERROR) + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/ssl_session_fetch_by_lua\*: handler return value: -1, sess get cb exit code: 0/s + +--- grep_error_log_out eval +[ +'', +'ssl_session_fetch_by_lua*: handler return value: -1, sess get cb exit code: 0 +', +'ssl_session_fetch_by_lua*: handler return value: -1, sess get cb exit code: 0 +', +] + +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 7: ngx.exit(ngx.ERROR) - yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { + ngx.sleep(0.001) + ngx.exit(ngx.ERROR) + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/ssl_session_fetch_by_lua\*: sess get cb exit code: 0/s + +--- grep_error_log_out eval +[ +'', +'ssl_session_fetch_by_lua*: sess get cb exit code: 0 +', +'ssl_session_fetch_by_lua*: sess get cb exit code: 0 +', +] + +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 8: lua exception - no yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { + error("bad bad bad") + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/ssl_session_fetch_by_lua_block:2: bad bad bad/s + +--- grep_error_log_out eval +[ +'', +'ssl_session_fetch_by_lua_block:2: bad bad bad +', +'ssl_session_fetch_by_lua_block:2: bad bad bad +', + +] + +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 9: lua exception - yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { + ngx.sleep(0.001) + error("bad bad bad") + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_protocols SSLv3; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/ssl_session_fetch_by_lua_block:3: bad bad bad|ssl_session_fetch_by_lua\*: sess get cb exit code: 0/s + +--- grep_error_log_out eval +[ +'', +'ssl_session_fetch_by_lua_block:3: bad bad bad +ssl_session_fetch_by_lua*: sess get cb exit code: 0 +', +'ssl_session_fetch_by_lua_block:3: bad bad bad +ssl_session_fetch_by_lua*: sess get cb exit code: 0 +', + +] + +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 10: get phase +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_block { print("get_phase: ", ngx.get_phase()) } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/get_phase: ssl_session_fetch/s + +--- grep_error_log_out eval +[ +'', +'get_phase: ssl_session_fetch +', +'get_phase: ssl_session_fetch +', +] + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 11: inter-operation with ssl_certificate_by_lua +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate_by_lua_block { + ngx.sleep(0.1) + print("ssl cert by lua is running!") + } + ssl_session_store_by_lua_block { print("ssl store session by lua is running!") } + ssl_session_fetch_by_lua_block { + ngx.sleep(0.1) + print("ssl fetch session by lua is running!") + } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } + +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/ssl ((fetch|store) session|cert) by lua is running!/s + +--- grep_error_log_out eval +[ +'ssl cert by lua is running! +ssl store session by lua is running! +', +'ssl fetch session by lua is running! +ssl cert by lua is running! +ssl store session by lua is running! +', +'ssl fetch session by lua is running! +ssl cert by lua is running! +ssl store session by lua is running! +', +] + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 12: simple logging (by file) +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_session_fetch_by_lua_file html/a.lua; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols SSLv3; + + server_tokens off; + } +--- config + server_tokens off; + lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(5000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + package.loaded.session = sess + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- user_files +>>> a.lua +print("ssl fetch sess by lua is running!") + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +close: 1 nil + +--- grep_error_log eval +qr/\S+:\d+: ssl fetch sess by lua is running!/s + +--- grep_error_log_out eval +[ +'', +'a.lua:1: ssl fetch sess by lua is running! +', +'a.lua:1: ssl fetch sess by lua is running! +', +] + +--- no_error_log +[error] +[alert] +[emerg] diff --git a/debian/modules/nginx-lua/t/144-shdict-incr-init.t b/debian/modules/nginx-lua/t/144-shdict-incr-init.t new file mode 100644 index 0000000..71bb566 --- /dev/null +++ b/debian/modules/nginx-lua/t/144-shdict-incr-init.t @@ -0,0 +1,226 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_process_enabled(1); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3 + 0); + +#no_diff(); +no_long_string(); +#master_on(); +#workers(2); + +run_tests(); + +__DATA__ + +=== TEST 1: incr key with init (key exists) +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + dogs:set("foo", 32) + local res, err = dogs:incr("foo", 10502, 1) + ngx.say("incr: ", res, " ", err) + ngx.say("foo = ", dogs:get("foo")) + } + } +--- request +GET /test +--- response_body +incr: 10534 nil +foo = 10534 +--- no_error_log +[error] + + + +=== TEST 2: incr key with init (key not exists) +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + dogs:flush_all() + dogs:set("bah", 32) + local res, err = dogs:incr("foo", 10502, 1) + ngx.say("incr: ", res, " ", err) + ngx.say("foo = ", dogs:get("foo")) + } + } +--- request +GET /test +--- response_body +incr: 10503 nil +foo = 10503 +--- no_error_log +[error] + + + +=== TEST 3: incr key with init (key expired and size not matched) +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + for i = 1, 20 do + dogs:set("bar" .. i, i, 0.001) + end + dogs:set("foo", "32", 0.001) + ngx.location.capture("/sleep/0.002") + local res, err = dogs:incr("foo", 10502, 0) + ngx.say("incr: ", res, " ", err) + ngx.say("foo = ", dogs:get("foo")) + } + } + location ~ ^/sleep/(.+) { + echo_sleep $1; + } +--- request +GET /test +--- response_body +incr: 10502 nil +foo = 10502 +--- no_error_log +[error] + + + +=== TEST 4: incr key with init (key expired and size matched) +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + for i = 1, 20 do + dogs:set("bar" .. i, i, 0.001) + end + dogs:set("foo", 32, 0.001) + ngx.location.capture("/sleep/0.002") + local res, err = dogs:incr("foo", 10502, 0) + ngx.say("incr: ", res, " ", err) + ngx.say("foo = ", dogs:get("foo")) + } + } + location ~ ^/sleep/(.+) { + echo_sleep $1; + } +--- request +GET /test +--- response_body +incr: 10502 nil +foo = 10502 +--- no_error_log +[error] + + + +=== TEST 5: incr key with init (forcibly override other valid entries) +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + dogs:flush_all() + local long_prefix = string.rep("1234567890", 100) + for i = 1, 1000 do + local success, err, forcible = dogs:set(long_prefix .. i, i) + if forcible then + dogs:delete(long_prefix .. i) + break + end + end + local res, err, forcible = dogs:incr(long_prefix .. "bar", 10502, 0) + ngx.say("incr: ", res, " ", err, " ", forcible) + local res, err, forcible = dogs:incr(long_prefix .. "foo", 10502, 0) + ngx.say("incr: ", res, " ", err, " ", forcible) + ngx.say("foo = ", dogs:get(long_prefix .. "foo")) + } + } +--- request +GET /test +--- response_body +incr: 10502 nil false +incr: 10502 nil true +foo = 10502 +--- no_error_log +[error] + + + +=== TEST 6: incr key without init (no forcible returned) +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + dogs:set("foo", 1) + local res, err, forcible = dogs:incr("foo", 1) + ngx.say("incr: ", res, " ", err, " ", forcible) + ngx.say("foo = ", dogs:get("foo")) + } + } +--- request +GET /test +--- response_body +incr: 2 nil nil +foo = 2 +--- no_error_log +[error] + + + +=== TEST 7: incr key (original value is not number) +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + dogs:set("foo", true) + local res, err = dogs:incr("foo", 1, 0) + ngx.say("incr: ", res, " ", err) + ngx.say("foo = ", dogs:get("foo")) + } + } +--- request +GET /test +--- response_body +incr: nil not a number +foo = true +--- no_error_log +[error] + + + +=== TEST 8: init is not number +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + local res, err, forcible = dogs:incr("foo", 1, "bar") + ngx.say("incr: ", res, " ", err, " ", forcible) + ngx.say("foo = ", dogs:get("foo")) + } + } +--- request +GET /test +--- error_code: 500 +--- response_body_like: 500 Internal Server Error +--- error_log +number expected, got string diff --git a/debian/modules/nginx-lua/t/145-shdict-list.t b/debian/modules/nginx-lua/t/145-shdict-list.t new file mode 100644 index 0000000..9bb1592 --- /dev/null +++ b/debian/modules/nginx-lua/t/145-shdict-list.t @@ -0,0 +1,745 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_process_enabled(1); +#log_level('warn'); + +#repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3 + 0); + +#no_diff(); +no_long_string(); +#master_on(); +#workers(2); + +run_tests(); + +__DATA__ + +=== TEST 1: lpush & lpop +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + local len, err = dogs:lpush("foo", "bar") + if len then + ngx.say("push success") + else + ngx.say("push err: ", err) + end + + local val, err = dogs:llen("foo") + ngx.say(val, " ", err) + + local val, err = dogs:lpop("foo") + ngx.say(val, " ", err) + + local val, err = dogs:llen("foo") + ngx.say(val, " ", err) + + local val, err = dogs:lpop("foo") + ngx.say(val, " ", err) + } + } +--- request +GET /test +--- response_body +push success +1 nil +bar nil +0 nil +nil nil +--- no_error_log +[error] + + + +=== TEST 2: get operation on list type +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + local len, err = dogs:lpush("foo", "bar") + if len then + ngx.say("push success") + else + ngx.say("push err: ", err) + end + + local val, err = dogs:get("foo") + ngx.say(val, " ", err) + } + } +--- request +GET /test +--- response_body +push success +nil value is a list +--- no_error_log +[error] + + + +=== TEST 3: set operation on list type +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + local len, err = dogs:lpush("foo", "bar") + if len then + ngx.say("push success") + else + ngx.say("push err: ", err) + end + + local ok, err = dogs:set("foo", "bar") + ngx.say(ok, " ", err) + + local val, err = dogs:get("foo") + ngx.say(val, " ", err) + } + } +--- request +GET /test +--- response_body +push success +true nil +bar nil +--- no_error_log +[error] + + + +=== TEST 4: replace operation on list type +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + local len, err = dogs:lpush("foo", "bar") + if len then + ngx.say("push success") + else + ngx.say("push err: ", err) + end + + local ok, err = dogs:replace("foo", "bar") + ngx.say(ok, " ", err) + + local val, err = dogs:get("foo") + ngx.say(val, " ", err) + } + } +--- request +GET /test +--- response_body +push success +true nil +bar nil +--- no_error_log +[error] + + + +=== TEST 5: add operation on list type +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + local len, err = dogs:lpush("foo", "bar") + if len then + ngx.say("push success") + else + ngx.say("push err: ", err) + end + + local ok, err = dogs:add("foo", "bar") + ngx.say(ok, " ", err) + + local val, err = dogs:get("foo") + ngx.say(val, " ", err) + } + } +--- request +GET /test +--- response_body +push success +false exists +nil value is a list +--- no_error_log +[error] + + + +=== TEST 6: delete operation on list type +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + local len, err = dogs:lpush("foo", "bar") + if len then + ngx.say("push success") + else + ngx.say("push err: ", err) + end + + local ok, err = dogs:delete("foo") + ngx.say(ok, " ", err) + + local val, err = dogs:get("foo") + ngx.say(val, " ", err) + } + } +--- request +GET /test +--- response_body +push success +true nil +nil nil +--- no_error_log +[error] + + + +=== TEST 7: incr operation on list type +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + local len, err = dogs:lpush("foo", "bar") + if len then + ngx.say("push success") + else + ngx.say("push err: ", err) + end + + local ok, err = dogs:incr("foo", 1) + ngx.say(ok, " ", err) + + local val, err = dogs:get("foo") + ngx.say(val, " ", err) + } + } +--- request +GET /test +--- response_body +push success +nil not a number +nil value is a list +--- no_error_log +[error] + + + +=== TEST 8: get_keys operation on list type +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + local len, err = dogs:lpush("foo", "bar") + if len then + ngx.say("push success") + else + ngx.say("push err: ", err) + end + + local keys, err = dogs:get_keys() + ngx.say("key: ", keys[1]) + } + } +--- request +GET /test +--- response_body +push success +key: foo +--- no_error_log +[error] + + + +=== TEST 9: push operation on key-value type +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + local ok, err = dogs:set("foo", "bar") + if ok then + ngx.say("set success") + else + ngx.say("set err: ", err) + end + + local len, err = dogs:lpush("foo", "bar") + ngx.say(len, " ", err) + + local val, err = dogs:get("foo") + ngx.say(val, " ", err) + } + } +--- request +GET /test +--- response_body +set success +nil value not a list +bar nil +--- no_error_log +[error] + + + +=== TEST 10: pop operation on key-value type +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + local ok, err = dogs:set("foo", "bar") + if ok then + ngx.say("set success") + else + ngx.say("set err: ", err) + end + + local val, err = dogs:lpop("foo") + ngx.say(val, " ", err) + + local val, err = dogs:get("foo") + ngx.say(val, " ", err) + } + } +--- request +GET /test +--- response_body +set success +nil value not a list +bar nil +--- no_error_log +[error] + + + +=== TEST 11: llen operation on key-value type +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + local ok, err = dogs:set("foo", "bar") + if ok then + ngx.say("set success") + else + ngx.say("set err: ", err) + end + + local val, err = dogs:llen("foo") + ngx.say(val, " ", err) + + local val, err = dogs:get("foo") + ngx.say(val, " ", err) + } + } +--- request +GET /test +--- response_body +set success +nil value not a list +bar nil +--- no_error_log +[error] + + + +=== TEST 12: lpush and lpop +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + for i = 1, 3 do + local len, err = dogs:lpush("foo", i) + if len ~= i then + ngx.say("push err: ", err) + break + end + end + + for i = 1, 3 do + local val, err = dogs:lpop("foo") + if not val then + ngx.say("pop err: ", err) + break + else + ngx.say(val) + end + end + } + } +--- request +GET /test +--- response_body +3 +2 +1 +--- no_error_log +[error] + + + +=== TEST 13: lpush and rpop +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + for i = 1, 3 do + local len, err = dogs:lpush("foo", i) + if len ~= i then + ngx.say("push err: ", err) + break + end + end + + for i = 1, 3 do + local val, err = dogs:rpop("foo") + if not val then + ngx.say("pop err: ", err) + break + else + ngx.say(val) + end + end + } + } +--- request +GET /test +--- response_body +1 +2 +3 +--- no_error_log +[error] + + + +=== TEST 14: rpush and lpop +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + for i = 1, 3 do + local len, err = dogs:rpush("foo", i) + if len ~= i then + ngx.say("push err: ", err) + break + end + end + + for i = 1, 3 do + local val, err = dogs:lpop("foo") + if not val then + ngx.say("pop err: ", err) + break + else + ngx.say(val) + end + end + } + } +--- request +GET /test +--- response_body +1 +2 +3 +--- no_error_log +[error] + + + +=== TEST 15: list removed: expired +--- http_config + lua_shared_dict dogs 900k; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + local N = 100000 + local max = 0 + + for i = 1, N do + local key = string.format("%05d", i) + + local len , err = dogs:lpush(key, i) + if not len then + max = i + break + end + end + + local keys = dogs:get_keys(0) + + ngx.say("max - 1 matched keys length: ", max - 1 == #keys) + + dogs:flush_all() + + local keys = dogs:get_keys(0) + + ngx.say("keys all expired, left number: ", #keys) + + for i = 100000, 1, -1 do + local key = string.format("%05d", i) + + local len, err = dogs:lpush(key, i) + if not len then + ngx.say("loop again, max matched: ", N + 1 - i == max) + break + end + end + + dogs:flush_all() + + dogs:flush_expired() + + for i = 1, N do + local key = string.format("%05d", i) + + local len, err = dogs:lpush(key, i) + if not len then + ngx.say("loop again, max matched: ", i == max) + break + end + end + } + } +--- request +GET /test +--- response_body +max - 1 matched keys length: true +keys all expired, left number: 0 +loop again, max matched: true +loop again, max matched: true +--- no_error_log +[error] +--- timeout: 9 + + + +=== TEST 16: list removed: forcibly +--- http_config + lua_shared_dict dogs 900k; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + local N = 200000 + local max = 0 + for i = 1, N do + local ok, err, forcible = dogs:set(i, i) + if not ok or forcible then + max = i + break + end + end + + local two = dogs:get(2) + + ngx.say("two == number 2: ", two == 2) + + dogs:flush_all() + dogs:flush_expired() + + local keys = dogs:get_keys(0) + + ngx.say("no one left: ", #keys) + + for i = 1, N do + local key = string.format("%05d", i) + + local len, err = dogs:lpush(key, i) + if not len then + break + end + end + + for i = 1, max do + local ok, err = dogs:set(i, i) + if not ok then + ngx.say("set err: ", err) + break + end + end + + local two = dogs:get(2) + + ngx.say("two == number 2: ", two == 2) + } + } +--- request +GET /test +--- response_body +two == number 2: true +no one left: 0 +two == number 2: true +--- no_error_log +[error] +--- timeout: 9 + + + +=== TEST 17: expire on all types +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + local len, err = dogs:lpush("list", "foo") + if not len then + ngx.say("push err: ", err) + end + + local ok, err = dogs:set("key", "bar") + if not ok then + ngx.say("set err: ", err) + end + + local keys = dogs:get_keys(0) + + ngx.say("keys number: ", #keys) + + dogs:flush_all() + + local keys = dogs:get_keys(0) + + ngx.say("keys number: ", #keys) + } + } +--- request +GET /test +--- response_body +keys number: 2 +keys number: 0 +--- no_error_log +[error] + + + +=== TEST 18: long list node +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + local long_str = string.rep("foo", 10) + + for i = 1, 3 do + local len, err = dogs:lpush("list", long_str) + if not len then + ngx.say("push err: ", err) + end + end + + for i = 1, 3 do + local val, err = dogs:lpop("list") + if val then + ngx.say(val) + end + end + } + } +--- request +GET /test +--- response_body +foofoofoofoofoofoofoofoofoofoo +foofoofoofoofoofoofoofoofoofoo +foofoofoofoofoofoofoofoofoofoo +--- no_error_log +[error] + + + +=== TEST 19: incr on expired list +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua_block { + local dogs = ngx.shared.dogs + + local long_str = string.rep("foo", 10 * 1024) -- 30k + + for i = 1, 100 do + for j = 1, 10 do + local key = "list" .. j + local len, err = dogs:lpush(key, long_str) + if not len then + ngx.say("push err: ", err) + end + end + + dogs:flush_all() + + for j = 10, 1, -1 do + local key = "list" .. j + local newval, err = dogs:incr(key, 1, 0) + if not newval then + ngx.say("incr err: ", err) + end + end + + dogs:flush_all() + end + + ngx.say("done") + } + } +--- request +GET /test +--- response_body +done +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/lib/CRC32.lua b/debian/modules/nginx-lua/t/lib/CRC32.lua index 70f4215..fcf260c 100755 --- a/debian/modules/nginx-lua/t/lib/CRC32.lua +++ b/debian/modules/nginx-lua/t/lib/CRC32.lua @@ -157,7 +157,7 @@ end -- CRC32.lua -- -- A pure Lua implementation of a CRC32 hashing algorithm. Slower than using a C implemtation, --- but useful having no other dependancies. +-- but useful having no other dependencies. -- -- -- Synopsis diff --git a/debian/modules/nginx-lua/util/build.sh b/debian/modules/nginx-lua/util/build.sh index 17841ed..1185e72 100755 --- a/debian/modules/nginx-lua/util/build.sh +++ b/debian/modules/nginx-lua/util/build.sh @@ -20,12 +20,12 @@ force=$2 #--with-cc=gcc46 \ #--with-cc=clang \ #--without-http_referer_module \ - #--with-http_v2_module \ #--with-http_spdy_module \ time ngx-build $force $version \ --with-ipv6 \ --with-cc-opt="-I$PCRE_INC -I$OPENSSL_INC" \ + --with-http_v2_module \ --with-http_realip_module \ --with-http_ssl_module \ --add-module=$root/../ndk-nginx-module \ diff --git a/debian/modules/nginx-lua/util/ngx-links b/debian/modules/nginx-lua/util/ngx-links index bf54f46..8afe91e 100755 --- a/debian/modules/nginx-lua/util/ngx-links +++ b/debian/modules/nginx-lua/util/ngx-links @@ -10,7 +10,7 @@ my %opts; getopts('f', \%opts) or die "Usage: $0 [-f] Options: - -f Override exising symbolic links with force + -f Override existing symbolic links with force "; my $root = shift || 'src'; From b04fb6c678504686d3eb5c3066f87082d6105a59 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 26 Aug 2016 16:09:41 +0300 Subject: [PATCH 137/651] Replace http-push module with nchan v1.0.2 by the same author --- debian/control | 5 +- debian/copyright | 19 +- debian/modules/README.Modules-versions | 6 +- .../{nginx-http-push => nchan}/LICENCE | 4 +- debian/modules/nchan/README.md | 597 + debian/modules/nchan/changelog.txt | 265 + debian/modules/nchan/cloc-exclude.txt | 17 + debian/modules/nchan/config | 104 + .../tests => nchan/dev}/.gitignore | 1 + debian/modules/nchan/dev/Gemfile | 28 + debian/modules/nchan/dev/authserver.rb | 62 + debian/modules/nchan/dev/bench-parallel.sh | 27 + debian/modules/nchan/dev/bench.rb | 178 + debian/modules/nchan/dev/cert-key.pem | 28 + debian/modules/nchan/dev/cert.pem | 22 + .../tests => nchan/dev}/chattertest.rb | 0 .../tests => nchan/dev}/debug.sh | 0 debian/modules/nchan/dev/dev.conf | 63 + .../tests => nchan/dev}/examine_coredump.sh | 2 +- .../modules/nchan/dev/gen_config_commands.rb | 129 + debian/modules/nchan/dev/longtest.rb | 184 + .../tests => nchan/dev}/memparse.lua | 76 +- debian/modules/nchan/dev/nginx | 1 + .../dev}/nginx-cachemanager.conf | 0 .../modules/nchan/dev/nginx-nchan/.gitignore | 6 + .../dev/nginx-nchan}/PKGBUILD | 136 +- debian/modules/nchan/dev/nginx-nchan/bl.txt | 6 + .../dev/nginx-nchan}/install | 0 .../dev/nginx-nchan/nchan} | 0 .../dev/nginx-nchan}/nginx.conf | 0 .../dev/nginx-nchan}/nginx.logrotate | 0 .../dev/nginx-nchan}/nginx.service | 0 .../dev/nginx-nchan}/ngx_slab.patch | 0 .../tests => nchan/dev}/nginx-proxy.conf | 0 debian/modules/nchan/dev/nginx.conf | 444 + debian/modules/nchan/dev/nginx.sh | 277 + debian/modules/nchan/dev/package/.gitignore | 1 + .../dev/package/nginx-nchan-static/.gitignore | 5 + .../dev/package/nginx-nchan-static/PKGBUILD | 165 + .../dev/package/nginx-nchan-static/nginx.conf | 1 + .../nginx-nchan-static/nginx.logrotate | 11 + .../package/nginx-nchan-static/nginx.service | 18 + debian/modules/nchan/dev/package/repackage.sh | 28 + debian/modules/nchan/dev/pub-multi.rb | 39 + debian/modules/nchan/dev/pub.rb | 90 + debian/modules/nchan/dev/pubsub.rb | 1483 + debian/modules/nchan/dev/rebuild.sh | 170 + debian/modules/nchan/dev/redis-trib.rb | 1696 + debian/modules/nchan/dev/redis.conf | 1018 + .../nchan/dev/redis_clusterconf/.gitignore | 1 + .../nchan/dev/redis_clusterconf/cluster.sh | 10 + .../nchan/dev/redis_clusterconf/failover.sh | 62 + .../dev/redis_clusterconf/redis-7000.conf | 1018 + .../dev/redis_clusterconf/redis-7001.conf | 1018 + .../dev/redis_clusterconf/redis-7002.conf | 1018 + .../dev/redis_clusterconf/redis-7003.conf | 1018 + .../dev/redis_clusterconf/redis-7004.conf | 1018 + .../dev/redis_clusterconf/redis-7005.conf | 1018 + .../dev/redis_clusterconf/redis-7006.conf | 1018 + .../redis-cluster-node-7000.conf | 7 + .../redis-cluster-node-7001.conf | 7 + .../redis-cluster-node-7002.conf | 7 + .../redis-cluster-node-7003.conf | 7 + .../redis-cluster-node-7004.conf | 7 + .../redis-cluster-node-7005.conf | 7 + .../redis-cluster-node-7006.conf | 2 + debian/modules/nchan/dev/redocument.rb | 295 + debian/modules/nchan/dev/rsck.sh | 67 + debian/modules/nchan/dev/sub.rb | 125 + .../tests => nchan/dev}/test-parallel.sh | 4 +- debian/modules/nchan/dev/test.rb | 875 + debian/modules/nchan/dev/vg.supp | 26977 ++++++++++++++++ debian/modules/nchan/src/.gitignore | 2 + debian/modules/nchan/src/hiredis/.gitignore | 7 + debian/modules/nchan/src/hiredis/.travis.yml | 24 + debian/modules/nchan/src/hiredis/CHANGELOG.md | 110 + debian/modules/nchan/src/hiredis/COPYING | 29 + debian/modules/nchan/src/hiredis/Makefile | 217 + debian/modules/nchan/src/hiredis/README.md | 392 + .../modules/nchan/src/hiredis/adapters/ae.h | 127 + .../nchan/src/hiredis/adapters/libev.h | 147 + .../nchan/src/hiredis/adapters/libevent.h | 108 + .../nchan/src/hiredis/adapters/libuv.h | 121 + debian/modules/nchan/src/hiredis/async.c | 687 + debian/modules/nchan/src/hiredis/async.h | 129 + debian/modules/nchan/src/hiredis/dict.c | 338 + debian/modules/nchan/src/hiredis/dict.h | 126 + .../nchan/src/hiredis/examples/example-ae.c | 62 + .../src/hiredis/examples/example-libev.c | 52 + .../src/hiredis/examples/example-libevent.c | 53 + .../src/hiredis/examples/example-libuv.c | 53 + .../nchan/src/hiredis/examples/example.c | 78 + debian/modules/nchan/src/hiredis/fmacros.h | 21 + debian/modules/nchan/src/hiredis/hiredis.c | 1021 + debian/modules/nchan/src/hiredis/hiredis.h | 223 + debian/modules/nchan/src/hiredis/net.c | 458 + debian/modules/nchan/src/hiredis/net.h | 53 + debian/modules/nchan/src/hiredis/read.c | 525 + debian/modules/nchan/src/hiredis/read.h | 116 + debian/modules/nchan/src/hiredis/sds.c | 1095 + debian/modules/nchan/src/hiredis/sds.h | 105 + debian/modules/nchan/src/hiredis/test.c | 807 + debian/modules/nchan/src/hiredis/win32.h | 42 + debian/modules/nchan/src/nchan_commands.rb | 412 + .../modules/nchan/src/nchan_config_commands.c | 408 + debian/modules/nchan/src/nchan_defs.c | 91 + debian/modules/nchan/src/nchan_defs.h | 107 + debian/modules/nchan/src/nchan_module.c | 817 + debian/modules/nchan/src/nchan_module.h | 74 + debian/modules/nchan/src/nchan_setup.c | 729 + debian/modules/nchan/src/nchan_types.h | 332 + debian/modules/nchan/src/nchan_variables.c | 231 + debian/modules/nchan/src/nchan_variables.h | 1 + .../nchan/src/nchan_websocket_publisher.c | 81 + .../nchan/src/nchan_websocket_publisher.h | 2 + .../nchan/src/store/memory/ipc-handlers.c | 804 + .../nchan/src/store/memory/ipc-handlers.h | 16 + debian/modules/nchan/src/store/memory/ipc.c | 529 + debian/modules/nchan/src/store/memory/ipc.h | 55 + .../modules/nchan/src/store/memory/memstore.c | 2861 ++ .../modules/nchan/src/store/memory/recycloc.c | 47 + .../nchan/src/store/memory/store-private.h | 148 + debian/modules/nchan/src/store/memory/store.h | 11 + .../src/store/ngx_rwlock.c | 6 +- .../src/store/ngx_rwlock.h | 0 .../modules/nchan/src/store/redis/cluster.c | 1257 + .../modules/nchan/src/store/redis/cluster.h | 30 + debian/modules/nchan/src/store/redis/cmp.c | 2835 ++ debian/modules/nchan/src/store/redis/cmp.h | 474 + .../modules/nchan/src/store/redis/rdsstore.c | 2799 ++ .../src/store/redis/redis_lua_commands.h | 1025 + .../src/store/redis/redis_nginx_adapter.c | 271 + .../src/store/redis/redis_nginx_adapter.h | 15 + .../nchan/src/store/redis/scripts/.gitignore | 1 + .../src/store/redis/scripts}/Gemfile | 10 +- .../src/store/redis/scripts/add_fakesub.lua | 29 + .../store/redis/scripts/channel_keepalive.lua | 34 + .../nchan/src/store/redis/scripts/delete.lua | 58 + .../src/store/redis/scripts/find_channel.lua | 45 + .../src/store/redis/scripts/get_message.lua | 156 + .../redis/scripts/get_message_from_key.lua | 9 + .../nchan/src/store/redis/scripts/publish.lua | 278 + .../store/redis/scripts/publish_status.lua | 26 + .../nchan/src/store/redis/scripts/rsck.lua | 199 + .../redis/scripts/subscriber_register.lua | 50 + .../redis/scripts/subscriber_unregister.lua | 49 + .../src/store/redis/scripts/testscripts.rb | 268 + .../nchan/src/store/redis/store-private.h | 195 + debian/modules/nchan/src/store/redis/store.h | 16 + debian/modules/nchan/src/store/spool.c | 1219 + debian/modules/nchan/src/store/spool.h | 113 + debian/modules/nchan/src/store/store_common.c | 7 + debian/modules/nchan/src/store/store_common.h | 12 + debian/modules/nchan/src/subscribers/common.c | 317 + debian/modules/nchan/src/subscribers/common.h | 22 + .../nchan/src/subscribers/eventsource.c | 337 + .../nchan/src/subscribers/eventsource.h | 4 + .../nchan/src/subscribers/http-chunked.c | 256 + .../nchan/src/subscribers/http-chunked.h | 4 + .../src/subscribers/http-multipart-mixed.c | 291 + .../src/subscribers/http-multipart-mixed.h | 3 + .../nchan/src/subscribers/http-raw-stream.c | 150 + .../nchan/src/subscribers/http-raw-stream.h | 1 + .../modules/nchan/src/subscribers/internal.c | 275 + .../modules/nchan/src/subscribers/internal.h | 30 + .../nchan/src/subscribers/intervalpoll.c | 32 + .../nchan/src/subscribers/intervalpoll.h | 1 + .../nchan/src/subscribers/longpoll-private.h | 34 + .../modules/nchan/src/subscribers/longpoll.c | 540 + .../modules/nchan/src/subscribers/longpoll.h | 2 + .../nchan/src/subscribers/memstore_ipc.c | 167 + .../nchan/src/subscribers/memstore_ipc.h | 2 + .../nchan/src/subscribers/memstore_multi.c | 179 + .../nchan/src/subscribers/memstore_multi.h | 2 + .../nchan/src/subscribers/memstore_redis.c | 251 + .../nchan/src/subscribers/memstore_redis.h | 4 + .../modules/nchan/src/subscribers/websocket.c | 1509 + .../modules/nchan/src/subscribers/websocket.h | 4 + debian/modules/nchan/src/uthash.h | 950 + .../nchan/src/util/nchan_bufchainpool.c | 141 + .../nchan/src/util/nchan_bufchainpool.h | 39 + .../modules/nchan/src/util/nchan_channel_id.c | 214 + .../modules/nchan/src/util/nchan_channel_id.h | 1 + .../nchan/src/util/nchan_channel_info.c | 133 + .../nchan/src/util/nchan_channel_info.h | 7 + debian/modules/nchan/src/util/nchan_list.c | 146 + debian/modules/nchan/src/util/nchan_list.h | 47 + debian/modules/nchan/src/util/nchan_msgid.c | 515 + debian/modules/nchan/src/util/nchan_msgid.h | 16 + debian/modules/nchan/src/util/nchan_output.c | 701 + debian/modules/nchan/src/util/nchan_output.h | 26 + debian/modules/nchan/src/util/nchan_rbtree.c | 379 + debian/modules/nchan/src/util/nchan_rbtree.h | 64 + debian/modules/nchan/src/util/nchan_reaper.c | 320 + debian/modules/nchan/src/util/nchan_reaper.h | 33 + .../nchan/src/util/nchan_reuse_queue.c | 151 + .../nchan/src/util/nchan_reuse_queue.h | 24 + .../modules/nchan/src/util/nchan_subrequest.c | 250 + .../modules/nchan/src/util/nchan_subrequest.h | 2 + .../modules/nchan/src/util/nchan_thingcache.c | 208 + .../modules/nchan/src/util/nchan_thingcache.h | 4 + debian/modules/nchan/src/util/nchan_util.c | 383 + debian/modules/nchan/src/util/nchan_util.h | 32 + .../nchan/src/util/ngx_nchan_hacked_slab.c | 761 + .../nchan/src/util/ngx_nchan_hacked_slab.h | 26 + debian/modules/nchan/src/util/shmem.c | 184 + debian/modules/nchan/src/util/shmem.h | 28 + debian/modules/nginx-http-push/README | 206 - debian/modules/nginx-http-push/changelog.txt | 53 - debian/modules/nginx-http-push/config | 26 - debian/modules/nginx-http-push/protocol.txt | 191 - .../nginx-http-push/src/ngx_http_push_defs.c | 59 - .../nginx-http-push/src/ngx_http_push_defs.h | 73 - .../src/ngx_http_push_module.c | 783 - .../src/ngx_http_push_module.h | 31 - .../src/ngx_http_push_module_setup.c | 361 - .../nginx-http-push/src/ngx_http_push_types.h | 120 - .../nginx-http-push/src/store/memory/store.c | 1180 - .../nginx-http-push/src/store/memory/store.h | 1 - .../src/store/ngx_http_push_module_ipc.c | 146 - .../src/store/ngx_http_push_module_ipc.h | 5 - .../src/store/ngx_http_push_store.h | 51 - .../nginx-http-push/src/store/rbtree_util.c | 246 - .../nginx-http-push/src/store/rbtree_util.h | 9 - .../tests/nginx-pushmodule/.gitignore | 5 - .../modules/nginx-http-push/tests/nginx.conf | 121 - debian/modules/nginx-http-push/tests/nginx.sh | 117 - debian/modules/nginx-http-push/tests/pub.rb | 54 - .../modules/nginx-http-push/tests/pubsub.rb | 375 - .../modules/nginx-http-push/tests/rebuild.sh | 55 - debian/modules/nginx-http-push/tests/sub.rb | 52 - debian/modules/nginx-http-push/tests/test.rb | 396 - debian/nginx-extras.NEWS | 6 + debian/rules | 2 +- 234 files changed, 79692 insertions(+), 4802 deletions(-) rename debian/modules/{nginx-http-push => nchan}/LICENCE (90%) create mode 100644 debian/modules/nchan/README.md create mode 100644 debian/modules/nchan/changelog.txt create mode 100644 debian/modules/nchan/cloc-exclude.txt create mode 100644 debian/modules/nchan/config rename debian/modules/{nginx-http-push/tests => nchan/dev}/.gitignore (90%) create mode 100644 debian/modules/nchan/dev/Gemfile create mode 100755 debian/modules/nchan/dev/authserver.rb create mode 100755 debian/modules/nchan/dev/bench-parallel.sh create mode 100755 debian/modules/nchan/dev/bench.rb create mode 100644 debian/modules/nchan/dev/cert-key.pem create mode 100644 debian/modules/nchan/dev/cert.pem rename debian/modules/{nginx-http-push/tests => nchan/dev}/chattertest.rb (100%) rename debian/modules/{nginx-http-push/tests => nchan/dev}/debug.sh (100%) create mode 100644 debian/modules/nchan/dev/dev.conf rename debian/modules/{nginx-http-push/tests => nchan/dev}/examine_coredump.sh (86%) create mode 100755 debian/modules/nchan/dev/gen_config_commands.rb create mode 100755 debian/modules/nchan/dev/longtest.rb rename debian/modules/{nginx-http-push/tests => nchan/dev}/memparse.lua (82%) create mode 120000 debian/modules/nchan/dev/nginx rename debian/modules/{nginx-http-push/tests => nchan/dev}/nginx-cachemanager.conf (100%) create mode 100644 debian/modules/nchan/dev/nginx-nchan/.gitignore rename debian/modules/{nginx-http-push/tests/nginx-pushmodule => nchan/dev/nginx-nchan}/PKGBUILD (53%) create mode 100644 debian/modules/nchan/dev/nginx-nchan/bl.txt rename debian/modules/{nginx-http-push/tests/nginx-pushmodule => nchan/dev/nginx-nchan}/install (100%) rename debian/modules/{nginx-http-push/tests/nginx-pushmodule/pushmodule => nchan/dev/nginx-nchan/nchan} (100%) rename debian/modules/{nginx-http-push/tests/nginx-pushmodule => nchan/dev/nginx-nchan}/nginx.conf (100%) rename debian/modules/{nginx-http-push/tests/nginx-pushmodule => nchan/dev/nginx-nchan}/nginx.logrotate (100%) rename debian/modules/{nginx-http-push/tests/nginx-pushmodule => nchan/dev/nginx-nchan}/nginx.service (100%) rename debian/modules/{nginx-http-push/tests/nginx-pushmodule => nchan/dev/nginx-nchan}/ngx_slab.patch (100%) rename debian/modules/{nginx-http-push/tests => nchan/dev}/nginx-proxy.conf (100%) create mode 100644 debian/modules/nchan/dev/nginx.conf create mode 100755 debian/modules/nchan/dev/nginx.sh create mode 100644 debian/modules/nchan/dev/package/.gitignore create mode 100644 debian/modules/nchan/dev/package/nginx-nchan-static/.gitignore create mode 100644 debian/modules/nchan/dev/package/nginx-nchan-static/PKGBUILD create mode 100644 debian/modules/nchan/dev/package/nginx-nchan-static/nginx.conf create mode 100644 debian/modules/nchan/dev/package/nginx-nchan-static/nginx.logrotate create mode 100644 debian/modules/nchan/dev/package/nginx-nchan-static/nginx.service create mode 100755 debian/modules/nchan/dev/package/repackage.sh create mode 100755 debian/modules/nchan/dev/pub-multi.rb create mode 100755 debian/modules/nchan/dev/pub.rb create mode 100644 debian/modules/nchan/dev/pubsub.rb create mode 100755 debian/modules/nchan/dev/rebuild.sh create mode 100755 debian/modules/nchan/dev/redis-trib.rb create mode 100644 debian/modules/nchan/dev/redis.conf create mode 100644 debian/modules/nchan/dev/redis_clusterconf/.gitignore create mode 100755 debian/modules/nchan/dev/redis_clusterconf/cluster.sh create mode 100755 debian/modules/nchan/dev/redis_clusterconf/failover.sh create mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-7000.conf create mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-7001.conf create mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-7002.conf create mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-7003.conf create mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-7004.conf create mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-7005.conf create mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-7006.conf create mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-cluster-node-7000.conf create mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-cluster-node-7001.conf create mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-cluster-node-7002.conf create mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-cluster-node-7003.conf create mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-cluster-node-7004.conf create mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-cluster-node-7005.conf create mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-cluster-node-7006.conf create mode 100755 debian/modules/nchan/dev/redocument.rb create mode 100755 debian/modules/nchan/dev/rsck.sh create mode 100755 debian/modules/nchan/dev/sub.rb rename debian/modules/{nginx-http-push/tests => nchan/dev}/test-parallel.sh (83%) create mode 100755 debian/modules/nchan/dev/test.rb create mode 100644 debian/modules/nchan/dev/vg.supp create mode 100644 debian/modules/nchan/src/.gitignore create mode 100644 debian/modules/nchan/src/hiredis/.gitignore create mode 100644 debian/modules/nchan/src/hiredis/.travis.yml create mode 100644 debian/modules/nchan/src/hiredis/CHANGELOG.md create mode 100644 debian/modules/nchan/src/hiredis/COPYING create mode 100644 debian/modules/nchan/src/hiredis/Makefile create mode 100644 debian/modules/nchan/src/hiredis/README.md create mode 100644 debian/modules/nchan/src/hiredis/adapters/ae.h create mode 100644 debian/modules/nchan/src/hiredis/adapters/libev.h create mode 100644 debian/modules/nchan/src/hiredis/adapters/libevent.h create mode 100644 debian/modules/nchan/src/hiredis/adapters/libuv.h create mode 100644 debian/modules/nchan/src/hiredis/async.c create mode 100644 debian/modules/nchan/src/hiredis/async.h create mode 100644 debian/modules/nchan/src/hiredis/dict.c create mode 100644 debian/modules/nchan/src/hiredis/dict.h create mode 100644 debian/modules/nchan/src/hiredis/examples/example-ae.c create mode 100644 debian/modules/nchan/src/hiredis/examples/example-libev.c create mode 100644 debian/modules/nchan/src/hiredis/examples/example-libevent.c create mode 100644 debian/modules/nchan/src/hiredis/examples/example-libuv.c create mode 100644 debian/modules/nchan/src/hiredis/examples/example.c create mode 100644 debian/modules/nchan/src/hiredis/fmacros.h create mode 100644 debian/modules/nchan/src/hiredis/hiredis.c create mode 100644 debian/modules/nchan/src/hiredis/hiredis.h create mode 100644 debian/modules/nchan/src/hiredis/net.c create mode 100644 debian/modules/nchan/src/hiredis/net.h create mode 100644 debian/modules/nchan/src/hiredis/read.c create mode 100644 debian/modules/nchan/src/hiredis/read.h create mode 100644 debian/modules/nchan/src/hiredis/sds.c create mode 100644 debian/modules/nchan/src/hiredis/sds.h create mode 100644 debian/modules/nchan/src/hiredis/test.c create mode 100644 debian/modules/nchan/src/hiredis/win32.h create mode 100644 debian/modules/nchan/src/nchan_commands.rb create mode 100644 debian/modules/nchan/src/nchan_config_commands.c create mode 100644 debian/modules/nchan/src/nchan_defs.c create mode 100644 debian/modules/nchan/src/nchan_defs.h create mode 100755 debian/modules/nchan/src/nchan_module.c create mode 100644 debian/modules/nchan/src/nchan_module.h create mode 100644 debian/modules/nchan/src/nchan_setup.c create mode 100644 debian/modules/nchan/src/nchan_types.h create mode 100644 debian/modules/nchan/src/nchan_variables.c create mode 100644 debian/modules/nchan/src/nchan_variables.h create mode 100644 debian/modules/nchan/src/nchan_websocket_publisher.c create mode 100644 debian/modules/nchan/src/nchan_websocket_publisher.h create mode 100644 debian/modules/nchan/src/store/memory/ipc-handlers.c create mode 100644 debian/modules/nchan/src/store/memory/ipc-handlers.h create mode 100755 debian/modules/nchan/src/store/memory/ipc.c create mode 100755 debian/modules/nchan/src/store/memory/ipc.h create mode 100755 debian/modules/nchan/src/store/memory/memstore.c create mode 100644 debian/modules/nchan/src/store/memory/recycloc.c create mode 100644 debian/modules/nchan/src/store/memory/store-private.h create mode 100644 debian/modules/nchan/src/store/memory/store.h rename debian/modules/{nginx-http-push => nchan}/src/store/ngx_rwlock.c (97%) rename debian/modules/{nginx-http-push => nchan}/src/store/ngx_rwlock.h (100%) create mode 100644 debian/modules/nchan/src/store/redis/cluster.c create mode 100644 debian/modules/nchan/src/store/redis/cluster.h create mode 100644 debian/modules/nchan/src/store/redis/cmp.c create mode 100644 debian/modules/nchan/src/store/redis/cmp.h create mode 100755 debian/modules/nchan/src/store/redis/rdsstore.c create mode 100644 debian/modules/nchan/src/store/redis/redis_lua_commands.h create mode 100644 debian/modules/nchan/src/store/redis/redis_nginx_adapter.c create mode 100644 debian/modules/nchan/src/store/redis/redis_nginx_adapter.h create mode 100644 debian/modules/nchan/src/store/redis/scripts/.gitignore rename debian/modules/{nginx-http-push/tests => nchan/src/store/redis/scripts}/Gemfile (61%) create mode 100644 debian/modules/nchan/src/store/redis/scripts/add_fakesub.lua create mode 100644 debian/modules/nchan/src/store/redis/scripts/channel_keepalive.lua create mode 100644 debian/modules/nchan/src/store/redis/scripts/delete.lua create mode 100644 debian/modules/nchan/src/store/redis/scripts/find_channel.lua create mode 100644 debian/modules/nchan/src/store/redis/scripts/get_message.lua create mode 100644 debian/modules/nchan/src/store/redis/scripts/get_message_from_key.lua create mode 100644 debian/modules/nchan/src/store/redis/scripts/publish.lua create mode 100644 debian/modules/nchan/src/store/redis/scripts/publish_status.lua create mode 100644 debian/modules/nchan/src/store/redis/scripts/rsck.lua create mode 100644 debian/modules/nchan/src/store/redis/scripts/subscriber_register.lua create mode 100644 debian/modules/nchan/src/store/redis/scripts/subscriber_unregister.lua create mode 100755 debian/modules/nchan/src/store/redis/scripts/testscripts.rb create mode 100644 debian/modules/nchan/src/store/redis/store-private.h create mode 100755 debian/modules/nchan/src/store/redis/store.h create mode 100755 debian/modules/nchan/src/store/spool.c create mode 100644 debian/modules/nchan/src/store/spool.h create mode 100644 debian/modules/nchan/src/store/store_common.c create mode 100644 debian/modules/nchan/src/store/store_common.h create mode 100644 debian/modules/nchan/src/subscribers/common.c create mode 100644 debian/modules/nchan/src/subscribers/common.h create mode 100644 debian/modules/nchan/src/subscribers/eventsource.c create mode 100644 debian/modules/nchan/src/subscribers/eventsource.h create mode 100644 debian/modules/nchan/src/subscribers/http-chunked.c create mode 100644 debian/modules/nchan/src/subscribers/http-chunked.h create mode 100644 debian/modules/nchan/src/subscribers/http-multipart-mixed.c create mode 100644 debian/modules/nchan/src/subscribers/http-multipart-mixed.h create mode 100644 debian/modules/nchan/src/subscribers/http-raw-stream.c create mode 100644 debian/modules/nchan/src/subscribers/http-raw-stream.h create mode 100644 debian/modules/nchan/src/subscribers/internal.c create mode 100644 debian/modules/nchan/src/subscribers/internal.h create mode 100644 debian/modules/nchan/src/subscribers/intervalpoll.c create mode 100644 debian/modules/nchan/src/subscribers/intervalpoll.h create mode 100644 debian/modules/nchan/src/subscribers/longpoll-private.h create mode 100644 debian/modules/nchan/src/subscribers/longpoll.c create mode 100644 debian/modules/nchan/src/subscribers/longpoll.h create mode 100644 debian/modules/nchan/src/subscribers/memstore_ipc.c create mode 100644 debian/modules/nchan/src/subscribers/memstore_ipc.h create mode 100644 debian/modules/nchan/src/subscribers/memstore_multi.c create mode 100644 debian/modules/nchan/src/subscribers/memstore_multi.h create mode 100644 debian/modules/nchan/src/subscribers/memstore_redis.c create mode 100644 debian/modules/nchan/src/subscribers/memstore_redis.h create mode 100644 debian/modules/nchan/src/subscribers/websocket.c create mode 100644 debian/modules/nchan/src/subscribers/websocket.h create mode 100644 debian/modules/nchan/src/uthash.h create mode 100644 debian/modules/nchan/src/util/nchan_bufchainpool.c create mode 100644 debian/modules/nchan/src/util/nchan_bufchainpool.h create mode 100644 debian/modules/nchan/src/util/nchan_channel_id.c create mode 100644 debian/modules/nchan/src/util/nchan_channel_id.h create mode 100644 debian/modules/nchan/src/util/nchan_channel_info.c create mode 100644 debian/modules/nchan/src/util/nchan_channel_info.h create mode 100644 debian/modules/nchan/src/util/nchan_list.c create mode 100644 debian/modules/nchan/src/util/nchan_list.h create mode 100644 debian/modules/nchan/src/util/nchan_msgid.c create mode 100644 debian/modules/nchan/src/util/nchan_msgid.h create mode 100644 debian/modules/nchan/src/util/nchan_output.c create mode 100644 debian/modules/nchan/src/util/nchan_output.h create mode 100644 debian/modules/nchan/src/util/nchan_rbtree.c create mode 100644 debian/modules/nchan/src/util/nchan_rbtree.h create mode 100644 debian/modules/nchan/src/util/nchan_reaper.c create mode 100644 debian/modules/nchan/src/util/nchan_reaper.h create mode 100644 debian/modules/nchan/src/util/nchan_reuse_queue.c create mode 100644 debian/modules/nchan/src/util/nchan_reuse_queue.h create mode 100644 debian/modules/nchan/src/util/nchan_subrequest.c create mode 100644 debian/modules/nchan/src/util/nchan_subrequest.h create mode 100644 debian/modules/nchan/src/util/nchan_thingcache.c create mode 100644 debian/modules/nchan/src/util/nchan_thingcache.h create mode 100644 debian/modules/nchan/src/util/nchan_util.c create mode 100644 debian/modules/nchan/src/util/nchan_util.h create mode 100644 debian/modules/nchan/src/util/ngx_nchan_hacked_slab.c create mode 100644 debian/modules/nchan/src/util/ngx_nchan_hacked_slab.h create mode 100644 debian/modules/nchan/src/util/shmem.c create mode 100644 debian/modules/nchan/src/util/shmem.h delete mode 100644 debian/modules/nginx-http-push/README delete mode 100644 debian/modules/nginx-http-push/changelog.txt delete mode 100644 debian/modules/nginx-http-push/config delete mode 100644 debian/modules/nginx-http-push/protocol.txt delete mode 100644 debian/modules/nginx-http-push/src/ngx_http_push_defs.c delete mode 100644 debian/modules/nginx-http-push/src/ngx_http_push_defs.h delete mode 100755 debian/modules/nginx-http-push/src/ngx_http_push_module.c delete mode 100644 debian/modules/nginx-http-push/src/ngx_http_push_module.h delete mode 100644 debian/modules/nginx-http-push/src/ngx_http_push_module_setup.c delete mode 100644 debian/modules/nginx-http-push/src/ngx_http_push_types.h delete mode 100755 debian/modules/nginx-http-push/src/store/memory/store.c delete mode 100644 debian/modules/nginx-http-push/src/store/memory/store.h delete mode 100644 debian/modules/nginx-http-push/src/store/ngx_http_push_module_ipc.c delete mode 100644 debian/modules/nginx-http-push/src/store/ngx_http_push_module_ipc.h delete mode 100755 debian/modules/nginx-http-push/src/store/ngx_http_push_store.h delete mode 100644 debian/modules/nginx-http-push/src/store/rbtree_util.c delete mode 100644 debian/modules/nginx-http-push/src/store/rbtree_util.h delete mode 100644 debian/modules/nginx-http-push/tests/nginx-pushmodule/.gitignore delete mode 100644 debian/modules/nginx-http-push/tests/nginx.conf delete mode 100755 debian/modules/nginx-http-push/tests/nginx.sh delete mode 100755 debian/modules/nginx-http-push/tests/pub.rb delete mode 100644 debian/modules/nginx-http-push/tests/pubsub.rb delete mode 100755 debian/modules/nginx-http-push/tests/rebuild.sh delete mode 100755 debian/modules/nginx-http-push/tests/sub.rb delete mode 100755 debian/modules/nginx-http-push/tests/test.rb create mode 100644 debian/nginx-extras.NEWS diff --git a/debian/control b/debian/control index 5badc14..912e6c4 100644 --- a/debian/control +++ b/debian/control @@ -24,7 +24,8 @@ Build-Depends: autotools-dev, libssl-dev, libxslt1-dev, po-debconf, - zlib1g-dev + zlib1g-dev, + libhiredis-dev Standards-Version: 3.9.8.0 Homepage: http://nginx.net Vcs-Git: https://anonscm.debian.org/cgit/collab-maint/nginx.git @@ -211,7 +212,7 @@ Description: nginx web/proxy server (extended version) MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. . THIRD PARTY MODULES: Auth PAM, Cache Purge, DAV Ext, Echo, Fancy Index, - Headers More, Embedded Lua, HTTP Push, HTTP Substitutions, Upload Progress, + Headers More, Embedded Lua, HTTP Substitutions, Nchan, Upload Progress, Upstream Fair Queue. Package: nginx-extras-dbg diff --git a/debian/copyright b/debian/copyright index 0edb73b..019dc9d 100644 --- a/debian/copyright +++ b/debian/copyright @@ -70,9 +70,20 @@ Copyright: Copyright (c) 2007 Grzegorz Nosek Igor Sysoev License: BSD-2-clause -Files: debian/modules/nginx-http-push/* -Copyright: Copyright (c) 2009 Leo Ponomarev -License: Expat +Files: debian/modules/nchan/* +Copyright: 2009-2016 Leo Ponomarev +License: MIT + +Files: debian/modules/nchan/src/store/redis/cmp.* +Copyright: 2015 Charles Gunyon +License: MIT + +Files: debian/modules/nchan/src/hiredis/* +Copyright: 2009-2011, Salvatore Sanfilippo + 2010-2011, Pieter Noordhuis + Matt Stancliff + Jan-Erik Rediger +License: BSD-3-clause Files: debian/modules/nginx-upload-progress/* Copyright: Brice Figureau @@ -173,7 +184,7 @@ License: BSD-4-clause OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -License: Expat +License: MIT Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index 1ad980c..6f32994 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -29,9 +29,9 @@ README for Modules versions Version: a18b409 Dynamic: No, https://github.com/gnosek/nginx-upstream-fair/pull/21 - nginx-push - Homepage: https://github.com/slact/nginx_http_push_module - Version: 0.73 + nchan + Homepage: https://github.com/slact/nchan + Version: 1.0.2 nginx-upload-progress Homepage: https://github.com/masterzen/nginx-upload-progress-module diff --git a/debian/modules/nginx-http-push/LICENCE b/debian/modules/nchan/LICENCE similarity index 90% rename from debian/modules/nginx-http-push/LICENCE rename to debian/modules/nchan/LICENCE index ad9c957..aed1f30 100644 --- a/debian/modules/nginx-http-push/LICENCE +++ b/debian/modules/nchan/LICENCE @@ -1,6 +1,6 @@ This work is distributed under the MIT Licence. -Copyright (c) 2009 Leo Ponomarev +Written by Leo Ponomarev (slact) 2009-2015. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation @@ -11,7 +11,7 @@ copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be +The above authorship notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, diff --git a/debian/modules/nchan/README.md b/debian/modules/nchan/README.md new file mode 100644 index 0000000..fecd417 --- /dev/null +++ b/debian/modules/nchan/README.md @@ -0,0 +1,597 @@ + + +https://nchan.slact.net + +Nchan is a scalable, flexible pub/sub server for the modern web, built as a module for the [Nginx](http://nginx.org) web server. It can be configured as a standalone server, or as a shim between your application and tens, thousands, or millions of live subscribers. It can buffer messages in memory, on-disk, or via [Redis](http://redis.io). All connections are handled asynchronously and distributed among any number of worker processes. It can also scale to many nginx server instances with [Redis](http://redis.io). + +Messages are [published](#publisher-endpoints) to channels with HTTP `POST` requests or websockets, and [subscribed](#subscriber-endpoint) also through websockets, [long-polling](#long-polling), [EventSource](#eventsource) (SSE), old-fashioned [interval polling](#interval-polling), [and](#http-chunked-transfer) [more](#http-multipart-mixed). Each subscriber can listen to [up to 255 channels](#channel-multiplexing) per connection, and can be optionally [authenticated](https://nchan.slact.net/details#authenticate-with-nchan_authorize_request) via a custom application url. An [events](#nchan_channel_event_string) [meta channel](#nchan_channel_events_channel_id) is also available for debugging. + +For use in a web browser, you can try the [NchanSubscriber.js](https://github.com/slact/nchan/blob/master/NchanSubscriber.js) wrapper library. It supports Long-Polling, EventSource, and resumable Websockets -- or you can build your own. + +## Status and History + +The latest Nchan release is v1.0.2 (August 29, 2016) ([changelog](https://nchan.slact.net/changelog)). + +The first iteration of Nchan was written in 2009-2010 as the [Nginx HTTP Push Module](https://pushmodule.slact.net), and was vastly refactored into its present state in 2014-2016. The present release is in the **testing** phase. The core features and old functionality are thoroughly tested and stable. Some of the new functionality, especially Redis Cluster may be a bit buggy. + +Please help make the entire codebase ready for production use! Report any quirks, bugs, leaks, crashes, or larvae you find. + +#### Upgrade from Nginx HTTP Push Module + +Although Nchan is backwards-compatible with all Push Module configuration directives, some of the more unusual and rarely used settings have been disabled and will be ignored (with a warning). See the [upgrade page](https://nchan.slact.net/upgrade) for a detailed list of changes and improvements, as well as a full list of incompatibilities. + + +## Does it scale? + +benchmarking internal subscriber response times + +Yes it does. Like Nginx, Nchan can easily handle as much traffic as you can throw at it. I've tried to benchmark it, but my benchmarking tools are much slower than Nchan. The data I've gathered is on how long Nchan itself takes to respond to every subscriber after publishing a message -- this excludes TCP handshake times and internal HTTP request parsing. Basically, it measures how Nchan scales assuming all other components are already tuned for scalability. The graphed data are averages of 5 runs with 50-byte messages. + +With a well-tuned OS and network stack on commodity server hardware, expect to handle upwards of 300K concurrent subscribers per second at minimal CPU load. Nchan can also be scaled out to multiple Nginx instances using the [Redis storage engine](#nchan_use_redis), and that too can be scaled up beyond a single-point-of-failure by using Redis Cluster. + +Currently, Nchan's performance is limited by available memory bandwidth. This can be improved significantly in future versions with fewer allocations and the use of contiguous memory pools. Please consider supporting Nchan to speed up the work of memory cache optimization. + +## Install + +#### Download Packages + - [Arch Linux](https://archlinux.org): [nginx-nchan](https://aur.archlinux.org/packages/nginx-nchan/) and [nginx-nchan-git](https://aur.archlinux.org/packages/nginx-nchan-git/) are available in the Arch User Repository. + - Mac OS X: a [homebrew](http://brew.sh) package is available. `brew tap homebrew/nginx; brew install nginx-full --with-nchan-module` + - [Debian](https://www.debian.org/): [nginx-common.deb](https://nchan.slact.net/download/nginx-common.deb) and [nginx-extras.deb](https://nchan.slact.net/download/nginx-extras.deb). Download both and install them with `dpkg -i`, followed by `sudo apt-get -f install`. These packages should soon be available directly from the Debian repository. + - [Ubuntu](http://www.ubuntu.com/): [nginx-common.ubuntu.deb](https://nchan.slact.net/download/nginx-common.ubuntu.deb) and [nginx-extras.ubuntu.deb](https://nchan.slact.net/download/nginx-extras.ubuntu.deb). Download both and install them with `dpkg -i`, followed by `sudo apt-get -f install`. Who knows when Ubuntu will add them to their repository?... + - [Fedora](https://fedoraproject.org): A 64-bit binary rpm and a source rpm are available: [nginx-nchan.x86_64.rpm](https://nchan.slact.net/download/nginx-nchan.x86-64.rpm), [ngx-nchan.src.rpm](https://nchan.slact.net/download/nginx-nchan.src.rpm). + - A statically compiled binary and associated linux nginx installation files are also [available as a tarball](https://nchan.slact.net/download/nginx-nchan-latest.tar.gz). + + +#### Build From Source +Grab the latest copy of Nginx from [nginx.org](http://nginx.org). Grab the latest Nchan source from [github](https://github.com/slact/nchan/releases). Follow the instructions for [building Nginx](https://www.nginx.com/resources/wiki/start/topics/tutorials/install/#source-releases), except during the `configure` stage, add +``` +./configure --add-module=path/to/nchan ... +``` + +If you're using Nginx > 1.9.11, you can build Nchan as a [dynamic module](https://www.nginx.com/blog/dynamic-modules-nginx-1-9-11/) with `--add-dynamic-module=path/to/nchan` + +Run `make`, `make install`, and enjoy. (Caution, contents may be hot.) + +## Conceptual Overview + +The basic unit of most pub/sub solutions is the messaging *channel*. Nchan is no different. Publishers send messages to channels with a certain *channel id*, and subscribers subscribed to those channels receive them. Some number of messages may be buffered for a time in a channel's message buffer before they are deleted. Pretty simple, right? + +Well... the trouble is that nginx configuration does not deal with channels, publishers, and subscribers. Rather, it has several sections for incoming requests to match against *server* and *location* sections. **Nchan configuration directives map servers and locations onto channel publishing and subscribing endpoints**: + +```nginx +#very basic nchan config +worker_processes 5; + +http { + server { + listen 80; + + location = /sub { + nchan_subscriber; + nchan_channel_id foobar; + } + + location = /pub { + nchan_publisher; + nchan_channel_id foobar; + } + } +} +``` + +The above maps requests to the URI `/sub` onto the channel `foobar`'s *subscriber endpoint* , and similarly `/pub` onto channel `foobar`'s *publisher endpoint*. + + +#### Publisher Endpoints + +Publisher endpoints are Nginx config *locations* with the [*`nchan_publisher`*](#nchan_publisher) directive. + +Messages can be published to a channel by sending HTTP **POST** requests with the message contents to the *publisher endpoint* locations. You can also publish messages through a **Websocket** connection to the same location. + +##### Publishing Messages + +Requests and websocket messages are responded to with information about the channel at time of message publication. Here's an example from publishing with `curl`: + +```console +> curl --request POST --data "test message" http://127.0.0.1:80/pub + + queued messages: 5 + last requested: 18 sec. ago + active subscribers: 0 + last message id: 1450755280:0 +``` + +The response can be in plaintext (as above), JSON, or XML, based on the request's *`Accept`* header: + +```console +> curl --request POST --data "test message" -H "Accept: text/json" http://127.0.0.2:80/pub + + {"messages": 6, "requested": 55, "subscribers": 0, "last_message_id": "1450755317:0" } +``` + +Websocket publishers also receive the same responses when publishing, with the encoding determined by the *`Accept`* header present during the handshake. + +The response code for an HTTP request is *`202` Accepted* if no subscribers are present at time of publication, or *`201` Created* if at least 1 subscriber was present. + +Metadata can be added to a message when using an HTTP POST request for publishing. A `Content-Type` header will be associated as the message's content type (and output to Long-Poll, Interval-Poll, and multipart/mixed subscribers). A `X-EventSource-Event` header can also be used to associate an EventSource `event:` line value with a message. + +##### Other Publisher Endpoint Actions + +**HTTP `GET`** requests return channel information without publishing a message. The response code is `200` if the channel exists, and `404` otherwise: +```console +> curl --request POST --data "test message" http://127.0.0.2:80/pub + ... + +> curl -v --request GET -H "Accept: text/json" http://127.0.0.2:80/pub + + {"messages": 1, "requested": 7, "subscribers": 0, "last_message_id": "1450755421:0" } +``` + + +**HTTP `DELETE`** requests delete a channel and end all subscriber connections. Like the `GET` requests, this returns a `200` status response with channel info if the channel existed, and a `404` otherwise. + +#### Subscriber Endpoint + +Subscriber endpoints are Nginx config *locations* with the [*`nchan_subscriber`*](#nchan_subscriber) directive. + +Nchan supports several different kinds of subscribers for receiving messages: [*Websocket*](#websocket), [*EventSource*](#eventsource) (Server Sent Events), [*Long-Poll*](#long-polling), [*Interval-Poll*](#interval-polling). [*HTTP chunked transfer*](#http-chunked-transfer), and [*HTTP multipart/mixed*](#http-multipart-mixed). + +- ##### Long-Polling + The tried-and-true server-push method supported by every browser out there. + Initiated by sending an HTTP `GET` request to a channel subscriber endpoint. + The long-polling subscriber walks through a channel's message queue via the built-in cache mechanism of HTTP clients, namely with the "`Last-Modified`" and "`Etag`" headers. Explicitly, to receive the next message for given a long-poll subscriber response, send a request with the "`If-Modified-Since`" header set to the previous response's "`Last-Modified`" header, and "`If-None-Match`" likewise set to the previous response's "`Etag`" header. + Sending a request without a "`If-Modified-Since`" or "`If-None-Match`" headers returns the oldest message in a channel's message queue, or waits until the next published message, depending on the value of the `nchan_subscriber_first_message` config directive. + A message's associated content type, if present, will be sent to this subscriber with the `Content-Type` header. + +- ##### Interval-Polling + Works just like long-polling, except if the requested message is not yet available, immediately responds with a `304 Not Modified`. + There is no way to differentiate between long-poll and interval-poll subscriber requests, so long-polling must be disabled for a subscriber location if you wish to use interval-polling. + +- ##### Websocket + Bidirectional communication for web browsers. Part of the [HTML5 spec](http://www.w3.org/TR/2014/REC-html5-20141028/single-page.html). Nchan supports the latest protocol version 13 ([RFC 6455](https://tools.ietf.org/html/rfc6455)). + Initiated by sending a websocket handshake to the desired subscriber endpoint location. + If the websocket connection is closed by the server, the `close` frame will contain the HTTP response code and status line describing the reason for closing the connection. Server-initiated keep-alive pings can be configured with the [`nchan_websocket_ping_interval`](#nchan_websocket_ping_interval) config directive. Websocket extensions are not yet supported. + Messages published through a websocket connection can be forwarded to an upstream application with the [`nchan_publisher_upstream_request`](nchan_publisher_upstream_request) config directive. + Websocket subscribers can use the custom `ws+meta.nchan` subprotocol to receive message metadata with messages, making websocket connections resumable. Messages received with this subprotocol are of the form +
+  id: message_id
+  content-type: message_content_type
+  \n
+  message_data
+  
+ The `content-type:` line may be omitted. +- ##### EventSource + Also known as [Server-Sent Events](https://en.wikipedia.org/wiki/Server-sent_events) or SSE, it predates Websockets in the [HTML5 spec](http://www.w3.org/TR/2014/REC-html5-20141028/single-page.html), and is a [very simple protocol](http://www.w3.org/TR/eventsource/#event-stream-interpretation). + Initiated by sending an HTTP `GET` request to a channel subscriber endpoint with the "`Accept: text/event-stream`" header. + Each message `data: ` segment will be prefaced by the message `id: `. + To resume a closed EventSource connection from the last-received message, one *should* start the connection with the "`Last-Event-ID`" header set to the last message's `id`. + Unfortunately, browsers [don't support setting](http://www.w3.org/TR/2011/WD-eventsource-20111020/#concept-event-stream-last-event-id) this header for an `EventSource` object, so by default the last message id is set either from the "`Last-Event-Id`" header or the `last_event_id` url query string argument. + This behavior can be configured via the [`nchan_subscriber_last_message_id`](#nchan_subscriber_last_message_id) config. + A message's associated `event` type, if present, will be sent to this subscriber with the `event:` line. + +- ##### HTTP [multipart/mixed](http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html#z0) + The `multipart/mixed` MIMEtype was conceived for emails, but hey, why not use it for HTTP? It's easy to parse and includes metadata with each message. + Initiated by including an `Accept: multipart/mixed` header. + The response headers and the unused "preamble" portion of the response body are sent right away, with the boundary string generated randomly for each subscriber. Each subsequent message will be sent as one part of the multipart message, and will include the message time and tag (`Last-Modified` and `Etag`) as well as the optional `Content-Type` headers. + Each message is terminated with the next multipart message's boundary **without a trailing newline**. While this conforms to the multipart spec, it is unusual as multipart messages are defined as *starting*, rather than ending with a boundary. + A message's associated content type, if present, will be sent to this subscriber with the `Content-Type` header. + +- ##### HTTP Raw Stream + A simple subscription method similar to the [streaming subscriber](https://github.com/wandenberg/nginx-push-stream-module/blob/master/docs/directives/subscribers.textile#push_stream_subscriber) of the [Nginx HTTP Push Stream Module](https://github.com/wandenberg/nginx-push-stream-module). Messages are appended to the response body, separated by a newline or configurable by `nchan_subscriber_http_raw_stream_separator`. + +- ##### HTTP [Chunked Transfer](http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1) + This subscription method uses the `chunked` `Transfer-Encoding` to receive messages. + Initiated by explicitly including `chunked` in the [`TE` header](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.39): + `TE: chunked` (or `TE: chunked;q=??` where the qval > 0) + The response headers are sent right away, and each message will be sent as an individual chunk. Note that because a zero-length chunk terminates the transfer, **zero-length messages will not be sent** to the subscriber. + Unlike the other subscriber types, the `chunked` subscriber cannot be used with http/2 because it dissallows chunked encoding. + +#### PubSub Endpoint + +PubSub endpoints are Nginx config *locations* with the [*`nchan_pubsub`*](#nchan_pubsub) directive. + +A combination of *publisher* and *subscriber* endpoints, this location treats all HTTP `GET` +requests as subscribers, and all HTTP `POST` as publishers. One simple use case is an echo server: + +```nginx + location = /pubsub { + nchan_pubsub; + nchan_channel_id foobar; + } +``` + +A more applicable setup may set different publisher and subscriber channel ids: + +```nginx + location = /pubsub { + nchan_pubsub; + nchan_publisher_channel_id foo; + nchan_subscriber_channel_id bar; + } +``` + +Here, subscribers will listen for messages on channel `foo`, and publishers will publish messages to channel `bar`. This can be useful when setting up websocket proxying between web clients and your application. + +### The Channel ID + +So far the examples have used static channel ids, which is not very useful in practice. It can be set to any nginx *variable*, such as a querystring argument, a header value, or a part of the location url: + +```nginx + location = /sub_by_ip { + #channel id is the subscriber's IP address + nchan_subscriber; + nchan_channel_id $remote_addr; + } + + location /sub_by_querystring { + #channel id is the query string parameter chanid + # GET /sub/sub_by_querystring?foo=bar&chanid=baz will have the channel id set to 'baz' + nchan_subscriber; + nchan_channel_id $arg_chanid; + } + + location ~ /sub/(\w+)$ { + #channel id is the word after /sub/ + # GET /sub/foobar_baz will have the channel id set to 'foobar_baz' + # I hope you know your regular expressions... + nchan_subscriber; + nchan_channel_id $1; #first capture of the location match + } +``` + +#### Channel Multiplexing + +Any subscriber location can be an endpoint for up to 255 channels. Messages published to all the specified channels will be delivered in-order to the subscriber. There are two ways to enable multiplexing: + +Up to 7 channel ids can be specified for the `nchan_channel_id` or `nchan_channel_subscriber_id` config directive: + +```nginx + location ~ /multisub/(\w+)/(\w+)$ { + nchan_subscriber; + nchan_channel_id "$1" "$2" "common_channel"; + #GET /multisub/foo/bar will be subscribed to: + # channels 'foo', 'bar', and 'common_channel', + #and will receive messages from all of the above. + } +``` + +For more than 7 channels, `nchan_channel_id_split_delimiter` can be used to split the `nchan_channel_id` or `nchan_channel_subscriber_id` into up to 255 individual channel ids: + +```nginx + location ~ /multisub-split/(.*)$ { + nchan_subscriber; + nchan_channel_id "$1"; + nchan_channel_id_split_delimiter ","; + #GET /multisub-split/foo,bar,baz,a will be subscribed to: + # channels 'foo', 'bar', 'baz', and 'a' + #and will receive messages from all of the above. + } +``` + +`DELETE` requests on any channel are forwarded to relevant multi-channel subscribers, and their connections are terminated. + +Publishing to multiple channels with a single request is also possible, with similar configuration: + +```nginx + location ~ /multipub/(\w+)/(\w+)$ { + nchan_publisher; + nchan_channel_id "$1" "$2" "another_channel"; + } +``` +## Storage + +Nchan can stores messages in memory, on disk, or via Redis. Memory storage is much faster, whereas Redis has additional overhead as is considerably slower for publishing messages, but offers near unlimited scalability for broadcast use cases with far more subscribers than publishers. + +### Memory Storage + +This storage method uses a segment of shared memory to store messages and channel data. Large messages as determined by Nginx's caching layer are stored on-disk. The size of the memory segment is configured with `nchan_max_reserved_memory`. Data stored here is not persistent, and is lost if Nginx is restarted or reloaded. + +### Redis + +Nchan can also store messages and channels on a Redis server, or in a Redis cluster. To use a Redis server, set `nchan_use_redis on;` and set the server url with `nchan_redis_url`. These two settings are inheritable by nested locations, so it is enough to set them within an `http { }` block to enable Redis for all Nchan locations in that block. Different locations can also use different Redis servers. + +To use a Redis Cluster, the Redis servers acting as cluster nodes need to be configured in an `upstream { }` block: + +```nginx + upstream redis_cluster { + nchan_redis_server redis://127.0.0.1:7000; + nchan_redis_server redis://127.0.0.1:7001; + nchan_redis_server redis://127.0.0.1:7002; + } +``` + +It is best to specify all master cluster nodes, but this is not required -- as long as Nchan can connect to at least 1 node, it will discover and connect to the whole cluster. + +To use Redis Cluster in an Nchan location, use the `nchan_redis_pass` setting: + +```nginx + location ~ /pubsub/(\w+)$ { + nchan_channel_id $1; + nchan_pubsub; + nchan_redis_pass redis_cluster; + } + +``` + +Note that `nchan_redis_pass` implies `nchan_use_redis on;`, and that this setting is *not* inherited by nested locations. + +When connecting several Nchan servers to the same Redis server (or cluster), the servers **must have their times synced up**. Failure to do so may result in missing and duplicated messages. + +## Variables + +Nchan makes several variables usabled in the config file: + +- `$nchan_channel_id` + The channel id extracted from a publisher or subscriber location request. For multiplexed locations, this is the first channel id in the list. + +- `$nchan_channel_id1`, `$nchan_channel_id2`, `$nchan_channel_id3`, `$nchan_channel_id4` + As above, but for the nth channel id in multiplexed channels. + +- `$nchan_subscriber_type` + For subscriber locations, this variable is set to the subscriber type (websocket, longpoll, etc.). + +- `$nchan_publisher_type` + For subscriber locations, this variable is set to the subscriber type (http or websocket). + +- `$nchan_prev_message_id`, `$nchan_message_id` + The current and previous (if applicable) message id for publisher request or subscriber response. + +- `$nchan_channel_event` + For channel events, this is the event name. Useful when configuring `nchan_channel_event_string`. + +Additionally, `nchan_stub_status` data is also exposed as variables. These are available only when `nchan_stub_status` is enabled on at least one location: + +- `$nchan_stub_status_total_published_messages` +- `$nchan_stub_status_stored_messages` +- `$nchan_stub_status_shared_memory_used` +- `$nchan_stub_status_channels` +- `$nchan_stub_status_subscribers` +- `$nchan_stub_status_redis_pending_commands` +- `$nchan_stub_status_redis_connected_servers` +- `$nchan_stub_status_total_ipc_alerts_received` +- `$nchan_stub_status_ipc_queued_alerts` +- `$nchan_stub_status_total_ipc_send_delay` +- `$nchan_stub_status_total_ipc_receive_delay` + + +## Configuration Directives + +- **nchan_channel_id** + arguments: 1 - 7 + default: `(none)` + context: server, location, if + > Channel id for a publisher or subscriber location. Can have up to 4 values to subscribe to up to 4 channels. + +- **nchan_channel_id_split_delimiter** + arguments: 1 + default: `(none)` + context: server, location, if + > Split the channel id into several ids for multiplexing using the delimiter string provided. + +- **nchan_eventsource_event** + arguments: 1 + default: `(none)` + context: server, location, if + > Set the EventSource `event:` line to this value. When used in a publisher location, overrides the published message's `X-EventSource-Event` header and associates the message with the given value. When used in a subscriber location, overrides all messages' associated `event:` string with the given value. + +- **nchan_longpoll_multipart_response** `[ off | on | raw ]` + arguments: 1 + default: `off` + context: server, location, if + > when set to 'on', enable sending multiple messages in a single longpoll response, separated using the multipart/mixed content-type scheme. If there is only one available message in response to a long-poll request, it is sent unmodified. This is useful for high-latency long-polling connections as a way to minimize round-trips to the server. When set to 'raw', sends multiple messages using the http-raw-stream message separator. + +- **nchan_publisher** `[ http | websocket ]` + arguments: 0 - 2 + default: `http websocket` + context: server, location, if + legacy name: push_publisher + > Defines a server or location as a publisher endpoint. Requests to a publisher location are treated as messages to be sent to subscribers. See the protocol documentation for a detailed description. + +- **nchan_publisher_channel_id** + arguments: 1 - 7 + default: `(none)` + context: server, location, if + > Channel id for publisher location. + +- **nchan_publisher_upstream_request** `` + arguments: 1 + context: server, location, if + > Send POST request to internal location (which may proxy to an upstream server) with published message in the request body. Useful for bridging websocket publishers with HTTP applications, or for transforming message via upstream application before publishing to a channel. + > The upstream response code determine how publishing will proceed. A `200 OK` will publish the message from the upstream response's body. A `304 Not Modified` will publish the message as it was received from the publisher. A `204 No Content` will result in the message not being published. + +- **nchan_pubsub** `[ http | websocket | eventsource | longpoll | intervalpoll | chunked | multipart-mixed | http-raw-stream ]` + arguments: 0 - 6 + default: `http websocket eventsource longpoll chunked multipart-mixed` + context: server, location, if + > Defines a server or location as a pubsub endpoint. For long-polling, GETs subscribe. and POSTs publish. For Websockets, publishing data on a connection does not yield a channel metadata response. Without additional configuration, this turns a location into an echo server. + +- **nchan_subscriber** `[ websocket | eventsource | longpoll | intervalpoll | chunked | multipart-mixed | http-raw-stream ]` + arguments: 0 - 5 + default: `websocket eventsource longpoll chunked multipart-mixed` + context: server, location, if + legacy name: push_subscriber + > Defines a server or location as a channel subscriber endpoint. This location represents a subscriber's interface to a channel's message queue. The queue is traversed automatically, starting at the position defined by the `nchan_subscriber_first_message` setting. + > The value is a list of permitted subscriber types. + +- **nchan_subscriber_channel_id** + arguments: 1 - 7 + default: `(none)` + context: server, location, if + > Channel id for subscriber location. Can have up to 4 values to subscribe to up to 4 channels. + +- **nchan_subscriber_compound_etag_message_id** + arguments: 1 + default: `off` + context: server, location, if + > Override the default behavior of using both `Last-Modified` and `Etag` headers for the message id. + > Enabling this option packs the entire message id into the `Etag` header, and discards + > `Last-Modified` and `If-Modified-Since` headers. + +- **nchan_subscriber_first_message** `[ oldest | newest | ]` + arguments: 1 + default: `oldest` + context: server, location, if + > Controls the first message received by a new subscriber. 'oldest' starts at the oldest available message in a channel's message queue, 'newest' waits until a message arrives. If a number `n` is specified, starts at `n`th message from the oldest. (`-n` start at `n`th from now). 0 is equivalent to 'newest'. + +- **nchan_subscriber_http_raw_stream_separator** `` + arguments: 1 + default: `\n` + context: server, location, if + > Message separator string for the http-raw-stream subscriber. Automatically terminated with a newline character. + +- **nchan_subscriber_last_message_id** + arguments: 1 - 5 + default: `$http_last_event_id $arg_last_event_id` + context: server, location, if + > If `If-Modified-Since` and `If-None-Match` headers are absent, set the message id to the first non-empty of these values. Used primarily as a workaround for the inability to set the first `Last-Message-Id` of a web browser's EventSource object. + +- **nchan_subscriber_message_id_custom_etag_header** + arguments: 1 + default: `(none)` + context: server, location, if + > Use a custom header instead of the Etag header for message ID in subscriber responses. This setting is a hack, useful when behind a caching proxy such as Cloudflare that under some conditions (like using gzip encoding) swallow the Etag header. + +- **nchan_subscriber_timeout** ` (seconds)` + arguments: 1 + default: `0 (none)` + context: http, server, location, if + legacy name: push_subscriber_timeout + > Maximum time a subscriber may wait for a message before being disconnected. If you don't want a subscriber's connection to timeout, set this to 0. When possible, the subscriber will get a response with a `408 Request Timeout` status; otherwise the subscriber will simply be disconnected. + +- **nchan_websocket_ping_interval** ` (seconds)` + arguments: 1 + default: `0 (none)` + context: server, location, if + > Interval for sending websocket ping frames. Disabled by default. + +- **nchan_authorize_request** `` + arguments: 1 + context: server, location, if + > Send GET request to internal location (which may proxy to an upstream server) for authorization of a publisher or subscriber request. A 200 response authorizes the request, a 403 response forbids it. + +- **nchan_max_reserved_memory** `` + arguments: 1 + default: `32M` + context: http + legacy name: push_max_reserved_memory + > The size of the shared memory chunk this module will use for message queuing and buffering. + +- **nchan_message_buffer_length** `` + arguments: 1 + default: `10` + context: http, server, location + legacy names: push_max_message_buffer_length, push_message_buffer_length + > Publisher configuration setting the maximum number of messages to store per channel. A channel's message buffer will retain a maximum of this many most recent messages. + +- **nchan_message_timeout** `
#{name}" + else + namestr = "**#{name}**" + end + + if val + lines << "- #{namestr} `#{val}`" + else + lines << "- #{namestr}" + end + + if Range === args + lines << " #{descr 'arguments', opt} #{args.first} #{opt[:mysite] ? "–" : "-"} #{args.exclude_end? ? args.last - 1 : args.last}" + elsif Numeric === args + lines << " #{descr 'arguments', opt} #{args}" + else + raise "invalid args: #{args}" + end + + if default + lines << " #{descr 'default', opt} `#{Array === default ? default.join(' ') : default}`" + end + + ctx_lookup = { main: :http, srv: :server, loc: :location } + ctx = contexts.map do |c| + ctx_lookup[c] || c; + end + lines << " #{descr 'context', opt} #{ctx.join ', '}" + + if legacy + if Array === self.legacy + lines << " #{descr 'legacy names', opt} #{legacy.join ', '}" + else + lines << " #{descr 'legacy name', opt} #{legacy}" + end + end + + if info + out = info.lines.map do |line| + " > #{line.chomp} " + end + lines << out.join("\n") + end + + lines.map! {|l| "#{l} "} + lines.join "\n" + end + + def to_txt(opt={}) + lines = [] + if value.class == Array + val = "[ #{value.join ' | '} ]" + elsif value + val = "#{value}" + end + + if val + lines << "#{name} #{val}" + else + lines << "#{name}" + end + + if Range === args + lines << " #{descr 'arguments', opt} #{args.first} - #{args.exclude_end? ? args.last - 1 : args.last}" + elsif Numeric === args + lines << " #{descr 'arguments', opt} #{args}" + else + raise "invalid args: #{args}" + end + + if default + lines << " #{descr 'default', opt} #{Array === default ? default.join(' ') : default}" + end + + ctx_lookup = { main: :http, srv: :server, loc: :location } + ctx = contexts.map do |c| + ctx_lookup[c] || c; + end + lines << " #{descr 'context', opt} #{ctx.join ', '}" + + if legacy + if Array === self.legacy + lines << " #{descr 'legacy names', opt} #{legacy.join ', '}" + else + lines << " #{descr 'legacy name', opt} #{legacy}" + end + end + + if info + out = info.lines.map do |line| + " #{line.chomp} " + end + lines << out.join("\n") + end + + lines.map! {|l| "#{l} "} + lines.join "\n" + end + end + + + def initialize(&block) + @cmds=[] + instance_eval &block + end + + def method_missing(name, *args) + define_cmd name, *args + end + + + def define_cmd(name, valid_contexts, handler, conf, opt={}) + cmd=Cmd.new name, handler + cmd.contexts= valid_contexts + + if Array === conf + cmd.conf=conf[0] + cmd.offset_name=conf[1] + else + cmd.conf=conf + end + + cmd.legacy = opt[:legacy] + cmd.alt = opt[:alt] + cmd.disabled = opt[:disabled] + cmd.undocumented = opt[:undocumented] + + cmd.args = opt.has_key?(:args) ? opt[:args] : 1 + cmd.group = opt[:group] + cmd.value = opt[:value] + cmd.default = opt[:default] + cmd.info = opt[:info] + + @cmds << cmd if !cmd.disabled && !cmd.undocumented + end + +end + + +class Order + def initialize(*args) + @i=0 + @ord = {} + args.each do |val| + @ord[val] = @i + @i+=1 + end + end + def [](val) + @ord[val] || Float::INFINITY + end +end + +begin + cf=eval File.read("#{ROOT_DIR}/#{SRC_DIR}/#{CONFIG_IN}") +rescue Exception => e + STDERR.puts e.message.gsub(/^\(eval\)/, "#{SRC_DIR}/#{CONFIG_IN}") + exit 1 +end + +cmds = cf.cmds + +group_order=Order.new(:pubsub, :security, :storage, :meta, :none, :development) + +cmds.sort! do |c1, c2| + if c1.group != c2.group + group_order[c1] - group_order[c2] + else + (c1.name < c2.name) ? -1 : 1 + end +end + + + +cmds.map! do |cmd| + cmd.to_md(:mysite => mysite) +end + + +config_documentation= cmds.join "\n\n" + +#if mysite +# config_documentation = "
#{config_documentation}
" +#end + +text = File.read(readme_path) + +if mysite + #remove first line + text.sub!(/^<.*?>$\n\n?/m, "") + #remove second line + text.sub!(/^https:\/\/nchan.slact.net$\n\n?/m, "") + + # add an #about link + text.prepend "\n" + + #add a table-of-contents div right before the first heading + text.sub! /^#/, "
\n#" +end + +config_heading = "## Configuration Directives" +text.gsub!(/(?<=^#{config_heading}$).*(?=^## )/m, "\n\n#{config_documentation}\n\n") + +if mysite + contrib_heading = "## Contribute" + text.gsub!(/(^#{contrib_heading}$).*(?=^## )?/m, "") +end + + +text.gsub!(/(?<=^The latest Nchan release is )\S+\s+\([^)]+\)/, "#{current_release} (#{current_release_date})") + +if mysite + text.gsub!(/https:\/\/nchan\.slact\.net\//, "/") +end + +File.open(readme_output_path, "w") {|file| file.puts text } + diff --git a/debian/modules/nchan/dev/rsck.sh b/debian/modules/nchan/dev/rsck.sh new file mode 100755 index 0000000..9cc0f32 --- /dev/null +++ b/debian/modules/nchan/dev/rsck.sh @@ -0,0 +1,67 @@ +#!/bin/bash + + +server="127.0.0.1" +port="6379" +db="0" +dir=$(dirname $0) +pushd $dir > /dev/null +fulldir=$(pwd) +popd > /dev/null + +while getopts "s:p:d:t:l:h" opt; do + case $opt in + s) + server=$OPTARG;; + p) + port=$OPTARG;; + d) + db=$OPTARG;; + t) + interval=$OPTARG;; + l) + logfile=$OPTARG;; + h) + echo "nchan redis server data consistency check" + echo " -s [server]" + echo " -p [port]" + echo " -d [db number]" + echo " -t [minutes] repeat at this interval" + echo " -l [logfile] log results to this file" + ;; + \?) + exit 1 + ;; + esac +done + +url="redis://$server:$port/$db" + +if [[ $interval ]]; then + echo "rsck $url every $interval minutes" +else + echo "rsck $url" +fi + +if [[ $logfile ]]; then + echo "logging to $logfile" +fi + +if [[ $interval ]]; then + sleeptime=$(echo "$interval * 60" | bc) +fi +while true; do + ret=$(redis-cli -p 8537 --eval $dir/../src/store/redis/scripts/rsck.lua --raw) + echo $ret + + if [[ $logfile ]]; then + printf "$(date)\n$ret\n\n" >> $logfile + fi + + if [[ ! $interval ]]; then + break + else + sleep $sleeptime + fi +done + diff --git a/debian/modules/nchan/dev/sub.rb b/debian/modules/nchan/dev/sub.rb new file mode 100755 index 0000000..f4bbef9 --- /dev/null +++ b/debian/modules/nchan/dev/sub.rb @@ -0,0 +1,125 @@ +#!/usr/bin/ruby +require 'securerandom' +require_relative 'pubsub.rb' +require "optparse" +require 'timers' + + +server= "localhost:8082" +par=1 + +opt = { + timeout: 60, + quit_message: 'FIN', + client: :longpoll, + extra_headers: nil, + nostore: true, + http2: false +} + +no_message=false +print_content_type = false +show_id=false +origin = nil + +url = nil +sub = nil + +opt_parser=OptionParser.new do |opts| + opts.on("-s", "--server SERVER (#{server})", "server and port."){|v| server=v} + opts.on("-p", "--parallel NUM (#{par})", "number of parallel clients"){|v| par = v.to_i} + opts.on("-t", "--timeout SEC (#{opt[:timeout]})", "Long-poll timeout"){|v| opt[:timeout] = v} + opts.on("-q", "--quit STRING (#{opt[:quit_message]})", "Quit message"){|v| opt[:quit_message] = v} + opts.on("-l", "--client STRING (#{opt[:client]})", "sub client (one of #{Subscriber::Client.unique_aliases.join ', '})") do |v| + opt[:client] = v.to_sym + end + opts.on("-c", "--content-type", "show received content-type"){|v| print_content_type = true} + opts.on("-i", "--id", "Print message id (last-modified and etag headers)."){|v| show_id = true} + opts.on("-n", "--no-message", "Don't output retrieved message."){|v| no_message = true} + opts.on("--origin STR", "Set Origin header if appplicable."){|v| origin = v} + opts.on("--full-url URL", "full subscriber url") do |v| + url = v + end + opts.on("--http2", "use HTTP/2"){opt[:http2] = true} + opts.on("-v", "--verbose", "somewhat rather extraneously wordful output") do + opt[:verbose] = true + Typhoeus::Config.verbose=true + end +end +opt_parser.banner="Usage: sub.rb [options] url" +opt_parser.parse! + +url ||= "#{opt[:http2] ? 'h2' : 'http'}://#{server}#{ARGV.last}" + +puts "Subscribing #{par} #{opt[:client]} client#{par!=1 ? "s":""} to #{url}." +puts "Timeout: #{opt[:timeout]}sec, quit msg: #{opt[:quit_message]}" + +if origin + opt[:extra_headers] ||= {} + opt[:extra_headers]['Origin'] = origin +end + +sub = Subscriber.new url, par, opt + + +NOMSGF="\r"*30 + "Received message %i, len:%i" +if no_message + class OutputTimer + include Celluloid + attr_reader :fired, :timer + + def initialize(interval = 0.5) + @count = 0 + @last_msg_length = 0 + @timer = every(interval) do + printf NOMSGF, @count, @last_msg_length + end + end + + def incoming(msg) + @count += 1 + @last_msg_length = msg.message.length + end + end + + output_timer = OutputTimer.new +end + +sub.on_message do |msg| + if no_message + output_timer.incoming(msg) + else + if msg.content_type + out = "(#{msg.content_type}) #{msg}" + else + out = msg.to_s + end + if show_id + out = "<#{msg.id}> #{out}" + end + puts out + end +end + +sub.on_failure do |err_msg| + if Subscriber::IntervalPollClient === sub.client + unless err_msg.match(/\(code 304\)/) + false + end + else + false + end +end + +sub.run +sub.wait +output_timer.terminate if output_timer + + +if sub.errors.count > 0 + puts "Errors:" + sub.errors.each do |err| + puts err + end + exit 1 +end diff --git a/debian/modules/nginx-http-push/tests/test-parallel.sh b/debian/modules/nchan/dev/test-parallel.sh similarity index 83% rename from debian/modules/nginx-http-push/tests/test-parallel.sh rename to debian/modules/nchan/dev/test-parallel.sh index c5e5ecb..389b2a5 100755 --- a/debian/modules/nginx-http-push/tests/test-parallel.sh +++ b/debian/modules/nchan/dev/test-parallel.sh @@ -10,7 +10,9 @@ if ! [[ $par =~ ^[0-9]+$ ]]; then fi for ((i = 0; i < $par; i++)); do - ./test.rb ${@:2} & + + echo bundle exec ./test.rb ${@:2} + bundle exec ./test.rb ${@:2} & done jobs=$(jobs -p) diff --git a/debian/modules/nchan/dev/test.rb b/debian/modules/nchan/dev/test.rb new file mode 100755 index 0000000..35db249 --- /dev/null +++ b/debian/modules/nchan/dev/test.rb @@ -0,0 +1,875 @@ +#!/usr/bin/ruby +require 'minitest' +require 'minitest/reporters' +require "minitest/autorun" +Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new(:color => true)] +require 'securerandom' +require_relative 'pubsub.rb' +require_relative 'authserver.rb' + +SERVER=ENV["PUSHMODULE_SERVER"] || "127.0.0.1" +PORT=ENV["PUSHMODULE_PORT"] || "8082" +DEFAULT_CLIENT=:longpoll +OMIT_LONGMSG=ENV["OMIT_LONGMSG"] +#Typhoeus::Config.verbose = true +def short_id + SecureRandom.hex.to_i(16).to_s(36)[0..5] +end + +def url(part="") + part=part[1..-1] if part[0]=="/" + "http://#{SERVER}:#{PORT}/#{part}" +end +puts "Server at #{url}" +def pubsub(concurrent_clients=1, opt={}) + test_name = caller_locations(1,1)[0].label + urlpart=opt[:urlpart] || 'broadcast' + timeout = opt[:timeout] + sub_url=opt[:sub] || "sub/broadcast/" + pub_url=opt[:pub] || "pub/" + chan_id = opt[:channel] || SecureRandom.hex + sub = Subscriber.new url("#{sub_url}#{chan_id}?test=#{test_name}"), concurrent_clients, timeout: timeout, use_message_id: opt[:use_message_id], quit_message: 'FIN', gzip: opt[:gzip], retry_delay: opt[:retry_delay], client: opt[:client] || DEFAULT_CLIENT, extra_headers: opt[:extra_headers], verbose: opt[:verbose] + pub = Publisher.new url("#{pub_url}#{chan_id}?test=#{test_name}"), timeout: timeout + return pub, sub +end +def verify(pub, sub, check_errors=true) + assert sub.errors.empty?, "There were subscriber errors: \r\n#{sub.errors.join "\r\n"}" if check_errors + ret, err = sub.messages.matches?(pub.messages) + assert ret, err || "Messages don't match" + i=0 + sub.messages.each do |msg| + assert_equal sub.concurrency, msg.times_seen, "Concurrent subscribers didn't all receive message #{i}." + i+=1 + end +end + +class PubSubTest < Minitest::Test + def setup + Celluloid.boot + end + + def test_interval_poll + pub, sub=pubsub 1, sub: "/sub/intervalpoll/", client: :intervalpoll, quit_message: 'FIN', retry_delay: 0.5 + ws_sub=Subscriber.new(sub.url, 1, client: :websocket, quit_message: 'FIN') + + got_304s=0 + sub.on_failure do |msg| + got_304s += 1 + assert_match /code 304/, msg #handshake will be treated as intervalpoll client?... + end + + ws_sub.run + sub.run + + sleep 0.4 + assert ws_sub.match_errors(/code 403/), "expected 403 for all non-intervalpoll subscribers, got #{sub.errors.pretty_inspect}" + ws_sub.terminate + + pub.post ["hello this", "is a thing"] + sleep 0.3 + pub.post ["oh now what", "is this even a thing?"] + sleep 0.1 + + sleep 1.5 + + pub.post "yoo" + pub.post "FIN" + + sub.wait + + verify pub, sub + sub.terminate + assert got_304s > 0, "Expected at least one 304 response" + end + + def test_channel_info + require 'json' + require 'nokogiri' + require 'yaml' + + subs=20 + + chan=SecureRandom.hex + pub, sub = pubsub(subs, channel: chan, client: :eventsource) + pub.nofail=true + pub.get + assert_equal 404, pub.response_code + + pub.post ["hello", "what is this i don't even"] + assert_equal 202, pub.response_code + pub.get + + assert_equal 200, pub.response_code + assert_match /last requested: -?\d+ sec/, pub.response_body + + pub.get "text/json" + + info_json=JSON.parse pub.response_body + assert_equal 2, info_json["messages"] + #assert_equal 0, info_json["requested"] + assert_equal 0, info_json["subscribers"] + + + sub.run + sub.wait :ready + sleep 0.15 + pub.get "text/json" + + info_json=JSON.parse pub.response_body + assert_equal 2, info_json["messages"] + #assert_equal 0, info_json["requested"] + assert_equal subs, info_json["subscribers"], "text/json subscriber count" + + pub.get "text/xml" + ix = Nokogiri::XML pub.response_body + assert_equal 2, ix.at_xpath('//messages').content.to_i + #assert_equal 0, ix.at_xpath('//requested').content.to_i + assert_equal subs, ix.at_xpath('//subscribers').content.to_i + + pub.get "text/yaml" + yaml_resp1=pub.response_body + pub.get "application/yaml" + yaml_resp2=pub.response_body + pub.get "application/x-yaml" + yaml_resp3=pub.response_body + yam=YAML.load pub.response_body + assert_equal 2, yam["messages"] + #assert_equal 0, yam["requested"] + assert_equal subs, yam["subscribers"] + + assert_equal yaml_resp1, yaml_resp2 + assert_equal yaml_resp2, yaml_resp3 + + + pub.accept="text/json" + + pub.post "FIN" + #stats right before FIN was issued + info_json=JSON.parse pub.response_body + assert_equal 3, info_json["messages"] + #assert_equal 0, info_json["requested"] + assert_equal subs, info_json["subscribers"] + + sub.wait + + pub.get "text/json" + info_json=JSON.parse pub.response_body + assert_equal 3, info_json["messages"], "number of messages received by channel is wrong" + #assert_equal 0, info_json["requested"] + assert_equal 0, info_json["subscribers"], "channel should say there are no subscribers" + + sub.terminate + end + + def multi_sub_url(pubs, prefix="/sub/multi/", delim="/") + ids = pubs.map{|v| v.id}.shuffle + "#{prefix}#{ids.join delim}" + end + + class MultiCheck + attr_accessor :id, :pub + def initialize(id) + self.id = id + self.pub = Publisher.new url("/pub/#{self.id}") + end + end + + + def test_channel_multiplexing(n=2, delimited=false) + + pubs = [] + n.times do |i| + pubs << MultiCheck.new(short_id) + end + + sub_url=delimited ? multi_sub_url(pubs, '/sub/split/', '_') : multi_sub_url(pubs) + + n = 15 + scrambles = 5 + subs = [] + scrambles.times do |i| + sub = Subscriber.new(url(sub_url), n, quit_message: 'FIN', retry_delay: 1, timeout: 20) + sub.on_failure { false } + subs << sub + end + + subs.each &:run + + pubs.each {|p| p.pub.post "FIRST from #{p.id}" } + + 10.times do |i| + pubs.each {|p| p.pub.post "hello #{i} from #{p.id}" } + end + + sleep 1 + + 5.times do |i| + pubs.first.pub.post "yes #{i} from #{pubs.first.id}" + end + + pubs.each do |p| + 10.times do |i| + p.pub.post "hello #{i} from #{p.id}" + end + end + + latesubs = Subscriber.new(url(sub_url), n, quit_message: 'FIN') + latesubs.on_failure { false } + subs << latesubs + latesubs.run + + sleep 1 + + 10.times do |i| + pubs.each {|p| p.pub.post "hello again #{i} from #{p.id}" } + end + + pubs.first.pub.post "FIN" + subs.each &:wait + sleep 1 + subs.each_with_index do |sub, sub_i| + + assert_equal 0, sub.errors.count, "Subscriber encountered #{sub.errors.count} errors: #{sub.errors.join ", "}" + + msgs=[] + pubs.each { |p| msgs << p.pub.messages.messages } + + sub.messages.each do |msg| + matched = false + for mm in msgs do + if mm.first == msg.message + matched = true + mm.shift + break + end + end + assert_equal matched, true, "message not matched" + end + + sub.terminate + end + + end + + def test_channel_multiplexing_5 + test_channel_multiplexing 5 + end + + def test_channel_delimitered_multiplexing_15 + test_channel_multiplexing 15, true + end + + def test_message_delivery + pub, sub = pubsub + sub.run + sleep 0.2 + assert_equal 0, sub.messages.messages.count + pub.post "hi there" + assert_equal 201, pub.response_code, "publisher response code" + sleep 0.2 + assert_equal 1, sub.messages.messages.count, "received message count" + pub.post "FIN" + assert_equal 201, pub.response_code, "publisher response code" + sleep 0.2 + assert_equal 2, sub.messages.messages.count, "recelived messages count" + assert sub.messages.matches? pub.messages + sub.terminate + end + + def test_publish_then_subscribe + pub, sub = pubsub + pub.post "hi there" + sub.run + pub.post "FIN" + sub.wait + assert_equal 2, sub.messages.messages.count + assert sub.messages.matches? pub.messages + sub.terminate + end + + def test_authorized_channels + #must be published to before subscribing + n=5 + pub, sub = pubsub n, timeout: 6, sub: "sub/authorized/" + sub.on_failure { false } + sub.run + sleep 1 + sub.wait + assert_equal n, sub.finished + + assert sub.match_errors(/code 403/), "expected 403 for all subscribers, got #{sub.errors.pretty_inspect}" + sub.reset + + pub.post %w( fweep ) + assert_match /20[12]/, pub.response_code.to_s + sleep 0.1 + + sub.run + + sleep 0.1 + pub.post ["fwoop", "FIN"] { assert_match /20[12]/, pub.response_code.to_s } + + + sub.wait + verify pub, sub + sub.terminate + end + + def test_deletion + #delete active channel + par=5 + pub, sub = pubsub par, timeout: 10 + sub.on_failure { false } + sub.run + sleep 0.2 + pub.delete + sleep 0.1 + assert_equal 200, pub.response_code + assert_equal par, pub.response_body.match(/subscribers:\s+(\d)/)[1].to_i, "subscriber count after deletion" + sub.wait + assert sub.match_errors(/code 410/), "Expected subscriber code 410: Gone, instead was \"#{sub.errors.first}\"" + + #delete channel with no subscribers + pub, sub = pubsub 5, timeout: 1 + pub.post "hello" + assert_equal 202, pub.response_code + pub.delete + assert_equal 200, pub.response_code + + #delete nonexistent channel + pub, sub = pubsub + pub.nofail=true + pub.delete + assert_equal 404, pub.response_code + end + + def test_no_message_buffer + chan_id=SecureRandom.hex + pub = Publisher.new url("/pub/nobuffer/#{chan_id}") + sub=[] + 40.times do + sub.push Subscriber.new(url("/sub/broadcast/#{chan_id}"), 1, use_message_id: false, quit_message: 'FIN') + end + + pub.post ["this message should not be delivered", "nor this one"] + + sub.each {|s| s.run} + sleep 1 + pub.post "received1" + sleep 1 + pub.post "received2" + sleep 1 + pub.post "FIN" + sub.each {|s| s.wait} + sub.each do |s| + assert s.errors.empty?, "There were subscriber errors: \r\n#{s.errors.join "\r\n"}" + ret, err = s.messages.matches? ["received1", "received2", "FIN"] + assert ret, err || "Messages don't match" + end + end + + def test_channel_isolation + rands= %w( foo bar baz bax qqqqqqqqqqqqqqqqqqq eleven andsoon andsoforth feh ) + pub=[] + sub=[] + 10.times do |i| + pub[i], sub[i]=pubsub 15 + sub[i].run + end + pub.each do |p| + rand(1..10).times do + p.post rands.sample + end + end + sleep 1 + pub.each do |p| + p.post 'FIN' + end + sub.each do |s| + s.wait + end + pub.each_with_index do |p, i| + verify p, sub[i] + end + sub.each {|s| s.terminate } + end + + def test_broadcast_3 + test_broadcast 3 + end + + def test_broadcast_20 + test_broadcast 20 + end + + def test_longpoll_multipart + pub, sub = pubsub 1, sub: 'sub/multipart/', use_message_id: false + + pub.post "first", "text/x-foobar" + pub.post ["1", "2", "3", "4"] + sub.run + sleep 0.5 + pub.post "FIN" + sub.wait + + verify pub, sub + sub.terminate + end + + def test_longpoll_multipart_extended(range=30..35) + range.each do |i| + pub, sub = pubsub 1, sub: 'sub/multipart/', use_message_id: false, timeout: 3 + i.times do |n| + pub.post "#{n+1}" + end + pub.post "FIN" + sub.run + sub.wait + verify pub, sub + sleep 0.1 + end + end + + def test_multiplexed_longpoll_multipart + chans= [short_id, short_id, short_id] + pub, sub = pubsub 1, sub: "sub/multipart_multiplex/#{chans.join "/"}", pub: "pub/#{chans[1]}", channel: "", use_message_id: false + + pub.post "first", "text/x-foobar" + pub.post ["1", "2", "3", "4"] + sub.run + sleep 0.5 + pub.post "FIN" + sub.wait + + verify pub, sub + sub.terminate + end + + + def test_broadcast(clients=400) + pub, sub = pubsub clients + pub.post "!!" + sub.run #celluloid async FTW + #sleep 2 + pub.post ["!!!!", "what is this", "it's nothing", "nothing at all really"] + pub.post "FIN" + sub.wait + sleep 0.5 + verify pub, sub + sub.terminate + end + + #def test_broadcast_10000 + # test_broadcast 10000 + #end + + def dont_test_subscriber_concurrency + chan=SecureRandom.hex + pub_first = Publisher.new url("pub/first#{chan}") + pub_last = Publisher.new url("pub/last#{chan}") + + sub_first, sub_last = [], [] + { url("sub/first/first#{chan}") => sub_first, url("sub/last/last#{chan}") => sub_last }.each do |url, arr| + 3.times do + sub=Subscriber.new(url, 1, quit_message: 'FIN', timeout: 20) + sub.on_failure do |resp, req| + false + end + arr << sub + end + end + + sub_first.each {|s| s.run; sleep 0.1 } + assert sub_first[0].no_errors? + sub_first[1..2].each do |s| + assert s.errors? + assert s.match_errors(/code 409/) + end + + sub_last.each {|s| s.run; sleep 0.1 } + assert sub_last[2].no_errors? + sub_last[0..1].each do |s| + assert s.errors? + assert s.match_errors(/code 40[49]/) + end + + pub_first.post %w( foo bar FIN ) + pub_last.post %w( foobar baz somethingelse FIN ) + + sub_first[0].wait + sub_last[2].wait + + verify pub_first, sub_first[0] + verify pub_last, sub_last[2] + + sub_first[1..2].each{ |s| assert s.messages.count == 0 } + sub_last[0..1].each{ |s| assert s.messages.count == 0 } + [sub_first, sub_last].each {|sub| sub.each{|s| s.terminate}} + end + + def test_queueing + pub, sub = pubsub 1 + pub.post %w( what is this_thing andnow 555555555555555555555 eleven FIN ), 'text/plain' + sleep 0.3 + sub.run + sub.wait + verify pub, sub + sub.terminate + end + + def test_long_message(kb=0.5) + pub, sub = pubsub 10, timeout: 10 + sub.run + sleep 0.2 + pub.post ["#{"q"*((kb * 1024)-3)}end", "FIN"] + sub.wait + verify pub, sub + sub.terminate + end + + unless OMIT_LONGMSG + #[5, 9, 9.5, 9.9, 10, 11, 15, 16, 17, 18, 19, 20, 30, 50, 100, 200, 300, 600, 900, 3000].each do |n| + [5, 10, 20, 200, 900].each do |n| + define_method "test_long_message_#{n}Kb" do + test_long_message n + end + end + + def test_message_length_range + pub, sub = pubsub 2, timeout: 15 + sub.run + + n=5 + while n <= 10000 do + pub.post "T" * n + n=(n*1.01) + 1 + sleep 0.001 + end + pub.post "FIN" + sub.wait + verify pub, sub + sub.terminate + end + + def generic_test_long_buffed_messages(client=:longpoll) + kb=2000 + #kb=2 + pub, sub = pubsub 1, sub: "/sub/broadcast/", timeout: 10, client: client + #pub, sub = pubsub 1, sub: "/sub/websocket_only/", client: :websocket + #sub.on_message do |msg| + # puts ">>>>>>>message: #{msg.message[0...10]}...|#{msg.message.length}|" + #end + sub.run + sleep 1 + m1="#{"q"*((kb * 1024)-3)}end" + m2="#{"r"*((kb * 1024)-3)}end" + i=0 + 15.times do + i+=1 + pub.post "#{i}#{m1}" + i+=1 + pub.post "#{i}#{m2}" + end + pub.post "FIN" + sub.wait + verify pub, sub + pub.delete + sub.terminate + end + + [:longpoll, :multipart, :eventsource, :websocket, :chunked].each do |client| + define_method "test_long_buffed_messages_#{client}" do + generic_test_long_buffed_messages client + end + end + + end + + def test_message_timeout + pub, sub = pubsub 1, pub: "/pub/2_sec_message_timeout/", timeout: 10 + pub.post %w( foo bar etcetera ) #these shouldn't get delivered + pub.messages.clear + sleep 3 + #binding.pry + sub.run + sleep 1 + pub.post %w( what is this even FIN ) + sub.wait + verify pub, sub + sub.terminate + end + + def test_subscriber_timeout + chan=SecureRandom.hex + sub=Subscriber.new(url("sub/timeout/#{chan}"), 5, timeout: 10) + sub.on_failure { false } + pub=Publisher.new url("pub/#{chan}") + sub.run + sleep 0.1 + pub.post "hello" + sub.wait + verify pub, sub, false + assert sub.match_errors(/code 408/) + sub.terminate + end + + def assert_header_includes(response, header, str) + assert response.headers[header].include?(str), "Response header '#{header}: #{response.headers[header]}' must contain \"#{str}\", but does not." + end + + def test_access_control_options + chan=SecureRandom.hex + + request = Typhoeus::Request.new url("sub/broadcast/#{chan}"), method: :OPTIONS, headers: { 'Origin':'example.com' } + resp = request.run + + assert_equal "*", resp.headers["Access-Control-Allow-Origin"] + %w( GET ).each do |v| + assert_header_includes resp, "Access-Control-Allow-Methods", v + assert_header_includes resp, "Allow", v + end + %w( If-None-Match If-Modified-Since Content-Type Cache-Control X-EventSource-Event ).each {|v| assert_header_includes resp, "Access-Control-Allow-Headers", v} + + request = Typhoeus::Request.new url("sub/broadcast/#{chan}"), method: :OPTIONS + resp = request.run + %w( GET ).each do |v| + assert_header_includes resp, "Allow", v + end + + + request = Typhoeus::Request.new url("pub/#{chan}"), method: :OPTIONS, headers: { 'Origin': "example.com" } + resp = request.run + assert_equal "*", resp.headers["Access-Control-Allow-Origin"] + %w( GET POST DELETE ).each do |v| + assert_header_includes resp, "Access-Control-Allow-Methods", v + assert_header_includes resp, "Allow", v + end + %w( Content-Type ).each {|v| assert_header_includes resp, "Access-Control-Allow-Headers", v} + + request = Typhoeus::Request.new url("pub/#{chan}"), method: :OPTIONS + resp = request.run + %w( GET POST DELETE ).each do |v| + assert_header_includes resp, "Allow", v + end + end + + def generic_test_access_control(opt) + pub, sub = pubsub 1, extra_headers: { Origin: opt[:origin] }, pub: opt[:pub_url], sub: opt[:sub_url] + + sub.on_message do |msg, bundle| + opt[:verify_sub_response].call(bundle) if opt[:verify_sub_response] + end + + pub.post "FIN" + sub.run + sub.wait + + yield pub, sub if block_given? + + sub.terminate + end + + def test_invalid_etag + chan_id=short_id + pub = Publisher.new url("/pub/#{chan_id}"), accept: 'text/json' + + pub.post "1. one!!" + sleep 1 + pub.post "2. tooo" + pub.post "3. throo" + sleep 1 + pub.post "4. fooo" + n = 0 + sub = Subscriber.new(url("/sub/multipart_multiplex/#{short_id}/#{short_id}/#{chan_id}"), 1, quit_message: 'FIN', retry_delay: 1, timeout: 20) + sub.on_message do |msg, bundle| + n=n+1 + if n == 2 + bundle.etag="null" + end + end + + sub.on_failure do |err| + assert_match /code 400/, err + false + end + + sub.run + sleep 1 + pub.post "5. faaa" + pub.post "FIN" + sub.wait + end + + #def test_expired_messages_with_subscribers + # chan = short_id + # pub, sub = pubsub 1, pub: "/pub/2_sec_message_timeout/", sub: "/sub/intervalpoll/", client: :intervalpoll, timeout: 9000, channel: short_id + # sub.on_failure do |err| + # puts "retry?!!" + # true + # end + # sub.run + # pub.post ["foo", "bar"] + # + # sleep 5 + # + # pub.post ["yeah", "what", "the"] + # sub.wait + #end + + def dont_test_auth + chan = short_id + + subs = [ :longpoll, :eventsource, :websocket, :multipart ] + + subs.each do |t| + sub = Subscriber.new(url("sub/auth_fail/#{chan}"), 1, client: t) + sub.on_failure { false } + sub.run + sub.wait + assert(sub.errors?) + assert /code 500/, sub.errors.first + sub.terminate + end + + auth_pid = Process.spawn("bundle exec ./authserver.rb -q") + while true + resp = Typhoeus.get("http://127.0.0.1:8053/", followlocation: true) + break unless resp.return_code == :couldnt_connect + sleep 0.20 + end + + subs.each do |t| + sub = Subscriber.new(url("sub/auth_fail/#{chan}"), 1, client: t) + sub.on_failure { false } + sub.run + sub.wait + assert(sub.errors?) + assert /code 403/, sub.errors.first + sub.terminate + end + + pub = Publisher.new url("pub/#{chan}") + + pub.post [ "wut", "waht", "FIN" ] + + subs.each do |t| + sub = Subscriber.new(url("sub/auth/#{chan}"), 1, client: t, quit_message: 'FIN') + sub.on_failure { false } + sub.run + sub.wait + verify pub, sub + end + + Process.kill 2, auth_pid + end + + def test_access_control + + ver= proc do |bundle| + assert_equal "*", bundle.headers["Access-Control-Allow-Origin"] + end + generic_test_access_control(origin: "example.com", verify_sub_response: ver) do |pub, sub| + verify pub, sub + end + + ver= proc do |bundle| + assert_equal "http://foo.bar", bundle.headers["Access-Control-Allow-Origin"] + %w( Last-Modified Etag ).each {|v| assert_header_includes bundle, "Access-Control-Expose-Headers", v} + end + generic_test_access_control(origin: "http://foo.bar", verify_sub_response: ver, sub_url: "sub/from_foo.bar/") do |pub, sub| + verify pub, sub + end + + #test forbidding stuff + pub, sub = pubsub 1, extra_headers: { "Origin": "http://forbidden.com" }, pub: "pub/from_foo.bar/", sub: "sub/from_foo.bar/", timeout: 1 + + pub.extra_headers={ "Origin": "http://foo.bar" } + pub.post "yeah" + + assert_match /20[12]/, pub.response_code.to_s + pub.extra_headers={ "Origin": "http://forbidden.com" } + post_failed = false + begin + pub.post "yeah" + rescue Exception => e + post_failed = true + assert_match /request failed:\s+403/, e.message + end + assert post_failed + + sub.on_failure { false } + + sub.run + sub.wait + + sub.errors.each do |err| + assert_match /code 403/, err + end + sub.terminate + + end + + def test_gzip + #bug: turning on gzip cleared the response etag + pub, sub = pubsub 1, sub: "/sub/gzip/", gzip: true, retry_delay: 0.3 + sub.run + sleep 0.1 + pub.post ["2", "123456789A", "alsdjklsdhflsajkfhl", "boq"] + sleep 1 + pub.post "foobar" + msg = "" + 200.times { msg << SecureRandom.hex } + pub.post msg + pub.post "FIN" + sub.wait + verify pub, sub + end + + def test_issue_212 #https://github.com/slact/nchan/issues/212 + chan1 = short_id + chan2 = short_id + sub = Subscriber.new url("/sub/multi/#{chan1}/#{chan2}"), 1, quit_message: 'FIN', client: :eventsource, timeout: 3 + sub.on_failure { false } + pub = Publisher.new url("/pub/#{chan1}") + pub_nobuf = Publisher.new url("/pub/nobuffer/#{chan2}") + sub.run + sub.wait :ready + + pub.post %w(yes what this and also) + sleep 1.1 + pub_nobuf.post "WHAT?!" + pub.messages << pub_nobuf.messages.first + pub.post %W(foo bar baz bzzzt FIN) + + sub.wait + + verify pub, sub + end + + def test_changing_buffer_length + chan = short_id + sub = Subscriber.new url("sub/broadcast/#{chan}"), 30, quit_message: 'FIN' + pub_delta = Publisher.new url("/pub/#{chan}") + pub_snapshot = Publisher.new url("/pub_1message/#{chan}") + + pub_delta.post %W(foo bar baz bzzzt FIN) + sub.run + sub.wait + verify pub_delta, sub + sub.reset + + pub_snapshot.post %W(blah anotherblah) + pub_snapshot.messages.clear + pub_snapshot.post "this is the real thing right here" + + pub_delta.messages.clear + pub_delta.messages << pub_snapshot.messages.first + pub_delta.post %W(d1 d2 d3 and_other_deltas FIN) + sub.run + sub.wait + + verify pub_delta, sub + end +end + + diff --git a/debian/modules/nchan/dev/vg.supp b/debian/modules/nchan/dev/vg.supp new file mode 100644 index 0000000..750e584 --- /dev/null +++ b/debian/modules/nchan/dev/vg.supp @@ -0,0 +1,26977 @@ +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_get_new_index + fun:SSL_get_ex_data_X509_STORE_CTX_idx + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_proxy_set_ssl + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_locations + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_get_new_index + fun:SSL_get_ex_data_X509_STORE_CTX_idx + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_proxy_set_ssl + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_locations + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_new_ex_data + fun:X509_STORE_new + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_proxy_set_ssl + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_locations + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_new_ex_data + fun:X509_STORE_new + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_proxy_set_ssl + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_locations + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_get_new_index + fun:SSL_get_ex_data_X509_STORE_CTX_idx + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_proxy_set_ssl + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_locations + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_get_new_index + fun:SSL_get_ex_data_X509_STORE_CTX_idx + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_proxy_set_ssl + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_locations + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:X509_STORE_new + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_proxy_set_ssl + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_locations + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:X509_STORE_new + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_proxy_set_ssl + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_locations + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:int_get_new_index + fun:SSL_get_ex_data_X509_STORE_CTX_idx + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_proxy_set_ssl + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_locations + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_crc32_table_init + fun:main +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_save_argv + fun:main +} +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_strerror_init + fun:main +} +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_init_setproctitle + fun:ngx_os_init + fun:main +} +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_strerror_init + fun:main +} +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:pool + fun:__static_initialization_and_destruction_0 + fun:_GLOBAL__sub_I_eh_alloc.cc + fun:call_init.part.0 + fun:_dl_init + obj:/usr/lib/ld-2.22.so + obj:* + obj:* + obj:* + obj:* + obj:* + obj:* +} +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_event_process_init + fun:ngx_worker_process_init + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_epoll_init + fun:ngx_event_process_init + fun:ngx_worker_process_init + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_regex_malloc + fun:pcre_study + fun:ngx_regex_module_init + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_list_init + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:* + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:* + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_conf_read_token + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_http_get_variable_index + fun:ngx_http_userid_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_array_create + fun:ngx_http_log_create_main_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_hash_init + fun:ngx_http_upstream_hide_headers_hash + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_regex_create_conf + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_list_create + fun:ngx_regex_create_conf + fun:ngx_init_cycle + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_pstrdup + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_init_connection + fun:ngx_event_accept + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes +} + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_event_accept + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_create_temp_buf + fun:ngx_http_wait_request_handler + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes +} + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_create_temp_buf + fun:ngx_http_header_filter + fun:ngx_http_chunked_header_filter + fun:ngx_http_range_header_filter + fun:ngx_http_gzip_header_filter + fun:ngx_http_ssi_header_filter + fun:ngx_http_charset_header_filter +} + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_rewrite_handler + fun:ngx_http_core_rewrite_phase + fun:ngx_http_core_run_phases + fun:ngx_http_handler + fun:ngx_http_process_request + fun:ngx_http_process_request_headers + fun:ngx_http_process_request_line +} + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_rewrite_handler + fun:ngx_http_core_rewrite_phase + fun:ngx_http_core_run_phases + fun:ngx_http_handler + fun:ngx_http_process_request + fun:ngx_http_process_request_headers + fun:ngx_http_process_request_line +} + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_list_init + fun:ngx_http_create_request + fun:ngx_http_keepalive_handler + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes +} + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_create_temp_buf + fun:ngx_http_header_filter + fun:ngx_http_chunked_header_filter + fun:ngx_http_range_header_filter + fun:ngx_http_gzip_header_filter + fun:ngx_http_ssi_header_filter + fun:ngx_http_charset_header_filter + fun:ngx_http_userid_filter +} + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_create_request + fun:ngx_http_keepalive_handler + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes +} + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_list_init + fun:ngx_http_process_request_line + fun:ngx_http_keepalive_handler + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes +} + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_create_request + fun:ngx_http_keepalive_handler + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes +} + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_keepalive_handler + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_create_temp_buf + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_events_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_events_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_events_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_epoll_create_conf + fun:ngx_events_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_epoll_create_conf + fun:ngx_events_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_autoindex_create_loc_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_index_create_loc_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_index_create_loc_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_map_create_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_map_create_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_upstream_hash_create_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_copy_filter_create_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_copy_filter_create_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_hash_add_key + fun:ngx_http_add_variable + fun:ngx_http_fastcgi_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_add_variable + fun:ngx_http_gzip_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_hash_add_key + fun:ngx_http_add_variable + fun:ngx_http_gzip_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_hash_add_key + fun:ngx_http_add_variable + fun:ngx_http_userid_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_get_variable_index + fun:ngx_http_userid_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_log_set_log + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_autoindex_create_loc_conf + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_index_create_loc_conf + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_index_create_loc_conf + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_upstream_hash_create_conf + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_copy_filter_create_conf + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_copy_filter_create_conf + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_add_variable + fun:ngx_http_rewrite_set + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_add_variable + fun:ngx_http_rewrite_set + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_get_variable_index + fun:ngx_http_rewrite_set + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server +} + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_crc32_table_init + fun:main +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_headers_add + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_array_create + fun:ngx_http_headers_add + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_script_start_code + fun:ngx_http_rewrite + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_regex_compile + fun:ngx_http_regex_compile + fun:ngx_http_rewrite + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_regex_compile + fun:ngx_http_regex_compile + fun:ngx_http_rewrite + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_regex_compile + fun:ngx_http_rewrite + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_script_init_arrays + fun:ngx_http_script_compile + fun:ngx_http_rewrite + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_array_create + fun:ngx_http_script_init_arrays + fun:ngx_http_script_compile + fun:ngx_http_rewrite + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_pstrdup + fun:ngx_http_core_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_get_full_name + fun:ngx_conf_full_name + fun:ngx_http_core_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_core_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_hash_init + fun:ngx_http_core_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pool_cleanup_add + fun:ngx_resolver_create + fun:ngx_http_core_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_index_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_array_create + fun:ngx_http_index_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_script_init_arrays + fun:ngx_http_script_compile + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_array_create + fun:ngx_http_script_init_arrays + fun:ngx_http_script_compile + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_hash_init + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_hash_init + fun:ngx_http_merge_types + fun:ngx_http_gzip_merge_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_hash_init + fun:ngx_http_ssi_init_main_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_hash_init + fun:ngx_http_merge_types + fun:ngx_http_ssi_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_hash_init + fun:ngx_http_merge_types + fun:ngx_http_charset_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_create_listening + fun:ngx_http_add_listening + fun:ngx_http_init_listening + fun:ngx_http_optimize_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_create_listening + fun:ngx_http_add_listening + fun:ngx_http_init_listening + fun:ngx_http_optimize_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_create_listening + fun:ngx_http_add_listening + fun:ngx_http_init_listening + fun:ngx_http_optimize_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_init_listening + fun:ngx_http_optimize_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_init_listening + fun:ngx_http_optimize_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_add_addrs + fun:ngx_http_init_listening + fun:ngx_http_optimize_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_core_module_init_conf + fun:ngx_init_cycle + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_core_module_init_conf + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_set_environment + fun:ngx_worker_process_init + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_add_variable + fun:ngx_http_ssi_preconfiguration + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_core_module_init_conf + fun:ngx_init_cycle + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pool_cleanup_add + fun:ngx_resolver_create + fun:ngx_http_core_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_autoindex_create_loc_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_autoindex_create_loc_conf + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_array_create + fun:ngx_http_index_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_hash_init + fun:ngx_http_merge_types + fun:ngx_http_charset_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_add_addrs + fun:ngx_http_init_listening + fun:ngx_http_optimize_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_add_variable + fun:ngx_http_fastcgi_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_add_variable + fun:ngx_http_ssi_preconfiguration + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_push + fun:ngx_http_script_add_var_code + fun:ngx_http_script_compile + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_push + fun:ngx_http_script_add_var_code + fun:ngx_http_script_compile + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler +} + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_event_accept + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_event_accept + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_init_connection + fun:ngx_event_accept + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_regex_exec + fun:ngx_http_core_find_location + fun:ngx_http_core_find_config_phase + fun:ngx_http_core_run_phases + fun:ngx_http_handler + fun:ngx_http_process_request + fun:ngx_http_process_request_headers + fun:ngx_http_process_request_line +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_script_complex_value_code + fun:ngx_http_rewrite_handler + fun:ngx_http_core_rewrite_phase + fun:ngx_http_core_run_phases + fun:ngx_http_handler + fun:ngx_http_process_request + fun:ngx_http_process_request_headers + fun:ngx_http_process_request_line +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_alloc_chain_link + fun:ngx_http_write_filter + fun:ngx_http_header_filter + fun:ngx_http_chunked_header_filter + fun:ngx_http_range_header_filter + fun:ngx_http_gzip_header_filter + fun:ngx_http_ssi_header_filter + fun:ngx_http_charset_header_filter +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_alloc_chain_link + fun:ngx_http_write_filter + fun:ngx_http_header_filter + fun:ngx_http_chunked_header_filter + fun:ngx_http_range_header_filter + fun:ngx_http_gzip_header_filter + fun:ngx_http_ssi_header_filter + fun:ngx_http_charset_header_filter +} + + + + + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_process_request_headers + fun:ngx_http_process_request_line + fun:ngx_http_keepalive_handler + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_init_connection + fun:ngx_event_accept + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_regex_exec + fun:ngx_http_core_find_location + fun:ngx_http_core_find_config_phase + fun:ngx_http_core_run_phases + fun:ngx_http_handler + fun:ngx_http_process_request + fun:ngx_http_process_request_headers + fun:ngx_http_process_request_line +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_script_complex_value_code + fun:ngx_http_rewrite_handler + fun:ngx_http_core_rewrite_phase + fun:ngx_http_core_run_phases + fun:ngx_http_handler + fun:ngx_http_process_request + fun:ngx_http_process_request_headers + fun:ngx_http_process_request_line +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_create_pool + fun:ngx_event_accept + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_create_pool + fun:ngx_http_create_request + fun:ngx_http_keepalive_handler + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_process_request_headers + fun:ngx_http_process_request_line + fun:ngx_http_keepalive_handler + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_push + fun:ngx_http_script_add_var_code + fun:ngx_http_script_compile + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_add_variable + fun:ngx_http_browser_add_variable + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_pstrdup + fun:ngx_init_cycle + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_pstrdup + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_add_variable + fun:ngx_http_fastcgi_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_core_module_init_conf + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_hash_init + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_get_full_name + fun:ngx_conf_full_name + fun:ngx_http_core_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_conf_read_token + fun:ngx_conf_parse + fun:ngx_events_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_create_pool + fun:ngx_init_cycle + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_upstream_hash_create_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_log_set_log + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_upstream_hash_create_conf + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_headers_add + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_script_start_code + fun:ngx_http_rewrite + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_regex_compile + fun:ngx_http_rewrite + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_script_init_arrays + fun:ngx_http_script_compile + fun:ngx_http_rewrite + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_core_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_index_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_script_init_arrays + fun:ngx_http_script_compile + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_create_pool + fun:ngx_http_push_init_module + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_push + fun:ngx_http_script_add_var_code + fun:ngx_http_script_compile + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_add_variable + fun:ngx_http_browser_add_variable + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_get_variable_index + fun:ngx_http_script_add_var_code + fun:ngx_http_script_compile + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_pstrdup + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_list_create + fun:ngx_regex_create_conf + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_add_variable + fun:ngx_http_rewrite_set + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_array_create + fun:ngx_http_script_init_arrays + fun:ngx_http_script_compile + fun:ngx_http_rewrite + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_hash_init + fun:ngx_http_ssi_init_main_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_get_variable_index + fun:ngx_http_script_add_var_code + fun:ngx_http_script_compile + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_hash_add_key + fun:ngx_http_add_variable + fun:ngx_http_fastcgi_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_hash_add_key + fun:ngx_http_add_variable + fun:ngx_http_gzip_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_hash_add_key + fun:ngx_http_add_variable + fun:ngx_http_userid_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_conf_read_token + fun:ngx_conf_parse + fun:ngx_events_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_create_temp_buf + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_core_module_create_conf + fun:ngx_init_cycle + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_core_module_create_conf + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_array_create + fun:ngx_http_headers_add + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:* + fun:* + fun:* + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_add_variable + fun:ngx_http_userid_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_array_create + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:* + fun:* + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_array_create + fun:ngx_http_script_init_arrays + fun:ngx_http_script_compile + fun:ngx_http_rewrite_value + fun:ngx_http_rewrite_set + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_core_create_loc_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_core_create_loc_conf + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_limit_conn_create_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_core_create_main_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_proxy_create_loc_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_proxy_create_loc_conf + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_limit_req_create_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_ssi_create_loc_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_push + fun:ngx_http_get_variable_index + fun:ngx_http_log_variable_compile + fun:ngx_http_log_compile_format + fun:ngx_http_log_init + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_referer_create_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_gzip_create_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_userid_create_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_regex_malloc + fun:pcre_compile2 + fun:ngx_regex_compile + fun:ngx_http_regex_compile + fun:ngx_http_core_regex_location + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_hash_init + fun:ngx_http_init_headers_in_hash + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_conf_read_token + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_hash_init + fun:ngx_http_upstream_init_main_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_hash_init + fun:ngx_http_variables_init_vars + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_push_create_loc_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_array_create + fun:ngx_http_script_start_code + fun:ngx_http_rewrite_value + fun:ngx_http_rewrite_set + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_create_temp_buf + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_autoindex_create_loc_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_proxy_create_loc_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_variables_add_core_vars + fun:ngx_http_core_preconfiguration + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_hash_add_key + fun:ngx_http_variables_add_core_vars + fun:ngx_http_core_preconfiguration + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_push + fun:ngx_hash_add_key + fun:ngx_http_variables_add_core_vars + fun:ngx_http_core_preconfiguration + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_push + fun:ngx_hash_add_key + fun:ngx_http_add_variable + fun:ngx_http_upstream_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_hash_init + fun:ngx_http_variables_init_vars + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_memcached_create_loc_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_hash_keys_array_init + fun:ngx_http_variables_add_core_vars + fun:ngx_http_core_preconfiguration + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_scgi_create_loc_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_uwsgi_create_loc_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_fastcgi_create_loc_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_core_create_loc_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_event_process_init + fun:ngx_worker_process_init + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_get_variable_index + fun:ngx_http_log_variable_compile + fun:ngx_http_log_compile_format + fun:ngx_http_log_init + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_regex_malloc + fun:pcre_compile2 + fun:ngx_regex_compile + fun:ngx_http_regex_compile + fun:ngx_http_rewrite + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_conf_set_path_slot + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_conf_merge_path_value + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_conf_merge_path_value + fun:ngx_http_fastcgi_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_conf_merge_path_value + fun:ngx_http_uwsgi_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_conf_merge_path_value + fun:ngx_http_scgi_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_add_variable + fun:ngx_http_proxy_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_event_core_create_conf + fun:ngx_events_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_array_create + fun:ngx_http_core_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_calloc + fun:ngx_resolver_create + fun:ngx_http_core_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_init_locations + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_array_create + fun:ngx_http_log_set_log + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_hash_init + fun:ngx_http_upstream_hide_headers_hash + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_hash_init + fun:ngx_http_upstream_hide_headers_hash + fun:ngx_http_fastcgi_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_hash_init + fun:ngx_http_upstream_hide_headers_hash + fun:ngx_http_uwsgi_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_hash_init + fun:ngx_http_upstream_hide_headers_hash + fun:ngx_http_scgi_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_master_process_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_list_init + fun:ngx_list_create + fun:ngx_regex_create_conf + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_hash_keys_array_init + fun:ngx_http_variables_add_core_vars + fun:ngx_http_core_preconfiguration + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_hash_keys_array_init + fun:ngx_http_variables_add_core_vars + fun:ngx_http_core_preconfiguration + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_hash_keys_array_init + fun:ngx_http_variables_add_core_vars + fun:ngx_http_core_preconfiguration + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_list_push + fun:ngx_regex_compile + fun:ngx_http_regex_compile + fun:ngx_http_core_regex_location + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_hash_init + fun:ngx_http_core_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_push_n + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_hash_init + fun:ngx_http_merge_types + fun:ngx_http_gzip_merge_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_hash_init + fun:ngx_http_merge_types + fun:ngx_http_ssi_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_hash_add_key + fun:ngx_http_add_variable + fun:ngx_http_ssi_preconfiguration + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_add_variable + fun:ngx_http_upstream_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_array_create + fun:ngx_init_cycle + fun:main +} + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_regex_compile + fun:ngx_http_regex_compile + fun:ngx_http_core_regex_location + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_regex_compile + fun:ngx_http_regex_compile + fun:ngx_http_core_regex_location + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_regex_compile + fun:ngx_http_core_regex_location + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_script_start_code + fun:ngx_http_rewrite_value + fun:ngx_http_rewrite_set + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_script_init_arrays + fun:ngx_http_script_compile + fun:ngx_http_rewrite_value + fun:ngx_http_rewrite_set + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_index_create_loc_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_index_create_loc_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_copy_filter_create_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_copy_filter_create_conf + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_add_variable + fun:ngx_http_upstream_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_hash_add_key + fun:ngx_http_add_variable + fun:ngx_http_upstream_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_hash_add_key + fun:ngx_http_add_variable + fun:ngx_http_browser_add_variable + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_conf_read_token + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_conf_read_token + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_core_module_create_conf + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_array_create + fun:ngx_http_script_start_code + fun:ngx_http_rewrite + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_push_n + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_hash_init + fun:ngx_http_init_headers_in_hash + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_init + fun:ngx_hash_add_key + fun:ngx_http_add_variable + fun:ngx_http_proxy_add_variables + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_conf_read_token + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_conf_read_token + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_calloc + fun:ngx_resolver_create + fun:ngx_http_core_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_hash_init + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_hash_init + fun:ngx_http_merge_types + fun:ngx_http_charset_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_hash_init + fun:ngx_http_upstream_init_main_conf + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_hash_init + fun:ngx_http_upstream_hide_headers_hash + fun:ngx_http_fastcgi_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_hash_init + fun:ngx_http_upstream_hide_headers_hash + fun:ngx_http_uwsgi_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_hash_init + fun:ngx_http_upstream_hide_headers_hash + fun:ngx_http_scgi_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_push + fun:ngx_http_get_variable_index + fun:ngx_http_script_add_var_code + fun:ngx_http_script_compile + fun:ngx_http_proxy_init_headers + fun:ngx_http_proxy_merge_loc_conf + fun:ngx_http_merge_servers + fun:ngx_http_block +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_regex_compile + fun:ngx_http_core_regex_location + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_script_start_code + fun:ngx_http_rewrite_value + fun:ngx_http_rewrite_set + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_array_create + fun:ngx_http_script_init_arrays + fun:ngx_http_script_compile + fun:ngx_http_rewrite_value + fun:ngx_http_rewrite_set + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location +} + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_event_accept + fun:ngx_event_process_posted + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_event_accept + fun:ngx_event_process_posted + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_event_accept + fun:ngx_event_process_posted + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_event_accept + fun:ngx_event_process_posted + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_event_accept + fun:ngx_event_process_posted + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_init_connection + fun:ngx_event_accept + fun:ngx_event_process_posted + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_init_connection + fun:ngx_event_accept + fun:ngx_event_process_posted + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_create_temp_buf + fun:ngx_http_wait_request_handler + fun:ngx_event_process_posted + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_init_connection + fun:ngx_event_accept + fun:ngx_event_process_posted + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_create_pool + fun:ngx_event_accept + fun:ngx_event_process_posted + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_init_connection + fun:ngx_event_accept + fun:ngx_event_process_posted + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_event_accept + fun:ngx_event_process_posted + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_create_temp_buf + fun:ngx_http_wait_request_handler + fun:ngx_event_process_posted + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes +} + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:BUF_strndup + fun:CONF_module_add + fun:OPENSSL_load_builtin_modules + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:BUF_strndup + fun:CONF_module_add + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_new_ex_data + fun:ENGINE_new + fun:ENGINE_load_dynamic + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_new_ex_data + fun:ENGINE_new + fun:ENGINE_load_dynamic + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_thread_set_item + fun:ERR_get_state + fun:ERR_clear_error + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_new_ex_data + fun:BIO_set + fun:BIO_new + fun:BIO_new_file + fun:def_load + fun:CONF_modules_load_file + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_new_ex_data + fun:BIO_set + fun:BIO_new + fun:BIO_new_file + fun:def_load + fun:CONF_modules_load_file + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:SSL_COMP_get_compression_methods + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_get_new_index + fun:COMP_zlib + fun:SSL_COMP_get_compression_methods + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_get_new_index + fun:COMP_zlib + fun:SSL_COMP_get_compression_methods + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:OpenSSL_add_all_digests + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:OBJ_NAME_add + fun:EVP_add_digest + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_get_new_index + fun:SSL_get_ex_data_X509_STORE_CTX_idx + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_get_new_index + fun:SSL_get_ex_data_X509_STORE_CTX_idx + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_new_ex_data + fun:X509_STORE_new + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_new_ex_data + fun:X509_STORE_new + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_new_ex_data + fun:x509_cb + fun:ASN1_item_ex_new + fun:ASN1_item_ex_d2i + fun:ASN1_item_d2i + fun:d2i_X509_AUX + fun:PEM_ASN1_read_bio + fun:ngx_ssl_certificate + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_new_ex_data + fun:x509_cb + fun:ASN1_item_ex_new + fun:ASN1_item_ex_d2i + fun:ASN1_item_d2i + fun:d2i_X509_AUX + fun:PEM_ASN1_read_bio + fun:ngx_ssl_certificate + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_new_ex_data + fun:RSA_new_method + fun:rsa_cb + fun:ASN1_item_ex_new + fun:ASN1_item_ex_d2i + fun:ASN1_item_d2i + fun:rsa_pub_decode + fun:X509_PUBKEY_get + fun:SSL_CTX_use_certificate + fun:ngx_ssl_certificate + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_new_ex_data + fun:RSA_new_method + fun:rsa_cb + fun:ASN1_item_ex_new + fun:ASN1_item_ex_d2i + fun:ASN1_item_d2i + fun:rsa_pub_decode + fun:X509_PUBKEY_get + fun:SSL_CTX_use_certificate + fun:ngx_ssl_certificate + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_new_ex_data + fun:DH_new_method + fun:ngx_ssl_dhparam + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_new_ex_data + fun:DH_new_method + fun:ngx_ssl_dhparam + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:CONF_module_add + fun:OPENSSL_load_builtin_modules + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:CONF_module_add + fun:OPENSSL_load_builtin_modules + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:ENGINE_new + fun:ENGINE_load_dynamic + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:ENGINE_new + fun:ENGINE_load_dynamic + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:engine_cleanup_add_last + fun:ENGINE_add + fun:ENGINE_load_dynamic + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:engine_cleanup_add_last + fun:ENGINE_add + fun:ENGINE_load_dynamic + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:BIO_set + fun:BIO_new + fun:BIO_new_file + fun:def_load + fun:CONF_modules_load_file + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:BIO_set + fun:BIO_new + fun:BIO_new_file + fun:def_load + fun:CONF_modules_load_file + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:SSL_COMP_get_compression_methods + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:SSL_COMP_get_compression_methods + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_get_new_index + fun:COMP_zlib + fun:SSL_COMP_get_compression_methods + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_get_new_index + fun:COMP_zlib + fun:SSL_COMP_get_compression_methods + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_get_new_index + fun:SSL_get_ex_data_X509_STORE_CTX_idx + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_get_new_index + fun:SSL_get_ex_data_X509_STORE_CTX_idx + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:X509_STORE_new + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:X509_STORE_new + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:x509_cb + fun:ASN1_item_ex_new + fun:ASN1_item_ex_d2i + fun:ASN1_item_d2i + fun:d2i_X509_AUX + fun:PEM_ASN1_read_bio + fun:ngx_ssl_certificate + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:x509_cb + fun:ASN1_item_ex_new + fun:ASN1_item_ex_d2i + fun:ASN1_item_d2i + fun:d2i_X509_AUX + fun:PEM_ASN1_read_bio + fun:ngx_ssl_certificate + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:RSA_new_method + fun:rsa_cb + fun:ASN1_item_ex_new + fun:ASN1_item_ex_d2i + fun:ASN1_item_d2i + fun:rsa_pub_decode + fun:X509_PUBKEY_get + fun:SSL_CTX_use_certificate + fun:ngx_ssl_certificate + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:RSA_new_method + fun:rsa_cb + fun:ASN1_item_ex_new + fun:ASN1_item_ex_d2i + fun:ASN1_item_d2i + fun:rsa_pub_decode + fun:X509_PUBKEY_get + fun:SSL_CTX_use_certificate + fun:ngx_ssl_certificate + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:DH_new_method + fun:ngx_ssl_dhparam + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:DH_new_method + fun:ngx_ssl_dhparam + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:int_get_new_index + fun:COMP_zlib + fun:SSL_COMP_get_compression_methods + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:int_get_new_index + fun:SSL_get_ex_data_X509_STORE_CTX_idx + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:CONF_module_add + fun:OPENSSL_load_builtin_modules + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:CONF_module_add + fun:OPENSSL_load_builtin_modules + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:CONF_module_add + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:realloc + fun:CRYPTO_realloc + fun:sk_insert + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_ECDH_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_RAND_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_COMP_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_new + fun:def_get_class + fun:int_new_ex_data + fun:ENGINE_new + fun:ENGINE_load_dynamic + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_new + fun:int_thread_get + fun:int_thread_set_item + fun:ERR_get_state + fun:ERR_clear_error + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_BUF_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_ECDSA_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_OBJ_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_new + fun:def_get_class + fun:int_new_ex_data + fun:ENGINE_new + fun:ENGINE_load_dynamic + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_new + fun:int_thread_get + fun:int_thread_set_item + fun:ERR_get_state + fun:ERR_clear_error + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_new + fun:OBJ_NAME_init + fun:OBJ_NAME_add + fun:EVP_add_cipher + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_new + fun:int_err_get + fun:int_err_set_item + fun:ERR_load_ERR_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:ENGINE_new + fun:ENGINE_load_dynamic + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_ERR_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_CRYPTO_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_UI_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_OCSP_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_DH_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_CONF_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:ERR_get_state + fun:ERR_clear_error + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_DSA_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_ERR_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_PKCS12_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_BIO_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_ERR_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_ENGINE_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_PKCS7_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_BN_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_PEM_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_X509_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_DSO_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_TS_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_RSA_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_X509V3_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_EVP_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_CMS_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:realloc + fun:CRYPTO_realloc + fun:lh_insert + fun:OBJ_NAME_add + fun:OpenSSL_add_all_ciphers + fun:OPENSSL_add_all_algorithms_noconf + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_ASN1_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_ERR_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_EC_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_SSL_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:realloc + fun:CRYPTO_realloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:BUF_strndup + fun:CONF_module_add + fun:OPENSSL_load_builtin_modules + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:engine_cleanup_add_last + fun:ENGINE_add + fun:ENGINE_load_dynamic + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:BUF_strndup + fun:CONF_module_add + fun:OPENSSL_load_builtin_modules + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:BUF_strndup + fun:CONF_module_add + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_new_ex_data + fun:ENGINE_new + fun:ENGINE_load_dynamic + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_new_ex_data + fun:ENGINE_new + fun:ENGINE_load_dynamic + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_thread_set_item + fun:ERR_get_state + fun:ERR_clear_error + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_new_ex_data + fun:BIO_set + fun:BIO_new + fun:BIO_new_file + fun:def_load + fun:CONF_modules_load_file + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_new_ex_data + fun:BIO_set + fun:BIO_new + fun:BIO_new_file + fun:def_load + fun:CONF_modules_load_file + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:SSL_COMP_get_compression_methods + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_get_new_index + fun:COMP_zlib + fun:SSL_COMP_get_compression_methods + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_get_new_index + fun:COMP_zlib + fun:SSL_COMP_get_compression_methods + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_get_new_index + fun:SSL_get_ex_data_X509_STORE_CTX_idx + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_get_new_index + fun:SSL_get_ex_data_X509_STORE_CTX_idx + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_new_ex_data + fun:X509_STORE_new + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_new_ex_data + fun:X509_STORE_new + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_new_ex_data + fun:x509_cb + fun:ASN1_item_ex_new + fun:ASN1_item_ex_d2i + fun:ASN1_item_d2i + fun:d2i_X509_AUX + fun:PEM_ASN1_read_bio + fun:ngx_ssl_certificate + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_new_ex_data + fun:x509_cb + fun:ASN1_item_ex_new + fun:ASN1_item_ex_d2i + fun:ASN1_item_d2i + fun:d2i_X509_AUX + fun:PEM_ASN1_read_bio + fun:ngx_ssl_certificate + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_new_ex_data + fun:RSA_new_method + fun:rsa_cb + fun:ASN1_item_ex_new + fun:ASN1_item_ex_d2i + fun:ASN1_item_d2i + fun:rsa_pub_decode + fun:X509_PUBKEY_get + fun:SSL_CTX_use_certificate + fun:ngx_ssl_certificate + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_new_ex_data + fun:RSA_new_method + fun:rsa_cb + fun:ASN1_item_ex_new + fun:ASN1_item_ex_d2i + fun:ASN1_item_d2i + fun:rsa_pub_decode + fun:X509_PUBKEY_get + fun:SSL_CTX_use_certificate + fun:ngx_ssl_certificate + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:def_get_class + fun:int_new_ex_data + fun:DH_new_method + fun:ngx_ssl_dhparam + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:def_get_class + fun:int_new_ex_data + fun:DH_new_method + fun:ngx_ssl_dhparam + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:CONF_module_add + fun:OPENSSL_load_builtin_modules + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:CONF_module_add + fun:OPENSSL_load_builtin_modules + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:ENGINE_new + fun:ENGINE_load_dynamic + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:ENGINE_new + fun:ENGINE_load_dynamic + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:BIO_set + fun:BIO_new + fun:BIO_new_file + fun:def_load + fun:CONF_modules_load_file + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:BIO_set + fun:BIO_new + fun:BIO_new_file + fun:def_load + fun:CONF_modules_load_file + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:SSL_COMP_get_compression_methods + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:SSL_COMP_get_compression_methods + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_get_new_index + fun:COMP_zlib + fun:SSL_COMP_get_compression_methods + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_get_new_index + fun:COMP_zlib + fun:SSL_COMP_get_compression_methods + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_get_new_index + fun:SSL_get_ex_data_X509_STORE_CTX_idx + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_get_new_index + fun:SSL_get_ex_data_X509_STORE_CTX_idx + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:X509_STORE_new + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:X509_STORE_new + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:x509_cb + fun:ASN1_item_ex_new + fun:ASN1_item_ex_d2i + fun:ASN1_item_d2i + fun:d2i_X509_AUX + fun:PEM_ASN1_read_bio + fun:ngx_ssl_certificate + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:x509_cb + fun:ASN1_item_ex_new + fun:ASN1_item_ex_d2i + fun:ASN1_item_d2i + fun:d2i_X509_AUX + fun:PEM_ASN1_read_bio + fun:ngx_ssl_certificate + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:RSA_new_method + fun:rsa_cb + fun:ASN1_item_ex_new + fun:ASN1_item_ex_d2i + fun:ASN1_item_d2i + fun:rsa_pub_decode + fun:X509_PUBKEY_get + fun:SSL_CTX_use_certificate + fun:ngx_ssl_certificate + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:RSA_new_method + fun:rsa_cb + fun:ASN1_item_ex_new + fun:ASN1_item_ex_d2i + fun:ASN1_item_d2i + fun:rsa_pub_decode + fun:X509_PUBKEY_get + fun:SSL_CTX_use_certificate + fun:ngx_ssl_certificate + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle +} + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:DH_new_method + fun:ngx_ssl_dhparam + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:sk_new + fun:def_get_class + fun:int_new_ex_data + fun:DH_new_method + fun:ngx_ssl_dhparam + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:int_get_new_index + fun:COMP_zlib + fun:SSL_COMP_get_compression_methods + fun:SSL_library_init + fun:ngx_ssl_init + fun:main +} + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:int_get_new_index + fun:SSL_get_ex_data_X509_STORE_CTX_idx + fun:SSL_CTX_new + fun:ngx_ssl_create + fun:ngx_http_ssl_merge_srv_conf + fun:ngx_http_merge_servers + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:CONF_module_add + fun:OPENSSL_load_builtin_modules + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:CONF_module_add + fun:OPENSSL_load_builtin_modules + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:CONF_module_add + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:realloc + fun:CRYPTO_realloc + fun:sk_insert + fun:int_get_new_index + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_ECDH_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_RAND_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_COMP_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_new + fun:def_get_class + fun:int_new_ex_data + fun:ENGINE_new + fun:ENGINE_load_dynamic + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_new + fun:int_thread_get + fun:int_thread_set_item + fun:ERR_get_state + fun:ERR_clear_error + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_BUF_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_ECDSA_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_OBJ_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_new + fun:def_get_class + fun:int_new_ex_data + fun:ENGINE_new + fun:ENGINE_load_dynamic + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_new + fun:int_thread_get + fun:int_thread_set_item + fun:ERR_get_state + fun:ERR_clear_error + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_new + fun:int_err_get + fun:int_err_set_item + fun:ERR_load_ERR_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_ERR_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_CRYPTO_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_UI_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_OCSP_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_DH_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_CONF_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:ERR_get_state + fun:ERR_clear_error + fun:ENGINE_load_builtin_engines + fun:OPENSSL_config + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_DSA_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_ERR_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_PKCS12_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_BIO_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_ERR_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_ENGINE_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_PKCS7_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_BN_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_PEM_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_X509_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_DSO_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_TS_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_RSA_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_X509V3_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_EVP_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_CMS_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_ASN1_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_ERR_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_EC_strings + fun:ERR_load_crypto_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ERR_load_SSL_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:CRYPTO_malloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:ngx_ssl_init + fun:main +} + + + + + + + + + + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:realloc + fun:CRYPTO_realloc + fun:lh_insert + fun:int_err_set_item + fun:ERR_load_strings + fun:SSL_load_error_strings + fun:ngx_ssl_init + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: indirect + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_upstream_process_header + fun:ngx_http_upstream_handler + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: indirect + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_upstream_create + fun:ngx_http_proxy_handler + fun:ngx_http_core_content_phase + fun:ngx_http_core_run_phases + fun:ngx_http_handler + fun:ngx_http_run_posted_requests + fun:ngx_http_request_handler + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: indirect + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_list_init + fun:ngx_http_upstream_process_header + fun:ngx_http_upstream_handler + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: indirect + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_proxy_handler + fun:ngx_http_core_content_phase + fun:ngx_http_core_run_phases + fun:ngx_http_handler + fun:ngx_http_run_posted_requests + fun:ngx_http_request_handler + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: indirect + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_http_proxy_handler + fun:ngx_http_core_content_phase + fun:ngx_http_core_run_phases + fun:ngx_http_handler + fun:ngx_http_run_posted_requests + fun:ngx_http_request_handler + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: indirect + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_pnalloc + fun:ngx_http_proxy_process_header + fun:ngx_http_proxy_process_status_line + fun:ngx_http_upstream_process_header + fun:ngx_http_upstream_handler + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: indirect + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_pcalloc + fun:ngx_chain_get_free_buf + fun:ngx_http_proxy_non_buffered_copy_filter + fun:ngx_http_upstream_process_header + fun:ngx_http_upstream_handler + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle + fun:main +} + +{ + + Memcheck:Leak + match-leak-kinds: indirect + fun:malloc + fun:ngx_alloc + fun:ngx_malloc + fun:ngx_palloc + fun:ngx_http_proxy_create_request + fun:ngx_http_upstream_init_request + fun:ngx_http_upstream_init + fun:ngx_http_read_client_request_body + fun:ngx_http_proxy_handler + fun:ngx_http_core_content_phase + fun:ngx_http_core_run_phases + fun:ngx_http_handler + fun:ngx_http_run_posted_requests + fun:ngx_http_request_handler + fun:ngx_epoll_process_events + fun:ngx_process_events_and_timers + fun:ngx_worker_process_cycle + fun:ngx_spawn_process + fun:ngx_start_worker_processes + fun:ngx_master_process_cycle +} + + + diff --git a/debian/modules/nchan/src/.gitignore b/debian/modules/nchan/src/.gitignore new file mode 100644 index 0000000..67fd4b3 --- /dev/null +++ b/debian/modules/nchan/src/.gitignore @@ -0,0 +1,2 @@ +nginx +nginx-source \ No newline at end of file diff --git a/debian/modules/nchan/src/hiredis/.gitignore b/debian/modules/nchan/src/hiredis/.gitignore new file mode 100644 index 0000000..c44b5c5 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/.gitignore @@ -0,0 +1,7 @@ +/hiredis-test +/examples/hiredis-example* +/*.o +/*.so +/*.dylib +/*.a +/*.pc diff --git a/debian/modules/nchan/src/hiredis/.travis.yml b/debian/modules/nchan/src/hiredis/.travis.yml new file mode 100644 index 0000000..1e1ce30 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/.travis.yml @@ -0,0 +1,24 @@ +language: c +sudo: false +compiler: + - gcc + - clang + +addons: + apt: + packages: + - libc6-dbg + - libc6-dev + - libc6:i386 + - libc6-dev-i386 + - libc6-dbg:i386 + - gcc-multilib + - valgrind + +env: + - CFLAGS="-Werror" + - PRE="valgrind --track-origins=yes --leak-check=full" + - TARGET="32bit" TARGET_VARS="32bit-vars" CFLAGS="-Werror" + - TARGET="32bit" TARGET_VARS="32bit-vars" PRE="valgrind --track-origins=yes --leak-check=full" + +script: make $TARGET CFLAGS="$CFLAGS" && make check PRE="$PRE" && make $TARGET_VARS hiredis-example diff --git a/debian/modules/nchan/src/hiredis/CHANGELOG.md b/debian/modules/nchan/src/hiredis/CHANGELOG.md new file mode 100644 index 0000000..a5015c5 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/CHANGELOG.md @@ -0,0 +1,110 @@ +### 0.13.3 (2015-09-16) + +* Revert "Clear `REDIS_CONNECTED` flag when connection is closed". +* Make tests pass on FreeBSD (Thanks, Giacomo Olgeni) + + +If the `REDIS_CONNECTED` flag is cleared, +the async onDisconnect callback function will never be called. +This causes problems as the disconnect is never reported back to the user. + +### 0.13.2 (2015-08-25) + +* Prevent crash on pending replies in async code (Thanks, @switch-st) +* Clear `REDIS_CONNECTED` flag when connection is closed (Thanks, Jerry Jacobs) +* Add MacOS X addapter (Thanks, @dizzus) +* Add Qt adapter (Thanks, Pietro Cerutti) +* Add Ivykis adapter (Thanks, Gergely Nagy) + +All adapters are provided as is and are only tested where possible. + +### 0.13.1 (2015-05-03) + +This is a bug fix release. +The new `reconnect` method introduced new struct members, which clashed with pre-defined names in pre-C99 code. +Another commit forced C99 compilation just to make it work, but of course this is not desirable for outside projects. +Other non-C99 code can now use hiredis as usual again. +Sorry for the inconvenience. + +* Fix memory leak in async reply handling (Salvatore Sanfilippo) +* Rename struct member to avoid name clash with pre-c99 code (Alex Balashov, ncopa) + +### 0.13.0 (2015-04-16) + +This release adds a minimal Windows compatibility layer. +The parser, standalone since v0.12.0, can now be compiled on Windows +(and thus used in other client libraries as well) + +* Windows compatibility layer for parser code (tzickel) +* Properly escape data printed to PKGCONF file (Dan Skorupski) +* Fix tests when assert() undefined (Keith Bennett, Matt Stancliff) +* Implement a reconnect method for the client context, this changes the structure of `redisContext` (Aaron Bedra) + +### 0.12.1 (2015-01-26) + +* Fix `make install`: DESTDIR support, install all required files, install PKGCONF in proper location +* Fix `make test` as 32 bit build on 64 bit platform + +### 0.12.0 (2015-01-22) + +* Add optional KeepAlive support + +* Try again on EINTR errors + +* Add libuv adapter + +* Add IPv6 support + +* Remove possiblity of multiple close on same fd + +* Add ability to bind source address on connect + +* Add redisConnectFd() and redisFreeKeepFd() + +* Fix getaddrinfo() memory leak + +* Free string if it is unused (fixes memory leak) + +* Improve redisAppendCommandArgv performance 2.5x + +* Add support for SO_REUSEADDR + +* Fix redisvFormatCommand format parsing + +* Add GLib 2.0 adapter + +* Refactor reading code into read.c + +* Fix errno error buffers to not clobber errors + +* Generate pkgconf during build + +* Silence _BSD_SOURCE warnings + +* Improve digit counting for multibulk creation + + +### 0.11.0 + +* Increase the maximum multi-bulk reply depth to 7. + +* Increase the read buffer size from 2k to 16k. + +* Use poll(2) instead of select(2) to support large fds (>= 1024). + +### 0.10.1 + +* Makefile overhaul. Important to check out if you override one or more + variables using environment variables or via arguments to the "make" tool. + +* Issue #45: Fix potential memory leak for a multi bulk reply with 0 elements + being created by the default reply object functions. + +* Issue #43: Don't crash in an asynchronous context when Redis returns an error + reply after the connection has been made (this happens when the maximum + number of connections is reached). + +### 0.10.0 + +* See commit log. + diff --git a/debian/modules/nchan/src/hiredis/COPYING b/debian/modules/nchan/src/hiredis/COPYING new file mode 100644 index 0000000..a5fc973 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/COPYING @@ -0,0 +1,29 @@ +Copyright (c) 2009-2011, Salvatore Sanfilippo +Copyright (c) 2010-2011, Pieter Noordhuis + +All rights reserved. + +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 Redis 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. diff --git a/debian/modules/nchan/src/hiredis/Makefile b/debian/modules/nchan/src/hiredis/Makefile new file mode 100644 index 0000000..cff2a84 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/Makefile @@ -0,0 +1,217 @@ +# Hiredis Makefile +# Copyright (C) 2010-2011 Salvatore Sanfilippo +# Copyright (C) 2010-2011 Pieter Noordhuis +# This file is released under the BSD license, see the COPYING file + +OBJ=net.o hiredis.o sds.o async.o read.o +EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib +TESTS=hiredis-test +LIBNAME=libhiredis +PKGCONFNAME=hiredis.pc + +HIREDIS_MAJOR=$(shell grep HIREDIS_MAJOR hiredis.h | awk '{print $$3}') +HIREDIS_MINOR=$(shell grep HIREDIS_MINOR hiredis.h | awk '{print $$3}') +HIREDIS_PATCH=$(shell grep HIREDIS_PATCH hiredis.h | awk '{print $$3}') +HIREDIS_SONAME=$(shell grep HIREDIS_SONAME hiredis.h | awk '{print $$3}') + +# Installation related variables and target +PREFIX?=/usr/local +INCLUDE_PATH?=include/hiredis +LIBRARY_PATH?=lib +PKGCONF_PATH?=pkgconfig +INSTALL_INCLUDE_PATH= $(DESTDIR)$(PREFIX)/$(INCLUDE_PATH) +INSTALL_LIBRARY_PATH= $(DESTDIR)$(PREFIX)/$(LIBRARY_PATH) +INSTALL_PKGCONF_PATH= $(INSTALL_LIBRARY_PATH)/$(PKGCONF_PATH) + +# redis-server configuration used for testing +REDIS_PORT=56379 +REDIS_SERVER=redis-server +define REDIS_TEST_CONFIG + daemonize yes + pidfile /tmp/hiredis-test-redis.pid + port $(REDIS_PORT) + bind 127.0.0.1 + unixsocket /tmp/hiredis-test-redis.sock +endef +export REDIS_TEST_CONFIG + +# Fallback to gcc when $CC is not in $PATH. +CC:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo $(CC) || echo gcc') +CXX:=$(shell sh -c 'type $(CXX) >/dev/null 2>/dev/null && echo $(CXX) || echo g++') +OPTIMIZATION?=-O3 +WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings +DEBUG?= -g -ggdb +REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG) $(ARCH) +REAL_LDFLAGS=$(LDFLAGS) $(ARCH) + +DYLIBSUFFIX=so +STLIBSUFFIX=a +DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_SONAME) +DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR) +DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX) +DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) +STLIBNAME=$(LIBNAME).$(STLIBSUFFIX) +STLIB_MAKE_CMD=ar rcs $(STLIBNAME) + +# Platform-specific overrides +uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') +ifeq ($(uname_S),SunOS) + REAL_LDFLAGS+= -ldl -lnsl -lsocket + DYLIB_MAKE_CMD=$(CC) -G -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS) + INSTALL= cp -r +endif +ifeq ($(uname_S),Darwin) + DYLIBSUFFIX=dylib + DYLIB_MINOR_NAME=$(LIBNAME).$(HIREDIS_SONAME).$(DYLIBSUFFIX) + DYLIB_MAKE_CMD=$(CC) -shared -Wl,-install_name,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) +endif + +all: $(DYLIBNAME) $(STLIBNAME) hiredis-test $(PKGCONFNAME) + +# Deps (use make dep to generate this) +async.o: async.c fmacros.h async.h hiredis.h read.h sds.h net.h dict.c dict.h +dict.o: dict.c fmacros.h dict.h +hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h net.h +net.o: net.c fmacros.h net.h hiredis.h read.h sds.h +read.o: read.c fmacros.h read.h sds.h +sds.o: sds.c sds.h +test.o: test.c fmacros.h hiredis.h read.h sds.h + +$(DYLIBNAME): $(OBJ) + $(DYLIB_MAKE_CMD) $(OBJ) + +$(STLIBNAME): $(OBJ) + $(STLIB_MAKE_CMD) $(OBJ) + +dynamic: $(DYLIBNAME) +static: $(STLIBNAME) + +# Binaries: +hiredis-example-libevent: examples/example-libevent.c adapters/libevent.h $(STLIBNAME) + $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -levent $(STLIBNAME) + +hiredis-example-libev: examples/example-libev.c adapters/libev.h $(STLIBNAME) + $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -lev $(STLIBNAME) + +hiredis-example-glib: examples/example-glib.c adapters/glib.h $(STLIBNAME) + $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) $(shell pkg-config --cflags --libs glib-2.0) -I. $< $(STLIBNAME) + +hiredis-example-ivykis: examples/example-ivykis.c adapters/ivykis.h $(STLIBNAME) + $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -livykis $(STLIBNAME) + +hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME) + $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -framework CoreFoundation $(STLIBNAME) + +ifndef AE_DIR +hiredis-example-ae: + @echo "Please specify AE_DIR (e.g. /src)" + @false +else +hiredis-example-ae: examples/example-ae.c adapters/ae.h $(STLIBNAME) + $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(AE_DIR) $< $(AE_DIR)/ae.o $(AE_DIR)/zmalloc.o $(AE_DIR)/../deps/jemalloc/lib/libjemalloc.a -pthread $(STLIBNAME) +endif + +ifndef LIBUV_DIR +hiredis-example-libuv: + @echo "Please specify LIBUV_DIR (e.g. ../libuv/)" + @false +else +hiredis-example-libuv: examples/example-libuv.c adapters/libuv.h $(STLIBNAME) + $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(LIBUV_DIR)/include $< $(LIBUV_DIR)/.libs/libuv.a -lpthread -lrt $(STLIBNAME) +endif + +ifeq ($(and $(QT_MOC),$(QT_INCLUDE_DIR),$(QT_LIBRARY_DIR)),) +hiredis-example-qt: + @echo "Please specify QT_MOC, QT_INCLUDE_DIR AND QT_LIBRARY_DIR" + @false +else +hiredis-example-qt: examples/example-qt.cpp adapters/qt.h $(STLIBNAME) + $(QT_MOC) adapters/qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \ + $(CXX) -x c++ -o qt-adapter-moc.o -c - $(REAL_CFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore + $(QT_MOC) examples/example-qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \ + $(CXX) -x c++ -o qt-example-moc.o -c - $(REAL_CFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore + $(CXX) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore -L$(QT_LIBRARY_DIR) qt-adapter-moc.o qt-example-moc.o $< -pthread $(STLIBNAME) -lQtCore +endif + +hiredis-example: examples/example.c $(STLIBNAME) + $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< $(STLIBNAME) + +examples: $(EXAMPLES) + +hiredis-test: test.o $(STLIBNAME) + +hiredis-%: %.o $(STLIBNAME) + $(CC) $(REAL_CFLAGS) -o $@ $(REAL_LDFLAGS) $< $(STLIBNAME) + +test: hiredis-test + ./hiredis-test + +check: hiredis-test + @echo "$$REDIS_TEST_CONFIG" | $(REDIS_SERVER) - + $(PRE) ./hiredis-test -h 127.0.0.1 -p $(REDIS_PORT) -s /tmp/hiredis-test-redis.sock || \ + ( kill `cat /tmp/hiredis-test-redis.pid` && false ) + kill `cat /tmp/hiredis-test-redis.pid` + +.c.o: + $(CC) -std=c99 -pedantic -c $(REAL_CFLAGS) $< + +clean: + rm -rf $(DYLIBNAME) $(STLIBNAME) $(TESTS) $(PKGCONFNAME) examples/hiredis-example* *.o *.gcda *.gcno *.gcov + +dep: + $(CC) -MM *.c + +ifeq ($(uname_S),SunOS) + INSTALL?= cp -r +endif + +INSTALL?= cp -a + +$(PKGCONFNAME): hiredis.h + @echo "Generating $@ for pkgconfig..." + @echo prefix=$(PREFIX) > $@ + @echo exec_prefix=\$${prefix} >> $@ + @echo libdir=$(PREFIX)/$(LIBRARY_PATH) >> $@ + @echo includedir=$(PREFIX)/$(INCLUDE_PATH) >> $@ + @echo >> $@ + @echo Name: hiredis >> $@ + @echo Description: Minimalistic C client library for Redis. >> $@ + @echo Version: $(HIREDIS_MAJOR).$(HIREDIS_MINOR).$(HIREDIS_PATCH) >> $@ + @echo Libs: -L\$${libdir} -lhiredis >> $@ + @echo Cflags: -I\$${includedir} -D_FILE_OFFSET_BITS=64 >> $@ + +install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME) + mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH) + $(INSTALL) hiredis.h async.h read.h sds.h adapters $(INSTALL_INCLUDE_PATH) + $(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME) + cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIBNAME) + $(INSTALL) $(STLIBNAME) $(INSTALL_LIBRARY_PATH) + mkdir -p $(INSTALL_PKGCONF_PATH) + $(INSTALL) $(PKGCONFNAME) $(INSTALL_PKGCONF_PATH) + +32bit: + @echo "" + @echo "WARNING: if this fails under Linux you probably need to install libc6-dev-i386" + @echo "" + $(MAKE) CFLAGS="-m32" LDFLAGS="-m32" + +32bit-vars: + $(eval CFLAGS=-m32) + $(eval LDFLAGS=-m32) + +gprof: + $(MAKE) CFLAGS="-pg" LDFLAGS="-pg" + +gcov: + $(MAKE) CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="-fprofile-arcs" + +coverage: gcov + make check + mkdir -p tmp/lcov + lcov -d . -c -o tmp/lcov/hiredis.info + genhtml --legend -o tmp/lcov/report tmp/lcov/hiredis.info + +noopt: + $(MAKE) OPTIMIZATION="" + +.PHONY: all test check clean dep install 32bit 32bit-vars gprof gcov noopt diff --git a/debian/modules/nchan/src/hiredis/README.md b/debian/modules/nchan/src/hiredis/README.md new file mode 100644 index 0000000..4f1a58d --- /dev/null +++ b/debian/modules/nchan/src/hiredis/README.md @@ -0,0 +1,392 @@ +[![Build Status](https://travis-ci.org/redis/hiredis.png)](https://travis-ci.org/redis/hiredis) + +# HIREDIS + +Hiredis is a minimalistic C client library for the [Redis](http://redis.io/) database. + +It is minimalistic because it just adds minimal support for the protocol, but +at the same time it uses a high level printf-alike API in order to make it +much higher level than otherwise suggested by its minimal code base and the +lack of explicit bindings for every Redis command. + +Apart from supporting sending commands and receiving replies, it comes with +a reply parser that is decoupled from the I/O layer. It +is a stream parser designed for easy reusability, which can for instance be used +in higher level language bindings for efficient reply parsing. + +Hiredis only supports the binary-safe Redis protocol, so you can use it with any +Redis version >= 1.2.0. + +The library comes with multiple APIs. There is the +*synchronous API*, the *asynchronous API* and the *reply parsing API*. + +## UPGRADING + +Version 0.9.0 is a major overhaul of hiredis in every aspect. However, upgrading existing +code using hiredis should not be a big pain. The key thing to keep in mind when +upgrading is that hiredis >= 0.9.0 uses a `redisContext*` to keep state, in contrast to +the stateless 0.0.1 that only has a file descriptor to work with. + +## Synchronous API + +To consume the synchronous API, there are only a few function calls that need to be introduced: + +```c +redisContext *redisConnect(const char *ip, int port); +void *redisCommand(redisContext *c, const char *format, ...); +void freeReplyObject(void *reply); +``` + +### Connecting + +The function `redisConnect` is used to create a so-called `redisContext`. The +context is where Hiredis holds state for a connection. The `redisContext` +struct has an integer `err` field that is non-zero when the connection is in +an error state. The field `errstr` will contain a string with a description of +the error. More information on errors can be found in the **Errors** section. +After trying to connect to Redis using `redisConnect` you should +check the `err` field to see if establishing the connection was successful: +```c +redisContext *c = redisConnect("127.0.0.1", 6379); +if (c != NULL && c->err) { + printf("Error: %s\n", c->errstr); + // handle error +} +``` + +### Sending commands + +There are several ways to issue commands to Redis. The first that will be introduced is +`redisCommand`. This function takes a format similar to printf. In the simplest form, +it is used like this: +```c +reply = redisCommand(context, "SET foo bar"); +``` + +The specifier `%s` interpolates a string in the command, and uses `strlen` to +determine the length of the string: +```c +reply = redisCommand(context, "SET foo %s", value); +``` +When you need to pass binary safe strings in a command, the `%b` specifier can be +used. Together with a pointer to the string, it requires a `size_t` length argument +of the string: +```c +reply = redisCommand(context, "SET foo %b", value, (size_t) valuelen); +``` +Internally, Hiredis splits the command in different arguments and will +convert it to the protocol used to communicate with Redis. +One or more spaces separates arguments, so you can use the specifiers +anywhere in an argument: +```c +reply = redisCommand(context, "SET key:%s %s", myid, value); +``` + +### Using replies + +The return value of `redisCommand` holds a reply when the command was +successfully executed. When an error occurs, the return value is `NULL` and +the `err` field in the context will be set (see section on **Errors**). +Once an error is returned the context cannot be reused and you should set up +a new connection. + +The standard replies that `redisCommand` are of the type `redisReply`. The +`type` field in the `redisReply` should be used to test what kind of reply +was received: + +* **`REDIS_REPLY_STATUS`**: + * The command replied with a status reply. The status string can be accessed using `reply->str`. + The length of this string can be accessed using `reply->len`. + +* **`REDIS_REPLY_ERROR`**: + * The command replied with an error. The error string can be accessed identical to `REDIS_REPLY_STATUS`. + +* **`REDIS_REPLY_INTEGER`**: + * The command replied with an integer. The integer value can be accessed using the + `reply->integer` field of type `long long`. + +* **`REDIS_REPLY_NIL`**: + * The command replied with a **nil** object. There is no data to access. + +* **`REDIS_REPLY_STRING`**: + * A bulk (string) reply. The value of the reply can be accessed using `reply->str`. + The length of this string can be accessed using `reply->len`. + +* **`REDIS_REPLY_ARRAY`**: + * A multi bulk reply. The number of elements in the multi bulk reply is stored in + `reply->elements`. Every element in the multi bulk reply is a `redisReply` object as well + and can be accessed via `reply->element[..index..]`. + Redis may reply with nested arrays but this is fully supported. + +Replies should be freed using the `freeReplyObject()` function. +Note that this function will take care of freeing sub-reply objects +contained in arrays and nested arrays, so there is no need for the user to +free the sub replies (it is actually harmful and will corrupt the memory). + +**Important:** the current version of hiredis (0.10.0) frees replies when the +asynchronous API is used. This means you should not call `freeReplyObject` when +you use this API. The reply is cleaned up by hiredis _after_ the callback +returns. This behavior will probably change in future releases, so make sure to +keep an eye on the changelog when upgrading (see issue #39). + +### Cleaning up + +To disconnect and free the context the following function can be used: +```c +void redisFree(redisContext *c); +``` +This function immediately closes the socket and then frees the allocations done in +creating the context. + +### Sending commands (cont'd) + +Together with `redisCommand`, the function `redisCommandArgv` can be used to issue commands. +It has the following prototype: +```c +void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); +``` +It takes the number of arguments `argc`, an array of strings `argv` and the lengths of the +arguments `argvlen`. For convenience, `argvlen` may be set to `NULL` and the function will +use `strlen(3)` on every argument to determine its length. Obviously, when any of the arguments +need to be binary safe, the entire array of lengths `argvlen` should be provided. + +The return value has the same semantic as `redisCommand`. + +### Pipelining + +To explain how Hiredis supports pipelining in a blocking connection, there needs to be +understanding of the internal execution flow. + +When any of the functions in the `redisCommand` family is called, Hiredis first formats the +command according to the Redis protocol. The formatted command is then put in the output buffer +of the context. This output buffer is dynamic, so it can hold any number of commands. +After the command is put in the output buffer, `redisGetReply` is called. This function has the +following two execution paths: + +1. The input buffer is non-empty: + * Try to parse a single reply from the input buffer and return it + * If no reply could be parsed, continue at *2* +2. The input buffer is empty: + * Write the **entire** output buffer to the socket + * Read from the socket until a single reply could be parsed + +The function `redisGetReply` is exported as part of the Hiredis API and can be used when a reply +is expected on the socket. To pipeline commands, the only things that needs to be done is +filling up the output buffer. For this cause, two commands can be used that are identical +to the `redisCommand` family, apart from not returning a reply: +```c +void redisAppendCommand(redisContext *c, const char *format, ...); +void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); +``` +After calling either function one or more times, `redisGetReply` can be used to receive the +subsequent replies. The return value for this function is either `REDIS_OK` or `REDIS_ERR`, where +the latter means an error occurred while reading a reply. Just as with the other commands, +the `err` field in the context can be used to find out what the cause of this error is. + +The following examples shows a simple pipeline (resulting in only a single call to `write(2)` and +a single call to `read(2)`): +```c +redisReply *reply; +redisAppendCommand(context,"SET foo bar"); +redisAppendCommand(context,"GET foo"); +redisGetReply(context,&reply); // reply for SET +freeReplyObject(reply); +redisGetReply(context,&reply); // reply for GET +freeReplyObject(reply); +``` +This API can also be used to implement a blocking subscriber: +```c +reply = redisCommand(context,"SUBSCRIBE foo"); +freeReplyObject(reply); +while(redisGetReply(context,&reply) == REDIS_OK) { + // consume message + freeReplyObject(reply); +} +``` +### Errors + +When a function call is not successful, depending on the function either `NULL` or `REDIS_ERR` is +returned. The `err` field inside the context will be non-zero and set to one of the +following constants: + +* **`REDIS_ERR_IO`**: + There was an I/O error while creating the connection, trying to write + to the socket or read from the socket. If you included `errno.h` in your + application, you can use the global `errno` variable to find out what is + wrong. + +* **`REDIS_ERR_EOF`**: + The server closed the connection which resulted in an empty read. + +* **`REDIS_ERR_PROTOCOL`**: + There was an error while parsing the protocol. + +* **`REDIS_ERR_OTHER`**: + Any other error. Currently, it is only used when a specified hostname to connect + to cannot be resolved. + +In every case, the `errstr` field in the context will be set to hold a string representation +of the error. + +## Asynchronous API + +Hiredis comes with an asynchronous API that works easily with any event library. +Examples are bundled that show using Hiredis with [libev](http://software.schmorp.de/pkg/libev.html) +and [libevent](http://monkey.org/~provos/libevent/). + +### Connecting + +The function `redisAsyncConnect` can be used to establish a non-blocking connection to +Redis. It returns a pointer to the newly created `redisAsyncContext` struct. The `err` field +should be checked after creation to see if there were errors creating the connection. +Because the connection that will be created is non-blocking, the kernel is not able to +instantly return if the specified host and port is able to accept a connection. +```c +redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); +if (c->err) { + printf("Error: %s\n", c->errstr); + // handle error +} +``` + +The asynchronous context can hold a disconnect callback function that is called when the +connection is disconnected (either because of an error or per user request). This function should +have the following prototype: +```c +void(const redisAsyncContext *c, int status); +``` +On a disconnect, the `status` argument is set to `REDIS_OK` when disconnection was initiated by the +user, or `REDIS_ERR` when the disconnection was caused by an error. When it is `REDIS_ERR`, the `err` +field in the context can be accessed to find out the cause of the error. + +The context object is always freed after the disconnect callback fired. When a reconnect is needed, +the disconnect callback is a good point to do so. + +Setting the disconnect callback can only be done once per context. For subsequent calls it will +return `REDIS_ERR`. The function to set the disconnect callback has the following prototype: +```c +int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn); +``` +### Sending commands and their callbacks + +In an asynchronous context, commands are automatically pipelined due to the nature of an event loop. +Therefore, unlike the synchronous API, there is only a single way to send commands. +Because commands are sent to Redis asynchronously, issuing a command requires a callback function +that is called when the reply is received. Reply callbacks should have the following prototype: +```c +void(redisAsyncContext *c, void *reply, void *privdata); +``` +The `privdata` argument can be used to curry arbitrary data to the callback from the point where +the command is initially queued for execution. + +The functions that can be used to issue commands in an asynchronous context are: +```c +int redisAsyncCommand( + redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, + const char *format, ...); +int redisAsyncCommandArgv( + redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, + int argc, const char **argv, const size_t *argvlen); +``` +Both functions work like their blocking counterparts. The return value is `REDIS_OK` when the command +was successfully added to the output buffer and `REDIS_ERR` otherwise. Example: when the connection +is being disconnected per user-request, no new commands may be added to the output buffer and `REDIS_ERR` is +returned on calls to the `redisAsyncCommand` family. + +If the reply for a command with a `NULL` callback is read, it is immediately freed. When the callback +for a command is non-`NULL`, the memory is freed immediately following the callback: the reply is only +valid for the duration of the callback. + +All pending callbacks are called with a `NULL` reply when the context encountered an error. + +### Disconnecting + +An asynchronous connection can be terminated using: +```c +void redisAsyncDisconnect(redisAsyncContext *ac); +``` +When this function is called, the connection is **not** immediately terminated. Instead, new +commands are no longer accepted and the connection is only terminated when all pending commands +have been written to the socket, their respective replies have been read and their respective +callbacks have been executed. After this, the disconnection callback is executed with the +`REDIS_OK` status and the context object is freed. + +### Hooking it up to event library *X* + +There are a few hooks that need to be set on the context object after it is created. +See the `adapters/` directory for bindings to *libev* and *libevent*. + +## Reply parsing API + +Hiredis comes with a reply parsing API that makes it easy for writing higher +level language bindings. + +The reply parsing API consists of the following functions: +```c +redisReader *redisReaderCreate(void); +void redisReaderFree(redisReader *reader); +int redisReaderFeed(redisReader *reader, const char *buf, size_t len); +int redisReaderGetReply(redisReader *reader, void **reply); +``` +The same set of functions are used internally by hiredis when creating a +normal Redis context, the above API just exposes it to the user for a direct +usage. + +### Usage + +The function `redisReaderCreate` creates a `redisReader` structure that holds a +buffer with unparsed data and state for the protocol parser. + +Incoming data -- most likely from a socket -- can be placed in the internal +buffer of the `redisReader` using `redisReaderFeed`. This function will make a +copy of the buffer pointed to by `buf` for `len` bytes. This data is parsed +when `redisReaderGetReply` is called. This function returns an integer status +and a reply object (as described above) via `void **reply`. The returned status +can be either `REDIS_OK` or `REDIS_ERR`, where the latter means something went +wrong (either a protocol error, or an out of memory error). + +The parser limits the level of nesting for multi bulk payloads to 7. If the +multi bulk nesting level is higher than this, the parser returns an error. + +### Customizing replies + +The function `redisReaderGetReply` creates `redisReply` and makes the function +argument `reply` point to the created `redisReply` variable. For instance, if +the response of type `REDIS_REPLY_STATUS` then the `str` field of `redisReply` +will hold the status as a vanilla C string. However, the functions that are +responsible for creating instances of the `redisReply` can be customized by +setting the `fn` field on the `redisReader` struct. This should be done +immediately after creating the `redisReader`. + +For example, [hiredis-rb](https://github.com/pietern/hiredis-rb/blob/master/ext/hiredis_ext/reader.c) +uses customized reply object functions to create Ruby objects. + +### Reader max buffer + +Both when using the Reader API directly or when using it indirectly via a +normal Redis context, the redisReader structure uses a buffer in order to +accumulate data from the server. +Usually this buffer is destroyed when it is empty and is larger than 16 +KiB in order to avoid wasting memory in unused buffers + +However when working with very big payloads destroying the buffer may slow +down performances considerably, so it is possible to modify the max size of +an idle buffer changing the value of the `maxbuf` field of the reader structure +to the desired value. The special value of 0 means that there is no maximum +value for an idle buffer, so the buffer will never get freed. + +For instance if you have a normal Redis context you can set the maximum idle +buffer to zero (unlimited) just with: +```c +context->reader->maxbuf = 0; +``` +This should be done only in order to maximize performances when working with +large payloads. The context should be set back to `REDIS_READER_MAX_BUF` again +as soon as possible in order to prevent allocation of useless memory. + +## AUTHORS + +Hiredis was written by Salvatore Sanfilippo (antirez at gmail) and +Pieter Noordhuis (pcnoordhuis at gmail) and is released under the BSD license. +Hiredis is currently maintained by Matt Stancliff (matt at genges dot com) and +Jan-Erik Rediger (janerik at fnordig dot com) diff --git a/debian/modules/nchan/src/hiredis/adapters/ae.h b/debian/modules/nchan/src/hiredis/adapters/ae.h new file mode 100644 index 0000000..5c551c2 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/adapters/ae.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2010-2011, Pieter Noordhuis + * + * All rights reserved. + * + * 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 Redis 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. + */ + +#ifndef __HIREDIS_AE_H__ +#define __HIREDIS_AE_H__ +#include +#include +#include "../hiredis.h" +#include "../async.h" + +typedef struct redisAeEvents { + redisAsyncContext *context; + aeEventLoop *loop; + int fd; + int reading, writing; +} redisAeEvents; + +static void redisAeReadEvent(aeEventLoop *el, int fd, void *privdata, int mask) { + ((void)el); ((void)fd); ((void)mask); + + redisAeEvents *e = (redisAeEvents*)privdata; + redisAsyncHandleRead(e->context); +} + +static void redisAeWriteEvent(aeEventLoop *el, int fd, void *privdata, int mask) { + ((void)el); ((void)fd); ((void)mask); + + redisAeEvents *e = (redisAeEvents*)privdata; + redisAsyncHandleWrite(e->context); +} + +static void redisAeAddRead(void *privdata) { + redisAeEvents *e = (redisAeEvents*)privdata; + aeEventLoop *loop = e->loop; + if (!e->reading) { + e->reading = 1; + aeCreateFileEvent(loop,e->fd,AE_READABLE,redisAeReadEvent,e); + } +} + +static void redisAeDelRead(void *privdata) { + redisAeEvents *e = (redisAeEvents*)privdata; + aeEventLoop *loop = e->loop; + if (e->reading) { + e->reading = 0; + aeDeleteFileEvent(loop,e->fd,AE_READABLE); + } +} + +static void redisAeAddWrite(void *privdata) { + redisAeEvents *e = (redisAeEvents*)privdata; + aeEventLoop *loop = e->loop; + if (!e->writing) { + e->writing = 1; + aeCreateFileEvent(loop,e->fd,AE_WRITABLE,redisAeWriteEvent,e); + } +} + +static void redisAeDelWrite(void *privdata) { + redisAeEvents *e = (redisAeEvents*)privdata; + aeEventLoop *loop = e->loop; + if (e->writing) { + e->writing = 0; + aeDeleteFileEvent(loop,e->fd,AE_WRITABLE); + } +} + +static void redisAeCleanup(void *privdata) { + redisAeEvents *e = (redisAeEvents*)privdata; + redisAeDelRead(privdata); + redisAeDelWrite(privdata); + free(e); +} + +static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) { + redisContext *c = &(ac->c); + redisAeEvents *e; + + /* Nothing should be attached when something is already attached */ + if (ac->ev.data != NULL) + return REDIS_ERR; + + /* Create container for context and r/w events */ + e = (redisAeEvents*)malloc(sizeof(*e)); + e->context = ac; + e->loop = loop; + e->fd = c->fd; + e->reading = e->writing = 0; + + /* Register functions to start/stop listening for events */ + ac->ev.addRead = redisAeAddRead; + ac->ev.delRead = redisAeDelRead; + ac->ev.addWrite = redisAeAddWrite; + ac->ev.delWrite = redisAeDelWrite; + ac->ev.cleanup = redisAeCleanup; + ac->ev.data = e; + + return REDIS_OK; +} +#endif diff --git a/debian/modules/nchan/src/hiredis/adapters/libev.h b/debian/modules/nchan/src/hiredis/adapters/libev.h new file mode 100644 index 0000000..2bf8d52 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/adapters/libev.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2010-2011, Pieter Noordhuis + * + * All rights reserved. + * + * 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 Redis 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. + */ + +#ifndef __HIREDIS_LIBEV_H__ +#define __HIREDIS_LIBEV_H__ +#include +#include +#include +#include "../hiredis.h" +#include "../async.h" + +typedef struct redisLibevEvents { + redisAsyncContext *context; + struct ev_loop *loop; + int reading, writing; + ev_io rev, wev; +} redisLibevEvents; + +static void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) { +#if EV_MULTIPLICITY + ((void)loop); +#endif + ((void)revents); + + redisLibevEvents *e = (redisLibevEvents*)watcher->data; + redisAsyncHandleRead(e->context); +} + +static void redisLibevWriteEvent(EV_P_ ev_io *watcher, int revents) { +#if EV_MULTIPLICITY + ((void)loop); +#endif + ((void)revents); + + redisLibevEvents *e = (redisLibevEvents*)watcher->data; + redisAsyncHandleWrite(e->context); +} + +static void redisLibevAddRead(void *privdata) { + redisLibevEvents *e = (redisLibevEvents*)privdata; + struct ev_loop *loop = e->loop; + ((void)loop); + if (!e->reading) { + e->reading = 1; + ev_io_start(EV_A_ &e->rev); + } +} + +static void redisLibevDelRead(void *privdata) { + redisLibevEvents *e = (redisLibevEvents*)privdata; + struct ev_loop *loop = e->loop; + ((void)loop); + if (e->reading) { + e->reading = 0; + ev_io_stop(EV_A_ &e->rev); + } +} + +static void redisLibevAddWrite(void *privdata) { + redisLibevEvents *e = (redisLibevEvents*)privdata; + struct ev_loop *loop = e->loop; + ((void)loop); + if (!e->writing) { + e->writing = 1; + ev_io_start(EV_A_ &e->wev); + } +} + +static void redisLibevDelWrite(void *privdata) { + redisLibevEvents *e = (redisLibevEvents*)privdata; + struct ev_loop *loop = e->loop; + ((void)loop); + if (e->writing) { + e->writing = 0; + ev_io_stop(EV_A_ &e->wev); + } +} + +static void redisLibevCleanup(void *privdata) { + redisLibevEvents *e = (redisLibevEvents*)privdata; + redisLibevDelRead(privdata); + redisLibevDelWrite(privdata); + free(e); +} + +static int redisLibevAttach(EV_P_ redisAsyncContext *ac) { + redisContext *c = &(ac->c); + redisLibevEvents *e; + + /* Nothing should be attached when something is already attached */ + if (ac->ev.data != NULL) + return REDIS_ERR; + + /* Create container for context and r/w events */ + e = (redisLibevEvents*)malloc(sizeof(*e)); + e->context = ac; +#if EV_MULTIPLICITY + e->loop = loop; +#else + e->loop = NULL; +#endif + e->reading = e->writing = 0; + e->rev.data = e; + e->wev.data = e; + + /* Register functions to start/stop listening for events */ + ac->ev.addRead = redisLibevAddRead; + ac->ev.delRead = redisLibevDelRead; + ac->ev.addWrite = redisLibevAddWrite; + ac->ev.delWrite = redisLibevDelWrite; + ac->ev.cleanup = redisLibevCleanup; + ac->ev.data = e; + + /* Initialize read/write events */ + ev_io_init(&e->rev,redisLibevReadEvent,c->fd,EV_READ); + ev_io_init(&e->wev,redisLibevWriteEvent,c->fd,EV_WRITE); + return REDIS_OK; +} + +#endif diff --git a/debian/modules/nchan/src/hiredis/adapters/libevent.h b/debian/modules/nchan/src/hiredis/adapters/libevent.h new file mode 100644 index 0000000..1c2b271 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/adapters/libevent.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2010-2011, Pieter Noordhuis + * + * All rights reserved. + * + * 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 Redis 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. + */ + +#ifndef __HIREDIS_LIBEVENT_H__ +#define __HIREDIS_LIBEVENT_H__ +#include +#include "../hiredis.h" +#include "../async.h" + +typedef struct redisLibeventEvents { + redisAsyncContext *context; + struct event rev, wev; +} redisLibeventEvents; + +static void redisLibeventReadEvent(int fd, short event, void *arg) { + ((void)fd); ((void)event); + redisLibeventEvents *e = (redisLibeventEvents*)arg; + redisAsyncHandleRead(e->context); +} + +static void redisLibeventWriteEvent(int fd, short event, void *arg) { + ((void)fd); ((void)event); + redisLibeventEvents *e = (redisLibeventEvents*)arg; + redisAsyncHandleWrite(e->context); +} + +static void redisLibeventAddRead(void *privdata) { + redisLibeventEvents *e = (redisLibeventEvents*)privdata; + event_add(&e->rev,NULL); +} + +static void redisLibeventDelRead(void *privdata) { + redisLibeventEvents *e = (redisLibeventEvents*)privdata; + event_del(&e->rev); +} + +static void redisLibeventAddWrite(void *privdata) { + redisLibeventEvents *e = (redisLibeventEvents*)privdata; + event_add(&e->wev,NULL); +} + +static void redisLibeventDelWrite(void *privdata) { + redisLibeventEvents *e = (redisLibeventEvents*)privdata; + event_del(&e->wev); +} + +static void redisLibeventCleanup(void *privdata) { + redisLibeventEvents *e = (redisLibeventEvents*)privdata; + event_del(&e->rev); + event_del(&e->wev); + free(e); +} + +static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) { + redisContext *c = &(ac->c); + redisLibeventEvents *e; + + /* Nothing should be attached when something is already attached */ + if (ac->ev.data != NULL) + return REDIS_ERR; + + /* Create container for context and r/w events */ + e = (redisLibeventEvents*)malloc(sizeof(*e)); + e->context = ac; + + /* Register functions to start/stop listening for events */ + ac->ev.addRead = redisLibeventAddRead; + ac->ev.delRead = redisLibeventDelRead; + ac->ev.addWrite = redisLibeventAddWrite; + ac->ev.delWrite = redisLibeventDelWrite; + ac->ev.cleanup = redisLibeventCleanup; + ac->ev.data = e; + + /* Initialize and install read/write events */ + event_set(&e->rev,c->fd,EV_READ,redisLibeventReadEvent,e); + event_set(&e->wev,c->fd,EV_WRITE,redisLibeventWriteEvent,e); + event_base_set(base,&e->rev); + event_base_set(base,&e->wev); + return REDIS_OK; +} +#endif diff --git a/debian/modules/nchan/src/hiredis/adapters/libuv.h b/debian/modules/nchan/src/hiredis/adapters/libuv.h new file mode 100644 index 0000000..3cdf3d3 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/adapters/libuv.h @@ -0,0 +1,121 @@ +#ifndef __HIREDIS_LIBUV_H__ +#define __HIREDIS_LIBUV_H__ +#include +#include +#include "../hiredis.h" +#include "../async.h" +#include + +typedef struct redisLibuvEvents { + redisAsyncContext* context; + uv_poll_t handle; + int events; +} redisLibuvEvents; + + +static void redisLibuvPoll(uv_poll_t* handle, int status, int events) { + redisLibuvEvents* p = (redisLibuvEvents*)handle->data; + + if (status != 0) { + return; + } + + if (events & UV_READABLE) { + redisAsyncHandleRead(p->context); + } + if (events & UV_WRITABLE) { + redisAsyncHandleWrite(p->context); + } +} + + +static void redisLibuvAddRead(void *privdata) { + redisLibuvEvents* p = (redisLibuvEvents*)privdata; + + p->events |= UV_READABLE; + + uv_poll_start(&p->handle, p->events, redisLibuvPoll); +} + + +static void redisLibuvDelRead(void *privdata) { + redisLibuvEvents* p = (redisLibuvEvents*)privdata; + + p->events &= ~UV_READABLE; + + if (p->events) { + uv_poll_start(&p->handle, p->events, redisLibuvPoll); + } else { + uv_poll_stop(&p->handle); + } +} + + +static void redisLibuvAddWrite(void *privdata) { + redisLibuvEvents* p = (redisLibuvEvents*)privdata; + + p->events |= UV_WRITABLE; + + uv_poll_start(&p->handle, p->events, redisLibuvPoll); +} + + +static void redisLibuvDelWrite(void *privdata) { + redisLibuvEvents* p = (redisLibuvEvents*)privdata; + + p->events &= ~UV_WRITABLE; + + if (p->events) { + uv_poll_start(&p->handle, p->events, redisLibuvPoll); + } else { + uv_poll_stop(&p->handle); + } +} + + +static void on_close(uv_handle_t* handle) { + redisLibuvEvents* p = (redisLibuvEvents*)handle->data; + + free(p); +} + + +static void redisLibuvCleanup(void *privdata) { + redisLibuvEvents* p = (redisLibuvEvents*)privdata; + + uv_close((uv_handle_t*)&p->handle, on_close); +} + + +static int redisLibuvAttach(redisAsyncContext* ac, uv_loop_t* loop) { + redisContext *c = &(ac->c); + + if (ac->ev.data != NULL) { + return REDIS_ERR; + } + + ac->ev.addRead = redisLibuvAddRead; + ac->ev.delRead = redisLibuvDelRead; + ac->ev.addWrite = redisLibuvAddWrite; + ac->ev.delWrite = redisLibuvDelWrite; + ac->ev.cleanup = redisLibuvCleanup; + + redisLibuvEvents* p = (redisLibuvEvents*)malloc(sizeof(*p)); + + if (!p) { + return REDIS_ERR; + } + + memset(p, 0, sizeof(*p)); + + if (uv_poll_init(loop, &p->handle, c->fd) != 0) { + return REDIS_ERR; + } + + ac->ev.data = p; + p->handle.data = p; + p->context = ac; + + return REDIS_OK; +} +#endif diff --git a/debian/modules/nchan/src/hiredis/async.c b/debian/modules/nchan/src/hiredis/async.c new file mode 100644 index 0000000..d955203 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/async.c @@ -0,0 +1,687 @@ +/* + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2011, Pieter Noordhuis + * + * All rights reserved. + * + * 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 Redis 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. + */ + +#include "fmacros.h" +#include +#include +#include +#include +#include +#include +#include "async.h" +#include "net.h" +#include "dict.c" +#include "sds.h" + +#define _EL_ADD_READ(ctx) do { \ + if ((ctx)->ev.addRead) (ctx)->ev.addRead((ctx)->ev.data); \ + } while(0) +#define _EL_DEL_READ(ctx) do { \ + if ((ctx)->ev.delRead) (ctx)->ev.delRead((ctx)->ev.data); \ + } while(0) +#define _EL_ADD_WRITE(ctx) do { \ + if ((ctx)->ev.addWrite) (ctx)->ev.addWrite((ctx)->ev.data); \ + } while(0) +#define _EL_DEL_WRITE(ctx) do { \ + if ((ctx)->ev.delWrite) (ctx)->ev.delWrite((ctx)->ev.data); \ + } while(0) +#define _EL_CLEANUP(ctx) do { \ + if ((ctx)->ev.cleanup) (ctx)->ev.cleanup((ctx)->ev.data); \ + } while(0); + +/* Forward declaration of function in hiredis.c */ +int __redisAppendCommand(redisContext *c, const char *cmd, size_t len); + +/* Functions managing dictionary of callbacks for pub/sub. */ +static unsigned int callbackHash(const void *key) { + return dictGenHashFunction((const unsigned char *)key, + sdslen((const sds)key)); +} + +static void *callbackValDup(void *privdata, const void *src) { + ((void) privdata); + redisCallback *dup = malloc(sizeof(*dup)); + memcpy(dup,src,sizeof(*dup)); + return dup; +} + +static int callbackKeyCompare(void *privdata, const void *key1, const void *key2) { + int l1, l2; + ((void) privdata); + + l1 = sdslen((const sds)key1); + l2 = sdslen((const sds)key2); + if (l1 != l2) return 0; + return memcmp(key1,key2,l1) == 0; +} + +static void callbackKeyDestructor(void *privdata, void *key) { + ((void) privdata); + sdsfree((sds)key); +} + +static void callbackValDestructor(void *privdata, void *val) { + ((void) privdata); + free(val); +} + +static dictType callbackDict = { + callbackHash, + NULL, + callbackValDup, + callbackKeyCompare, + callbackKeyDestructor, + callbackValDestructor +}; + +static redisAsyncContext *redisAsyncInitialize(redisContext *c) { + redisAsyncContext *ac; + + ac = realloc(c,sizeof(redisAsyncContext)); + if (ac == NULL) + return NULL; + + c = &(ac->c); + + /* The regular connect functions will always set the flag REDIS_CONNECTED. + * For the async API, we want to wait until the first write event is + * received up before setting this flag, so reset it here. */ + c->flags &= ~REDIS_CONNECTED; + + ac->err = 0; + ac->errstr = NULL; + ac->data = NULL; + + ac->ev.data = NULL; + ac->ev.addRead = NULL; + ac->ev.delRead = NULL; + ac->ev.addWrite = NULL; + ac->ev.delWrite = NULL; + ac->ev.cleanup = NULL; + + ac->onConnect = NULL; + ac->onDisconnect = NULL; + + ac->replies.head = NULL; + ac->replies.tail = NULL; + ac->sub.invalid.head = NULL; + ac->sub.invalid.tail = NULL; + ac->sub.channels = dictCreate(&callbackDict,NULL); + ac->sub.patterns = dictCreate(&callbackDict,NULL); + return ac; +} + +/* We want the error field to be accessible directly instead of requiring + * an indirection to the redisContext struct. */ +static void __redisAsyncCopyError(redisAsyncContext *ac) { + if (!ac) + return; + + redisContext *c = &(ac->c); + ac->err = c->err; + ac->errstr = c->errstr; +} + +redisAsyncContext *redisAsyncConnect(const char *ip, int port) { + redisContext *c; + redisAsyncContext *ac; + + c = redisConnectNonBlock(ip,port); + if (c == NULL) + return NULL; + + ac = redisAsyncInitialize(c); + if (ac == NULL) { + redisFree(c); + return NULL; + } + + __redisAsyncCopyError(ac); + return ac; +} + +redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, + const char *source_addr) { + redisContext *c = redisConnectBindNonBlock(ip,port,source_addr); + redisAsyncContext *ac = redisAsyncInitialize(c); + __redisAsyncCopyError(ac); + return ac; +} + +redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port, + const char *source_addr) { + redisContext *c = redisConnectBindNonBlockWithReuse(ip,port,source_addr); + redisAsyncContext *ac = redisAsyncInitialize(c); + __redisAsyncCopyError(ac); + return ac; +} + +redisAsyncContext *redisAsyncConnectUnix(const char *path) { + redisContext *c; + redisAsyncContext *ac; + + c = redisConnectUnixNonBlock(path); + if (c == NULL) + return NULL; + + ac = redisAsyncInitialize(c); + if (ac == NULL) { + redisFree(c); + return NULL; + } + + __redisAsyncCopyError(ac); + return ac; +} + +int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn) { + if (ac->onConnect == NULL) { + ac->onConnect = fn; + + /* The common way to detect an established connection is to wait for + * the first write event to be fired. This assumes the related event + * library functions are already set. */ + _EL_ADD_WRITE(ac); + return REDIS_OK; + } + return REDIS_ERR; +} + +int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn) { + if (ac->onDisconnect == NULL) { + ac->onDisconnect = fn; + return REDIS_OK; + } + return REDIS_ERR; +} + +/* Helper functions to push/shift callbacks */ +static int __redisPushCallback(redisCallbackList *list, redisCallback *source) { + redisCallback *cb; + + /* Copy callback from stack to heap */ + cb = malloc(sizeof(*cb)); + if (cb == NULL) + return REDIS_ERR_OOM; + + if (source != NULL) { + memcpy(cb,source,sizeof(*cb)); + cb->next = NULL; + } + + /* Store callback in list */ + if (list->head == NULL) + list->head = cb; + if (list->tail != NULL) + list->tail->next = cb; + list->tail = cb; + return REDIS_OK; +} + +static int __redisShiftCallback(redisCallbackList *list, redisCallback *target) { + redisCallback *cb = list->head; + if (cb != NULL) { + list->head = cb->next; + if (cb == list->tail) + list->tail = NULL; + + /* Copy callback from heap to stack */ + if (target != NULL) + memcpy(target,cb,sizeof(*cb)); + free(cb); + return REDIS_OK; + } + return REDIS_ERR; +} + +static void __redisRunCallback(redisAsyncContext *ac, redisCallback *cb, redisReply *reply) { + redisContext *c = &(ac->c); + if (cb->fn != NULL) { + c->flags |= REDIS_IN_CALLBACK; + cb->fn(ac,reply,cb->privdata); + c->flags &= ~REDIS_IN_CALLBACK; + } +} + +/* Helper function to free the context. */ +static void __redisAsyncFree(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + redisCallback cb; + dictIterator *it; + dictEntry *de; + + /* Execute pending callbacks with NULL reply. */ + while (__redisShiftCallback(&ac->replies,&cb) == REDIS_OK) + __redisRunCallback(ac,&cb,NULL); + + /* Execute callbacks for invalid commands */ + while (__redisShiftCallback(&ac->sub.invalid,&cb) == REDIS_OK) + __redisRunCallback(ac,&cb,NULL); + + /* Run subscription callbacks callbacks with NULL reply */ + it = dictGetIterator(ac->sub.channels); + while ((de = dictNext(it)) != NULL) + __redisRunCallback(ac,dictGetEntryVal(de),NULL); + dictReleaseIterator(it); + dictRelease(ac->sub.channels); + + it = dictGetIterator(ac->sub.patterns); + while ((de = dictNext(it)) != NULL) + __redisRunCallback(ac,dictGetEntryVal(de),NULL); + dictReleaseIterator(it); + dictRelease(ac->sub.patterns); + + /* Signal event lib to clean up */ + _EL_CLEANUP(ac); + + /* Execute disconnect callback. When redisAsyncFree() initiated destroying + * this context, the status will always be REDIS_OK. */ + if (ac->onDisconnect && (c->flags & REDIS_CONNECTED)) { + if (c->flags & REDIS_FREEING) { + ac->onDisconnect(ac,REDIS_OK); + } else { + ac->onDisconnect(ac,(ac->err == 0) ? REDIS_OK : REDIS_ERR); + } + } + + /* Cleanup self */ + redisFree(c); +} + +/* Free the async context. When this function is called from a callback, + * control needs to be returned to redisProcessCallbacks() before actual + * free'ing. To do so, a flag is set on the context which is picked up by + * redisProcessCallbacks(). Otherwise, the context is immediately free'd. */ +void redisAsyncFree(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + c->flags |= REDIS_FREEING; + if (!(c->flags & REDIS_IN_CALLBACK)) + __redisAsyncFree(ac); +} + +/* Helper function to make the disconnect happen and clean up. */ +static void __redisAsyncDisconnect(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + + /* Make sure error is accessible if there is any */ + __redisAsyncCopyError(ac); + + if (ac->err == 0) { + /* For clean disconnects, there should be no pending callbacks. */ + assert(__redisShiftCallback(&ac->replies,NULL) == REDIS_ERR); + } else { + /* Disconnection is caused by an error, make sure that pending + * callbacks cannot call new commands. */ + c->flags |= REDIS_DISCONNECTING; + } + + /* For non-clean disconnects, __redisAsyncFree() will execute pending + * callbacks with a NULL-reply. */ + __redisAsyncFree(ac); +} + +/* Tries to do a clean disconnect from Redis, meaning it stops new commands + * from being issued, but tries to flush the output buffer and execute + * callbacks for all remaining replies. When this function is called from a + * callback, there might be more replies and we can safely defer disconnecting + * to redisProcessCallbacks(). Otherwise, we can only disconnect immediately + * when there are no pending callbacks. */ +void redisAsyncDisconnect(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + c->flags |= REDIS_DISCONNECTING; + if (!(c->flags & REDIS_IN_CALLBACK) && ac->replies.head == NULL) + __redisAsyncDisconnect(ac); +} + +static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply, redisCallback *dstcb) { + redisContext *c = &(ac->c); + dict *callbacks; + dictEntry *de; + int pvariant; + char *stype; + sds sname; + + /* Custom reply functions are not supported for pub/sub. This will fail + * very hard when they are used... */ + if (reply->type == REDIS_REPLY_ARRAY) { + assert(reply->elements >= 2); + assert(reply->element[0]->type == REDIS_REPLY_STRING); + stype = reply->element[0]->str; + pvariant = (tolower(stype[0]) == 'p') ? 1 : 0; + + if (pvariant) + callbacks = ac->sub.patterns; + else + callbacks = ac->sub.channels; + + /* Locate the right callback */ + assert(reply->element[1]->type == REDIS_REPLY_STRING); + sname = sdsnewlen(reply->element[1]->str,reply->element[1]->len); + de = dictFind(callbacks,sname); + if (de != NULL) { + memcpy(dstcb,dictGetEntryVal(de),sizeof(*dstcb)); + + /* If this is an unsubscribe message, remove it. */ + if (strcasecmp(stype+pvariant,"unsubscribe") == 0) { + dictDelete(callbacks,sname); + + /* If this was the last unsubscribe message, revert to + * non-subscribe mode. */ + assert(reply->element[2]->type == REDIS_REPLY_INTEGER); + if (reply->element[2]->integer == 0) + c->flags &= ~REDIS_SUBSCRIBED; + } + } + sdsfree(sname); + } else { + /* Shift callback for invalid commands. */ + __redisShiftCallback(&ac->sub.invalid,dstcb); + } + return REDIS_OK; +} + +void redisProcessCallbacks(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + redisCallback cb = {NULL, NULL, NULL}; + void *reply = NULL; + int status; + + while((status = redisGetReply(c,&reply)) == REDIS_OK) { + if (reply == NULL) { + /* When the connection is being disconnected and there are + * no more replies, this is the cue to really disconnect. */ + if (c->flags & REDIS_DISCONNECTING && sdslen(c->obuf) == 0 + && ac->replies.head == NULL) { + __redisAsyncDisconnect(ac); + return; + } + + /* If monitor mode, repush callback */ + if(c->flags & REDIS_MONITORING) { + __redisPushCallback(&ac->replies,&cb); + } + + /* When the connection is not being disconnected, simply stop + * trying to get replies and wait for the next loop tick. */ + break; + } + + /* Even if the context is subscribed, pending regular callbacks will + * get a reply before pub/sub messages arrive. */ + if (__redisShiftCallback(&ac->replies,&cb) != REDIS_OK) { + /* + * A spontaneous reply in a not-subscribed context can be the error + * reply that is sent when a new connection exceeds the maximum + * number of allowed connections on the server side. + * + * This is seen as an error instead of a regular reply because the + * server closes the connection after sending it. + * + * To prevent the error from being overwritten by an EOF error the + * connection is closed here. See issue #43. + * + * Another possibility is that the server is loading its dataset. + * In this case we also want to close the connection, and have the + * user wait until the server is ready to take our request. + */ + if (((redisReply*)reply)->type == REDIS_REPLY_ERROR) { + c->err = REDIS_ERR_OTHER; + snprintf(c->errstr,sizeof(c->errstr),"%s",((redisReply*)reply)->str); + c->reader->fn->freeObject(reply); + __redisAsyncDisconnect(ac); + return; + } + /* No more regular callbacks and no errors, the context *must* be subscribed or monitoring. */ + assert((c->flags & REDIS_SUBSCRIBED || c->flags & REDIS_MONITORING)); + if(c->flags & REDIS_SUBSCRIBED) + __redisGetSubscribeCallback(ac,reply,&cb); + } + + if (cb.fn != NULL) { + __redisRunCallback(ac,&cb,reply); + c->reader->fn->freeObject(reply); + + /* Proceed with free'ing when redisAsyncFree() was called. */ + if (c->flags & REDIS_FREEING) { + __redisAsyncFree(ac); + return; + } + } else { + /* No callback for this reply. This can either be a NULL callback, + * or there were no callbacks to begin with. Either way, don't + * abort with an error, but simply ignore it because the client + * doesn't know what the server will spit out over the wire. */ + c->reader->fn->freeObject(reply); + } + } + + /* Disconnect when there was an error reading the reply */ + if (status != REDIS_OK) + __redisAsyncDisconnect(ac); +} + +/* Internal helper function to detect socket status the first time a read or + * write event fires. When connecting was not successful, the connect callback + * is called with a REDIS_ERR status and the context is free'd. */ +static int __redisAsyncHandleConnect(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + + if (redisCheckSocketError(c) == REDIS_ERR) { + /* Try again later when connect(2) is still in progress. */ + if (errno == EINPROGRESS) + return REDIS_OK; + + if (ac->onConnect) ac->onConnect(ac,REDIS_ERR); + __redisAsyncDisconnect(ac); + return REDIS_ERR; + } + + /* Mark context as connected. */ + c->flags |= REDIS_CONNECTED; + if (ac->onConnect) ac->onConnect(ac,REDIS_OK); + return REDIS_OK; +} + +/* This function should be called when the socket is readable. + * It processes all replies that can be read and executes their callbacks. + */ +void redisAsyncHandleRead(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + + if (!(c->flags & REDIS_CONNECTED)) { + /* Abort connect was not successful. */ + if (__redisAsyncHandleConnect(ac) != REDIS_OK) + return; + /* Try again later when the context is still not connected. */ + if (!(c->flags & REDIS_CONNECTED)) + return; + } + + if (redisBufferRead(c) == REDIS_ERR) { + __redisAsyncDisconnect(ac); + } else { + /* Always re-schedule reads */ + _EL_ADD_READ(ac); + redisProcessCallbacks(ac); + } +} + +void redisAsyncHandleWrite(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + int done = 0; + + if (!(c->flags & REDIS_CONNECTED)) { + /* Abort connect was not successful. */ + if (__redisAsyncHandleConnect(ac) != REDIS_OK) + return; + /* Try again later when the context is still not connected. */ + if (!(c->flags & REDIS_CONNECTED)) + return; + } + + if (redisBufferWrite(c,&done) == REDIS_ERR) { + __redisAsyncDisconnect(ac); + } else { + /* Continue writing when not done, stop writing otherwise */ + if (!done) + _EL_ADD_WRITE(ac); + else + _EL_DEL_WRITE(ac); + + /* Always schedule reads after writes */ + _EL_ADD_READ(ac); + } +} + +/* Sets a pointer to the first argument and its length starting at p. Returns + * the number of bytes to skip to get to the following argument. */ +static const char *nextArgument(const char *start, const char **str, size_t *len) { + const char *p = start; + if (p[0] != '$') { + p = strchr(p,'$'); + if (p == NULL) return NULL; + } + + *len = (int)strtol(p+1,NULL,10); + p = strchr(p,'\r'); + assert(p); + *str = p+2; + return p+2+(*len)+2; +} + +/* Helper function for the redisAsyncCommand* family of functions. Writes a + * formatted command to the output buffer and registers the provided callback + * function with the context. */ +static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len) { + redisContext *c = &(ac->c); + redisCallback cb; + int pvariant, hasnext; + const char *cstr, *astr; + size_t clen, alen; + const char *p; + sds sname; + int ret; + + /* Don't accept new commands when the connection is about to be closed. */ + if (c->flags & (REDIS_DISCONNECTING | REDIS_FREEING)) return REDIS_ERR; + + /* Setup callback */ + cb.fn = fn; + cb.privdata = privdata; + + /* Find out which command will be appended. */ + p = nextArgument(cmd,&cstr,&clen); + assert(p != NULL); + hasnext = (p[0] == '$'); + pvariant = (tolower(cstr[0]) == 'p') ? 1 : 0; + cstr += pvariant; + clen -= pvariant; + + if (hasnext && strncasecmp(cstr,"subscribe\r\n",11) == 0) { + c->flags |= REDIS_SUBSCRIBED; + + /* Add every channel/pattern to the list of subscription callbacks. */ + while ((p = nextArgument(p,&astr,&alen)) != NULL) { + sname = sdsnewlen(astr,alen); + if (pvariant) + ret = dictReplace(ac->sub.patterns,sname,&cb); + else + ret = dictReplace(ac->sub.channels,sname,&cb); + + if (ret == 0) sdsfree(sname); + } + } else if (strncasecmp(cstr,"unsubscribe\r\n",13) == 0) { + /* It is only useful to call (P)UNSUBSCRIBE when the context is + * subscribed to one or more channels or patterns. */ + if (!(c->flags & REDIS_SUBSCRIBED)) return REDIS_ERR; + + /* (P)UNSUBSCRIBE does not have its own response: every channel or + * pattern that is unsubscribed will receive a message. This means we + * should not append a callback function for this command. */ + } else if(strncasecmp(cstr,"monitor\r\n",9) == 0) { + /* Set monitor flag and push callback */ + c->flags |= REDIS_MONITORING; + __redisPushCallback(&ac->replies,&cb); + } else { + if (c->flags & REDIS_SUBSCRIBED) + /* This will likely result in an error reply, but it needs to be + * received and passed to the callback. */ + __redisPushCallback(&ac->sub.invalid,&cb); + else + __redisPushCallback(&ac->replies,&cb); + } + + __redisAppendCommand(c,cmd,len); + + /* Always schedule a write when the write buffer is non-empty */ + _EL_ADD_WRITE(ac); + + return REDIS_OK; +} + +int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap) { + char *cmd; + int len; + int status; + len = redisvFormatCommand(&cmd,format,ap); + + /* We don't want to pass -1 or -2 to future functions as a length. */ + if (len < 0) + return REDIS_ERR; + + status = __redisAsyncCommand(ac,fn,privdata,cmd,len); + free(cmd); + return status; +} + +int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...) { + va_list ap; + int status; + va_start(ap,format); + status = redisvAsyncCommand(ac,fn,privdata,format,ap); + va_end(ap); + return status; +} + +int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen) { + sds cmd; + int len; + int status; + len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen); + status = __redisAsyncCommand(ac,fn,privdata,cmd,len); + sdsfree(cmd); + return status; +} + +int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len) { + int status = __redisAsyncCommand(ac,fn,privdata,cmd,len); + return status; +} diff --git a/debian/modules/nchan/src/hiredis/async.h b/debian/modules/nchan/src/hiredis/async.h new file mode 100644 index 0000000..59cbf46 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/async.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2011, Pieter Noordhuis + * + * All rights reserved. + * + * 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 Redis 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. + */ + +#ifndef __HIREDIS_ASYNC_H +#define __HIREDIS_ASYNC_H +#include "hiredis.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct redisAsyncContext; /* need forward declaration of redisAsyncContext */ +struct dict; /* dictionary header is included in async.c */ + +/* Reply callback prototype and container */ +typedef void (redisCallbackFn)(struct redisAsyncContext*, void*, void*); +typedef struct redisCallback { + struct redisCallback *next; /* simple singly linked list */ + redisCallbackFn *fn; + void *privdata; +} redisCallback; + +/* List of callbacks for either regular replies or pub/sub */ +typedef struct redisCallbackList { + redisCallback *head, *tail; +} redisCallbackList; + +/* Connection callback prototypes */ +typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status); +typedef void (redisConnectCallback)(const struct redisAsyncContext*, int status); + +/* Context for an async connection to Redis */ +typedef struct redisAsyncContext { + /* Hold the regular context, so it can be realloc'ed. */ + redisContext c; + + /* Setup error flags so they can be used directly. */ + int err; + char *errstr; + + /* Not used by hiredis */ + void *data; + + /* Event library data and hooks */ + struct { + void *data; + + /* Hooks that are called when the library expects to start + * reading/writing. These functions should be idempotent. */ + void (*addRead)(void *privdata); + void (*delRead)(void *privdata); + void (*addWrite)(void *privdata); + void (*delWrite)(void *privdata); + void (*cleanup)(void *privdata); + } ev; + + /* Called when either the connection is terminated due to an error or per + * user request. The status is set accordingly (REDIS_OK, REDIS_ERR). */ + redisDisconnectCallback *onDisconnect; + + /* Called when the first write event was received. */ + redisConnectCallback *onConnect; + + /* Regular command callbacks */ + redisCallbackList replies; + + /* Subscription callbacks */ + struct { + redisCallbackList invalid; + struct dict *channels; + struct dict *patterns; + } sub; +} redisAsyncContext; + +/* Functions that proxy to hiredis */ +redisAsyncContext *redisAsyncConnect(const char *ip, int port); +redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr); +redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port, + const char *source_addr); +redisAsyncContext *redisAsyncConnectUnix(const char *path); +int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn); +int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn); +void redisAsyncDisconnect(redisAsyncContext *ac); +void redisAsyncFree(redisAsyncContext *ac); + +/* Handle read/write events */ +void redisAsyncHandleRead(redisAsyncContext *ac); +void redisAsyncHandleWrite(redisAsyncContext *ac); + +/* Command functions for an async context. Write the command to the + * output buffer and register the provided callback. */ +int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap); +int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...); +int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen); +int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/debian/modules/nchan/src/hiredis/dict.c b/debian/modules/nchan/src/hiredis/dict.c new file mode 100644 index 0000000..e17a625 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/dict.c @@ -0,0 +1,338 @@ +/* Hash table implementation. + * + * This file implements in memory hash tables with insert/del/replace/find/ + * get-random-element operations. Hash tables will auto resize if needed + * tables of power of two in size are used, collisions are handled by + * chaining. See the source code for more information... :) + * + * Copyright (c) 2006-2010, Salvatore Sanfilippo + * All rights reserved. + * + * 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 Redis 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. + */ + +#include "fmacros.h" +#include +#include +#include +#include "dict.h" + +/* -------------------------- private prototypes ---------------------------- */ + +static int _dictExpandIfNeeded(dict *ht); +static unsigned long _dictNextPower(unsigned long size); +static int _dictKeyIndex(dict *ht, const void *key); +static int _dictInit(dict *ht, dictType *type, void *privDataPtr); + +/* -------------------------- hash functions -------------------------------- */ + +/* Generic hash function (a popular one from Bernstein). + * I tested a few and this was the best. */ +static unsigned int dictGenHashFunction(const unsigned char *buf, int len) { + unsigned int hash = 5381; + + while (len--) + hash = ((hash << 5) + hash) + (*buf++); /* hash * 33 + c */ + return hash; +} + +/* ----------------------------- API implementation ------------------------- */ + +/* Reset an hashtable already initialized with ht_init(). + * NOTE: This function should only called by ht_destroy(). */ +static void _dictReset(dict *ht) { + ht->table = NULL; + ht->size = 0; + ht->sizemask = 0; + ht->used = 0; +} + +/* Create a new hash table */ +static dict *dictCreate(dictType *type, void *privDataPtr) { + dict *ht = malloc(sizeof(*ht)); + _dictInit(ht,type,privDataPtr); + return ht; +} + +/* Initialize the hash table */ +static int _dictInit(dict *ht, dictType *type, void *privDataPtr) { + _dictReset(ht); + ht->type = type; + ht->privdata = privDataPtr; + return DICT_OK; +} + +/* Expand or create the hashtable */ +static int dictExpand(dict *ht, unsigned long size) { + dict n; /* the new hashtable */ + unsigned long realsize = _dictNextPower(size), i; + + /* the size is invalid if it is smaller than the number of + * elements already inside the hashtable */ + if (ht->used > size) + return DICT_ERR; + + _dictInit(&n, ht->type, ht->privdata); + n.size = realsize; + n.sizemask = realsize-1; + n.table = calloc(realsize,sizeof(dictEntry*)); + + /* Copy all the elements from the old to the new table: + * note that if the old hash table is empty ht->size is zero, + * so dictExpand just creates an hash table. */ + n.used = ht->used; + for (i = 0; i < ht->size && ht->used > 0; i++) { + dictEntry *he, *nextHe; + + if (ht->table[i] == NULL) continue; + + /* For each hash entry on this slot... */ + he = ht->table[i]; + while(he) { + unsigned int h; + + nextHe = he->next; + /* Get the new element index */ + h = dictHashKey(ht, he->key) & n.sizemask; + he->next = n.table[h]; + n.table[h] = he; + ht->used--; + /* Pass to the next element */ + he = nextHe; + } + } + assert(ht->used == 0); + free(ht->table); + + /* Remap the new hashtable in the old */ + *ht = n; + return DICT_OK; +} + +/* Add an element to the target hash table */ +static int dictAdd(dict *ht, void *key, void *val) { + int index; + dictEntry *entry; + + /* Get the index of the new element, or -1 if + * the element already exists. */ + if ((index = _dictKeyIndex(ht, key)) == -1) + return DICT_ERR; + + /* Allocates the memory and stores key */ + entry = malloc(sizeof(*entry)); + entry->next = ht->table[index]; + ht->table[index] = entry; + + /* Set the hash entry fields. */ + dictSetHashKey(ht, entry, key); + dictSetHashVal(ht, entry, val); + ht->used++; + return DICT_OK; +} + +/* Add an element, discarding the old if the key already exists. + * Return 1 if the key was added from scratch, 0 if there was already an + * element with such key and dictReplace() just performed a value update + * operation. */ +static int dictReplace(dict *ht, void *key, void *val) { + dictEntry *entry, auxentry; + + /* Try to add the element. If the key + * does not exists dictAdd will succeed. */ + if (dictAdd(ht, key, val) == DICT_OK) + return 1; + /* It already exists, get the entry */ + entry = dictFind(ht, key); + /* Free the old value and set the new one */ + /* Set the new value and free the old one. Note that it is important + * to do that in this order, as the value may just be exactly the same + * as the previous one. In this context, think to reference counting, + * you want to increment (set), and then decrement (free), and not the + * reverse. */ + auxentry = *entry; + dictSetHashVal(ht, entry, val); + dictFreeEntryVal(ht, &auxentry); + return 0; +} + +/* Search and remove an element */ +static int dictDelete(dict *ht, const void *key) { + unsigned int h; + dictEntry *de, *prevde; + + if (ht->size == 0) + return DICT_ERR; + h = dictHashKey(ht, key) & ht->sizemask; + de = ht->table[h]; + + prevde = NULL; + while(de) { + if (dictCompareHashKeys(ht,key,de->key)) { + /* Unlink the element from the list */ + if (prevde) + prevde->next = de->next; + else + ht->table[h] = de->next; + + dictFreeEntryKey(ht,de); + dictFreeEntryVal(ht,de); + free(de); + ht->used--; + return DICT_OK; + } + prevde = de; + de = de->next; + } + return DICT_ERR; /* not found */ +} + +/* Destroy an entire hash table */ +static int _dictClear(dict *ht) { + unsigned long i; + + /* Free all the elements */ + for (i = 0; i < ht->size && ht->used > 0; i++) { + dictEntry *he, *nextHe; + + if ((he = ht->table[i]) == NULL) continue; + while(he) { + nextHe = he->next; + dictFreeEntryKey(ht, he); + dictFreeEntryVal(ht, he); + free(he); + ht->used--; + he = nextHe; + } + } + /* Free the table and the allocated cache structure */ + free(ht->table); + /* Re-initialize the table */ + _dictReset(ht); + return DICT_OK; /* never fails */ +} + +/* Clear & Release the hash table */ +static void dictRelease(dict *ht) { + _dictClear(ht); + free(ht); +} + +static dictEntry *dictFind(dict *ht, const void *key) { + dictEntry *he; + unsigned int h; + + if (ht->size == 0) return NULL; + h = dictHashKey(ht, key) & ht->sizemask; + he = ht->table[h]; + while(he) { + if (dictCompareHashKeys(ht, key, he->key)) + return he; + he = he->next; + } + return NULL; +} + +static dictIterator *dictGetIterator(dict *ht) { + dictIterator *iter = malloc(sizeof(*iter)); + + iter->ht = ht; + iter->index = -1; + iter->entry = NULL; + iter->nextEntry = NULL; + return iter; +} + +static dictEntry *dictNext(dictIterator *iter) { + while (1) { + if (iter->entry == NULL) { + iter->index++; + if (iter->index >= + (signed)iter->ht->size) break; + iter->entry = iter->ht->table[iter->index]; + } else { + iter->entry = iter->nextEntry; + } + if (iter->entry) { + /* We need to save the 'next' here, the iterator user + * may delete the entry we are returning. */ + iter->nextEntry = iter->entry->next; + return iter->entry; + } + } + return NULL; +} + +static void dictReleaseIterator(dictIterator *iter) { + free(iter); +} + +/* ------------------------- private functions ------------------------------ */ + +/* Expand the hash table if needed */ +static int _dictExpandIfNeeded(dict *ht) { + /* If the hash table is empty expand it to the initial size, + * if the table is "full" dobule its size. */ + if (ht->size == 0) + return dictExpand(ht, DICT_HT_INITIAL_SIZE); + if (ht->used == ht->size) + return dictExpand(ht, ht->size*2); + return DICT_OK; +} + +/* Our hash table capability is a power of two */ +static unsigned long _dictNextPower(unsigned long size) { + unsigned long i = DICT_HT_INITIAL_SIZE; + + if (size >= LONG_MAX) return LONG_MAX; + while(1) { + if (i >= size) + return i; + i *= 2; + } +} + +/* Returns the index of a free slot that can be populated with + * an hash entry for the given 'key'. + * If the key already exists, -1 is returned. */ +static int _dictKeyIndex(dict *ht, const void *key) { + unsigned int h; + dictEntry *he; + + /* Expand the hashtable if needed */ + if (_dictExpandIfNeeded(ht) == DICT_ERR) + return -1; + /* Compute the key hash value */ + h = dictHashKey(ht, key) & ht->sizemask; + /* Search if this slot does not already contain the given key */ + he = ht->table[h]; + while(he) { + if (dictCompareHashKeys(ht, key, he->key)) + return -1; + he = he->next; + } + return h; +} + diff --git a/debian/modules/nchan/src/hiredis/dict.h b/debian/modules/nchan/src/hiredis/dict.h new file mode 100644 index 0000000..95fcd28 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/dict.h @@ -0,0 +1,126 @@ +/* Hash table implementation. + * + * This file implements in memory hash tables with insert/del/replace/find/ + * get-random-element operations. Hash tables will auto resize if needed + * tables of power of two in size are used, collisions are handled by + * chaining. See the source code for more information... :) + * + * Copyright (c) 2006-2010, Salvatore Sanfilippo + * All rights reserved. + * + * 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 Redis 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. + */ + +#ifndef __DICT_H +#define __DICT_H + +#define DICT_OK 0 +#define DICT_ERR 1 + +/* Unused arguments generate annoying warnings... */ +#define DICT_NOTUSED(V) ((void) V) + +typedef struct dictEntry { + void *key; + void *val; + struct dictEntry *next; +} dictEntry; + +typedef struct dictType { + unsigned int (*hashFunction)(const void *key); + void *(*keyDup)(void *privdata, const void *key); + void *(*valDup)(void *privdata, const void *obj); + int (*keyCompare)(void *privdata, const void *key1, const void *key2); + void (*keyDestructor)(void *privdata, void *key); + void (*valDestructor)(void *privdata, void *obj); +} dictType; + +typedef struct dict { + dictEntry **table; + dictType *type; + unsigned long size; + unsigned long sizemask; + unsigned long used; + void *privdata; +} dict; + +typedef struct dictIterator { + dict *ht; + int index; + dictEntry *entry, *nextEntry; +} dictIterator; + +/* This is the initial size of every hash table */ +#define DICT_HT_INITIAL_SIZE 4 + +/* ------------------------------- Macros ------------------------------------*/ +#define dictFreeEntryVal(ht, entry) \ + if ((ht)->type->valDestructor) \ + (ht)->type->valDestructor((ht)->privdata, (entry)->val) + +#define dictSetHashVal(ht, entry, _val_) do { \ + if ((ht)->type->valDup) \ + entry->val = (ht)->type->valDup((ht)->privdata, _val_); \ + else \ + entry->val = (_val_); \ +} while(0) + +#define dictFreeEntryKey(ht, entry) \ + if ((ht)->type->keyDestructor) \ + (ht)->type->keyDestructor((ht)->privdata, (entry)->key) + +#define dictSetHashKey(ht, entry, _key_) do { \ + if ((ht)->type->keyDup) \ + entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \ + else \ + entry->key = (_key_); \ +} while(0) + +#define dictCompareHashKeys(ht, key1, key2) \ + (((ht)->type->keyCompare) ? \ + (ht)->type->keyCompare((ht)->privdata, key1, key2) : \ + (key1) == (key2)) + +#define dictHashKey(ht, key) (ht)->type->hashFunction(key) + +#define dictGetEntryKey(he) ((he)->key) +#define dictGetEntryVal(he) ((he)->val) +#define dictSlots(ht) ((ht)->size) +#define dictSize(ht) ((ht)->used) + +/* API */ +static unsigned int dictGenHashFunction(const unsigned char *buf, int len); +static dict *dictCreate(dictType *type, void *privDataPtr); +static int dictExpand(dict *ht, unsigned long size); +static int dictAdd(dict *ht, void *key, void *val); +static int dictReplace(dict *ht, void *key, void *val); +static int dictDelete(dict *ht, const void *key); +static void dictRelease(dict *ht); +static dictEntry * dictFind(dict *ht, const void *key); +static dictIterator *dictGetIterator(dict *ht); +static dictEntry *dictNext(dictIterator *iter); +static void dictReleaseIterator(dictIterator *iter); + +#endif /* __DICT_H */ diff --git a/debian/modules/nchan/src/hiredis/examples/example-ae.c b/debian/modules/nchan/src/hiredis/examples/example-ae.c new file mode 100644 index 0000000..8efa730 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/examples/example-ae.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include + +#include +#include +#include + +/* Put event loop in the global scope, so it can be explicitly stopped */ +static aeEventLoop *loop; + +void getCallback(redisAsyncContext *c, void *r, void *privdata) { + redisReply *reply = r; + if (reply == NULL) return; + printf("argv[%s]: %s\n", (char*)privdata, reply->str); + + /* Disconnect after receiving the reply to GET */ + redisAsyncDisconnect(c); +} + +void connectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + aeStop(loop); + return; + } + + printf("Connected...\n"); +} + +void disconnectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + aeStop(loop); + return; + } + + printf("Disconnected...\n"); + aeStop(loop); +} + +int main (int argc, char **argv) { + signal(SIGPIPE, SIG_IGN); + + redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); + if (c->err) { + /* Let *c leak for now... */ + printf("Error: %s\n", c->errstr); + return 1; + } + + loop = aeCreateEventLoop(64); + redisAeAttach(loop, c); + redisAsyncSetConnectCallback(c,connectCallback); + redisAsyncSetDisconnectCallback(c,disconnectCallback); + redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); + redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); + aeMain(loop); + return 0; +} + diff --git a/debian/modules/nchan/src/hiredis/examples/example-libev.c b/debian/modules/nchan/src/hiredis/examples/example-libev.c new file mode 100644 index 0000000..cc8b166 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/examples/example-libev.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +#include +#include +#include + +void getCallback(redisAsyncContext *c, void *r, void *privdata) { + redisReply *reply = r; + if (reply == NULL) return; + printf("argv[%s]: %s\n", (char*)privdata, reply->str); + + /* Disconnect after receiving the reply to GET */ + redisAsyncDisconnect(c); +} + +void connectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + return; + } + printf("Connected...\n"); +} + +void disconnectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + return; + } + printf("Disconnected...\n"); +} + +int main (int argc, char **argv) { + signal(SIGPIPE, SIG_IGN); + + redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); + if (c->err) { + /* Let *c leak for now... */ + printf("Error: %s\n", c->errstr); + return 1; + } + + redisLibevAttach(EV_DEFAULT_ c); + redisAsyncSetConnectCallback(c,connectCallback); + redisAsyncSetDisconnectCallback(c,disconnectCallback); + redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); + redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); + ev_loop(EV_DEFAULT_ 0); + return 0; +} diff --git a/debian/modules/nchan/src/hiredis/examples/example-libevent.c b/debian/modules/nchan/src/hiredis/examples/example-libevent.c new file mode 100644 index 0000000..d333c22 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/examples/example-libevent.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include + +#include +#include +#include + +void getCallback(redisAsyncContext *c, void *r, void *privdata) { + redisReply *reply = r; + if (reply == NULL) return; + printf("argv[%s]: %s\n", (char*)privdata, reply->str); + + /* Disconnect after receiving the reply to GET */ + redisAsyncDisconnect(c); +} + +void connectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + return; + } + printf("Connected...\n"); +} + +void disconnectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + return; + } + printf("Disconnected...\n"); +} + +int main (int argc, char **argv) { + signal(SIGPIPE, SIG_IGN); + struct event_base *base = event_base_new(); + + redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); + if (c->err) { + /* Let *c leak for now... */ + printf("Error: %s\n", c->errstr); + return 1; + } + + redisLibeventAttach(c,base); + redisAsyncSetConnectCallback(c,connectCallback); + redisAsyncSetDisconnectCallback(c,disconnectCallback); + redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); + redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); + event_base_dispatch(base); + return 0; +} diff --git a/debian/modules/nchan/src/hiredis/examples/example-libuv.c b/debian/modules/nchan/src/hiredis/examples/example-libuv.c new file mode 100644 index 0000000..a5462d4 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/examples/example-libuv.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include + +#include +#include +#include + +void getCallback(redisAsyncContext *c, void *r, void *privdata) { + redisReply *reply = r; + if (reply == NULL) return; + printf("argv[%s]: %s\n", (char*)privdata, reply->str); + + /* Disconnect after receiving the reply to GET */ + redisAsyncDisconnect(c); +} + +void connectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + return; + } + printf("Connected...\n"); +} + +void disconnectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + return; + } + printf("Disconnected...\n"); +} + +int main (int argc, char **argv) { + signal(SIGPIPE, SIG_IGN); + uv_loop_t* loop = uv_default_loop(); + + redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); + if (c->err) { + /* Let *c leak for now... */ + printf("Error: %s\n", c->errstr); + return 1; + } + + redisLibuvAttach(c,loop); + redisAsyncSetConnectCallback(c,connectCallback); + redisAsyncSetDisconnectCallback(c,disconnectCallback); + redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); + redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); + uv_run(loop, UV_RUN_DEFAULT); + return 0; +} diff --git a/debian/modules/nchan/src/hiredis/examples/example.c b/debian/modules/nchan/src/hiredis/examples/example.c new file mode 100644 index 0000000..4d494c5 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/examples/example.c @@ -0,0 +1,78 @@ +#include +#include +#include + +#include + +int main(int argc, char **argv) { + unsigned int j; + redisContext *c; + redisReply *reply; + const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1"; + int port = (argc > 2) ? atoi(argv[2]) : 6379; + + struct timeval timeout = { 1, 500000 }; // 1.5 seconds + c = redisConnectWithTimeout(hostname, port, timeout); + if (c == NULL || c->err) { + if (c) { + printf("Connection error: %s\n", c->errstr); + redisFree(c); + } else { + printf("Connection error: can't allocate redis context\n"); + } + exit(1); + } + + /* PING server */ + reply = redisCommand(c,"PING"); + printf("PING: %s\n", reply->str); + freeReplyObject(reply); + + /* Set a key */ + reply = redisCommand(c,"SET %s %s", "foo", "hello world"); + printf("SET: %s\n", reply->str); + freeReplyObject(reply); + + /* Set a key using binary safe API */ + reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5); + printf("SET (binary API): %s\n", reply->str); + freeReplyObject(reply); + + /* Try a GET and two INCR */ + reply = redisCommand(c,"GET foo"); + printf("GET foo: %s\n", reply->str); + freeReplyObject(reply); + + reply = redisCommand(c,"INCR counter"); + printf("INCR counter: %lld\n", reply->integer); + freeReplyObject(reply); + /* again ... */ + reply = redisCommand(c,"INCR counter"); + printf("INCR counter: %lld\n", reply->integer); + freeReplyObject(reply); + + /* Create a list of numbers, from 0 to 9 */ + reply = redisCommand(c,"DEL mylist"); + freeReplyObject(reply); + for (j = 0; j < 10; j++) { + char buf[64]; + + snprintf(buf,64,"%u",j); + reply = redisCommand(c,"LPUSH mylist element-%s", buf); + freeReplyObject(reply); + } + + /* Let's check what we have inside the list */ + reply = redisCommand(c,"LRANGE mylist 0 -1"); + if (reply->type == REDIS_REPLY_ARRAY) { + for (j = 0; j < reply->elements; j++) { + printf("%u) %s\n", j, reply->element[j]->str); + } + } + freeReplyObject(reply); + + /* Disconnects and frees the context */ + redisFree(c); + + return 0; +} diff --git a/debian/modules/nchan/src/hiredis/fmacros.h b/debian/modules/nchan/src/hiredis/fmacros.h new file mode 100644 index 0000000..19d7b21 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/fmacros.h @@ -0,0 +1,21 @@ +#ifndef __HIREDIS_FMACRO_H +#define __HIREDIS_FMACRO_H + +#if defined(__linux__) +#define _BSD_SOURCE +#define _DEFAULT_SOURCE +#endif + +#if defined(__sun__) +#define _POSIX_C_SOURCE 200112L +#elif defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) +#define _XOPEN_SOURCE 600 +#else +#define _XOPEN_SOURCE +#endif + +#if __APPLE__ && __MACH__ +#define _OSX +#endif + +#endif diff --git a/debian/modules/nchan/src/hiredis/hiredis.c b/debian/modules/nchan/src/hiredis/hiredis.c new file mode 100644 index 0000000..2b876d9 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/hiredis.c @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2014, Pieter Noordhuis + * Copyright (c) 2015, Matt Stancliff , + * Jan-Erik Rediger + * + * All rights reserved. + * + * 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 Redis 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. + */ + +#include "fmacros.h" +#include +#include +#include +#include +#include +#include + +#include "hiredis.h" +#include "net.h" +#include "sds.h" + +static redisReply *createReplyObject(int type); +static void *createStringObject(const redisReadTask *task, char *str, size_t len); +static void *createArrayObject(const redisReadTask *task, int elements); +static void *createIntegerObject(const redisReadTask *task, long long value); +static void *createNilObject(const redisReadTask *task); + +/* Default set of functions to build the reply. Keep in mind that such a + * function returning NULL is interpreted as OOM. */ +static redisReplyObjectFunctions defaultFunctions = { + createStringObject, + createArrayObject, + createIntegerObject, + createNilObject, + freeReplyObject +}; + +/* Create a reply object */ +static redisReply *createReplyObject(int type) { + redisReply *r = calloc(1,sizeof(*r)); + + if (r == NULL) + return NULL; + + r->type = type; + return r; +} + +/* Free a reply object */ +void freeReplyObject(void *reply) { + redisReply *r = reply; + size_t j; + + if (r == NULL) + return; + + switch(r->type) { + case REDIS_REPLY_INTEGER: + break; /* Nothing to free */ + case REDIS_REPLY_ARRAY: + if (r->element != NULL) { + for (j = 0; j < r->elements; j++) + if (r->element[j] != NULL) + freeReplyObject(r->element[j]); + free(r->element); + } + break; + case REDIS_REPLY_ERROR: + case REDIS_REPLY_STATUS: + case REDIS_REPLY_STRING: + if (r->str != NULL) + free(r->str); + break; + } + free(r); +} + +static void *createStringObject(const redisReadTask *task, char *str, size_t len) { + redisReply *r, *parent; + char *buf; + + r = createReplyObject(task->type); + if (r == NULL) + return NULL; + + buf = malloc(len+1); + if (buf == NULL) { + freeReplyObject(r); + return NULL; + } + + assert(task->type == REDIS_REPLY_ERROR || + task->type == REDIS_REPLY_STATUS || + task->type == REDIS_REPLY_STRING); + + /* Copy string value */ + memcpy(buf,str,len); + buf[len] = '\0'; + r->str = buf; + r->len = len; + + if (task->parent) { + parent = task->parent->obj; + assert(parent->type == REDIS_REPLY_ARRAY); + parent->element[task->idx] = r; + } + return r; +} + +static void *createArrayObject(const redisReadTask *task, int elements) { + redisReply *r, *parent; + + r = createReplyObject(REDIS_REPLY_ARRAY); + if (r == NULL) + return NULL; + + if (elements > 0) { + r->element = calloc(elements,sizeof(redisReply*)); + if (r->element == NULL) { + freeReplyObject(r); + return NULL; + } + } + + r->elements = elements; + + if (task->parent) { + parent = task->parent->obj; + assert(parent->type == REDIS_REPLY_ARRAY); + parent->element[task->idx] = r; + } + return r; +} + +static void *createIntegerObject(const redisReadTask *task, long long value) { + redisReply *r, *parent; + + r = createReplyObject(REDIS_REPLY_INTEGER); + if (r == NULL) + return NULL; + + r->integer = value; + + if (task->parent) { + parent = task->parent->obj; + assert(parent->type == REDIS_REPLY_ARRAY); + parent->element[task->idx] = r; + } + return r; +} + +static void *createNilObject(const redisReadTask *task) { + redisReply *r, *parent; + + r = createReplyObject(REDIS_REPLY_NIL); + if (r == NULL) + return NULL; + + if (task->parent) { + parent = task->parent->obj; + assert(parent->type == REDIS_REPLY_ARRAY); + parent->element[task->idx] = r; + } + return r; +} + +/* Return the number of digits of 'v' when converted to string in radix 10. + * Implementation borrowed from link in redis/src/util.c:string2ll(). */ +static uint32_t countDigits(uint64_t v) { + uint32_t result = 1; + for (;;) { + if (v < 10) return result; + if (v < 100) return result + 1; + if (v < 1000) return result + 2; + if (v < 10000) return result + 3; + v /= 10000U; + result += 4; + } +} + +/* Helper that calculates the bulk length given a certain string length. */ +static size_t bulklen(size_t len) { + return 1+countDigits(len)+2+len+2; +} + +int redisvFormatCommand(char **target, const char *format, va_list ap) { + const char *c = format; + char *cmd = NULL; /* final command */ + int pos; /* position in final command */ + sds curarg, newarg; /* current argument */ + int touched = 0; /* was the current argument touched? */ + char **curargv = NULL, **newargv = NULL; + int argc = 0; + int totlen = 0; + int error_type = 0; /* 0 = no error; -1 = memory error; -2 = format error */ + int j; + + /* Abort if there is not target to set */ + if (target == NULL) + return -1; + + /* Build the command string accordingly to protocol */ + curarg = sdsempty(); + if (curarg == NULL) + return -1; + + while(*c != '\0') { + if (*c != '%' || c[1] == '\0') { + if (*c == ' ') { + if (touched) { + newargv = realloc(curargv,sizeof(char*)*(argc+1)); + if (newargv == NULL) goto memory_err; + curargv = newargv; + curargv[argc++] = curarg; + totlen += bulklen(sdslen(curarg)); + + /* curarg is put in argv so it can be overwritten. */ + curarg = sdsempty(); + if (curarg == NULL) goto memory_err; + touched = 0; + } + } else { + newarg = sdscatlen(curarg,c,1); + if (newarg == NULL) goto memory_err; + curarg = newarg; + touched = 1; + } + } else { + char *arg; + size_t size; + + /* Set newarg so it can be checked even if it is not touched. */ + newarg = curarg; + + switch(c[1]) { + case 's': + arg = va_arg(ap,char*); + size = strlen(arg); + if (size > 0) + newarg = sdscatlen(curarg,arg,size); + break; + case 'b': + arg = va_arg(ap,char*); + size = va_arg(ap,size_t); + if (size > 0) + newarg = sdscatlen(curarg,arg,size); + break; + case '%': + newarg = sdscat(curarg,"%"); + break; + default: + /* Try to detect printf format */ + { + static const char intfmts[] = "diouxX"; + static const char flags[] = "#0-+ "; + char _format[16]; + const char *_p = c+1; + size_t _l = 0; + va_list _cpy; + + /* Flags */ + while (*_p != '\0' && strchr(flags,*_p) != NULL) _p++; + + /* Field width */ + while (*_p != '\0' && isdigit(*_p)) _p++; + + /* Precision */ + if (*_p == '.') { + _p++; + while (*_p != '\0' && isdigit(*_p)) _p++; + } + + /* Copy va_list before consuming with va_arg */ + va_copy(_cpy,ap); + + /* Integer conversion (without modifiers) */ + if (strchr(intfmts,*_p) != NULL) { + va_arg(ap,int); + goto fmt_valid; + } + + /* Double conversion (without modifiers) */ + if (strchr("eEfFgGaA",*_p) != NULL) { + va_arg(ap,double); + goto fmt_valid; + } + + /* Size: char */ + if (_p[0] == 'h' && _p[1] == 'h') { + _p += 2; + if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { + va_arg(ap,int); /* char gets promoted to int */ + goto fmt_valid; + } + goto fmt_invalid; + } + + /* Size: short */ + if (_p[0] == 'h') { + _p += 1; + if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { + va_arg(ap,int); /* short gets promoted to int */ + goto fmt_valid; + } + goto fmt_invalid; + } + + /* Size: long long */ + if (_p[0] == 'l' && _p[1] == 'l') { + _p += 2; + if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { + va_arg(ap,long long); + goto fmt_valid; + } + goto fmt_invalid; + } + + /* Size: long */ + if (_p[0] == 'l') { + _p += 1; + if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { + va_arg(ap,long); + goto fmt_valid; + } + goto fmt_invalid; + } + + fmt_invalid: + va_end(_cpy); + goto format_err; + + fmt_valid: + _l = (_p+1)-c; + if (_l < sizeof(_format)-2) { + memcpy(_format,c,_l); + _format[_l] = '\0'; + newarg = sdscatvprintf(curarg,_format,_cpy); + + /* Update current position (note: outer blocks + * increment c twice so compensate here) */ + c = _p-1; + } + + va_end(_cpy); + break; + } + } + + if (newarg == NULL) goto memory_err; + curarg = newarg; + + touched = 1; + c++; + } + c++; + } + + /* Add the last argument if needed */ + if (touched) { + newargv = realloc(curargv,sizeof(char*)*(argc+1)); + if (newargv == NULL) goto memory_err; + curargv = newargv; + curargv[argc++] = curarg; + totlen += bulklen(sdslen(curarg)); + } else { + sdsfree(curarg); + } + + /* Clear curarg because it was put in curargv or was free'd. */ + curarg = NULL; + + /* Add bytes needed to hold multi bulk count */ + totlen += 1+countDigits(argc)+2; + + /* Build the command at protocol level */ + cmd = malloc(totlen+1); + if (cmd == NULL) goto memory_err; + + pos = sprintf(cmd,"*%d\r\n",argc); + for (j = 0; j < argc; j++) { + pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j])); + memcpy(cmd+pos,curargv[j],sdslen(curargv[j])); + pos += sdslen(curargv[j]); + sdsfree(curargv[j]); + cmd[pos++] = '\r'; + cmd[pos++] = '\n'; + } + assert(pos == totlen); + cmd[pos] = '\0'; + + free(curargv); + *target = cmd; + return totlen; + +format_err: + error_type = -2; + goto cleanup; + +memory_err: + error_type = -1; + goto cleanup; + +cleanup: + if (curargv) { + while(argc--) + sdsfree(curargv[argc]); + free(curargv); + } + + sdsfree(curarg); + + /* No need to check cmd since it is the last statement that can fail, + * but do it anyway to be as defensive as possible. */ + if (cmd != NULL) + free(cmd); + + return error_type; +} + +/* Format a command according to the Redis protocol. This function + * takes a format similar to printf: + * + * %s represents a C null terminated string you want to interpolate + * %b represents a binary safe string + * + * When using %b you need to provide both the pointer to the string + * and the length in bytes as a size_t. Examples: + * + * len = redisFormatCommand(target, "GET %s", mykey); + * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen); + */ +int redisFormatCommand(char **target, const char *format, ...) { + va_list ap; + int len; + va_start(ap,format); + len = redisvFormatCommand(target,format,ap); + va_end(ap); + + /* The API says "-1" means bad result, but we now also return "-2" in some + * cases. Force the return value to always be -1. */ + if (len < 0) + len = -1; + + return len; +} + +/* Format a command according to the Redis protocol using an sds string and + * sdscatfmt for the processing of arguments. This function takes the + * number of arguments, an array with arguments and an array with their + * lengths. If the latter is set to NULL, strlen will be used to compute the + * argument lengths. + */ +int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv, + const size_t *argvlen) +{ + sds cmd; + unsigned long long totlen; + int j; + size_t len; + + /* Abort on a NULL target */ + if (target == NULL) + return -1; + + /* Calculate our total size */ + totlen = 1+countDigits(argc)+2; + for (j = 0; j < argc; j++) { + len = argvlen ? argvlen[j] : strlen(argv[j]); + totlen += bulklen(len); + } + + /* Use an SDS string for command construction */ + cmd = sdsempty(); + if (cmd == NULL) + return -1; + + /* We already know how much storage we need */ + cmd = sdsMakeRoomFor(cmd, totlen); + if (cmd == NULL) + return -1; + + /* Construct command */ + cmd = sdscatfmt(cmd, "*%i\r\n", argc); + for (j=0; j < argc; j++) { + len = argvlen ? argvlen[j] : strlen(argv[j]); + cmd = sdscatfmt(cmd, "$%T\r\n", len); + cmd = sdscatlen(cmd, argv[j], len); + cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1); + } + + assert(sdslen(cmd)==totlen); + + *target = cmd; + return totlen; +} + +void redisFreeSdsCommand(sds cmd) { + sdsfree(cmd); +} + +/* Format a command according to the Redis protocol. This function takes the + * number of arguments, an array with arguments and an array with their + * lengths. If the latter is set to NULL, strlen will be used to compute the + * argument lengths. + */ +int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen) { + char *cmd = NULL; /* final command */ + int pos; /* position in final command */ + size_t len; + int totlen, j; + + /* Abort on a NULL target */ + if (target == NULL) + return -1; + + /* Calculate number of bytes needed for the command */ + totlen = 1+countDigits(argc)+2; + for (j = 0; j < argc; j++) { + len = argvlen ? argvlen[j] : strlen(argv[j]); + totlen += bulklen(len); + } + + /* Build the command at protocol level */ + cmd = malloc(totlen+1); + if (cmd == NULL) + return -1; + + pos = sprintf(cmd,"*%d\r\n",argc); + for (j = 0; j < argc; j++) { + len = argvlen ? argvlen[j] : strlen(argv[j]); + pos += sprintf(cmd+pos,"$%zu\r\n",len); + memcpy(cmd+pos,argv[j],len); + pos += len; + cmd[pos++] = '\r'; + cmd[pos++] = '\n'; + } + assert(pos == totlen); + cmd[pos] = '\0'; + + *target = cmd; + return totlen; +} + +void redisFreeCommand(char *cmd) { + free(cmd); +} + +void __redisSetError(redisContext *c, int type, const char *str) { + size_t len; + + c->err = type; + if (str != NULL) { + len = strlen(str); + len = len < (sizeof(c->errstr)-1) ? len : (sizeof(c->errstr)-1); + memcpy(c->errstr,str,len); + c->errstr[len] = '\0'; + } else { + /* Only REDIS_ERR_IO may lack a description! */ + assert(type == REDIS_ERR_IO); + __redis_strerror_r(errno, c->errstr, sizeof(c->errstr)); + } +} + +redisReader *redisReaderCreate(void) { + return redisReaderCreateWithFunctions(&defaultFunctions); +} + +static redisContext *redisContextInit(void) { + redisContext *c; + + c = calloc(1,sizeof(redisContext)); + if (c == NULL) + return NULL; + + c->err = 0; + c->errstr[0] = '\0'; + c->obuf = sdsempty(); + c->reader = redisReaderCreate(); + c->tcp.host = NULL; + c->tcp.source_addr = NULL; + c->unix_sock.path = NULL; + c->timeout = NULL; + + if (c->obuf == NULL || c->reader == NULL) { + redisFree(c); + return NULL; + } + + return c; +} + +void redisFree(redisContext *c) { + if (c == NULL) + return; + if (c->fd > 0) + close(c->fd); + if (c->obuf != NULL) + sdsfree(c->obuf); + if (c->reader != NULL) + redisReaderFree(c->reader); + if (c->tcp.host) + free(c->tcp.host); + if (c->tcp.source_addr) + free(c->tcp.source_addr); + if (c->unix_sock.path) + free(c->unix_sock.path); + if (c->timeout) + free(c->timeout); + free(c); +} + +int redisFreeKeepFd(redisContext *c) { + int fd = c->fd; + c->fd = -1; + redisFree(c); + return fd; +} + +int redisReconnect(redisContext *c) { + c->err = 0; + memset(c->errstr, '\0', strlen(c->errstr)); + + if (c->fd > 0) { + close(c->fd); + } + + sdsfree(c->obuf); + redisReaderFree(c->reader); + + c->obuf = sdsempty(); + c->reader = redisReaderCreate(); + + if (c->connection_type == REDIS_CONN_TCP) { + return redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port, + c->timeout, c->tcp.source_addr); + } else if (c->connection_type == REDIS_CONN_UNIX) { + return redisContextConnectUnix(c, c->unix_sock.path, c->timeout); + } else { + /* Something bad happened here and shouldn't have. There isn't + enough information in the context to reconnect. */ + __redisSetError(c,REDIS_ERR_OTHER,"Not enough information to reconnect"); + } + + return REDIS_ERR; +} + +/* Connect to a Redis instance. On error the field error in the returned + * context will be set to the return value of the error function. + * When no set of reply functions is given, the default set will be used. */ +redisContext *redisConnect(const char *ip, int port) { + redisContext *c; + + c = redisContextInit(); + if (c == NULL) + return NULL; + + c->flags |= REDIS_BLOCK; + redisContextConnectTcp(c,ip,port,NULL); + return c; +} + +redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) { + redisContext *c; + + c = redisContextInit(); + if (c == NULL) + return NULL; + + c->flags |= REDIS_BLOCK; + redisContextConnectTcp(c,ip,port,&tv); + return c; +} + +redisContext *redisConnectNonBlock(const char *ip, int port) { + redisContext *c; + + c = redisContextInit(); + if (c == NULL) + return NULL; + + c->flags &= ~REDIS_BLOCK; + redisContextConnectTcp(c,ip,port,NULL); + return c; +} + +redisContext *redisConnectBindNonBlock(const char *ip, int port, + const char *source_addr) { + redisContext *c = redisContextInit(); + c->flags &= ~REDIS_BLOCK; + redisContextConnectBindTcp(c,ip,port,NULL,source_addr); + return c; +} + +redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, + const char *source_addr) { + redisContext *c = redisContextInit(); + c->flags &= ~REDIS_BLOCK; + c->flags |= REDIS_REUSEADDR; + redisContextConnectBindTcp(c,ip,port,NULL,source_addr); + return c; +} + +redisContext *redisConnectUnix(const char *path) { + redisContext *c; + + c = redisContextInit(); + if (c == NULL) + return NULL; + + c->flags |= REDIS_BLOCK; + redisContextConnectUnix(c,path,NULL); + return c; +} + +redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) { + redisContext *c; + + c = redisContextInit(); + if (c == NULL) + return NULL; + + c->flags |= REDIS_BLOCK; + redisContextConnectUnix(c,path,&tv); + return c; +} + +redisContext *redisConnectUnixNonBlock(const char *path) { + redisContext *c; + + c = redisContextInit(); + if (c == NULL) + return NULL; + + c->flags &= ~REDIS_BLOCK; + redisContextConnectUnix(c,path,NULL); + return c; +} + +redisContext *redisConnectFd(int fd) { + redisContext *c; + + c = redisContextInit(); + if (c == NULL) + return NULL; + + c->fd = fd; + c->flags |= REDIS_BLOCK | REDIS_CONNECTED; + return c; +} + +/* Set read/write timeout on a blocking socket. */ +int redisSetTimeout(redisContext *c, const struct timeval tv) { + if (c->flags & REDIS_BLOCK) + return redisContextSetTimeout(c,tv); + return REDIS_ERR; +} + +/* Enable connection KeepAlive. */ +int redisEnableKeepAlive(redisContext *c) { + if (redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL) != REDIS_OK) + return REDIS_ERR; + return REDIS_OK; +} + +/* Use this function to handle a read event on the descriptor. It will try + * and read some bytes from the socket and feed them to the reply parser. + * + * After this function is called, you may use redisContextReadReply to + * see if there is a reply available. */ +int redisBufferRead(redisContext *c) { + char buf[1024*16]; + int nread; + + /* Return early when the context has seen an error. */ + if (c->err) + return REDIS_ERR; + + nread = read(c->fd,buf,sizeof(buf)); + if (nread == -1) { + if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) { + /* Try again later */ + } else { + __redisSetError(c,REDIS_ERR_IO,NULL); + return REDIS_ERR; + } + } else if (nread == 0) { + __redisSetError(c,REDIS_ERR_EOF,"Server closed the connection"); + return REDIS_ERR; + } else { + if (redisReaderFeed(c->reader,buf,nread) != REDIS_OK) { + __redisSetError(c,c->reader->err,c->reader->errstr); + return REDIS_ERR; + } + } + return REDIS_OK; +} + +/* Write the output buffer to the socket. + * + * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was + * successfully written to the socket. When the buffer is empty after the + * write operation, "done" is set to 1 (if given). + * + * Returns REDIS_ERR if an error occurred trying to write and sets + * c->errstr to hold the appropriate error string. + */ +int redisBufferWrite(redisContext *c, int *done) { + int nwritten; + + /* Return early when the context has seen an error. */ + if (c->err) + return REDIS_ERR; + + if (sdslen(c->obuf) > 0) { + nwritten = write(c->fd,c->obuf,sdslen(c->obuf)); + if (nwritten == -1) { + if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) { + /* Try again later */ + } else { + __redisSetError(c,REDIS_ERR_IO,NULL); + return REDIS_ERR; + } + } else if (nwritten > 0) { + if (nwritten == (signed)sdslen(c->obuf)) { + sdsfree(c->obuf); + c->obuf = sdsempty(); + } else { + sdsrange(c->obuf,nwritten,-1); + } + } + } + if (done != NULL) *done = (sdslen(c->obuf) == 0); + return REDIS_OK; +} + +/* Internal helper function to try and get a reply from the reader, + * or set an error in the context otherwise. */ +int redisGetReplyFromReader(redisContext *c, void **reply) { + if (redisReaderGetReply(c->reader,reply) == REDIS_ERR) { + __redisSetError(c,c->reader->err,c->reader->errstr); + return REDIS_ERR; + } + return REDIS_OK; +} + +int redisGetReply(redisContext *c, void **reply) { + int wdone = 0; + void *aux = NULL; + + /* Try to read pending replies */ + if (redisGetReplyFromReader(c,&aux) == REDIS_ERR) + return REDIS_ERR; + + /* For the blocking context, flush output buffer and read reply */ + if (aux == NULL && c->flags & REDIS_BLOCK) { + /* Write until done */ + do { + if (redisBufferWrite(c,&wdone) == REDIS_ERR) + return REDIS_ERR; + } while (!wdone); + + /* Read until there is a reply */ + do { + if (redisBufferRead(c) == REDIS_ERR) + return REDIS_ERR; + if (redisGetReplyFromReader(c,&aux) == REDIS_ERR) + return REDIS_ERR; + } while (aux == NULL); + } + + /* Set reply object */ + if (reply != NULL) *reply = aux; + return REDIS_OK; +} + + +/* Helper function for the redisAppendCommand* family of functions. + * + * Write a formatted command to the output buffer. When this family + * is used, you need to call redisGetReply yourself to retrieve + * the reply (or replies in pub/sub). + */ +int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) { + sds newbuf; + + newbuf = sdscatlen(c->obuf,cmd,len); + if (newbuf == NULL) { + __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); + return REDIS_ERR; + } + + c->obuf = newbuf; + return REDIS_OK; +} + +int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) { + + if (__redisAppendCommand(c, cmd, len) != REDIS_OK) { + return REDIS_ERR; + } + + return REDIS_OK; +} + +int redisvAppendCommand(redisContext *c, const char *format, va_list ap) { + char *cmd; + int len; + + len = redisvFormatCommand(&cmd,format,ap); + if (len == -1) { + __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); + return REDIS_ERR; + } else if (len == -2) { + __redisSetError(c,REDIS_ERR_OTHER,"Invalid format string"); + return REDIS_ERR; + } + + if (__redisAppendCommand(c,cmd,len) != REDIS_OK) { + free(cmd); + return REDIS_ERR; + } + + free(cmd); + return REDIS_OK; +} + +int redisAppendCommand(redisContext *c, const char *format, ...) { + va_list ap; + int ret; + + va_start(ap,format); + ret = redisvAppendCommand(c,format,ap); + va_end(ap); + return ret; +} + +int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) { + sds cmd; + int len; + + len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen); + if (len == -1) { + __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); + return REDIS_ERR; + } + + if (__redisAppendCommand(c,cmd,len) != REDIS_OK) { + sdsfree(cmd); + return REDIS_ERR; + } + + sdsfree(cmd); + return REDIS_OK; +} + +/* Helper function for the redisCommand* family of functions. + * + * Write a formatted command to the output buffer. If the given context is + * blocking, immediately read the reply into the "reply" pointer. When the + * context is non-blocking, the "reply" pointer will not be used and the + * command is simply appended to the write buffer. + * + * Returns the reply when a reply was successfully retrieved. Returns NULL + * otherwise. When NULL is returned in a blocking context, the error field + * in the context will be set. + */ +static void *__redisBlockForReply(redisContext *c) { + void *reply; + + if (c->flags & REDIS_BLOCK) { + if (redisGetReply(c,&reply) != REDIS_OK) + return NULL; + return reply; + } + return NULL; +} + +void *redisvCommand(redisContext *c, const char *format, va_list ap) { + if (redisvAppendCommand(c,format,ap) != REDIS_OK) + return NULL; + return __redisBlockForReply(c); +} + +void *redisCommand(redisContext *c, const char *format, ...) { + va_list ap; + void *reply = NULL; + va_start(ap,format); + reply = redisvCommand(c,format,ap); + va_end(ap); + return reply; +} + +void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) { + if (redisAppendCommandArgv(c,argc,argv,argvlen) != REDIS_OK) + return NULL; + return __redisBlockForReply(c); +} diff --git a/debian/modules/nchan/src/hiredis/hiredis.h b/debian/modules/nchan/src/hiredis/hiredis.h new file mode 100644 index 0000000..edba658 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/hiredis.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2014, Pieter Noordhuis + * Copyright (c) 2015, Matt Stancliff , + * Jan-Erik Rediger + * + * All rights reserved. + * + * 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 Redis 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. + */ + +#ifndef __HIREDIS_H +#define __HIREDIS_H +#include "read.h" +#include /* for va_list */ +#include /* for struct timeval */ +#include /* uintXX_t, etc */ +#include "sds.h" /* for sds */ + +#define HIREDIS_MAJOR 0 +#define HIREDIS_MINOR 13 +#define HIREDIS_PATCH 3 +#define HIREDIS_SONAME 0.13 + +/* Connection type can be blocking or non-blocking and is set in the + * least significant bit of the flags field in redisContext. */ +#define REDIS_BLOCK 0x1 + +/* Connection may be disconnected before being free'd. The second bit + * in the flags field is set when the context is connected. */ +#define REDIS_CONNECTED 0x2 + +/* The async API might try to disconnect cleanly and flush the output + * buffer and read all subsequent replies before disconnecting. + * This flag means no new commands can come in and the connection + * should be terminated once all replies have been read. */ +#define REDIS_DISCONNECTING 0x4 + +/* Flag specific to the async API which means that the context should be clean + * up as soon as possible. */ +#define REDIS_FREEING 0x8 + +/* Flag that is set when an async callback is executed. */ +#define REDIS_IN_CALLBACK 0x10 + +/* Flag that is set when the async context has one or more subscriptions. */ +#define REDIS_SUBSCRIBED 0x20 + +/* Flag that is set when monitor mode is active */ +#define REDIS_MONITORING 0x40 + +/* Flag that is set when we should set SO_REUSEADDR before calling bind() */ +#define REDIS_REUSEADDR 0x80 + +#define REDIS_KEEPALIVE_INTERVAL 15 /* seconds */ + +/* number of times we retry to connect in the case of EADDRNOTAVAIL and + * SO_REUSEADDR is being used. */ +#define REDIS_CONNECT_RETRIES 10 + +/* strerror_r has two completely different prototypes and behaviors + * depending on system issues, so we need to operate on the error buffer + * differently depending on which strerror_r we're using. */ +#ifndef _GNU_SOURCE +/* "regular" POSIX strerror_r that does the right thing. */ +#define __redis_strerror_r(errno, buf, len) \ + do { \ + strerror_r((errno), (buf), (len)); \ + } while (0) +#else +/* "bad" GNU strerror_r we need to clean up after. */ +#define __redis_strerror_r(errno, buf, len) \ + do { \ + char *err_str = strerror_r((errno), (buf), (len)); \ + /* If return value _isn't_ the start of the buffer we passed in, \ + * then GNU strerror_r returned an internal static buffer and we \ + * need to copy the result into our private buffer. */ \ + if (err_str != (buf)) { \ + buf[(len)] = '\0'; \ + strncat((buf), err_str, ((len) - 1)); \ + } \ + } while (0) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is the reply object returned by redisCommand() */ +typedef struct redisReply { + int type; /* REDIS_REPLY_* */ + long long integer; /* The integer when type is REDIS_REPLY_INTEGER */ + int len; /* Length of string */ + char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */ + size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */ + struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */ +} redisReply; + +redisReader *redisReaderCreate(void); + +/* Function to free the reply objects hiredis returns by default. */ +void freeReplyObject(void *reply); + +/* Functions to format a command according to the protocol. */ +int redisvFormatCommand(char **target, const char *format, va_list ap); +int redisFormatCommand(char **target, const char *format, ...); +int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen); +int redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen); +void redisFreeCommand(char *cmd); +void redisFreeSdsCommand(sds cmd); + +enum redisConnectionType { + REDIS_CONN_TCP, + REDIS_CONN_UNIX, +}; + +/* Context for a connection to Redis */ +typedef struct redisContext { + int err; /* Error flags, 0 when there is no error */ + char errstr[128]; /* String representation of error when applicable */ + int fd; + int flags; + char *obuf; /* Write buffer */ + redisReader *reader; /* Protocol reader */ + + enum redisConnectionType connection_type; + struct timeval *timeout; + + struct { + char *host; + char *source_addr; + int port; + } tcp; + + struct { + char *path; + } unix_sock; + +} redisContext; + +redisContext *redisConnect(const char *ip, int port); +redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv); +redisContext *redisConnectNonBlock(const char *ip, int port); +redisContext *redisConnectBindNonBlock(const char *ip, int port, + const char *source_addr); +redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, + const char *source_addr); +redisContext *redisConnectUnix(const char *path); +redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv); +redisContext *redisConnectUnixNonBlock(const char *path); +redisContext *redisConnectFd(int fd); + +/** + * Reconnect the given context using the saved information. + * + * This re-uses the exact same connect options as in the initial connection. + * host, ip (or path), timeout and bind address are reused, + * flags are used unmodified from the existing context. + * + * Returns REDIS_OK on successful connect or REDIS_ERR otherwise. + */ +int redisReconnect(redisContext *c); + +int redisSetTimeout(redisContext *c, const struct timeval tv); +int redisEnableKeepAlive(redisContext *c); +void redisFree(redisContext *c); +int redisFreeKeepFd(redisContext *c); +int redisBufferRead(redisContext *c); +int redisBufferWrite(redisContext *c, int *done); + +/* In a blocking context, this function first checks if there are unconsumed + * replies to return and returns one if so. Otherwise, it flushes the output + * buffer to the socket and reads until it has a reply. In a non-blocking + * context, it will return unconsumed replies until there are no more. */ +int redisGetReply(redisContext *c, void **reply); +int redisGetReplyFromReader(redisContext *c, void **reply); + +/* Write a formatted command to the output buffer. Use these functions in blocking mode + * to get a pipeline of commands. */ +int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len); + +/* Write a command to the output buffer. Use these functions in blocking mode + * to get a pipeline of commands. */ +int redisvAppendCommand(redisContext *c, const char *format, va_list ap); +int redisAppendCommand(redisContext *c, const char *format, ...); +int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); + +/* Issue a command to Redis. In a blocking context, it is identical to calling + * redisAppendCommand, followed by redisGetReply. The function will return + * NULL if there was an error in performing the request, otherwise it will + * return the reply. In a non-blocking context, it is identical to calling + * only redisAppendCommand and will always return NULL. */ +void *redisvCommand(redisContext *c, const char *format, va_list ap); +void *redisCommand(redisContext *c, const char *format, ...); +void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/debian/modules/nchan/src/hiredis/net.c b/debian/modules/nchan/src/hiredis/net.c new file mode 100644 index 0000000..60a2dc7 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/net.c @@ -0,0 +1,458 @@ +/* Extracted from anet.c to work properly with Hiredis error reporting. + * + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2014, Pieter Noordhuis + * Copyright (c) 2015, Matt Stancliff , + * Jan-Erik Rediger + * + * All rights reserved. + * + * 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 Redis 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. + */ + +#include "fmacros.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "net.h" +#include "sds.h" + +/* Defined in hiredis.c */ +void __redisSetError(redisContext *c, int type, const char *str); + +static void redisContextCloseFd(redisContext *c) { + if (c && c->fd >= 0) { + close(c->fd); + c->fd = -1; + } +} + +static void __redisSetErrorFromErrno(redisContext *c, int type, const char *prefix) { + char buf[128] = { 0 }; + size_t len = 0; + + if (prefix != NULL) + len = snprintf(buf,sizeof(buf),"%s: ",prefix); + __redis_strerror_r(errno, (char *)(buf + len), sizeof(buf) - len); + __redisSetError(c,type,buf); +} + +static int redisSetReuseAddr(redisContext *c) { + int on = 1; + if (setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { + __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); + redisContextCloseFd(c); + return REDIS_ERR; + } + return REDIS_OK; +} + +static int redisCreateSocket(redisContext *c, int type) { + int s; + if ((s = socket(type, SOCK_STREAM, 0)) == -1) { + __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); + return REDIS_ERR; + } + c->fd = s; + if (type == AF_INET) { + if (redisSetReuseAddr(c) == REDIS_ERR) { + return REDIS_ERR; + } + } + return REDIS_OK; +} + +static int redisSetBlocking(redisContext *c, int blocking) { + int flags; + + /* Set the socket nonblocking. + * Note that fcntl(2) for F_GETFL and F_SETFL can't be + * interrupted by a signal. */ + if ((flags = fcntl(c->fd, F_GETFL)) == -1) { + __redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_GETFL)"); + redisContextCloseFd(c); + return REDIS_ERR; + } + + if (blocking) + flags &= ~O_NONBLOCK; + else + flags |= O_NONBLOCK; + + if (fcntl(c->fd, F_SETFL, flags) == -1) { + __redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_SETFL)"); + redisContextCloseFd(c); + return REDIS_ERR; + } + return REDIS_OK; +} + +int redisKeepAlive(redisContext *c, int interval) { + int val = 1; + int fd = c->fd; + + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1){ + __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); + return REDIS_ERR; + } + + val = interval; + +#ifdef _OSX + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0) { + __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); + return REDIS_ERR; + } +#else +#if defined(__GLIBC__) && !defined(__FreeBSD_kernel__) + val = interval; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) { + __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); + return REDIS_ERR; + } + + val = interval/3; + if (val == 0) val = 1; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) { + __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); + return REDIS_ERR; + } + + val = 3; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) { + __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); + return REDIS_ERR; + } +#endif +#endif + + return REDIS_OK; +} + +static int redisSetTcpNoDelay(redisContext *c) { + int yes = 1; + if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) { + __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(TCP_NODELAY)"); + redisContextCloseFd(c); + return REDIS_ERR; + } + return REDIS_OK; +} + +#define __MAX_MSEC (((LONG_MAX) - 999) / 1000) + +static int redisContextWaitReady(redisContext *c, const struct timeval *timeout) { + struct pollfd wfd[1]; + long msec; + + msec = -1; + wfd[0].fd = c->fd; + wfd[0].events = POLLOUT; + + /* Only use timeout when not NULL. */ + if (timeout != NULL) { + if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) { + __redisSetErrorFromErrno(c, REDIS_ERR_IO, NULL); + redisContextCloseFd(c); + return REDIS_ERR; + } + + msec = (timeout->tv_sec * 1000) + ((timeout->tv_usec + 999) / 1000); + + if (msec < 0 || msec > INT_MAX) { + msec = INT_MAX; + } + } + + if (errno == EINPROGRESS) { + int res; + + if ((res = poll(wfd, 1, msec)) == -1) { + __redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)"); + redisContextCloseFd(c); + return REDIS_ERR; + } else if (res == 0) { + errno = ETIMEDOUT; + __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); + redisContextCloseFd(c); + return REDIS_ERR; + } + + if (redisCheckSocketError(c) != REDIS_OK) + return REDIS_ERR; + + return REDIS_OK; + } + + __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); + redisContextCloseFd(c); + return REDIS_ERR; +} + +int redisCheckSocketError(redisContext *c) { + int err = 0; + socklen_t errlen = sizeof(err); + + if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { + __redisSetErrorFromErrno(c,REDIS_ERR_IO,"getsockopt(SO_ERROR)"); + return REDIS_ERR; + } + + if (err) { + errno = err; + __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); + return REDIS_ERR; + } + + return REDIS_OK; +} + +int redisContextSetTimeout(redisContext *c, const struct timeval tv) { + if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)) == -1) { + __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_RCVTIMEO)"); + return REDIS_ERR; + } + if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,&tv,sizeof(tv)) == -1) { + __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_SNDTIMEO)"); + return REDIS_ERR; + } + return REDIS_OK; +} + +static int _redisContextConnectTcp(redisContext *c, const char *addr, int port, + const struct timeval *timeout, + const char *source_addr) { + int s, rv, n; + char _port[6]; /* strlen("65535"); */ + struct addrinfo hints, *servinfo, *bservinfo, *p, *b; + int blocking = (c->flags & REDIS_BLOCK); + int reuseaddr = (c->flags & REDIS_REUSEADDR); + int reuses = 0; + + c->connection_type = REDIS_CONN_TCP; + c->tcp.port = port; + + /* We need to take possession of the passed parameters + * to make them reusable for a reconnect. + * We also carefully check we don't free data we already own, + * as in the case of the reconnect method. + * + * This is a bit ugly, but atleast it works and doesn't leak memory. + **/ + if (c->tcp.host != addr) { + if (c->tcp.host) + free(c->tcp.host); + + c->tcp.host = strdup(addr); + } + + if (timeout) { + if (c->timeout != timeout) { + if (c->timeout == NULL) + c->timeout = malloc(sizeof(struct timeval)); + + memcpy(c->timeout, timeout, sizeof(struct timeval)); + } + } else { + if (c->timeout) + free(c->timeout); + c->timeout = NULL; + } + + if (source_addr == NULL) { + free(c->tcp.source_addr); + c->tcp.source_addr = NULL; + } else if (c->tcp.source_addr != source_addr) { + free(c->tcp.source_addr); + c->tcp.source_addr = strdup(source_addr); + } + + snprintf(_port, 6, "%d", port); + memset(&hints,0,sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + /* Try with IPv6 if no IPv4 address was found. We do it in this order since + * in a Redis client you can't afford to test if you have IPv6 connectivity + * as this would add latency to every connect. Otherwise a more sensible + * route could be: Use IPv6 if both addresses are available and there is IPv6 + * connectivity. */ + if ((rv = getaddrinfo(c->tcp.host,_port,&hints,&servinfo)) != 0) { + hints.ai_family = AF_INET6; + if ((rv = getaddrinfo(addr,_port,&hints,&servinfo)) != 0) { + __redisSetError(c,REDIS_ERR_OTHER,gai_strerror(rv)); + return REDIS_ERR; + } + } + for (p = servinfo; p != NULL; p = p->ai_next) { +addrretry: + if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1) + continue; + + c->fd = s; + if (redisSetBlocking(c,0) != REDIS_OK) + goto error; + if (c->tcp.source_addr) { + int bound = 0; + /* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */ + if ((rv = getaddrinfo(c->tcp.source_addr, NULL, &hints, &bservinfo)) != 0) { + char buf[128]; + snprintf(buf,sizeof(buf),"Can't get addr: %s",gai_strerror(rv)); + __redisSetError(c,REDIS_ERR_OTHER,buf); + goto error; + } + + if (reuseaddr) { + n = 1; + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*) &n, + sizeof(n)) < 0) { + goto error; + } + } + + for (b = bservinfo; b != NULL; b = b->ai_next) { + if (bind(s,b->ai_addr,b->ai_addrlen) != -1) { + bound = 1; + break; + } + } + freeaddrinfo(bservinfo); + if (!bound) { + char buf[128]; + snprintf(buf,sizeof(buf),"Can't bind socket: %s",strerror(errno)); + __redisSetError(c,REDIS_ERR_OTHER,buf); + goto error; + } + } + if (connect(s,p->ai_addr,p->ai_addrlen) == -1) { + if (errno == EHOSTUNREACH) { + redisContextCloseFd(c); + continue; + } else if (errno == EINPROGRESS && !blocking) { + /* This is ok. */ + } else if (errno == EADDRNOTAVAIL && reuseaddr) { + if (++reuses >= REDIS_CONNECT_RETRIES) { + goto error; + } else { + goto addrretry; + } + } else { + if (redisContextWaitReady(c,c->timeout) != REDIS_OK) + goto error; + } + } + if (blocking && redisSetBlocking(c,1) != REDIS_OK) + goto error; + if (redisSetTcpNoDelay(c) != REDIS_OK) + goto error; + + c->flags |= REDIS_CONNECTED; + rv = REDIS_OK; + goto end; + } + if (p == NULL) { + char buf[128]; + snprintf(buf,sizeof(buf),"Can't create socket: %s",strerror(errno)); + __redisSetError(c,REDIS_ERR_OTHER,buf); + goto error; + } + +error: + rv = REDIS_ERR; +end: + freeaddrinfo(servinfo); + return rv; // Need to return REDIS_OK if alright +} + +int redisContextConnectTcp(redisContext *c, const char *addr, int port, + const struct timeval *timeout) { + return _redisContextConnectTcp(c, addr, port, timeout, NULL); +} + +int redisContextConnectBindTcp(redisContext *c, const char *addr, int port, + const struct timeval *timeout, + const char *source_addr) { + return _redisContextConnectTcp(c, addr, port, timeout, source_addr); +} + +int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout) { + int blocking = (c->flags & REDIS_BLOCK); + struct sockaddr_un sa; + + if (redisCreateSocket(c,AF_LOCAL) < 0) + return REDIS_ERR; + if (redisSetBlocking(c,0) != REDIS_OK) + return REDIS_ERR; + + c->connection_type = REDIS_CONN_UNIX; + if (c->unix_sock.path != path) + c->unix_sock.path = strdup(path); + + if (timeout) { + if (c->timeout != timeout) { + if (c->timeout == NULL) + c->timeout = malloc(sizeof(struct timeval)); + + memcpy(c->timeout, timeout, sizeof(struct timeval)); + } + } else { + if (c->timeout) + free(c->timeout); + c->timeout = NULL; + } + + sa.sun_family = AF_LOCAL; + strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1); + if (connect(c->fd, (struct sockaddr*)&sa, sizeof(sa)) == -1) { + if (errno == EINPROGRESS && !blocking) { + /* This is ok. */ + } else { + if (redisContextWaitReady(c,c->timeout) != REDIS_OK) + return REDIS_ERR; + } + } + + /* Reset socket to be blocking after connect(2). */ + if (blocking && redisSetBlocking(c,1) != REDIS_OK) + return REDIS_ERR; + + c->flags |= REDIS_CONNECTED; + return REDIS_OK; +} diff --git a/debian/modules/nchan/src/hiredis/net.h b/debian/modules/nchan/src/hiredis/net.h new file mode 100644 index 0000000..2f1a0bf --- /dev/null +++ b/debian/modules/nchan/src/hiredis/net.h @@ -0,0 +1,53 @@ +/* Extracted from anet.c to work properly with Hiredis error reporting. + * + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2014, Pieter Noordhuis + * Copyright (c) 2015, Matt Stancliff , + * Jan-Erik Rediger + * + * All rights reserved. + * + * 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 Redis 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. + */ + +#ifndef __NET_H +#define __NET_H + +#include "hiredis.h" + +#if defined(__sun) +#define AF_LOCAL AF_UNIX +#endif + +int redisCheckSocketError(redisContext *c); +int redisContextSetTimeout(redisContext *c, const struct timeval tv); +int redisContextConnectTcp(redisContext *c, const char *addr, int port, const struct timeval *timeout); +int redisContextConnectBindTcp(redisContext *c, const char *addr, int port, + const struct timeval *timeout, + const char *source_addr); +int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout); +int redisKeepAlive(redisContext *c, int interval); + +#endif diff --git a/debian/modules/nchan/src/hiredis/read.c b/debian/modules/nchan/src/hiredis/read.c new file mode 100644 index 0000000..df1a467 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/read.c @@ -0,0 +1,525 @@ +/* + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2011, Pieter Noordhuis + * + * All rights reserved. + * + * 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 Redis 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. + */ + + +#include "fmacros.h" +#include +#include +#ifndef _MSC_VER +#include +#endif +#include +#include +#include + +#include "read.h" +#include "sds.h" + +static void __redisReaderSetError(redisReader *r, int type, const char *str) { + size_t len; + + if (r->reply != NULL && r->fn && r->fn->freeObject) { + r->fn->freeObject(r->reply); + r->reply = NULL; + } + + /* Clear input buffer on errors. */ + if (r->buf != NULL) { + sdsfree(r->buf); + r->buf = NULL; + r->pos = r->len = 0; + } + + /* Reset task stack. */ + r->ridx = -1; + + /* Set error. */ + r->err = type; + len = strlen(str); + len = len < (sizeof(r->errstr)-1) ? len : (sizeof(r->errstr)-1); + memcpy(r->errstr,str,len); + r->errstr[len] = '\0'; +} + +static size_t chrtos(char *buf, size_t size, char byte) { + size_t len = 0; + + switch(byte) { + case '\\': + case '"': + len = snprintf(buf,size,"\"\\%c\"",byte); + break; + case '\n': len = snprintf(buf,size,"\"\\n\""); break; + case '\r': len = snprintf(buf,size,"\"\\r\""); break; + case '\t': len = snprintf(buf,size,"\"\\t\""); break; + case '\a': len = snprintf(buf,size,"\"\\a\""); break; + case '\b': len = snprintf(buf,size,"\"\\b\""); break; + default: + if (isprint(byte)) + len = snprintf(buf,size,"\"%c\"",byte); + else + len = snprintf(buf,size,"\"\\x%02x\"",(unsigned char)byte); + break; + } + + return len; +} + +static void __redisReaderSetErrorProtocolByte(redisReader *r, char byte) { + char cbuf[8], sbuf[128]; + + chrtos(cbuf,sizeof(cbuf),byte); + snprintf(sbuf,sizeof(sbuf), + "Protocol error, got %s as reply type byte", cbuf); + __redisReaderSetError(r,REDIS_ERR_PROTOCOL,sbuf); +} + +static void __redisReaderSetErrorOOM(redisReader *r) { + __redisReaderSetError(r,REDIS_ERR_OOM,"Out of memory"); +} + +static char *readBytes(redisReader *r, unsigned int bytes) { + char *p; + if (r->len-r->pos >= bytes) { + p = r->buf+r->pos; + r->pos += bytes; + return p; + } + return NULL; +} + +/* Find pointer to \r\n. */ +static char *seekNewline(char *s, size_t len) { + int pos = 0; + int _len = len-1; + + /* Position should be < len-1 because the character at "pos" should be + * followed by a \n. Note that strchr cannot be used because it doesn't + * allow to search a limited length and the buffer that is being searched + * might not have a trailing NULL character. */ + while (pos < _len) { + while(pos < _len && s[pos] != '\r') pos++; + if (s[pos] != '\r') { + /* Not found. */ + return NULL; + } else { + if (s[pos+1] == '\n') { + /* Found. */ + return s+pos; + } else { + /* Continue searching. */ + pos++; + } + } + } + return NULL; +} + +/* Read a long long value starting at *s, under the assumption that it will be + * terminated by \r\n. Ambiguously returns -1 for unexpected input. */ +static long long readLongLong(char *s) { + long long v = 0; + int dec, mult = 1; + char c; + + if (*s == '-') { + mult = -1; + s++; + } else if (*s == '+') { + mult = 1; + s++; + } + + while ((c = *(s++)) != '\r') { + dec = c - '0'; + if (dec >= 0 && dec < 10) { + v *= 10; + v += dec; + } else { + /* Should not happen... */ + return -1; + } + } + + return mult*v; +} + +static char *readLine(redisReader *r, int *_len) { + char *p, *s; + int len; + + p = r->buf+r->pos; + s = seekNewline(p,(r->len-r->pos)); + if (s != NULL) { + len = s-(r->buf+r->pos); + r->pos += len+2; /* skip \r\n */ + if (_len) *_len = len; + return p; + } + return NULL; +} + +static void moveToNextTask(redisReader *r) { + redisReadTask *cur, *prv; + while (r->ridx >= 0) { + /* Return a.s.a.p. when the stack is now empty. */ + if (r->ridx == 0) { + r->ridx--; + return; + } + + cur = &(r->rstack[r->ridx]); + prv = &(r->rstack[r->ridx-1]); + assert(prv->type == REDIS_REPLY_ARRAY); + if (cur->idx == prv->elements-1) { + r->ridx--; + } else { + /* Reset the type because the next item can be anything */ + assert(cur->idx < prv->elements); + cur->type = -1; + cur->elements = -1; + cur->idx++; + return; + } + } +} + +static int processLineItem(redisReader *r) { + redisReadTask *cur = &(r->rstack[r->ridx]); + void *obj; + char *p; + int len; + + if ((p = readLine(r,&len)) != NULL) { + if (cur->type == REDIS_REPLY_INTEGER) { + if (r->fn && r->fn->createInteger) + obj = r->fn->createInteger(cur,readLongLong(p)); + else + obj = (void*)REDIS_REPLY_INTEGER; + } else { + /* Type will be error or status. */ + if (r->fn && r->fn->createString) + obj = r->fn->createString(cur,p,len); + else + obj = (void*)(size_t)(cur->type); + } + + if (obj == NULL) { + __redisReaderSetErrorOOM(r); + return REDIS_ERR; + } + + /* Set reply if this is the root object. */ + if (r->ridx == 0) r->reply = obj; + moveToNextTask(r); + return REDIS_OK; + } + + return REDIS_ERR; +} + +static int processBulkItem(redisReader *r) { + redisReadTask *cur = &(r->rstack[r->ridx]); + void *obj = NULL; + char *p, *s; + long len; + unsigned long bytelen; + int success = 0; + + p = r->buf+r->pos; + s = seekNewline(p,r->len-r->pos); + if (s != NULL) { + p = r->buf+r->pos; + bytelen = s-(r->buf+r->pos)+2; /* include \r\n */ + len = readLongLong(p); + + if (len < 0) { + /* The nil object can always be created. */ + if (r->fn && r->fn->createNil) + obj = r->fn->createNil(cur); + else + obj = (void*)REDIS_REPLY_NIL; + success = 1; + } else { + /* Only continue when the buffer contains the entire bulk item. */ + bytelen += len+2; /* include \r\n */ + if (r->pos+bytelen <= r->len) { + if (r->fn && r->fn->createString) + obj = r->fn->createString(cur,s+2,len); + else + obj = (void*)REDIS_REPLY_STRING; + success = 1; + } + } + + /* Proceed when obj was created. */ + if (success) { + if (obj == NULL) { + __redisReaderSetErrorOOM(r); + return REDIS_ERR; + } + + r->pos += bytelen; + + /* Set reply if this is the root object. */ + if (r->ridx == 0) r->reply = obj; + moveToNextTask(r); + return REDIS_OK; + } + } + + return REDIS_ERR; +} + +static int processMultiBulkItem(redisReader *r) { + redisReadTask *cur = &(r->rstack[r->ridx]); + void *obj; + char *p; + long elements; + int root = 0; + + /* Set error for nested multi bulks with depth > 7 */ + if (r->ridx == 8) { + __redisReaderSetError(r,REDIS_ERR_PROTOCOL, + "No support for nested multi bulk replies with depth > 7"); + return REDIS_ERR; + } + + if ((p = readLine(r,NULL)) != NULL) { + elements = readLongLong(p); + root = (r->ridx == 0); + + if (elements == -1) { + if (r->fn && r->fn->createNil) + obj = r->fn->createNil(cur); + else + obj = (void*)REDIS_REPLY_NIL; + + if (obj == NULL) { + __redisReaderSetErrorOOM(r); + return REDIS_ERR; + } + + moveToNextTask(r); + } else { + if (r->fn && r->fn->createArray) + obj = r->fn->createArray(cur,elements); + else + obj = (void*)REDIS_REPLY_ARRAY; + + if (obj == NULL) { + __redisReaderSetErrorOOM(r); + return REDIS_ERR; + } + + /* Modify task stack when there are more than 0 elements. */ + if (elements > 0) { + cur->elements = elements; + cur->obj = obj; + r->ridx++; + r->rstack[r->ridx].type = -1; + r->rstack[r->ridx].elements = -1; + r->rstack[r->ridx].idx = 0; + r->rstack[r->ridx].obj = NULL; + r->rstack[r->ridx].parent = cur; + r->rstack[r->ridx].privdata = r->privdata; + } else { + moveToNextTask(r); + } + } + + /* Set reply if this is the root object. */ + if (root) r->reply = obj; + return REDIS_OK; + } + + return REDIS_ERR; +} + +static int processItem(redisReader *r) { + redisReadTask *cur = &(r->rstack[r->ridx]); + char *p; + + /* check if we need to read type */ + if (cur->type < 0) { + if ((p = readBytes(r,1)) != NULL) { + switch (p[0]) { + case '-': + cur->type = REDIS_REPLY_ERROR; + break; + case '+': + cur->type = REDIS_REPLY_STATUS; + break; + case ':': + cur->type = REDIS_REPLY_INTEGER; + break; + case '$': + cur->type = REDIS_REPLY_STRING; + break; + case '*': + cur->type = REDIS_REPLY_ARRAY; + break; + default: + __redisReaderSetErrorProtocolByte(r,*p); + return REDIS_ERR; + } + } else { + /* could not consume 1 byte */ + return REDIS_ERR; + } + } + + /* process typed item */ + switch(cur->type) { + case REDIS_REPLY_ERROR: + case REDIS_REPLY_STATUS: + case REDIS_REPLY_INTEGER: + return processLineItem(r); + case REDIS_REPLY_STRING: + return processBulkItem(r); + case REDIS_REPLY_ARRAY: + return processMultiBulkItem(r); + default: + assert(NULL); + return REDIS_ERR; /* Avoid warning. */ + } +} + +redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) { + redisReader *r; + + r = calloc(sizeof(redisReader),1); + if (r == NULL) + return NULL; + + r->err = 0; + r->errstr[0] = '\0'; + r->fn = fn; + r->buf = sdsempty(); + r->maxbuf = REDIS_READER_MAX_BUF; + if (r->buf == NULL) { + free(r); + return NULL; + } + + r->ridx = -1; + return r; +} + +void redisReaderFree(redisReader *r) { + if (r->reply != NULL && r->fn && r->fn->freeObject) + r->fn->freeObject(r->reply); + if (r->buf != NULL) + sdsfree(r->buf); + free(r); +} + +int redisReaderFeed(redisReader *r, const char *buf, size_t len) { + sds newbuf; + + /* Return early when this reader is in an erroneous state. */ + if (r->err) + return REDIS_ERR; + + /* Copy the provided buffer. */ + if (buf != NULL && len >= 1) { + /* Destroy internal buffer when it is empty and is quite large. */ + if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) { + sdsfree(r->buf); + r->buf = sdsempty(); + r->pos = 0; + + /* r->buf should not be NULL since we just free'd a larger one. */ + assert(r->buf != NULL); + } + + newbuf = sdscatlen(r->buf,buf,len); + if (newbuf == NULL) { + __redisReaderSetErrorOOM(r); + return REDIS_ERR; + } + + r->buf = newbuf; + r->len = sdslen(r->buf); + } + + return REDIS_OK; +} + +int redisReaderGetReply(redisReader *r, void **reply) { + /* Default target pointer to NULL. */ + if (reply != NULL) + *reply = NULL; + + /* Return early when this reader is in an erroneous state. */ + if (r->err) + return REDIS_ERR; + + /* When the buffer is empty, there will never be a reply. */ + if (r->len == 0) + return REDIS_OK; + + /* Set first item to process when the stack is empty. */ + if (r->ridx == -1) { + r->rstack[0].type = -1; + r->rstack[0].elements = -1; + r->rstack[0].idx = -1; + r->rstack[0].obj = NULL; + r->rstack[0].parent = NULL; + r->rstack[0].privdata = r->privdata; + r->ridx = 0; + } + + /* Process items in reply. */ + while (r->ridx >= 0) + if (processItem(r) != REDIS_OK) + break; + + /* Return ASAP when an error occurred. */ + if (r->err) + return REDIS_ERR; + + /* Discard part of the buffer when we've consumed at least 1k, to avoid + * doing unnecessary calls to memmove() in sds.c. */ + if (r->pos >= 1024) { + sdsrange(r->buf,r->pos,-1); + r->pos = 0; + r->len = sdslen(r->buf); + } + + /* Emit a reply when there is one. */ + if (r->ridx == -1) { + if (reply != NULL) + *reply = r->reply; + r->reply = NULL; + } + return REDIS_OK; +} diff --git a/debian/modules/nchan/src/hiredis/read.h b/debian/modules/nchan/src/hiredis/read.h new file mode 100644 index 0000000..180e6c6 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/read.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2011, Pieter Noordhuis + * + * All rights reserved. + * + * 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 Redis 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. + */ + + +#ifndef __HIREDIS_READ_H +#define __HIREDIS_READ_H +#include /* for size_t */ + +#define REDIS_ERR -1 +#define REDIS_OK 0 + +/* When an error occurs, the err flag in a context is set to hold the type of + * error that occurred. REDIS_ERR_IO means there was an I/O error and you + * should use the "errno" variable to find out what is wrong. + * For other values, the "errstr" field will hold a description. */ +#define REDIS_ERR_IO 1 /* Error in read or write */ +#define REDIS_ERR_EOF 3 /* End of file */ +#define REDIS_ERR_PROTOCOL 4 /* Protocol error */ +#define REDIS_ERR_OOM 5 /* Out of memory */ +#define REDIS_ERR_OTHER 2 /* Everything else... */ + +#define REDIS_REPLY_STRING 1 +#define REDIS_REPLY_ARRAY 2 +#define REDIS_REPLY_INTEGER 3 +#define REDIS_REPLY_NIL 4 +#define REDIS_REPLY_STATUS 5 +#define REDIS_REPLY_ERROR 6 + +#define REDIS_READER_MAX_BUF (1024*16) /* Default max unused reader buffer. */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct redisReadTask { + int type; + int elements; /* number of elements in multibulk container */ + int idx; /* index in parent (array) object */ + void *obj; /* holds user-generated value for a read task */ + struct redisReadTask *parent; /* parent task */ + void *privdata; /* user-settable arbitrary field */ +} redisReadTask; + +typedef struct redisReplyObjectFunctions { + void *(*createString)(const redisReadTask*, char*, size_t); + void *(*createArray)(const redisReadTask*, int); + void *(*createInteger)(const redisReadTask*, long long); + void *(*createNil)(const redisReadTask*); + void (*freeObject)(void*); +} redisReplyObjectFunctions; + +typedef struct redisReader { + int err; /* Error flags, 0 when there is no error */ + char errstr[128]; /* String representation of error when applicable */ + + char *buf; /* Read buffer */ + size_t pos; /* Buffer cursor */ + size_t len; /* Buffer length */ + size_t maxbuf; /* Max length of unused buffer */ + + redisReadTask rstack[9]; + int ridx; /* Index of current read task */ + void *reply; /* Temporary reply pointer */ + + redisReplyObjectFunctions *fn; + void *privdata; +} redisReader; + +/* Public API for the protocol parser. */ +redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn); +void redisReaderFree(redisReader *r); +int redisReaderFeed(redisReader *r, const char *buf, size_t len); +int redisReaderGetReply(redisReader *r, void **reply); + +/* Backwards compatibility, can be removed on big version bump. */ +#define redisReplyReaderCreate redisReaderCreate +#define redisReplyReaderFree redisReaderFree +#define redisReplyReaderFeed redisReaderFeed +#define redisReplyReaderGetReply redisReaderGetReply +#define redisReplyReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p)) +#define redisReplyReaderGetObject(_r) (((redisReader*)(_r))->reply) +#define redisReplyReaderGetError(_r) (((redisReader*)(_r))->errstr) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/debian/modules/nchan/src/hiredis/sds.c b/debian/modules/nchan/src/hiredis/sds.c new file mode 100644 index 0000000..f01247d --- /dev/null +++ b/debian/modules/nchan/src/hiredis/sds.c @@ -0,0 +1,1095 @@ +/* SDS (Simple Dynamic Strings), A C dynamic strings library. + * + * Copyright (c) 2006-2014, Salvatore Sanfilippo + * All rights reserved. + * + * 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 Redis 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. + */ + +#include +#include +#include +#include +#include + +#include "sds.h" + +/* Create a new sds string with the content specified by the 'init' pointer + * and 'initlen'. + * If NULL is used for 'init' the string is initialized with zero bytes. + * + * The string is always null-termined (all the sds strings are, always) so + * even if you create an sds string with: + * + * mystring = sdsnewlen("abc",3"); + * + * You can print the string with printf() as there is an implicit \0 at the + * end of the string. However the string is binary safe and can contain + * \0 characters in the middle, as the length is stored in the sds header. */ +sds sdsnewlen(const void *init, size_t initlen) { + struct sdshdr *sh; + + if (init) { + sh = malloc(sizeof *sh+initlen+1); + } else { + sh = calloc(sizeof *sh+initlen+1,1); + } + if (sh == NULL) return NULL; + sh->len = initlen; + sh->free = 0; + if (initlen && init) + memcpy(sh->buf, init, initlen); + sh->buf[initlen] = '\0'; + return (char*)sh->buf; +} + +/* Create an empty (zero length) sds string. Even in this case the string + * always has an implicit null term. */ +sds sdsempty(void) { + return sdsnewlen("",0); +} + +/* Create a new sds string starting from a null termined C string. */ +sds sdsnew(const char *init) { + size_t initlen = (init == NULL) ? 0 : strlen(init); + return sdsnewlen(init, initlen); +} + +/* Duplicate an sds string. */ +sds sdsdup(const sds s) { + return sdsnewlen(s, sdslen(s)); +} + +/* Free an sds string. No operation is performed if 's' is NULL. */ +void sdsfree(sds s) { + if (s == NULL) return; + free(s-sizeof(struct sdshdr)); +} + +/* Set the sds string length to the length as obtained with strlen(), so + * considering as content only up to the first null term character. + * + * This function is useful when the sds string is hacked manually in some + * way, like in the following example: + * + * s = sdsnew("foobar"); + * s[2] = '\0'; + * sdsupdatelen(s); + * printf("%d\n", sdslen(s)); + * + * The output will be "2", but if we comment out the call to sdsupdatelen() + * the output will be "6" as the string was modified but the logical length + * remains 6 bytes. */ +void sdsupdatelen(sds s) { + struct sdshdr *sh = (void*) (s-sizeof *sh); + int reallen = strlen(s); + sh->free += (sh->len-reallen); + sh->len = reallen; +} + +/* Modify an sds string on-place to make it empty (zero length). + * However all the existing buffer is not discarded but set as free space + * so that next append operations will not require allocations up to the + * number of bytes previously available. */ +void sdsclear(sds s) { + struct sdshdr *sh = (void*) (s-sizeof *sh); + sh->free += sh->len; + sh->len = 0; + sh->buf[0] = '\0'; +} + +/* Enlarge the free space at the end of the sds string so that the caller + * is sure that after calling this function can overwrite up to addlen + * bytes after the end of the string, plus one more byte for nul term. + * + * Note: this does not change the *length* of the sds string as returned + * by sdslen(), but only the free buffer space we have. */ +sds sdsMakeRoomFor(sds s, size_t addlen) { + struct sdshdr *sh, *newsh; + size_t free = sdsavail(s); + size_t len, newlen; + + if (free >= addlen) return s; + len = sdslen(s); + sh = (void*) (s-sizeof *sh); + newlen = (len+addlen); + if (newlen < SDS_MAX_PREALLOC) + newlen *= 2; + else + newlen += SDS_MAX_PREALLOC; + newsh = realloc(sh, sizeof *newsh+newlen+1); + if (newsh == NULL) return NULL; + + newsh->free = newlen - len; + return newsh->buf; +} + +/* Reallocate the sds string so that it has no free space at the end. The + * contained string remains not altered, but next concatenation operations + * will require a reallocation. + * + * After the call, the passed sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. */ +sds sdsRemoveFreeSpace(sds s) { + struct sdshdr *sh; + + sh = (void*) (s-sizeof *sh); + sh = realloc(sh, sizeof *sh+sh->len+1); + sh->free = 0; + return sh->buf; +} + +/* Return the total size of the allocation of the specifed sds string, + * including: + * 1) The sds header before the pointer. + * 2) The string. + * 3) The free buffer at the end if any. + * 4) The implicit null term. + */ +size_t sdsAllocSize(sds s) { + struct sdshdr *sh = (void*) (s-sizeof *sh); + + return sizeof(*sh)+sh->len+sh->free+1; +} + +/* Increment the sds length and decrements the left free space at the + * end of the string according to 'incr'. Also set the null term + * in the new end of the string. + * + * This function is used in order to fix the string length after the + * user calls sdsMakeRoomFor(), writes something after the end of + * the current string, and finally needs to set the new length. + * + * Note: it is possible to use a negative increment in order to + * right-trim the string. + * + * Usage example: + * + * Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the + * following schema, to cat bytes coming from the kernel to the end of an + * sds string without copying into an intermediate buffer: + * + * oldlen = sdslen(s); + * s = sdsMakeRoomFor(s, BUFFER_SIZE); + * nread = read(fd, s+oldlen, BUFFER_SIZE); + * ... check for nread <= 0 and handle it ... + * sdsIncrLen(s, nread); + */ +void sdsIncrLen(sds s, int incr) { + struct sdshdr *sh = (void*) (s-sizeof *sh); + + assert(sh->free >= incr); + sh->len += incr; + sh->free -= incr; + assert(sh->free >= 0); + s[sh->len] = '\0'; +} + +/* Grow the sds to have the specified length. Bytes that were not part of + * the original length of the sds will be set to zero. + * + * if the specified length is smaller than the current length, no operation + * is performed. */ +sds sdsgrowzero(sds s, size_t len) { + struct sdshdr *sh = (void*) (s-sizeof *sh); + size_t totlen, curlen = sh->len; + + if (len <= curlen) return s; + s = sdsMakeRoomFor(s,len-curlen); + if (s == NULL) return NULL; + + /* Make sure added region doesn't contain garbage */ + sh = (void*)(s-sizeof *sh); + memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */ + totlen = sh->len+sh->free; + sh->len = len; + sh->free = totlen-sh->len; + return s; +} + +/* Append the specified binary-safe string pointed by 't' of 'len' bytes to the + * end of the specified sds string 's'. + * + * After the call, the passed sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. */ +sds sdscatlen(sds s, const void *t, size_t len) { + struct sdshdr *sh; + size_t curlen = sdslen(s); + + s = sdsMakeRoomFor(s,len); + if (s == NULL) return NULL; + sh = (void*) (s-sizeof *sh); + memcpy(s+curlen, t, len); + sh->len = curlen+len; + sh->free = sh->free-len; + s[curlen+len] = '\0'; + return s; +} + +/* Append the specified null termianted C string to the sds string 's'. + * + * After the call, the passed sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. */ +sds sdscat(sds s, const char *t) { + return sdscatlen(s, t, strlen(t)); +} + +/* Append the specified sds 't' to the existing sds 's'. + * + * After the call, the modified sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. */ +sds sdscatsds(sds s, const sds t) { + return sdscatlen(s, t, sdslen(t)); +} + +/* Destructively modify the sds string 's' to hold the specified binary + * safe string pointed by 't' of length 'len' bytes. */ +sds sdscpylen(sds s, const char *t, size_t len) { + struct sdshdr *sh = (void*) (s-sizeof *sh); + size_t totlen = sh->free+sh->len; + + if (totlen < len) { + s = sdsMakeRoomFor(s,len-sh->len); + if (s == NULL) return NULL; + sh = (void*) (s-sizeof *sh); + totlen = sh->free+sh->len; + } + memcpy(s, t, len); + s[len] = '\0'; + sh->len = len; + sh->free = totlen-len; + return s; +} + +/* Like sdscpylen() but 't' must be a null-termined string so that the length + * of the string is obtained with strlen(). */ +sds sdscpy(sds s, const char *t) { + return sdscpylen(s, t, strlen(t)); +} + +/* Helper for sdscatlonglong() doing the actual number -> string + * conversion. 's' must point to a string with room for at least + * SDS_LLSTR_SIZE bytes. + * + * The function returns the length of the null-terminated string + * representation stored at 's'. */ +#define SDS_LLSTR_SIZE 21 +int sdsll2str(char *s, long long value) { + char *p, aux; + unsigned long long v; + size_t l; + + /* Generate the string representation, this method produces + * an reversed string. */ + v = (value < 0) ? -value : value; + p = s; + do { + *p++ = '0'+(v%10); + v /= 10; + } while(v); + if (value < 0) *p++ = '-'; + + /* Compute length and add null term. */ + l = p-s; + *p = '\0'; + + /* Reverse the string. */ + p--; + while(s < p) { + aux = *s; + *s = *p; + *p = aux; + s++; + p--; + } + return l; +} + +/* Identical sdsll2str(), but for unsigned long long type. */ +int sdsull2str(char *s, unsigned long long v) { + char *p, aux; + size_t l; + + /* Generate the string representation, this method produces + * an reversed string. */ + p = s; + do { + *p++ = '0'+(v%10); + v /= 10; + } while(v); + + /* Compute length and add null term. */ + l = p-s; + *p = '\0'; + + /* Reverse the string. */ + p--; + while(s < p) { + aux = *s; + *s = *p; + *p = aux; + s++; + p--; + } + return l; +} + +/* Like sdscatpritf() but gets va_list instead of being variadic. */ +sds sdscatvprintf(sds s, const char *fmt, va_list ap) { + va_list cpy; + char *buf, *t; + size_t buflen = 16; + + while(1) { + buf = malloc(buflen); + if (buf == NULL) return NULL; + buf[buflen-2] = '\0'; + va_copy(cpy,ap); + vsnprintf(buf, buflen, fmt, cpy); + if (buf[buflen-2] != '\0') { + free(buf); + buflen *= 2; + continue; + } + break; + } + t = sdscat(s, buf); + free(buf); + return t; +} + +/* Append to the sds string 's' a string obtained using printf-alike format + * specifier. + * + * After the call, the modified sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. + * + * Example: + * + * s = sdsnew("Sum is: "); + * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b); + * + * Often you need to create a string from scratch with the printf-alike + * format. When this is the need, just use sdsempty() as the target string: + * + * s = sdscatprintf(sdsempty(), "... your format ...", args); + */ +sds sdscatprintf(sds s, const char *fmt, ...) { + va_list ap; + char *t; + va_start(ap, fmt); + t = sdscatvprintf(s,fmt,ap); + va_end(ap); + return t; +} + +/* This function is similar to sdscatprintf, but much faster as it does + * not rely on sprintf() family functions implemented by the libc that + * are often very slow. Moreover directly handling the sds string as + * new data is concatenated provides a performance improvement. + * + * However this function only handles an incompatible subset of printf-alike + * format specifiers: + * + * %s - C String + * %S - SDS string + * %i - signed int + * %I - 64 bit signed integer (long long, int64_t) + * %u - unsigned int + * %U - 64 bit unsigned integer (unsigned long long, uint64_t) + * %T - A size_t variable. + * %% - Verbatim "%" character. + */ +sds sdscatfmt(sds s, char const *fmt, ...) { + struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr))); + size_t initlen = sdslen(s); + const char *f = fmt; + int i; + va_list ap; + + va_start(ap,fmt); + f = fmt; /* Next format specifier byte to process. */ + i = initlen; /* Position of the next byte to write to dest str. */ + while(*f) { + char next, *str; + int l; + long long num; + unsigned long long unum; + + /* Make sure there is always space for at least 1 char. */ + if (sh->free == 0) { + s = sdsMakeRoomFor(s,1); + sh = (void*) (s-(sizeof(struct sdshdr))); + } + + switch(*f) { + case '%': + next = *(f+1); + f++; + switch(next) { + case 's': + case 'S': + str = va_arg(ap,char*); + l = (next == 's') ? strlen(str) : sdslen(str); + if (sh->free < l) { + s = sdsMakeRoomFor(s,l); + sh = (void*) (s-(sizeof(struct sdshdr))); + } + memcpy(s+i,str,l); + sh->len += l; + sh->free -= l; + i += l; + break; + case 'i': + case 'I': + if (next == 'i') + num = va_arg(ap,int); + else + num = va_arg(ap,long long); + { + char buf[SDS_LLSTR_SIZE]; + l = sdsll2str(buf,num); + if (sh->free < l) { + s = sdsMakeRoomFor(s,l); + sh = (void*) (s-(sizeof(struct sdshdr))); + } + memcpy(s+i,buf,l); + sh->len += l; + sh->free -= l; + i += l; + } + break; + case 'u': + case 'U': + case 'T': + if (next == 'u') + unum = va_arg(ap,unsigned int); + else if(next == 'U') + unum = va_arg(ap,unsigned long long); + else + unum = (unsigned long long)va_arg(ap,size_t); + { + char buf[SDS_LLSTR_SIZE]; + l = sdsull2str(buf,unum); + if (sh->free < l) { + s = sdsMakeRoomFor(s,l); + sh = (void*) (s-(sizeof(struct sdshdr))); + } + memcpy(s+i,buf,l); + sh->len += l; + sh->free -= l; + i += l; + } + break; + default: /* Handle %% and generally %. */ + s[i++] = next; + sh->len += 1; + sh->free -= 1; + break; + } + break; + default: + s[i++] = *f; + sh->len += 1; + sh->free -= 1; + break; + } + f++; + } + va_end(ap); + + /* Add null-term */ + s[i] = '\0'; + return s; +} + + +/* Remove the part of the string from left and from right composed just of + * contiguous characters found in 'cset', that is a null terminted C string. + * + * After the call, the modified sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. + * + * Example: + * + * s = sdsnew("AA...AA.a.aa.aHelloWorld :::"); + * s = sdstrim(s,"A. :"); + * printf("%s\n", s); + * + * Output will be just "Hello World". + */ +void sdstrim(sds s, const char *cset) { + struct sdshdr *sh = (void*) (s-sizeof *sh); + char *start, *end, *sp, *ep; + size_t len; + + sp = start = s; + ep = end = s+sdslen(s)-1; + while(sp <= end && strchr(cset, *sp)) sp++; + while(ep > start && strchr(cset, *ep)) ep--; + len = (sp > ep) ? 0 : ((ep-sp)+1); + if (sh->buf != sp) memmove(sh->buf, sp, len); + sh->buf[len] = '\0'; + sh->free = sh->free+(sh->len-len); + sh->len = len; +} + +/* Turn the string into a smaller (or equal) string containing only the + * substring specified by the 'start' and 'end' indexes. + * + * start and end can be negative, where -1 means the last character of the + * string, -2 the penultimate character, and so forth. + * + * The interval is inclusive, so the start and end characters will be part + * of the resulting string. + * + * The string is modified in-place. + * + * Example: + * + * s = sdsnew("Hello World"); + * sdsrange(s,1,-1); => "ello World" + */ +void sdsrange(sds s, int start, int end) { + struct sdshdr *sh = (void*) (s-sizeof *sh); + size_t newlen, len = sdslen(s); + + if (len == 0) return; + if (start < 0) { + start = len+start; + if (start < 0) start = 0; + } + if (end < 0) { + end = len+end; + if (end < 0) end = 0; + } + newlen = (start > end) ? 0 : (end-start)+1; + if (newlen != 0) { + if (start >= (signed)len) { + newlen = 0; + } else if (end >= (signed)len) { + end = len-1; + newlen = (start > end) ? 0 : (end-start)+1; + } + } else { + start = 0; + } + if (start && newlen) memmove(sh->buf, sh->buf+start, newlen); + sh->buf[newlen] = 0; + sh->free = sh->free+(sh->len-newlen); + sh->len = newlen; +} + +/* Apply tolower() to every character of the sds string 's'. */ +void sdstolower(sds s) { + int len = sdslen(s), j; + + for (j = 0; j < len; j++) s[j] = tolower(s[j]); +} + +/* Apply toupper() to every character of the sds string 's'. */ +void sdstoupper(sds s) { + int len = sdslen(s), j; + + for (j = 0; j < len; j++) s[j] = toupper(s[j]); +} + +/* Compare two sds strings s1 and s2 with memcmp(). + * + * Return value: + * + * 1 if s1 > s2. + * -1 if s1 < s2. + * 0 if s1 and s2 are exactly the same binary string. + * + * If two strings share exactly the same prefix, but one of the two has + * additional characters, the longer string is considered to be greater than + * the smaller one. */ +int sdscmp(const sds s1, const sds s2) { + size_t l1, l2, minlen; + int cmp; + + l1 = sdslen(s1); + l2 = sdslen(s2); + minlen = (l1 < l2) ? l1 : l2; + cmp = memcmp(s1,s2,minlen); + if (cmp == 0) return l1-l2; + return cmp; +} + +/* Split 's' with separator in 'sep'. An array + * of sds strings is returned. *count will be set + * by reference to the number of tokens returned. + * + * On out of memory, zero length string, zero length + * separator, NULL is returned. + * + * Note that 'sep' is able to split a string using + * a multi-character separator. For example + * sdssplit("foo_-_bar","_-_"); will return two + * elements "foo" and "bar". + * + * This version of the function is binary-safe but + * requires length arguments. sdssplit() is just the + * same function but for zero-terminated strings. + */ +sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count) { + int elements = 0, slots = 5, start = 0, j; + sds *tokens; + + if (seplen < 1 || len < 0) return NULL; + + tokens = malloc(sizeof(sds)*slots); + if (tokens == NULL) return NULL; + + if (len == 0) { + *count = 0; + return tokens; + } + for (j = 0; j < (len-(seplen-1)); j++) { + /* make sure there is room for the next element and the final one */ + if (slots < elements+2) { + sds *newtokens; + + slots *= 2; + newtokens = realloc(tokens,sizeof(sds)*slots); + if (newtokens == NULL) goto cleanup; + tokens = newtokens; + } + /* search the separator */ + if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0)) { + tokens[elements] = sdsnewlen(s+start,j-start); + if (tokens[elements] == NULL) goto cleanup; + elements++; + start = j+seplen; + j = j+seplen-1; /* skip the separator */ + } + } + /* Add the final element. We are sure there is room in the tokens array. */ + tokens[elements] = sdsnewlen(s+start,len-start); + if (tokens[elements] == NULL) goto cleanup; + elements++; + *count = elements; + return tokens; + +cleanup: + { + int i; + for (i = 0; i < elements; i++) sdsfree(tokens[i]); + free(tokens); + *count = 0; + return NULL; + } +} + +/* Free the result returned by sdssplitlen(), or do nothing if 'tokens' is NULL. */ +void sdsfreesplitres(sds *tokens, int count) { + if (!tokens) return; + while(count--) + sdsfree(tokens[count]); + free(tokens); +} + +/* Create an sds string from a long long value. It is much faster than: + * + * sdscatprintf(sdsempty(),"%lld\n", value); + */ +sds sdsfromlonglong(long long value) { + char buf[32], *p; + unsigned long long v; + + v = (value < 0) ? -value : value; + p = buf+31; /* point to the last character */ + do { + *p-- = '0'+(v%10); + v /= 10; + } while(v); + if (value < 0) *p-- = '-'; + p++; + return sdsnewlen(p,32-(p-buf)); +} + +/* Append to the sds string "s" an escaped string representation where + * all the non-printable characters (tested with isprint()) are turned into + * escapes in the form "\n\r\a...." or "\x". + * + * After the call, the modified sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. */ +sds sdscatrepr(sds s, const char *p, size_t len) { + s = sdscatlen(s,"\"",1); + while(len--) { + switch(*p) { + case '\\': + case '"': + s = sdscatprintf(s,"\\%c",*p); + break; + case '\n': s = sdscatlen(s,"\\n",2); break; + case '\r': s = sdscatlen(s,"\\r",2); break; + case '\t': s = sdscatlen(s,"\\t",2); break; + case '\a': s = sdscatlen(s,"\\a",2); break; + case '\b': s = sdscatlen(s,"\\b",2); break; + default: + if (isprint(*p)) + s = sdscatprintf(s,"%c",*p); + else + s = sdscatprintf(s,"\\x%02x",(unsigned char)*p); + break; + } + p++; + } + return sdscatlen(s,"\"",1); +} + +/* Helper function for sdssplitargs() that returns non zero if 'c' + * is a valid hex digit. */ +int is_hex_digit(char c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F'); +} + +/* Helper function for sdssplitargs() that converts a hex digit into an + * integer from 0 to 15 */ +int hex_digit_to_int(char c) { + switch(c) { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'a': case 'A': return 10; + case 'b': case 'B': return 11; + case 'c': case 'C': return 12; + case 'd': case 'D': return 13; + case 'e': case 'E': return 14; + case 'f': case 'F': return 15; + default: return 0; + } +} + +/* Split a line into arguments, where every argument can be in the + * following programming-language REPL-alike form: + * + * foo bar "newline are supported\n" and "\xff\x00otherstuff" + * + * The number of arguments is stored into *argc, and an array + * of sds is returned. + * + * The caller should free the resulting array of sds strings with + * sdsfreesplitres(). + * + * Note that sdscatrepr() is able to convert back a string into + * a quoted string in the same format sdssplitargs() is able to parse. + * + * The function returns the allocated tokens on success, even when the + * input string is empty, or NULL if the input contains unbalanced + * quotes or closed quotes followed by non space characters + * as in: "foo"bar or "foo' + */ +sds *sdssplitargs(const char *line, int *argc) { + const char *p = line; + char *current = NULL; + char **vector = NULL; + + *argc = 0; + while(1) { + /* skip blanks */ + while(*p && isspace(*p)) p++; + if (*p) { + /* get a token */ + int inq=0; /* set to 1 if we are in "quotes" */ + int insq=0; /* set to 1 if we are in 'single quotes' */ + int done=0; + + if (current == NULL) current = sdsempty(); + while(!done) { + if (inq) { + if (*p == '\\' && *(p+1) == 'x' && + is_hex_digit(*(p+2)) && + is_hex_digit(*(p+3))) + { + unsigned char byte; + + byte = (hex_digit_to_int(*(p+2))*16)+ + hex_digit_to_int(*(p+3)); + current = sdscatlen(current,(char*)&byte,1); + p += 3; + } else if (*p == '\\' && *(p+1)) { + char c; + + p++; + switch(*p) { + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'b': c = '\b'; break; + case 'a': c = '\a'; break; + default: c = *p; break; + } + current = sdscatlen(current,&c,1); + } else if (*p == '"') { + /* closing quote must be followed by a space or + * nothing at all. */ + if (*(p+1) && !isspace(*(p+1))) goto err; + done=1; + } else if (!*p) { + /* unterminated quotes */ + goto err; + } else { + current = sdscatlen(current,p,1); + } + } else if (insq) { + if (*p == '\\' && *(p+1) == '\'') { + p++; + current = sdscatlen(current,"'",1); + } else if (*p == '\'') { + /* closing quote must be followed by a space or + * nothing at all. */ + if (*(p+1) && !isspace(*(p+1))) goto err; + done=1; + } else if (!*p) { + /* unterminated quotes */ + goto err; + } else { + current = sdscatlen(current,p,1); + } + } else { + switch(*p) { + case ' ': + case '\n': + case '\r': + case '\t': + case '\0': + done=1; + break; + case '"': + inq=1; + break; + case '\'': + insq=1; + break; + default: + current = sdscatlen(current,p,1); + break; + } + } + if (*p) p++; + } + /* add the token to the vector */ + vector = realloc(vector,((*argc)+1)*sizeof(char*)); + vector[*argc] = current; + (*argc)++; + current = NULL; + } else { + /* Even on empty input string return something not NULL. */ + if (vector == NULL) vector = malloc(sizeof(void*)); + return vector; + } + } + +err: + while((*argc)--) + sdsfree(vector[*argc]); + free(vector); + if (current) sdsfree(current); + *argc = 0; + return NULL; +} + +/* Modify the string substituting all the occurrences of the set of + * characters specified in the 'from' string to the corresponding character + * in the 'to' array. + * + * For instance: sdsmapchars(mystring, "ho", "01", 2) + * will have the effect of turning the string "hello" into "0ell1". + * + * The function returns the sds string pointer, that is always the same + * as the input pointer since no resize is needed. */ +sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) { + size_t j, i, l = sdslen(s); + + for (j = 0; j < l; j++) { + for (i = 0; i < setlen; i++) { + if (s[j] == from[i]) { + s[j] = to[i]; + break; + } + } + } + return s; +} + +/* Join an array of C strings using the specified separator (also a C string). + * Returns the result as an sds string. */ +sds sdsjoin(char **argv, int argc, char *sep, size_t seplen) { + sds join = sdsempty(); + int j; + + for (j = 0; j < argc; j++) { + join = sdscat(join, argv[j]); + if (j != argc-1) join = sdscatlen(join,sep,seplen); + } + return join; +} + +/* Like sdsjoin, but joins an array of SDS strings. */ +sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen) { + sds join = sdsempty(); + int j; + + for (j = 0; j < argc; j++) { + join = sdscatsds(join, argv[j]); + if (j != argc-1) join = sdscatlen(join,sep,seplen); + } + return join; +} + +#ifdef SDS_TEST_MAIN +#include +#include "testhelp.h" + +int main(void) { + { + struct sdshdr *sh; + sds x = sdsnew("foo"), y; + + test_cond("Create a string and obtain the length", + sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0) + + sdsfree(x); + x = sdsnewlen("foo",2); + test_cond("Create a string with specified length", + sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0) + + x = sdscat(x,"bar"); + test_cond("Strings concatenation", + sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0); + + x = sdscpy(x,"a"); + test_cond("sdscpy() against an originally longer string", + sdslen(x) == 1 && memcmp(x,"a\0",2) == 0) + + x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk"); + test_cond("sdscpy() against an originally shorter string", + sdslen(x) == 33 && + memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0) + + sdsfree(x); + x = sdscatprintf(sdsempty(),"%d",123); + test_cond("sdscatprintf() seems working in the base case", + sdslen(x) == 3 && memcmp(x,"123\0",4) ==0) + + sdsfree(x); + x = sdsnew("xxciaoyyy"); + sdstrim(x,"xy"); + test_cond("sdstrim() correctly trims characters", + sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0) + + y = sdsdup(x); + sdsrange(y,1,1); + test_cond("sdsrange(...,1,1)", + sdslen(y) == 1 && memcmp(y,"i\0",2) == 0) + + sdsfree(y); + y = sdsdup(x); + sdsrange(y,1,-1); + test_cond("sdsrange(...,1,-1)", + sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) + + sdsfree(y); + y = sdsdup(x); + sdsrange(y,-2,-1); + test_cond("sdsrange(...,-2,-1)", + sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0) + + sdsfree(y); + y = sdsdup(x); + sdsrange(y,2,1); + test_cond("sdsrange(...,2,1)", + sdslen(y) == 0 && memcmp(y,"\0",1) == 0) + + sdsfree(y); + y = sdsdup(x); + sdsrange(y,1,100); + test_cond("sdsrange(...,1,100)", + sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) + + sdsfree(y); + y = sdsdup(x); + sdsrange(y,100,100); + test_cond("sdsrange(...,100,100)", + sdslen(y) == 0 && memcmp(y,"\0",1) == 0) + + sdsfree(y); + sdsfree(x); + x = sdsnew("foo"); + y = sdsnew("foa"); + test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0) + + sdsfree(y); + sdsfree(x); + x = sdsnew("bar"); + y = sdsnew("bar"); + test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0) + + sdsfree(y); + sdsfree(x); + x = sdsnew("aar"); + y = sdsnew("bar"); + test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0) + + sdsfree(y); + sdsfree(x); + x = sdsnewlen("\a\n\0foo\r",7); + y = sdscatrepr(sdsempty(),x,sdslen(x)); + test_cond("sdscatrepr(...data...)", + memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0) + + { + int oldfree; + + sdsfree(x); + x = sdsnew("0"); + sh = (void*) (x-(sizeof(struct sdshdr))); + test_cond("sdsnew() free/len buffers", sh->len == 1 && sh->free == 0); + x = sdsMakeRoomFor(x,1); + sh = (void*) (x-(sizeof(struct sdshdr))); + test_cond("sdsMakeRoomFor()", sh->len == 1 && sh->free > 0); + oldfree = sh->free; + x[1] = '1'; + sdsIncrLen(x,1); + test_cond("sdsIncrLen() -- content", x[0] == '0' && x[1] == '1'); + test_cond("sdsIncrLen() -- len", sh->len == 2); + test_cond("sdsIncrLen() -- free", sh->free == oldfree-1); + } + } + test_report() + return 0; +} +#endif diff --git a/debian/modules/nchan/src/hiredis/sds.h b/debian/modules/nchan/src/hiredis/sds.h new file mode 100644 index 0000000..19a2abd --- /dev/null +++ b/debian/modules/nchan/src/hiredis/sds.h @@ -0,0 +1,105 @@ +/* SDS (Simple Dynamic Strings), A C dynamic strings library. + * + * Copyright (c) 2006-2014, Salvatore Sanfilippo + * All rights reserved. + * + * 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 Redis 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. + */ + +#ifndef __SDS_H +#define __SDS_H + +#define SDS_MAX_PREALLOC (1024*1024) + +#include +#include +#ifdef _MSC_VER +#include "win32.h" +#endif + +typedef char *sds; + +struct sdshdr { + int len; + int free; + char buf[]; +}; + +static inline size_t sdslen(const sds s) { + struct sdshdr *sh = (struct sdshdr *)(s-sizeof *sh); + return sh->len; +} + +static inline size_t sdsavail(const sds s) { + struct sdshdr *sh = (struct sdshdr *)(s-sizeof *sh); + return sh->free; +} + +sds sdsnewlen(const void *init, size_t initlen); +sds sdsnew(const char *init); +sds sdsempty(void); +size_t sdslen(const sds s); +sds sdsdup(const sds s); +void sdsfree(sds s); +size_t sdsavail(const sds s); +sds sdsgrowzero(sds s, size_t len); +sds sdscatlen(sds s, const void *t, size_t len); +sds sdscat(sds s, const char *t); +sds sdscatsds(sds s, const sds t); +sds sdscpylen(sds s, const char *t, size_t len); +sds sdscpy(sds s, const char *t); + +sds sdscatvprintf(sds s, const char *fmt, va_list ap); +#ifdef __GNUC__ +sds sdscatprintf(sds s, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); +#else +sds sdscatprintf(sds s, const char *fmt, ...); +#endif + +sds sdscatfmt(sds s, char const *fmt, ...); +void sdstrim(sds s, const char *cset); +void sdsrange(sds s, int start, int end); +void sdsupdatelen(sds s); +void sdsclear(sds s); +int sdscmp(const sds s1, const sds s2); +sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count); +void sdsfreesplitres(sds *tokens, int count); +void sdstolower(sds s); +void sdstoupper(sds s); +sds sdsfromlonglong(long long value); +sds sdscatrepr(sds s, const char *p, size_t len); +sds *sdssplitargs(const char *line, int *argc); +sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen); +sds sdsjoin(char **argv, int argc, char *sep, size_t seplen); +sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen); + +/* Low level functions exposed to the user API */ +sds sdsMakeRoomFor(sds s, size_t addlen); +void sdsIncrLen(sds s, int incr); +sds sdsRemoveFreeSpace(sds s); +size_t sdsAllocSize(sds s); + +#endif diff --git a/debian/modules/nchan/src/hiredis/test.c b/debian/modules/nchan/src/hiredis/test.c new file mode 100644 index 0000000..d5e8217 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/test.c @@ -0,0 +1,807 @@ +#include "fmacros.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hiredis.h" +#include "net.h" + +enum connection_type { + CONN_TCP, + CONN_UNIX, + CONN_FD +}; + +struct config { + enum connection_type type; + + struct { + const char *host; + int port; + struct timeval timeout; + } tcp; + + struct { + const char *path; + } unix; +}; + +/* The following lines make up our testing "framework" :) */ +static int tests = 0, fails = 0; +#define test(_s) { printf("#%02d ", ++tests); printf(_s); } +#define test_cond(_c) if(_c) printf("\033[0;32mPASSED\033[0;0m\n"); else {printf("\033[0;31mFAILED\033[0;0m\n"); fails++;} + +static long long usec(void) { + struct timeval tv; + gettimeofday(&tv,NULL); + return (((long long)tv.tv_sec)*1000000)+tv.tv_usec; +} + +/* The assert() calls below have side effects, so we need assert() + * even if we are compiling without asserts (-DNDEBUG). */ +#ifdef NDEBUG +#undef assert +#define assert(e) (void)(e) +#endif + +static redisContext *select_database(redisContext *c) { + redisReply *reply; + + /* Switch to DB 9 for testing, now that we know we can chat. */ + reply = redisCommand(c,"SELECT 9"); + assert(reply != NULL); + freeReplyObject(reply); + + /* Make sure the DB is emtpy */ + reply = redisCommand(c,"DBSIZE"); + assert(reply != NULL); + if (reply->type == REDIS_REPLY_INTEGER && reply->integer == 0) { + /* Awesome, DB 9 is empty and we can continue. */ + freeReplyObject(reply); + } else { + printf("Database #9 is not empty, test can not continue\n"); + exit(1); + } + + return c; +} + +static int disconnect(redisContext *c, int keep_fd) { + redisReply *reply; + + /* Make sure we're on DB 9. */ + reply = redisCommand(c,"SELECT 9"); + assert(reply != NULL); + freeReplyObject(reply); + reply = redisCommand(c,"FLUSHDB"); + assert(reply != NULL); + freeReplyObject(reply); + + /* Free the context as well, but keep the fd if requested. */ + if (keep_fd) + return redisFreeKeepFd(c); + redisFree(c); + return -1; +} + +static redisContext *connect(struct config config) { + redisContext *c = NULL; + + if (config.type == CONN_TCP) { + c = redisConnect(config.tcp.host, config.tcp.port); + } else if (config.type == CONN_UNIX) { + c = redisConnectUnix(config.unix.path); + } else if (config.type == CONN_FD) { + /* Create a dummy connection just to get an fd to inherit */ + redisContext *dummy_ctx = redisConnectUnix(config.unix.path); + if (dummy_ctx) { + int fd = disconnect(dummy_ctx, 1); + printf("Connecting to inherited fd %d\n", fd); + c = redisConnectFd(fd); + } + } else { + assert(NULL); + } + + if (c == NULL) { + printf("Connection error: can't allocate redis context\n"); + exit(1); + } else if (c->err) { + printf("Connection error: %s\n", c->errstr); + redisFree(c); + exit(1); + } + + return select_database(c); +} + +static void test_format_commands(void) { + char *cmd; + int len; + + test("Format command without interpolation: "); + len = redisFormatCommand(&cmd,"SET foo bar"); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && + len == 4+4+(3+2)+4+(3+2)+4+(3+2)); + free(cmd); + + test("Format command with %%s string interpolation: "); + len = redisFormatCommand(&cmd,"SET %s %s","foo","bar"); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && + len == 4+4+(3+2)+4+(3+2)+4+(3+2)); + free(cmd); + + test("Format command with %%s and an empty string: "); + len = redisFormatCommand(&cmd,"SET %s %s","foo",""); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 && + len == 4+4+(3+2)+4+(3+2)+4+(0+2)); + free(cmd); + + test("Format command with an empty string in between proper interpolations: "); + len = redisFormatCommand(&cmd,"SET %s %s","","foo"); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$0\r\n\r\n$3\r\nfoo\r\n",len) == 0 && + len == 4+4+(3+2)+4+(0+2)+4+(3+2)); + free(cmd); + + test("Format command with %%b string interpolation: "); + len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"b\0r",(size_t)3); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nb\0r\r\n",len) == 0 && + len == 4+4+(3+2)+4+(3+2)+4+(3+2)); + free(cmd); + + test("Format command with %%b and an empty string: "); + len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"",(size_t)0); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 && + len == 4+4+(3+2)+4+(3+2)+4+(0+2)); + free(cmd); + + test("Format command with literal %%: "); + len = redisFormatCommand(&cmd,"SET %% %%"); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$1\r\n%\r\n$1\r\n%\r\n",len) == 0 && + len == 4+4+(3+2)+4+(1+2)+4+(1+2)); + free(cmd); + + /* Vararg width depends on the type. These tests make sure that the + * width is correctly determined using the format and subsequent varargs + * can correctly be interpolated. */ +#define INTEGER_WIDTH_TEST(fmt, type) do { \ + type value = 123; \ + test("Format command with printf-delegation (" #type "): "); \ + len = redisFormatCommand(&cmd,"key:%08" fmt " str:%s", value, "hello"); \ + test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:00000123\r\n$9\r\nstr:hello\r\n",len) == 0 && \ + len == 4+5+(12+2)+4+(9+2)); \ + free(cmd); \ +} while(0) + +#define FLOAT_WIDTH_TEST(type) do { \ + type value = 123.0; \ + test("Format command with printf-delegation (" #type "): "); \ + len = redisFormatCommand(&cmd,"key:%08.3f str:%s", value, "hello"); \ + test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:0123.000\r\n$9\r\nstr:hello\r\n",len) == 0 && \ + len == 4+5+(12+2)+4+(9+2)); \ + free(cmd); \ +} while(0) + + INTEGER_WIDTH_TEST("d", int); + INTEGER_WIDTH_TEST("hhd", char); + INTEGER_WIDTH_TEST("hd", short); + INTEGER_WIDTH_TEST("ld", long); + INTEGER_WIDTH_TEST("lld", long long); + INTEGER_WIDTH_TEST("u", unsigned int); + INTEGER_WIDTH_TEST("hhu", unsigned char); + INTEGER_WIDTH_TEST("hu", unsigned short); + INTEGER_WIDTH_TEST("lu", unsigned long); + INTEGER_WIDTH_TEST("llu", unsigned long long); + FLOAT_WIDTH_TEST(float); + FLOAT_WIDTH_TEST(double); + + test("Format command with invalid printf format: "); + len = redisFormatCommand(&cmd,"key:%08p %b",(void*)1234,"foo",(size_t)3); + test_cond(len == -1); + + const char *argv[3]; + argv[0] = "SET"; + argv[1] = "foo\0xxx"; + argv[2] = "bar"; + size_t lens[3] = { 3, 7, 3 }; + int argc = 3; + + test("Format command by passing argc/argv without lengths: "); + len = redisFormatCommandArgv(&cmd,argc,argv,NULL); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && + len == 4+4+(3+2)+4+(3+2)+4+(3+2)); + free(cmd); + + test("Format command by passing argc/argv with lengths: "); + len = redisFormatCommandArgv(&cmd,argc,argv,lens); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 && + len == 4+4+(3+2)+4+(7+2)+4+(3+2)); + free(cmd); +} + +static void test_append_formatted_commands(struct config config) { + redisContext *c; + redisReply *reply; + char *cmd; + int len; + + c = connect(config); + + test("Append format command: "); + + len = redisFormatCommand(&cmd, "SET foo bar"); + + test_cond(redisAppendFormattedCommand(c, cmd, len) == REDIS_OK); + + assert(redisGetReply(c, (void*)&reply) == REDIS_OK); + + free(cmd); + freeReplyObject(reply); + + disconnect(c, 0); +} + +static void test_reply_reader(void) { + redisReader *reader; + void *reply; + int ret; + int i; + + test("Error handling in reply parser: "); + reader = redisReaderCreate(); + redisReaderFeed(reader,(char*)"@foo\r\n",6); + ret = redisReaderGetReply(reader,NULL); + test_cond(ret == REDIS_ERR && + strcasecmp(reader->errstr,"Protocol error, got \"@\" as reply type byte") == 0); + redisReaderFree(reader); + + /* when the reply already contains multiple items, they must be free'd + * on an error. valgrind will bark when this doesn't happen. */ + test("Memory cleanup in reply parser: "); + reader = redisReaderCreate(); + redisReaderFeed(reader,(char*)"*2\r\n",4); + redisReaderFeed(reader,(char*)"$5\r\nhello\r\n",11); + redisReaderFeed(reader,(char*)"@foo\r\n",6); + ret = redisReaderGetReply(reader,NULL); + test_cond(ret == REDIS_ERR && + strcasecmp(reader->errstr,"Protocol error, got \"@\" as reply type byte") == 0); + redisReaderFree(reader); + + test("Set error on nested multi bulks with depth > 7: "); + reader = redisReaderCreate(); + + for (i = 0; i < 9; i++) { + redisReaderFeed(reader,(char*)"*1\r\n",4); + } + + ret = redisReaderGetReply(reader,NULL); + test_cond(ret == REDIS_ERR && + strncasecmp(reader->errstr,"No support for",14) == 0); + redisReaderFree(reader); + + test("Works with NULL functions for reply: "); + reader = redisReaderCreate(); + reader->fn = NULL; + redisReaderFeed(reader,(char*)"+OK\r\n",5); + ret = redisReaderGetReply(reader,&reply); + test_cond(ret == REDIS_OK && reply == (void*)REDIS_REPLY_STATUS); + redisReaderFree(reader); + + test("Works when a single newline (\\r\\n) covers two calls to feed: "); + reader = redisReaderCreate(); + reader->fn = NULL; + redisReaderFeed(reader,(char*)"+OK\r",4); + ret = redisReaderGetReply(reader,&reply); + assert(ret == REDIS_OK && reply == NULL); + redisReaderFeed(reader,(char*)"\n",1); + ret = redisReaderGetReply(reader,&reply); + test_cond(ret == REDIS_OK && reply == (void*)REDIS_REPLY_STATUS); + redisReaderFree(reader); + + test("Don't reset state after protocol error: "); + reader = redisReaderCreate(); + reader->fn = NULL; + redisReaderFeed(reader,(char*)"x",1); + ret = redisReaderGetReply(reader,&reply); + assert(ret == REDIS_ERR); + ret = redisReaderGetReply(reader,&reply); + test_cond(ret == REDIS_ERR && reply == NULL); + redisReaderFree(reader); + + /* Regression test for issue #45 on GitHub. */ + test("Don't do empty allocation for empty multi bulk: "); + reader = redisReaderCreate(); + redisReaderFeed(reader,(char*)"*0\r\n",4); + ret = redisReaderGetReply(reader,&reply); + test_cond(ret == REDIS_OK && + ((redisReply*)reply)->type == REDIS_REPLY_ARRAY && + ((redisReply*)reply)->elements == 0); + freeReplyObject(reply); + redisReaderFree(reader); +} + +static void test_free_null(void) { + void *redisContext = NULL; + void *reply = NULL; + + test("Don't fail when redisFree is passed a NULL value: "); + redisFree(redisContext); + test_cond(redisContext == NULL); + + test("Don't fail when freeReplyObject is passed a NULL value: "); + freeReplyObject(reply); + test_cond(reply == NULL); +} + +static void test_blocking_connection_errors(void) { + redisContext *c; + + test("Returns error when host cannot be resolved: "); + c = redisConnect((char*)"idontexist.test", 6379); + test_cond(c->err == REDIS_ERR_OTHER && + (strcmp(c->errstr,"Name or service not known") == 0 || + strcmp(c->errstr,"Can't resolve: idontexist.test") == 0 || + strcmp(c->errstr,"nodename nor servname provided, or not known") == 0 || + strcmp(c->errstr,"No address associated with hostname") == 0 || + strcmp(c->errstr,"Temporary failure in name resolution") == 0 || + strcmp(c->errstr,"hostname nor servname provided, or not known") == 0 || + strcmp(c->errstr,"no address associated with name") == 0)); + redisFree(c); + + test("Returns error when the port is not open: "); + c = redisConnect((char*)"localhost", 1); + test_cond(c->err == REDIS_ERR_IO && + strcmp(c->errstr,"Connection refused") == 0); + redisFree(c); + + test("Returns error when the unix socket path doesn't accept connections: "); + c = redisConnectUnix((char*)"/tmp/idontexist.sock"); + test_cond(c->err == REDIS_ERR_IO); /* Don't care about the message... */ + redisFree(c); +} + +static void test_blocking_connection(struct config config) { + redisContext *c; + redisReply *reply; + + c = connect(config); + + test("Is able to deliver commands: "); + reply = redisCommand(c,"PING"); + test_cond(reply->type == REDIS_REPLY_STATUS && + strcasecmp(reply->str,"pong") == 0) + freeReplyObject(reply); + + test("Is a able to send commands verbatim: "); + reply = redisCommand(c,"SET foo bar"); + test_cond (reply->type == REDIS_REPLY_STATUS && + strcasecmp(reply->str,"ok") == 0) + freeReplyObject(reply); + + test("%%s String interpolation works: "); + reply = redisCommand(c,"SET %s %s","foo","hello world"); + freeReplyObject(reply); + reply = redisCommand(c,"GET foo"); + test_cond(reply->type == REDIS_REPLY_STRING && + strcmp(reply->str,"hello world") == 0); + freeReplyObject(reply); + + test("%%b String interpolation works: "); + reply = redisCommand(c,"SET %b %b","foo",(size_t)3,"hello\x00world",(size_t)11); + freeReplyObject(reply); + reply = redisCommand(c,"GET foo"); + test_cond(reply->type == REDIS_REPLY_STRING && + memcmp(reply->str,"hello\x00world",11) == 0) + + test("Binary reply length is correct: "); + test_cond(reply->len == 11) + freeReplyObject(reply); + + test("Can parse nil replies: "); + reply = redisCommand(c,"GET nokey"); + test_cond(reply->type == REDIS_REPLY_NIL) + freeReplyObject(reply); + + /* test 7 */ + test("Can parse integer replies: "); + reply = redisCommand(c,"INCR mycounter"); + test_cond(reply->type == REDIS_REPLY_INTEGER && reply->integer == 1) + freeReplyObject(reply); + + test("Can parse multi bulk replies: "); + freeReplyObject(redisCommand(c,"LPUSH mylist foo")); + freeReplyObject(redisCommand(c,"LPUSH mylist bar")); + reply = redisCommand(c,"LRANGE mylist 0 -1"); + test_cond(reply->type == REDIS_REPLY_ARRAY && + reply->elements == 2 && + !memcmp(reply->element[0]->str,"bar",3) && + !memcmp(reply->element[1]->str,"foo",3)) + freeReplyObject(reply); + + /* m/e with multi bulk reply *before* other reply. + * specifically test ordering of reply items to parse. */ + test("Can handle nested multi bulk replies: "); + freeReplyObject(redisCommand(c,"MULTI")); + freeReplyObject(redisCommand(c,"LRANGE mylist 0 -1")); + freeReplyObject(redisCommand(c,"PING")); + reply = (redisCommand(c,"EXEC")); + test_cond(reply->type == REDIS_REPLY_ARRAY && + reply->elements == 2 && + reply->element[0]->type == REDIS_REPLY_ARRAY && + reply->element[0]->elements == 2 && + !memcmp(reply->element[0]->element[0]->str,"bar",3) && + !memcmp(reply->element[0]->element[1]->str,"foo",3) && + reply->element[1]->type == REDIS_REPLY_STATUS && + strcasecmp(reply->element[1]->str,"pong") == 0); + freeReplyObject(reply); + + disconnect(c, 0); +} + +static void test_blocking_connection_timeouts(struct config config) { + redisContext *c; + redisReply *reply; + ssize_t s; + const char *cmd = "DEBUG SLEEP 3\r\n"; + struct timeval tv; + + c = connect(config); + test("Successfully completes a command when the timeout is not exceeded: "); + reply = redisCommand(c,"SET foo fast"); + freeReplyObject(reply); + tv.tv_sec = 0; + tv.tv_usec = 10000; + redisSetTimeout(c, tv); + reply = redisCommand(c, "GET foo"); + test_cond(reply != NULL && reply->type == REDIS_REPLY_STRING && memcmp(reply->str, "fast", 4) == 0); + freeReplyObject(reply); + disconnect(c, 0); + + c = connect(config); + test("Does not return a reply when the command times out: "); + s = write(c->fd, cmd, strlen(cmd)); + tv.tv_sec = 0; + tv.tv_usec = 10000; + redisSetTimeout(c, tv); + reply = redisCommand(c, "GET foo"); + test_cond(s > 0 && reply == NULL && c->err == REDIS_ERR_IO && strcmp(c->errstr, "Resource temporarily unavailable") == 0); + freeReplyObject(reply); + + test("Reconnect properly reconnects after a timeout: "); + redisReconnect(c); + reply = redisCommand(c, "PING"); + test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "PONG") == 0); + freeReplyObject(reply); + + test("Reconnect properly uses owned parameters: "); + config.tcp.host = "foo"; + config.unix.path = "foo"; + redisReconnect(c); + reply = redisCommand(c, "PING"); + test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "PONG") == 0); + freeReplyObject(reply); + + disconnect(c, 0); +} + +static void test_blocking_io_errors(struct config config) { + redisContext *c; + redisReply *reply; + void *_reply; + int major, minor; + + /* Connect to target given by config. */ + c = connect(config); + { + /* Find out Redis version to determine the path for the next test */ + const char *field = "redis_version:"; + char *p, *eptr; + + reply = redisCommand(c,"INFO"); + p = strstr(reply->str,field); + major = strtol(p+strlen(field),&eptr,10); + p = eptr+1; /* char next to the first "." */ + minor = strtol(p,&eptr,10); + freeReplyObject(reply); + } + + test("Returns I/O error when the connection is lost: "); + reply = redisCommand(c,"QUIT"); + if (major > 2 || (major == 2 && minor > 0)) { + /* > 2.0 returns OK on QUIT and read() should be issued once more + * to know the descriptor is at EOF. */ + test_cond(strcasecmp(reply->str,"OK") == 0 && + redisGetReply(c,&_reply) == REDIS_ERR); + freeReplyObject(reply); + } else { + test_cond(reply == NULL); + } + + /* On 2.0, QUIT will cause the connection to be closed immediately and + * the read(2) for the reply on QUIT will set the error to EOF. + * On >2.0, QUIT will return with OK and another read(2) needed to be + * issued to find out the socket was closed by the server. In both + * conditions, the error will be set to EOF. */ + assert(c->err == REDIS_ERR_EOF && + strcmp(c->errstr,"Server closed the connection") == 0); + redisFree(c); + + c = connect(config); + test("Returns I/O error on socket timeout: "); + struct timeval tv = { 0, 1000 }; + assert(redisSetTimeout(c,tv) == REDIS_OK); + test_cond(redisGetReply(c,&_reply) == REDIS_ERR && + c->err == REDIS_ERR_IO && errno == EAGAIN); + redisFree(c); +} + +static void test_invalid_timeout_errors(struct config config) { + redisContext *c; + + test("Set error when an invalid timeout usec value is given to redisConnectWithTimeout: "); + + config.tcp.timeout.tv_sec = 0; + config.tcp.timeout.tv_usec = 10000001; + + c = redisConnectWithTimeout(config.tcp.host, config.tcp.port, config.tcp.timeout); + + test_cond(c->err == REDIS_ERR_IO); + redisFree(c); + + test("Set error when an invalid timeout sec value is given to redisConnectWithTimeout: "); + + config.tcp.timeout.tv_sec = (((LONG_MAX) - 999) / 1000) + 1; + config.tcp.timeout.tv_usec = 0; + + c = redisConnectWithTimeout(config.tcp.host, config.tcp.port, config.tcp.timeout); + + test_cond(c->err == REDIS_ERR_IO); + redisFree(c); +} + +static void test_throughput(struct config config) { + redisContext *c = connect(config); + redisReply **replies; + int i, num; + long long t1, t2; + + test("Throughput:\n"); + for (i = 0; i < 500; i++) + freeReplyObject(redisCommand(c,"LPUSH mylist foo")); + + num = 1000; + replies = malloc(sizeof(redisReply*)*num); + t1 = usec(); + for (i = 0; i < num; i++) { + replies[i] = redisCommand(c,"PING"); + assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_STATUS); + } + t2 = usec(); + for (i = 0; i < num; i++) freeReplyObject(replies[i]); + free(replies); + printf("\t(%dx PING: %.3fs)\n", num, (t2-t1)/1000000.0); + + replies = malloc(sizeof(redisReply*)*num); + t1 = usec(); + for (i = 0; i < num; i++) { + replies[i] = redisCommand(c,"LRANGE mylist 0 499"); + assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_ARRAY); + assert(replies[i] != NULL && replies[i]->elements == 500); + } + t2 = usec(); + for (i = 0; i < num; i++) freeReplyObject(replies[i]); + free(replies); + printf("\t(%dx LRANGE with 500 elements: %.3fs)\n", num, (t2-t1)/1000000.0); + + num = 10000; + replies = malloc(sizeof(redisReply*)*num); + for (i = 0; i < num; i++) + redisAppendCommand(c,"PING"); + t1 = usec(); + for (i = 0; i < num; i++) { + assert(redisGetReply(c, (void*)&replies[i]) == REDIS_OK); + assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_STATUS); + } + t2 = usec(); + for (i = 0; i < num; i++) freeReplyObject(replies[i]); + free(replies); + printf("\t(%dx PING (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0); + + replies = malloc(sizeof(redisReply*)*num); + for (i = 0; i < num; i++) + redisAppendCommand(c,"LRANGE mylist 0 499"); + t1 = usec(); + for (i = 0; i < num; i++) { + assert(redisGetReply(c, (void*)&replies[i]) == REDIS_OK); + assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_ARRAY); + assert(replies[i] != NULL && replies[i]->elements == 500); + } + t2 = usec(); + for (i = 0; i < num; i++) freeReplyObject(replies[i]); + free(replies); + printf("\t(%dx LRANGE with 500 elements (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0); + + disconnect(c, 0); +} + +// static long __test_callback_flags = 0; +// static void __test_callback(redisContext *c, void *privdata) { +// ((void)c); +// /* Shift to detect execution order */ +// __test_callback_flags <<= 8; +// __test_callback_flags |= (long)privdata; +// } +// +// static void __test_reply_callback(redisContext *c, redisReply *reply, void *privdata) { +// ((void)c); +// /* Shift to detect execution order */ +// __test_callback_flags <<= 8; +// __test_callback_flags |= (long)privdata; +// if (reply) freeReplyObject(reply); +// } +// +// static redisContext *__connect_nonblock() { +// /* Reset callback flags */ +// __test_callback_flags = 0; +// return redisConnectNonBlock("127.0.0.1", port, NULL); +// } +// +// static void test_nonblocking_connection() { +// redisContext *c; +// int wdone = 0; +// +// test("Calls command callback when command is issued: "); +// c = __connect_nonblock(); +// redisSetCommandCallback(c,__test_callback,(void*)1); +// redisCommand(c,"PING"); +// test_cond(__test_callback_flags == 1); +// redisFree(c); +// +// test("Calls disconnect callback on redisDisconnect: "); +// c = __connect_nonblock(); +// redisSetDisconnectCallback(c,__test_callback,(void*)2); +// redisDisconnect(c); +// test_cond(__test_callback_flags == 2); +// redisFree(c); +// +// test("Calls disconnect callback and free callback on redisFree: "); +// c = __connect_nonblock(); +// redisSetDisconnectCallback(c,__test_callback,(void*)2); +// redisSetFreeCallback(c,__test_callback,(void*)4); +// redisFree(c); +// test_cond(__test_callback_flags == ((2 << 8) | 4)); +// +// test("redisBufferWrite against empty write buffer: "); +// c = __connect_nonblock(); +// test_cond(redisBufferWrite(c,&wdone) == REDIS_OK && wdone == 1); +// redisFree(c); +// +// test("redisBufferWrite against not yet connected fd: "); +// c = __connect_nonblock(); +// redisCommand(c,"PING"); +// test_cond(redisBufferWrite(c,NULL) == REDIS_ERR && +// strncmp(c->error,"write:",6) == 0); +// redisFree(c); +// +// test("redisBufferWrite against closed fd: "); +// c = __connect_nonblock(); +// redisCommand(c,"PING"); +// redisDisconnect(c); +// test_cond(redisBufferWrite(c,NULL) == REDIS_ERR && +// strncmp(c->error,"write:",6) == 0); +// redisFree(c); +// +// test("Process callbacks in the right sequence: "); +// c = __connect_nonblock(); +// redisCommandWithCallback(c,__test_reply_callback,(void*)1,"PING"); +// redisCommandWithCallback(c,__test_reply_callback,(void*)2,"PING"); +// redisCommandWithCallback(c,__test_reply_callback,(void*)3,"PING"); +// +// /* Write output buffer */ +// wdone = 0; +// while(!wdone) { +// usleep(500); +// redisBufferWrite(c,&wdone); +// } +// +// /* Read until at least one callback is executed (the 3 replies will +// * arrive in a single packet, causing all callbacks to be executed in +// * a single pass). */ +// while(__test_callback_flags == 0) { +// assert(redisBufferRead(c) == REDIS_OK); +// redisProcessCallbacks(c); +// } +// test_cond(__test_callback_flags == 0x010203); +// redisFree(c); +// +// test("redisDisconnect executes pending callbacks with NULL reply: "); +// c = __connect_nonblock(); +// redisSetDisconnectCallback(c,__test_callback,(void*)1); +// redisCommandWithCallback(c,__test_reply_callback,(void*)2,"PING"); +// redisDisconnect(c); +// test_cond(__test_callback_flags == 0x0201); +// redisFree(c); +// } + +int main(int argc, char **argv) { + struct config cfg = { + .tcp = { + .host = "127.0.0.1", + .port = 6379 + }, + .unix = { + .path = "/tmp/redis.sock" + } + }; + int throughput = 1; + int test_inherit_fd = 1; + + /* Ignore broken pipe signal (for I/O error tests). */ + signal(SIGPIPE, SIG_IGN); + + /* Parse command line options. */ + argv++; argc--; + while (argc) { + if (argc >= 2 && !strcmp(argv[0],"-h")) { + argv++; argc--; + cfg.tcp.host = argv[0]; + } else if (argc >= 2 && !strcmp(argv[0],"-p")) { + argv++; argc--; + cfg.tcp.port = atoi(argv[0]); + } else if (argc >= 2 && !strcmp(argv[0],"-s")) { + argv++; argc--; + cfg.unix.path = argv[0]; + } else if (argc >= 1 && !strcmp(argv[0],"--skip-throughput")) { + throughput = 0; + } else if (argc >= 1 && !strcmp(argv[0],"--skip-inherit-fd")) { + test_inherit_fd = 0; + } else { + fprintf(stderr, "Invalid argument: %s\n", argv[0]); + exit(1); + } + argv++; argc--; + } + + test_format_commands(); + test_reply_reader(); + test_blocking_connection_errors(); + test_free_null(); + + printf("\nTesting against TCP connection (%s:%d):\n", cfg.tcp.host, cfg.tcp.port); + cfg.type = CONN_TCP; + test_blocking_connection(cfg); + test_blocking_connection_timeouts(cfg); + test_blocking_io_errors(cfg); + test_invalid_timeout_errors(cfg); + test_append_formatted_commands(cfg); + if (throughput) test_throughput(cfg); + + printf("\nTesting against Unix socket connection (%s):\n", cfg.unix.path); + cfg.type = CONN_UNIX; + test_blocking_connection(cfg); + test_blocking_connection_timeouts(cfg); + test_blocking_io_errors(cfg); + if (throughput) test_throughput(cfg); + + if (test_inherit_fd) { + printf("\nTesting against inherited fd (%s):\n", cfg.unix.path); + cfg.type = CONN_FD; + test_blocking_connection(cfg); + } + + + if (fails) { + printf("*** %d TESTS FAILED ***\n", fails); + return 1; + } + + printf("ALL TESTS PASSED\n"); + return 0; +} diff --git a/debian/modules/nchan/src/hiredis/win32.h b/debian/modules/nchan/src/hiredis/win32.h new file mode 100644 index 0000000..1a27c18 --- /dev/null +++ b/debian/modules/nchan/src/hiredis/win32.h @@ -0,0 +1,42 @@ +#ifndef _WIN32_HELPER_INCLUDE +#define _WIN32_HELPER_INCLUDE +#ifdef _MSC_VER + +#ifndef inline +#define inline __inline +#endif + +#ifndef va_copy +#define va_copy(d,s) ((d) = (s)) +#endif + +#ifndef snprintf +#define snprintf c99_snprintf + +__inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap) +{ + int count = -1; + + if (size != 0) + count = _vsnprintf_s(str, size, _TRUNCATE, format, ap); + if (count == -1) + count = _vscprintf(format, ap); + + return count; +} + +__inline int c99_snprintf(char* str, size_t size, const char* format, ...) +{ + int count; + va_list ap; + + va_start(ap, format); + count = c99_vsnprintf(str, size, format, ap); + va_end(ap); + + return count; +} +#endif + +#endif +#endif \ No newline at end of file diff --git a/debian/modules/nchan/src/nchan_commands.rb b/debian/modules/nchan/src/nchan_commands.rb new file mode 100644 index 0000000..8f4126a --- /dev/null +++ b/debian/modules/nchan/src/nchan_commands.rb @@ -0,0 +1,412 @@ +CfCmd.new do + + nchan_channel_id [:srv, :loc, :if], + :nchan_set_pubsub_channel_id, + :loc_conf, + args: 1..7, + alt: [ :nchan_pubsub_channel_id ], + + group: "pubsub", + default: "(none)", + info: "Channel id for a publisher or subscriber location. Can have up to 4 values to subscribe to up to 4 channels." + + nchan_publisher_channel_id [:srv, :loc, :if], + :nchan_set_pub_channel_id, + :loc_conf, + args: 1..7, + alt: [ :nchan_pub_channel_id ], + + group: "pubsub", + default: "(none)", + info: "Channel id for publisher location." + + nchan_publisher_upstream_request [:srv, :loc, :if], + :ngx_http_set_complex_value_slot, + [:loc_conf, :publisher_upstream_request_url], + + group: "pubsub", + value: "", + info: <<-EOS.gsub(/^ {8}/, '') + Send POST request to internal location (which may proxy to an upstream server) with published message in the request body. Useful for bridging websocket publishers with HTTP applications, or for transforming message via upstream application before publishing to a channel. + The upstream response code determine how publishing will proceed. A `200 OK` will publish the message from the upstream response's body. A `304 Not Modified` will publish the message as it was received from the publisher. A `204 No Content` will result in the message not being published. + EOS + + nchan_channel_id_split_delimiter [:srv, :loc, :if], + :ngx_conf_set_str_slot, + [:loc_conf, :channel_id_split_delimiter], + + group: "pubsub", + default: "(none)", + info: "Split the channel id into several ids for multiplexing using the delimiter string provided." + + + nchan_subscriber_channel_id [:srv, :loc, :if], + :nchan_set_sub_channel_id, + :loc_conf, + args: 1..7, + alt: [ :nchan_sub_channel_id ], + group: "pubsub", + + default: "(none)", + info: "Channel id for subscriber location. Can have up to 4 values to subscribe to up to 4 channels." + + nchan_pubsub [:srv, :loc, :if], + :nchan_pubsub_directive, + :loc_conf, + args: 0..6, + + group: "pubsub", + value: ["http", "websocket", "eventsource", "longpoll", "intervalpoll", "chunked", "multipart-mixed", "http-raw-stream"], + default: ["http", "websocket", "eventsource", "longpoll", "chunked", "multipart-mixed"], + info: "Defines a server or location as a pubsub endpoint. For long-polling, GETs subscribe. and POSTs publish. For Websockets, publishing data on a connection does not yield a channel metadata response. Without additional configuration, this turns a location into an echo server." + + + nchan_longpoll_multipart_response [:srv, :loc, :if], + :nchan_set_longpoll_multipart, + [:loc_conf, :longpoll_multimsg], + args: 1, + + group: "pubsub", + default: "off", + value: ["off", "on", "raw"], + info: "when set to 'on', enable sending multiple messages in a single longpoll response, separated using the multipart/mixed content-type scheme. If there is only one available message in response to a long-poll request, it is sent unmodified. This is useful for high-latency long-polling connections as a way to minimize round-trips to the server. When set to 'raw', sends multiple messages using the http-raw-stream message separator." + + nchan_eventsource_event [:srv, :loc, :if], + :ngx_conf_set_str_slot, + [:loc_conf, :eventsource_event], + args: 1, + + group: "pubsub", + default: "(none)", + info: "Set the EventSource `event:` line to this value. When used in a publisher location, overrides the published message's `X-EventSource-Event` header and associates the message with the given value. When used in a subscriber location, overrides all messages' associated `event:` string with the given value." + + + nchan_subscriber [:srv, :loc, :if], + :nchan_subscriber_directive, + :loc_conf, + args: 0..5, + legacy: "push_subscriber", + + group: "pubsub", + value: ["websocket", "eventsource", "longpoll", "intervalpoll", "chunked", "multipart-mixed", "http-raw-stream"], + default: ["websocket", "eventsource", "longpoll", "chunked", "multipart-mixed"], + info: "Defines a server or location as a channel subscriber endpoint. This location represents a subscriber's interface to a channel's message queue. The queue is traversed automatically, starting at the position defined by the `nchan_subscriber_first_message` setting. \n The value is a list of permitted subscriber types." + + nchan_subscriber_compound_etag_message_id [:srv, :loc, :if], + :ngx_conf_set_flag_slot, + [:loc_conf, :msg_in_etag_only], + args: 1, + + group: "pubsub", + default: "off", + info: <<-EOS.gsub(/^ {8}/, '') + Override the default behavior of using both `Last-Modified` and `Etag` headers for the message id. + Enabling this option packs the entire message id into the `Etag` header, and discards + `Last-Modified` and `If-Modified-Since` headers. + EOS + + nchan_subscriber_message_id_custom_etag_header [:srv, :loc, :if], + :ngx_conf_set_str_slot, + [:loc_conf, :custom_msgtag_header], + args: 1, + + group: "pubsub", + default: "(none)", + info: <<-EOS.gsub(/^ {8}/, '') + Use a custom header instead of the Etag header for message ID in subscriber responses. This setting is a hack, useful when behind a caching proxy such as Cloudflare that under some conditions (like using gzip encoding) swallow the Etag header. + EOS + + nchan_subscriber_last_message_id [:srv, :loc, :if], + :nchan_subscriber_last_message_id, + :loc_conf, + args: 1..5, + + group: "pubsub", + default: ["$http_last_event_id", "$arg_last_event_id"], + info: "If `If-Modified-Since` and `If-None-Match` headers are absent, set the message id to the first non-empty of these values. Used primarily as a workaround for the inability to set the first `Last-Message-Id` of a web browser's EventSource object. " + + nchan_subscriber_http_raw_stream_separator [:srv, :loc, :if], + :nchan_set_raw_subscriber_separator, + [:loc_conf, :subscriber_http_raw_stream_separator], + args: 1, + + group: "pubsub", + value: "", + default: "\\n", + info: "Message separator string for the http-raw-stream subscriber. Automatically terminated with a newline character." + + nchan_subscriber_first_message [:srv, :loc, :if], + :nchan_subscriber_first_message_directive, + :loc_conf, + args: 1, + + group: "pubsub", + value: ["oldest", "newest", ""], + default: "oldest", + info: "Controls the first message received by a new subscriber. 'oldest' starts at the oldest available message in a channel's message queue, 'newest' waits until a message arrives. If a number `n` is specified, starts at `n`th message from the oldest. (`-n` start at `n`th from now). 0 is equivalent to 'newest'." + + + #nchan_subscriber_concurrency [:main, :srv, :loc, :if], + # :nchan_set_subscriber_concurrency, + # [:loc_conf, :subscriber_concurrency], + # legacy: "push_subscriber_concurrency", + # + # group: "pubsub", + # value: [ :last, :first, :broadcast ], + # info: "Controls how multiple subscriber requests to a channel (identified by some common ID) are handled.The values work as follows: + # - broadcast: any number of concurrent subscriber requests may be held. + # - last: only the most recent subscriber request is kept, all others get a 409 Conflict response. + # - first: only the oldest subscriber request is kept, all others get a 409 Conflict response." + + nchan_websocket_ping_interval [:srv, :loc, :if], + :ngx_conf_set_sec_slot, + [:loc_conf, :websocket_ping_interval], + + group: "pubsub", + value: " (seconds)", + default: "0 (none)", + info: "Interval for sending websocket ping frames. Disabled by default." + + nchan_publisher [:srv, :loc, :if], + :nchan_publisher_directive, + :loc_conf, + args: 0..2, + legacy: "push_publisher", + + group: "pubsub", + value: ["http", "websocket"], + default: ["http", "websocket"], + info: "Defines a server or location as a publisher endpoint. Requests to a publisher location are treated as messages to be sent to subscribers. See the protocol documentation for a detailed description." + + nchan_subscriber_timeout [:main, :srv, :loc, :if], + :ngx_conf_set_sec_slot, + [:loc_conf, :subscriber_timeout], + legacy: "push_subscriber_timeout", + + group: "pubsub", + value: " (seconds)", + default: "0 (none)", + info: "Maximum time a subscriber may wait for a message before being disconnected. If you don't want a subscriber's connection to timeout, set this to 0. When possible, the subscriber will get a response with a `408 Request Timeout` status; otherwise the subscriber will simply be disconnected." + + nchan_authorize_request [:srv, :loc, :if], + :ngx_http_set_complex_value_slot, + [:loc_conf, :authorize_request_url], + + group: "security", + value: "", + info: "Send GET request to internal location (which may proxy to an upstream server) for authorization of a publisher or subscriber request. A 200 response authorizes the request, a 403 response forbids it." + + nchan_store_messages [:main, :srv, :loc, :if], + :nchan_store_messages_directive, + :loc_conf, + legacy: "push_store_messages", + + group: "storage", + value: [:on, :off], + default: :on, + info: "Publisher configuration. \"`off`\" is equivalent to setting `nchan_message_buffer_length 0`, which disables the buffering of old messages. Using this setting is not recommended when publishing very quickly, as it may result in missed messages." + + nchan_max_reserved_memory [:main], + :ngx_conf_set_size_slot, + [:main_conf, :shm_size], + legacy: "push_max_reserved_memory", + + group: "storage", + value: "", + default: "32M", + info: "The size of the shared memory chunk this module will use for message queuing and buffering." + + nchan_redis_url [:main, :srv, :loc], + :ngx_conf_set_redis_url, + [:loc_conf, :"redis.url"], + + group: "storage", + default: "127.0.0.1:6379", + info: "The path to a redis server, of the form 'redis://:password@hostname:6379/0'. Shorthand of the form 'host:port' or just 'host' is also accepted." + + nchan_redis_pass [:main, :srv, :loc], + :ngx_conf_set_redis_upstream_pass, + [:loc_conf, :"redis"], + + group: "storage", + info: "Use an upstream config block for Redis servers." + + nchan_redis_pass_inheritable [:main, :srv, :loc], + :ngx_conf_set_flag_slot, + [:loc_conf, :"redis.upstream_inheritable"], + + undocumented: true, + group: "debug" + + nchan_redis_publish_msgpacked_max_size [:main], + :ngx_conf_set_size_slot, + [:main_conf, :redis_publish_message_msgkey_size], + undocumented: true, + group: "storage" + + nchan_redis_server [:upstream], + :ngx_conf_upstream_redis_server, + :loc_conf, + group: "storage", + info: "Used in upstream { } blocks to set redis servers." + + nchan_use_redis [:main, :srv, :loc], + :ngx_conf_enable_redis, + [:loc_conf, :"redis.url_enabled"], + + group: "storage", + value: [ :on, :off ], + default: :off, + info: "Use redis for message storage at this location." + + nchan_redis_ping_interval [:main, :srv, :loc], + :ngx_conf_set_sec_slot, + [:loc_conf, :"redis.ping_interval"], + + group: "storage", + default: "4m", + info: "Send a keepalive command to redis to keep the Nchan redis clients from disconnecting. Set to 0 to disable." + + nchan_redis_fakesub_timer_interval [:main], + :ngx_conf_set_msec_slot, + [:main_conf, :redis_fakesub_timer_interval], + + group: "tweak", + undocumented: true, + default: "100ms" + + nchan_redis_idle_channel_cache_timeout [:main, :srv, :loc], + :ngx_conf_set_sec_slot, + [:loc_conf, :redis_idle_channel_cache_timeout], + + group: "storage", + value: "

' after the header */ ngx_str_t header; /**< File name for header, or empty if none. */ ngx_str_t footer; /**< File name for footer, or empty if none. */ ngx_str_t css_href; /**< Link to a CSS stylesheet, or empty if none. */ + ngx_str_t time_format; /**< Format used for file timestamps. */ ngx_array_t *ignore; /**< List of files to ignore in listings. */ } ngx_http_fancyindex_loc_conf_t; @@ -113,17 +224,19 @@ typedef struct { -static int ngx_libc_cdecl +static ngx_int_t ngx_libc_cdecl + ngx_http_fancyindex_cmp_entries_dirs_first(const void *one, const void *two); +static ngx_int_t ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_name_desc(const void *one, const void *two); -static int ngx_libc_cdecl +static ngx_int_t ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_size_desc(const void *one, const void *two); -static int ngx_libc_cdecl +static ngx_int_t ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_mtime_desc(const void *one, const void *two); -static int ngx_libc_cdecl +static ngx_int_t ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_name_asc(const void *one, const void *two); -static int ngx_libc_cdecl +static ngx_int_t ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_size_asc(const void *one, const void *two); -static int ngx_libc_cdecl +static ngx_int_t ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_mtime_asc(const void *one, const void *two); static ngx_int_t ngx_http_fancyindex_error(ngx_http_request_t *r, @@ -174,6 +287,13 @@ static ngx_command_t ngx_http_fancyindex_commands[] = { offsetof(ngx_http_fancyindex_loc_conf_t, default_sort), &ngx_http_fancyindex_sort_criteria }, + { ngx_string("fancyindex_directories_first"), + 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_fancyindex_loc_conf_t, dirs_first), + NULL }, + { ngx_string("fancyindex_localtime"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -223,6 +343,27 @@ static ngx_command_t ngx_http_fancyindex_commands[] = { 0, NULL }, + { ngx_string("fancyindex_hide_symlinks"), + 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_fancyindex_loc_conf_t, hide_symlinks), + NULL }, + + { ngx_string("fancyindex_show_path"), + 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_fancyindex_loc_conf_t, show_path), + NULL }, + + { ngx_string("fancyindex_time_format"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fancyindex_loc_conf_t, time_format), + NULL }, + ngx_null_command }; @@ -406,7 +547,7 @@ make_content_buf( { ngx_http_fancyindex_entry_t *entry; - int (*sort_cmp_func) (const void*, const void*); + ngx_int_t (*sort_cmp_func) (const void*, const void*); const char *sort_url_args = ""; off_t length; @@ -421,11 +562,6 @@ make_content_buf( ngx_dir_t dir; ngx_buf_t *b; - static char *months[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", - }; - /* * NGX_DIR_MASK_LEN is lesser than NGX_HTTP_FANCYINDEX_PREALLOCATE */ @@ -497,9 +633,14 @@ make_content_buf( if (ngx_de_name(&dir)[0] == '.') continue; + if (alcf->hide_symlinks && ngx_de_is_link (&dir)) + continue; + #if NGX_PCRE { - ngx_str_t str = { len, ngx_de_name(&dir) }; + ngx_str_t str; + str.len = len; + str.data = ngx_de_name(&dir); if (alcf->ignore && ngx_regex_exec_array(alcf->ignore, &str, r->connection->log) @@ -588,12 +729,29 @@ make_content_buf( /* * Calculate needed buffer length. */ - len = r->uri.len - + ngx_sizeof_ssz(t05_body2) - + ngx_sizeof_ssz(t06_list1) - + ngx_sizeof_ssz(t_parentdir_entry) - + ngx_sizeof_ssz(t07_list2) - ; + if (alcf->show_path) + len = r->uri.len + + ngx_sizeof_ssz(t05_body2) + + ngx_sizeof_ssz(t06_list1) + + ngx_sizeof_ssz(t_parentdir_entry) + + ngx_sizeof_ssz(t07_list2) + + ngx_fancyindex_timefmt_calc_size (&alcf->time_format) * entries.nelts + ; + else + len = r->uri.len + + ngx_sizeof_ssz(t06_list1) + + ngx_sizeof_ssz(t_parentdir_entry) + + ngx_sizeof_ssz(t07_list2) + + ngx_fancyindex_timefmt_calc_size (&alcf->time_format) * entries.nelts + ; + + /* + * If we are a the root of the webserver (URI = "/" --> length of 1), + * do not display the "Parent Directory" link. + */ + if (r->uri.len == 1) { + len -= ngx_sizeof_ssz(t_parentdir_entry); + } entry = entries.elts; for (i = 0; i < entries.nelts; i++) { @@ -609,14 +767,15 @@ make_content_buf( len += ngx_sizeof_ssz("") + entry[i].name.len + entry[i].utf_len + alcf->name_length + ngx_sizeof_ssz(">") + ngx_sizeof_ssz("") + 20 /* File size */ - + ngx_sizeof_ssz("") - + ngx_sizeof_ssz(" 28-Sep-1970 12:00 ") - + ngx_sizeof_ssz("\n") + + ngx_sizeof_ssz("") /* Date prefix */ + + ngx_sizeof_ssz("\n") /* Date suffix */ + 2 /* CR LF */ ; } @@ -707,31 +866,48 @@ make_content_buf( /* Sort entries, if needed */ if (entries.nelts > 1) { - ngx_qsort(entry, (size_t) entries.nelts, + /* Use ngx_sort for stability */ + ngx_sort(entry, (size_t) entries.nelts, sizeof(ngx_http_fancyindex_entry_t), sort_cmp_func); + + if (alcf->dirs_first) + { + /* Sort directories first */ + ngx_sort(entry, (size_t) entries.nelts, + sizeof(ngx_http_fancyindex_entry_t), + ngx_http_fancyindex_cmp_entries_dirs_first); + } + } - b->last = ngx_cpymem_str(b->last, r->uri); - b->last = ngx_cpymem_ssz(b->last, t05_body2); + /* Display the path, if needed */ + if (alcf->show_path){ + b->last = ngx_cpymem_str(b->last, r->uri); + b->last = ngx_cpymem_ssz(b->last, t05_body2); + } + + /* Open the tag */ b->last = ngx_cpymem_ssz(b->last, t06_list1); tp = ngx_timeofday(); - /* "Parent dir" entry, always first */ - b->last = ngx_cpymem_ssz(b->last, - "" - "" + "" + "" + "" + ""); } - b->last = ngx_cpymem_ssz(b->last, - "\">Parent directory/" - "" - "" - ""); /* Entries for directories and files */ for (i = 0; i < entries.nelts; i++) { @@ -757,6 +933,9 @@ make_content_buf( } } + *b->last++ = '"'; + b->last = ngx_cpymem_ssz(b->last, " title=\""); + b->last = ngx_cpymem_str(b->last, entry[i].name); *b->last++ = '"'; *b->last++ = '>'; @@ -842,14 +1021,9 @@ make_content_buf( } ngx_gmtime(entry[i].mtime + tp->gmtoff * 60 * alcf->localtime, &tm); - - b->last = ngx_sprintf(b->last, "", - tm.ngx_tm_mday, - months[tm.ngx_tm_mon - 1], - tm.ngx_tm_year, - tm.ngx_tm_hour, - tm.ngx_tm_min); - + b->last = ngx_cpymem_ssz(b->last, ""); *b->last++ = CR; *b->last++ = LF; @@ -899,7 +1073,7 @@ ngx_http_fancyindex_handler(ngx_http_request_t *r) return NGX_DECLINED; } - if ((rc = make_content_buf(r, &out[0].buf, alcf) != NGX_OK)) + if ((rc = make_content_buf(r, &out[0].buf, alcf)) != NGX_OK) return rc; out[0].buf->last_in_chain = 1; @@ -910,8 +1084,7 @@ ngx_http_fancyindex_handler(ngx_http_request_t *r) r->headers_out.content_type.data = (u_char *) "text/html"; rc = ngx_http_send_header(r); - - if (rc != NGX_OK || r->header_only) + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) return rc; if (alcf->header.len > 0) { @@ -943,7 +1116,7 @@ ngx_http_fancyindex_handler(ngx_http_request_t *r) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: header subrequest status = %i", sr->headers_out.status); - /* ngx_http_subrequest returns NGX_OK(0), not NGX_HTTP_OK(200) */ + /* ngx_http_subrequest returns NGX_OK(0), not NGX_HTTP_OK(200) */ if (sr->headers_out.status != NGX_OK) { /* * XXX: Should we write a message to the error log just in case @@ -1038,112 +1211,81 @@ add_builtin_header: return (r != r->main) ? rc : ngx_http_send_special(r, NGX_HTTP_LAST); } +static ngx_int_t ngx_libc_cdecl +ngx_http_fancyindex_cmp_entries_dirs_first(const void *one, const void *two) +{ + ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; + ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; -static int ngx_libc_cdecl + /* move the directories to the start */ + if (first->dir && !second->dir) { + return -1; + } + if (!first->dir && second->dir) { + return 1; + } + + return 0; +} + + +static ngx_int_t ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_name_desc(const void *one, const void *two) { ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; - /* move the directories to the start */ - if (first->dir && !second->dir) { - return -1; - } - if (!first->dir && second->dir) { - return 1; - } - return (int) ngx_strcmp(second->name.data, first->name.data); } -static int ngx_libc_cdecl +static ngx_int_t ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_size_desc(const void *one, const void *two) { ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; - /* move the directories to the start */ - if (first->dir && !second->dir) { - return -1; - } - if (!first->dir && second->dir) { - return 1; - } - - return second->size - first->size; + return (int) (second->size - first->size); } -static int ngx_libc_cdecl +static ngx_int_t ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_mtime_desc(const void *one, const void *two) { ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; - /* move the directories to the start */ - if (first->dir && !second->dir) { - return -1; - } - if (!first->dir && second->dir) { - return 1; - } - - return second->mtime - first->mtime; + return (int) (second->mtime - first->mtime); } -static int ngx_libc_cdecl +static ngx_int_t ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_name_asc(const void *one, const void *two) { ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; - /* move the directories to the start */ - if (first->dir && !second->dir) { - return -1; - } - if (!first->dir && second->dir) { - return 1; - } - return (int) ngx_strcmp(first->name.data, second->name.data); } -static int ngx_libc_cdecl +static ngx_int_t ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_size_asc(const void *one, const void *two) { ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; - /* move the directories to the start */ - if (first->dir && !second->dir) { - return -1; - } - if (!first->dir && second->dir) { - return 1; - } - - return first->size - second->size; + return (int) (first->size - second->size); } -static int ngx_libc_cdecl +static ngx_int_t ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_mtime_asc(const void *one, const void *two) { ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; - /* move the directories to the start */ - if (first->dir && !second->dir) { - return -1; - } - if (!first->dir && second->dir) { - return 1; - } - - return first->mtime - second->mtime; + return (int) (first->mtime - second->mtime); } @@ -1171,17 +1313,24 @@ ngx_http_fancyindex_create_loc_conf(ngx_conf_t *cf) /* * Set by ngx_pcalloc: - * conf->header.len = 0 - * conf->header.data = NULL - * conf->footer.len = 0 - * conf->footer.data = NULL + * conf->header.len = 0 + * conf->header.data = NULL + * conf->footer.len = 0 + * conf->footer.data = NULL + * conf->css_href.len = 0 + * conf->css_href.data = NULL + * conf->time_format.len = 0 + * conf->time_format.data = NULL */ - conf->enable = NGX_CONF_UNSET; - conf->default_sort = NGX_CONF_UNSET_UINT; - conf->localtime = NGX_CONF_UNSET; - conf->name_length = NGX_CONF_UNSET_UINT; - conf->exact_size = NGX_CONF_UNSET; - conf->ignore = NGX_CONF_UNSET_PTR; + conf->enable = NGX_CONF_UNSET; + conf->default_sort = NGX_CONF_UNSET_UINT; + conf->dirs_first = NGX_CONF_UNSET; + conf->localtime = NGX_CONF_UNSET; + conf->name_length = NGX_CONF_UNSET_UINT; + conf->exact_size = NGX_CONF_UNSET; + conf->ignore = NGX_CONF_UNSET_PTR; + conf->hide_symlinks = NGX_CONF_UNSET; + conf->show_path = NGX_CONF_UNSET; return conf; } @@ -1193,16 +1342,30 @@ ngx_http_fancyindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_fancyindex_loc_conf_t *prev = parent; ngx_http_fancyindex_loc_conf_t *conf = child; + (void) cf; /* unused */ + ngx_conf_merge_value(conf->enable, prev->enable, 0); ngx_conf_merge_uint_value(conf->default_sort, prev->default_sort, NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME); + ngx_conf_merge_value(conf->dirs_first, prev->dirs_first, 1); ngx_conf_merge_value(conf->localtime, prev->localtime, 0); ngx_conf_merge_value(conf->exact_size, prev->exact_size, 1); + ngx_conf_merge_value(conf->show_path, prev->show_path, 1); ngx_conf_merge_uint_value(conf->name_length, prev->name_length, 50); ngx_conf_merge_str_value(conf->header, prev->header, ""); ngx_conf_merge_str_value(conf->footer, prev->footer, ""); + ngx_conf_merge_str_value(conf->css_href, prev->css_href, ""); + ngx_conf_merge_str_value(conf->time_format, prev->time_format, "%Y-%b-%d %H:%M"); ngx_conf_merge_ptr_value(conf->ignore, prev->ignore, NULL); + ngx_conf_merge_value(conf->hide_symlinks, prev->hide_symlinks, 0); + + /* Just make sure we haven't disabled the show_path directive without providing a custom header */ + if (conf->show_path == 0 && conf->header.len == 0) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "FancyIndex : cannot set show_path to off without providing a custom header !"); + return NGX_CONF_ERROR; + } return NGX_CONF_OK; } @@ -1214,6 +1377,8 @@ ngx_http_fancyindex_ignore(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_http_fancyindex_loc_conf_t *alcf = conf; ngx_str_t *value; + (void) cmd; /* unused */ + #if (NGX_PCRE) ngx_uint_t i; ngx_regex_elt_t *re; diff --git a/debian/modules/ngx-fancyindex/t/00-build-artifacts.test b/debian/modules/ngx-fancyindex/t/00-build-artifacts.test new file mode 100644 index 0000000..b9bc1ac --- /dev/null +++ b/debian/modules/ngx-fancyindex/t/00-build-artifacts.test @@ -0,0 +1,22 @@ +#! /bin/bash +cat <<--- +This test checks that the built Nginx either has the dynamic fancyindex +module available, or that it's not there (for static builds). +-- + +readonly nginx_path="${PREFIX}/sbin/nginx" +readonly so_path="${PREFIX}/modules/ngx_http_fancyindex_module.so" + +if [[ ! -x ${nginx_path} ]] ; then + fail "executable binary not found at '%s'\n" "${nginx_path}" +fi + +if ${DYNAMIC} ; then + if [[ ! -r ${so_path} ]] ; then + fail "module not found at '%s'\n" "${so_path}" + fi +else + if [[ -r ${so_path} ]] ; then + fail "module should not exist at '%s'\n" "${so_path}" + fi +fi diff --git a/debian/modules/ngx-fancyindex/t/01-smoke-hasindex.test b/debian/modules/ngx-fancyindex/t/01-smoke-hasindex.test new file mode 100644 index 0000000..19706a4 --- /dev/null +++ b/debian/modules/ngx-fancyindex/t/01-smoke-hasindex.test @@ -0,0 +1,7 @@ +#! /bin/bash +cat <<--- +This test fetches the root directory served by Nginx, which has no index file, +and checks that the output contains something that resembles a directory index. +-- +nginx_start +grep 'Index of' <( fetch ) diff --git a/debian/modules/ngx-fancyindex/t/02-smoke-indexisfancy.test b/debian/modules/ngx-fancyindex/t/02-smoke-indexisfancy.test new file mode 100644 index 0000000..10cc403 --- /dev/null +++ b/debian/modules/ngx-fancyindex/t/02-smoke-indexisfancy.test @@ -0,0 +1,11 @@ +#! /bin/bash +cat <<--- +This test fetches the root directory served by Nginx, which has no index file, +and checks that the output contains something that resembles the output from +the fancyindex module. +-- +nginx_start +content=$(fetch --with-headers) +grep 'Index of /' <<< "${content}" # It is an index +grep '\' <<< "${content}" # It contains a table +grep '^ Content-Type:[[:space:]]*text/html' <<< "${content}" diff --git a/debian/modules/ngx-fancyindex/t/build-and-run b/debian/modules/ngx-fancyindex/t/build-and-run new file mode 100755 index 0000000..68584b7 --- /dev/null +++ b/debian/modules/ngx-fancyindex/t/build-and-run @@ -0,0 +1,25 @@ +#! /bin/bash +set -e + +if [[ $# -lt 1 || $# -gt 2 ]] ; then + echo "Usage: $0 [1]" 1>&2 + exit 1 +fi + +readonly NGINX=$1 + +if [[ $2 -eq 1 ]] ; then + readonly DYNAMIC=$2 +fi + +cd "$(dirname "$0")/.." +wget -O - http://nginx.org/download/nginx-${NGINX}.tar.gz | tar -xzf - +rm -rf prefix/ +cd nginx-${NGINX} +./configure \ + --add-${DYNAMIC:+dynamic-}module=.. \ + --with-http_addition_module \ + --prefix="$(pwd)/../prefix" +make install +cd .. +exec ./t/run prefix ${DYNAMIC} diff --git a/debian/modules/ngx-fancyindex/t/has-index.test b/debian/modules/ngx-fancyindex/t/has-index.test new file mode 100644 index 0000000..cf34207 --- /dev/null +++ b/debian/modules/ngx-fancyindex/t/has-index.test @@ -0,0 +1,7 @@ +#! /bin/bash +cat <<--- +This test ensures that the "index.html" is returned instead of a directory +listing when fetching a directory which contains an index file. +-- +nginx_start +diff -u "${TESTDIR}/has-index/index.html" <( fetch /has-index/ ) 1>&2 diff --git a/debian/modules/ngx-fancyindex/t/has-index/index.html b/debian/modules/ngx-fancyindex/t/has-index/index.html new file mode 100644 index 0000000..419ae86 --- /dev/null +++ b/debian/modules/ngx-fancyindex/t/has-index/index.html @@ -0,0 +1,10 @@ + + + + + Index file test + + + This is index.html. + + diff --git a/debian/modules/ngx-fancyindex/t/nginx.conf b/debian/modules/ngx-fancyindex/t/nginx.conf new file mode 100644 index 0000000..2b99a3d --- /dev/null +++ b/debian/modules/ngx-fancyindex/t/nginx.conf @@ -0,0 +1,25 @@ +worker_processes 1; + + +events { + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + sendfile on; + keepalive_timeout 65; + server { + listen 80; + server_name localhost; + location / { + root html; + index index.html index.htm; + } + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root html; + } + } +} diff --git a/debian/modules/ngx-fancyindex/t/preamble b/debian/modules/ngx-fancyindex/t/preamble new file mode 100644 index 0000000..a571381 --- /dev/null +++ b/debian/modules/ngx-fancyindex/t/preamble @@ -0,0 +1,84 @@ +#! /bin/bash +# +# preamble +# Copyright (C) 2016 Adrian Perez +# +# Distributed under terms of the MIT license. +# + +function nginx_conf_generate () { + if ${DYNAMIC} ; then + echo 'load_module modules/ngx_http_fancyindex_module.so;' + fi + cat <<-EOF + worker_processes 1; + events { worker_connections 1024; } + http { + include mime.types; + default_type application/octet-stream; + sendfile on; + keepalive_timeout 65; + server { + server_name localhost; + listen 127.0.0.1:8888; + root ${TESTDIR}; + error_page 500 502 503 504 /50x.html; + location = /50x.html { root html; } + location / { + index index.html; + fancyindex on; + $* + } + } + } + EOF +} + +readonly NGINX_CONF="${PREFIX}/conf/nginx.conf" +readonly NGINX_PID="${PREFIX}/logs/nginx.pid" +rm -f "${NGINX_CONF}" "${NGINX_PID}" +mkdir -p "${PREFIX}/logs" + +function nginx () { + env - PATH="${PATH}" "${PREFIX}/sbin/nginx" "$@" +} + +function nginx_conf () { + nginx_conf_generate "$@" > "${NGINX_CONF}" +} + +function nginx_is_running () { + [[ -r ${NGINX_PID} ]] && kill -0 $(< "${NGINX_PID}") +} + +function nginx_stop () { + if nginx_is_running ; then nginx -s stop ; fi + rm -f "${NGINX_PID}" +} +trap nginx_stop EXIT + +function nginx_start () { + if [[ $# -gt 0 || ! -r ${NGINX_CONF} ]] ; then nginx_conf "$@" ; fi + nginx_stop # Ensure that it is not running. + nginx +} + +function fetch () { + local -a opts=( -q ) + if [[ $1 = --with-headers ]] ; then + opts+=( -S ) + shift + fi + wget "${opts[@]}" -O- "http://localhost:8888${1:-/}" 2>&1 +} + +function fail () { + printf "(FF) " + printf "$@" + exit 1 +} 1>&2 + +function warn () { + printf "(WW)" + printf "$@" +} 1>&2 diff --git a/debian/modules/ngx-fancyindex/t/run b/debian/modules/ngx-fancyindex/t/run new file mode 100755 index 0000000..2001bff --- /dev/null +++ b/debian/modules/ngx-fancyindex/t/run @@ -0,0 +1,67 @@ +#! /bin/bash +set -e + +if [[ $# -lt 1 || $# -gt 2 ]] ; then + echo "Usage: $0 [1]" 1>&2 + exit 1 +fi + +# Obtain the absolute path to the tests directory +pushd "$(dirname "$0")" &> /dev/null +readonly T=$(pwd) +popd &> /dev/null +export T + +# Same for the nginx prefix directory +pushd "$1" &> /dev/null +readonly prefix=$(pwd) +popd &> /dev/null + +dynamic=false +if [[ $# -gt 1 && $2 -eq 1 ]] ; then + dynamic=true +fi +readonly dynamic + +declare -a t_pass=( ) +declare -a t_fail=( ) + +for t in "$T"/*.test ; do + name="t/${t##*/}" + name=${name%.test} + printf "${name} ... " + errfile="${name}.err" + outfile="${name}.out" + shfile="${name}.sh" + cat > "${shfile}" <<-EOF + readonly DYNAMIC=${dynamic} + readonly TESTDIR='$T' + readonly PREFIX='${prefix}' + $(< "$T/preamble") + $(< "$t") + EOF + if bash -e "${shfile}" > "${outfile}" 2> "${errfile}" ; then + t_pass+=( "${name}" ) + printf 'passed\n' + else + t_fail+=( "${name}" ) + printf 'failed\n' + fi +done + +for name in "${t_fail[@]}" ; do + echo + printf '=== %s.out\n' "${name}" + cat "${name}.out" + echo + printf '=== %s.err\n' "${name}" + cat "${name}.err" + echo +done + +printf '=== passed/failed/total: %d/%d/%d\n' \ + ${#t_pass[@]} ${#t_fail[@]} $(( ${#t_pass[@]} + ${#t_fail[@]} )) + +if [[ ${#t_fail[@]} -gt 0 ]] ; then + exit 1 +fi diff --git a/debian/modules/ngx-fancyindex/template.h b/debian/modules/ngx-fancyindex/template.h index 8375a1f..4881ac7 100644 --- a/debian/modules/ngx-fancyindex/template.h +++ b/debian/modules/ngx-fancyindex/template.h @@ -66,9 +66,9 @@ static const u_char t06_list1[] = "" "\n" "" "" -"" -"" -"" +"" +"" +"" "" "" "\n" diff --git a/debian/modules/ngx-fancyindex/template.html b/debian/modules/ngx-fancyindex/template.html index eb0a40d..bc41292 100644 --- a/debian/modules/ngx-fancyindex/template.html +++ b/debian/modules/ngx-fancyindex/template.html @@ -64,9 +64,9 @@ - - - + + + From cf3d323bd558ed215d2ad4cf106840e2d3b63c07 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 31 Aug 2016 13:00:13 +0300 Subject: [PATCH 148/651] mod: Convert fancyindex to a dynamic module --- debian/control | 9 +++++++++ debian/libnginx-mod-http-fancyindex.nginx | 13 +++++++++++++ debian/libnginx-mod.conf/mod-http-fancyindex.conf | 1 + debian/rules | 4 ++-- debian/tests/control | 3 +++ 5 files changed, 28 insertions(+), 2 deletions(-) create mode 100755 debian/libnginx-mod-http-fancyindex.nginx create mode 100644 debian/libnginx-mod.conf/mod-http-fancyindex.conf diff --git a/debian/control b/debian/control index a61ee9f..1eb6d70 100644 --- a/debian/control +++ b/debian/control @@ -195,6 +195,7 @@ Depends: nginx-common (= ${source:Version}), libnginx-mod-http-upstream-fair (= ${binary:Version}), libnginx-mod-http-headers-more-filter (= ${binary:Version}), libnginx-mod-http-cache-purge (= ${binary:Version}), + libnginx-mod-http-fancyindex (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} Breaks: nginx (<< 1.4.5-1) @@ -395,3 +396,11 @@ Description: Purge content from Nginx caches Cache Purge module adds purging capabilities to Nginx. It allows purging content from caches used by all of Nginx proxy modules, like FastCGI, Proxy, SCGI and uWSGI. + +Package: libnginx-mod-http-fancyindex +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: Fancy indexes module for the Nginx + The Fancy Index module makes possible the generation of file listings, like + the built-in autoindex module does, but adding a touch of style by introducing + ways to customize the result. diff --git a/debian/libnginx-mod-http-fancyindex.nginx b/debian/libnginx-mod-http-fancyindex.nginx new file mode 100755 index 0000000..78c206f --- /dev/null +++ b/debian/libnginx-mod-http-fancyindex.nginx @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use File::Basename; + +# Guess module name +$module = basename($0, '.nginx'); +$module =~ s/^libnginx-mod-//; + +$modulepath = $module; +$modulepath =~ s/-/_/g; + +print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod.conf/mod-http-fancyindex.conf b/debian/libnginx-mod.conf/mod-http-fancyindex.conf new file mode 100644 index 0000000..4aa4f2f --- /dev/null +++ b/debian/libnginx-mod.conf/mod-http-fancyindex.conf @@ -0,0 +1 @@ +load_module modules/ngx_http_fancyindex_module.so; diff --git a/debian/rules b/debian/rules index f6a814a..7a15973 100755 --- a/debian/rules +++ b/debian/rules @@ -11,7 +11,7 @@ DEBIAN_NGINX_PERL_LDFLAGS:= $(shell DEB_BUILD_MAINT_OPTIONS=hardening=+all,-pie export DEBIAN_NGINX_PERL_LDFLAGS FLAVOURS := full light extras -DYN_MODS := http-geoip http-image-filter http-xslt-filter mail stream http-auth-pam http-lua http-perl http-ndk nchan http-echo http-upstream-fair http-headers-more-filter http-cache-purge +DYN_MODS := http-geoip http-image-filter http-xslt-filter mail stream http-auth-pam http-lua http-perl http-ndk nchan http-echo http-upstream-fair http-headers-more-filter http-cache-purge http-fancyindex MODULESDIR = $(CURDIR)/debian/modules BASEDIR = $(CURDIR) @@ -111,7 +111,7 @@ extras_configure_flags := \ --add-module=$(MODULESDIR)/nginx-dav-ext-module \ --add-dynamic-module=$(MODULESDIR)/nginx-development-kit \ --add-dynamic-module=$(MODULESDIR)/nginx-echo \ - --add-module=$(MODULESDIR)/ngx-fancyindex \ + --add-dynamic-module=$(MODULESDIR)/ngx-fancyindex \ --add-dynamic-module=$(MODULESDIR)/nchan \ --add-dynamic-module=$(MODULESDIR)/nginx-lua \ --add-module=$(MODULESDIR)/nginx-upload-progress \ diff --git a/debian/tests/control b/debian/tests/control index bdffd81..ddc1e4e 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -17,6 +17,7 @@ Depends: nginx-full, libnginx-mod-http-auth-pam, libnginx-mod-http-cache-purge, libnginx-mod-http-echo, + libnginx-mod-http-fancyindex, libnginx-mod-http-geoip, libnginx-mod-http-headers-more-filter, libnginx-mod-http-image-filter, @@ -35,6 +36,7 @@ Depends: nginx-light, libnginx-mod-http-auth-pam, libnginx-mod-http-cache-purge, libnginx-mod-http-echo, + libnginx-mod-http-fancyindex, libnginx-mod-http-geoip, libnginx-mod-http-headers-more-filter, libnginx-mod-http-image-filter, @@ -53,6 +55,7 @@ Depends: nginx-extras, libnginx-mod-http-auth-pam, libnginx-mod-http-cache-purge, libnginx-mod-http-echo, + libnginx-mod-http-fancyindex, libnginx-mod-http-geoip, libnginx-mod-http-headers-more-filter, libnginx-mod-http-image-filter, From 4dd8c07889e827a479bb038f5a854329b1990ccb Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 31 Aug 2016 13:12:16 +0300 Subject: [PATCH 149/651] Upgrade upload-progress module to v0.9.2 --- debian/modules/README.Modules-versions | 3 +-- debian/modules/nginx-upload-progress/CHANGES | 4 ++++ debian/modules/nginx-upload-progress/config | 12 ++++++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index d2537a4..b9a37e3 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -35,8 +35,7 @@ README for Modules versions nginx-upload-progress Homepage: https://github.com/masterzen/nginx-upload-progress-module rm -r debian/nginx-upload-progress/test - Version: v0.9.1 - Dynamic: No, https://github.com/masterzen/nginx-upload-progress-module/issues/46 + Version: v0.9.2 nginx-cache-purge Homepage: https://github.com/FRiCKLE/ngx_cache_purge/ diff --git a/debian/modules/nginx-upload-progress/CHANGES b/debian/modules/nginx-upload-progress/CHANGES index f33b435..1de19aa 100644 --- a/debian/modules/nginx-upload-progress/CHANGES +++ b/debian/modules/nginx-upload-progress/CHANGES @@ -1,3 +1,7 @@ +nginx_upload_progress release 0.9.2 03 Aug 2016 + + * Allow to build as an externally loadable module (thanks to Peter Tonoli). + nginx_upload_progress release 0.9.0 06 Apr 2012 * INCOMPATIBLE CHANGE: JSONP is now the default output for nginx upload diff --git a/debian/modules/nginx-upload-progress/config b/debian/modules/nginx-upload-progress/config index 5cf6fa1..364af8c 100644 --- a/debian/modules/nginx-upload-progress/config +++ b/debian/modules/nginx-upload-progress/config @@ -1,3 +1,11 @@ ngx_addon_name=ngx_http_uploadprogress_module -HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES ngx_http_uploadprogress_module" -NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_uploadprogress_module.c" +if test -n "$ngx_module_link"; then + ngx_module_type=FILTER + ngx_module_name=ngx_http_uploadprogress_module + ngx_module_srcs="$ngx_addon_dir/ngx_http_uploadprogress_module.c" + + . auto/module +else + HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES ngx_http_uploadprogress_module" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_uploadprogress_module.c" +fi From 577178cdffd44bd01896d6ed0dc489d37764a16c Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 31 Aug 2016 13:18:37 +0300 Subject: [PATCH 150/651] mod: Convert upload progress module to dynamic --- debian/control | 12 ++++++++++++ debian/libnginx-mod-http-uploadprogress.nginx | 13 +++++++++++++ .../libnginx-mod.conf/mod-http-uploadprogress.conf | 1 + debian/rules | 4 ++-- debian/tests/control | 3 +++ 5 files changed, 31 insertions(+), 2 deletions(-) create mode 100755 debian/libnginx-mod-http-uploadprogress.nginx create mode 100644 debian/libnginx-mod.conf/mod-http-uploadprogress.conf diff --git a/debian/control b/debian/control index 1eb6d70..7f2bb3e 100644 --- a/debian/control +++ b/debian/control @@ -196,6 +196,7 @@ Depends: nginx-common (= ${source:Version}), libnginx-mod-http-headers-more-filter (= ${binary:Version}), libnginx-mod-http-cache-purge (= ${binary:Version}), libnginx-mod-http-fancyindex (= ${binary:Version}), + libnginx-mod-http-uploadprogress (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} Breaks: nginx (<< 1.4.5-1) @@ -404,3 +405,14 @@ Description: Fancy indexes module for the Nginx The Fancy Index module makes possible the generation of file listings, like the built-in autoindex module does, but adding a touch of style by introducing ways to customize the result. + +Package: libnginx-mod-http-uploadprogress +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: Upload progress system for Nginx + Upload progress module is an implementation of an upload progress system, that + monitors RFC1867 POST uploads as they are transmitted to upstream servers. + . + It works by tracking the uploads proxied by Nginx to upstream servers without + analysing the uploaded content and offers a web API to report upload progress + in Javscript, Json or any other format. diff --git a/debian/libnginx-mod-http-uploadprogress.nginx b/debian/libnginx-mod-http-uploadprogress.nginx new file mode 100755 index 0000000..78c206f --- /dev/null +++ b/debian/libnginx-mod-http-uploadprogress.nginx @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use File::Basename; + +# Guess module name +$module = basename($0, '.nginx'); +$module =~ s/^libnginx-mod-//; + +$modulepath = $module; +$modulepath =~ s/-/_/g; + +print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod.conf/mod-http-uploadprogress.conf b/debian/libnginx-mod.conf/mod-http-uploadprogress.conf new file mode 100644 index 0000000..edc0c0b --- /dev/null +++ b/debian/libnginx-mod.conf/mod-http-uploadprogress.conf @@ -0,0 +1 @@ +load_module modules/ngx_http_uploadprogress_module.so; diff --git a/debian/rules b/debian/rules index 7a15973..adbbd42 100755 --- a/debian/rules +++ b/debian/rules @@ -11,7 +11,7 @@ DEBIAN_NGINX_PERL_LDFLAGS:= $(shell DEB_BUILD_MAINT_OPTIONS=hardening=+all,-pie export DEBIAN_NGINX_PERL_LDFLAGS FLAVOURS := full light extras -DYN_MODS := http-geoip http-image-filter http-xslt-filter mail stream http-auth-pam http-lua http-perl http-ndk nchan http-echo http-upstream-fair http-headers-more-filter http-cache-purge http-fancyindex +DYN_MODS := http-geoip http-image-filter http-xslt-filter mail stream http-auth-pam http-lua http-perl http-ndk nchan http-echo http-upstream-fair http-headers-more-filter http-cache-purge http-fancyindex http-uploadprogress MODULESDIR = $(CURDIR)/debian/modules BASEDIR = $(CURDIR) @@ -114,7 +114,7 @@ extras_configure_flags := \ --add-dynamic-module=$(MODULESDIR)/ngx-fancyindex \ --add-dynamic-module=$(MODULESDIR)/nchan \ --add-dynamic-module=$(MODULESDIR)/nginx-lua \ - --add-module=$(MODULESDIR)/nginx-upload-progress \ + --add-dynamic-module=$(MODULESDIR)/nginx-upload-progress \ --add-dynamic-module=$(MODULESDIR)/nginx-upstream-fair \ --add-module=$(MODULESDIR)/ngx_http_substitutions_filter_module diff --git a/debian/tests/control b/debian/tests/control index ddc1e4e..e5a4d83 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -23,6 +23,7 @@ Depends: nginx-full, libnginx-mod-http-image-filter, libnginx-mod-http-lua, libnginx-mod-http-perl, + libnginx-mod-http-uploadprogress, libnginx-mod-http-upstream-fair, libnginx-mod-http-xslt-filter, libnginx-mod-mail, @@ -42,6 +43,7 @@ Depends: nginx-light, libnginx-mod-http-image-filter, libnginx-mod-http-lua, libnginx-mod-http-perl, + libnginx-mod-http-uploadprogress, libnginx-mod-http-upstream-fair, libnginx-mod-http-xslt-filter, libnginx-mod-mail, @@ -61,6 +63,7 @@ Depends: nginx-extras, libnginx-mod-http-image-filter, libnginx-mod-http-lua, libnginx-mod-http-perl, + libnginx-mod-http-uploadprogress, libnginx-mod-http-upstream-fair, libnginx-mod-http-xslt-filter, libnginx-mod-mail, From 3381e6e548c38039b44b5a77464dfe87bb840927 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 31 Aug 2016 14:44:11 +0300 Subject: [PATCH 151/651] mod: Convert substitution module to dynamic --- debian/control | 11 +++++++++++ debian/libnginx-mod-http-subs-filter.nginx | 13 +++++++++++++ .../libnginx-mod.conf/mod-http-subs-filter.conf | 1 + debian/modules/README.Modules-versions | 3 +-- .../ngx_http_substitutions_filter_module/config | 16 ++++++++++++++-- debian/rules | 6 +++--- debian/tests/control | 3 +++ 7 files changed, 46 insertions(+), 7 deletions(-) create mode 100755 debian/libnginx-mod-http-subs-filter.nginx create mode 100644 debian/libnginx-mod.conf/mod-http-subs-filter.conf diff --git a/debian/control b/debian/control index 7f2bb3e..c986066 100644 --- a/debian/control +++ b/debian/control @@ -92,6 +92,7 @@ Depends: nginx-common (= ${source:Version}), libnginx-mod-http-auth-pam (= ${binary:Version}), libnginx-mod-http-echo (= ${binary:Version}), libnginx-mod-http-upstream-fair (= ${binary:Version}), + libnginx-mod-http-subs-filter (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} Breaks: nginx (<< 1.4.5-1) @@ -197,6 +198,7 @@ Depends: nginx-common (= ${source:Version}), libnginx-mod-http-cache-purge (= ${binary:Version}), libnginx-mod-http-fancyindex (= ${binary:Version}), libnginx-mod-http-uploadprogress (= ${binary:Version}), + libnginx-mod-http-subs-filter (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} Breaks: nginx (<< 1.4.5-1) @@ -416,3 +418,12 @@ Description: Upload progress system for Nginx It works by tracking the uploads proxied by Nginx to upstream servers without analysing the uploaded content and offers a web API to report upload progress in Javscript, Json or any other format. + +Package: libnginx-mod-http-subs-filter +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: Substitution filter module for Nginx + Subsitution Nginx module can do both regular expression and fixed string + substitutions on response bodies. The module is quite different from Nginx's + native Substitution module. It scans the output chains buffer and + matches string line by line, just like Apache's mod_substitute. diff --git a/debian/libnginx-mod-http-subs-filter.nginx b/debian/libnginx-mod-http-subs-filter.nginx new file mode 100755 index 0000000..78c206f --- /dev/null +++ b/debian/libnginx-mod-http-subs-filter.nginx @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use File::Basename; + +# Guess module name +$module = basename($0, '.nginx'); +$module =~ s/^libnginx-mod-//; + +$modulepath = $module; +$modulepath =~ s/-/_/g; + +print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod.conf/mod-http-subs-filter.conf b/debian/libnginx-mod.conf/mod-http-subs-filter.conf new file mode 100644 index 0000000..fe34b6c --- /dev/null +++ b/debian/libnginx-mod.conf/mod-http-subs-filter.conf @@ -0,0 +1 @@ +load_module modules/ngx_http_subs_filter_module.so; diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index b9a37e3..a87f25d 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -52,5 +52,4 @@ README for Modules versions ngx_http_substitutions_filter_module Homepage: https://github.com/yaoweibin/ngx_http_substitutions_filter_module - Version: v0.6.4 - Dynamic: No, https://github.com/yaoweibin/ngx_http_substitutions_filter_module/pull/19 + Version: v0.6.4+pull/19 diff --git a/debian/modules/ngx_http_substitutions_filter_module/config b/debian/modules/ngx_http_substitutions_filter_module/config index fdb016c..f1de029 100644 --- a/debian/modules/ngx_http_substitutions_filter_module/config +++ b/debian/modules/ngx_http_substitutions_filter_module/config @@ -1,3 +1,15 @@ ngx_addon_name=ngx_http_subs_filter_module -HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_subs_filter_module" -NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_subs_filter_module.c" + +if test -n "$ngx_module_link"; then + ngx_module_type=HTTP_FILTER + ngx_module_name=ngx_http_subs_filter_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs="$ngx_addon_dir/ngx_http_subs_filter_module.c" + ngx_module_libs="" + + . auto/module +else + HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_subs_filter_module" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_subs_filter_module.c" +fi diff --git a/debian/rules b/debian/rules index adbbd42..8ae25ac 100755 --- a/debian/rules +++ b/debian/rules @@ -11,7 +11,7 @@ DEBIAN_NGINX_PERL_LDFLAGS:= $(shell DEB_BUILD_MAINT_OPTIONS=hardening=+all,-pie export DEBIAN_NGINX_PERL_LDFLAGS FLAVOURS := full light extras -DYN_MODS := http-geoip http-image-filter http-xslt-filter mail stream http-auth-pam http-lua http-perl http-ndk nchan http-echo http-upstream-fair http-headers-more-filter http-cache-purge http-fancyindex http-uploadprogress +DYN_MODS := http-geoip http-image-filter http-xslt-filter mail stream http-auth-pam http-lua http-perl http-ndk nchan http-echo http-upstream-fair http-headers-more-filter http-cache-purge http-fancyindex http-uploadprogress http-subs-filter MODULESDIR = $(CURDIR)/debian/modules BASEDIR = $(CURDIR) @@ -85,7 +85,7 @@ full_configure_flags := \ --add-module=$(MODULESDIR)/nginx-dav-ext-module \ --add-dynamic-module=$(MODULESDIR)/nginx-echo \ --add-dynamic-module=$(MODULESDIR)/nginx-upstream-fair \ - --add-module=$(MODULESDIR)/ngx_http_substitutions_filter_module + --add-dynamic-module=$(MODULESDIR)/ngx_http_substitutions_filter_module extras_configure_flags := \ $(common_configure_flags) \ @@ -116,7 +116,7 @@ extras_configure_flags := \ --add-dynamic-module=$(MODULESDIR)/nginx-lua \ --add-dynamic-module=$(MODULESDIR)/nginx-upload-progress \ --add-dynamic-module=$(MODULESDIR)/nginx-upstream-fair \ - --add-module=$(MODULESDIR)/ngx_http_substitutions_filter_module + --add-dynamic-module=$(MODULESDIR)/ngx_http_substitutions_filter_module %: dh $@ --with systemd diff --git a/debian/tests/control b/debian/tests/control index e5a4d83..86a0da7 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -23,6 +23,7 @@ Depends: nginx-full, libnginx-mod-http-image-filter, libnginx-mod-http-lua, libnginx-mod-http-perl, + libnginx-mod-http-subs-filter, libnginx-mod-http-uploadprogress, libnginx-mod-http-upstream-fair, libnginx-mod-http-xslt-filter, @@ -43,6 +44,7 @@ Depends: nginx-light, libnginx-mod-http-image-filter, libnginx-mod-http-lua, libnginx-mod-http-perl, + libnginx-mod-http-subs-filter, libnginx-mod-http-uploadprogress, libnginx-mod-http-upstream-fair, libnginx-mod-http-xslt-filter, @@ -63,6 +65,7 @@ Depends: nginx-extras, libnginx-mod-http-image-filter, libnginx-mod-http-lua, libnginx-mod-http-perl, + libnginx-mod-http-subs-filter, libnginx-mod-http-uploadprogress, libnginx-mod-http-upstream-fair, libnginx-mod-http-xslt-filter, From 14e6282c9bfec49372025158a42dba4dc1b1b44d Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 31 Aug 2016 16:12:37 +0300 Subject: [PATCH 152/651] Update d/changelog --- debian/changelog | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/debian/changelog b/debian/changelog index 1c253a7..9d34e8c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,11 +2,26 @@ nginx (1.10.1-2) UNRELEASED; urgency=medium [ Christos Trochalakis ] * debian/control: - Don't allow building against liblua5.1-0-dev on architectures - that libluajit is available. + + Don't allow building against liblua5.1-0-dev on architectures + that libluajit is available. + Enable slice module on all flavors. (Closes: #815080) - * debian/modules/nginx-lua: - + Update nginx-lua to v0.10.6 + + Enable SCGI & uWSGI module for nginx-light. + + Convert to dynamic module packages: + o libnginx-mod-nchan + o libnginx-mod-http-echo + o libnginx-mod-http-upstream-fair + o libnginx-mod-http-headers-more-filter + o libnginx-mod-http-cache-purge + o libnginx-mod-http-fancyindex + o libnginx-mod-http-uploadprogress + o libnginx-mod-http-subs-filter + * debian/modules: + + Replace http-push with nchan v1.0.2 (Closes: #836134) + + Upgrade nginx-lua to v0.10.6 + + Upgrade nginx-echo to v0.60 + + Upgrade headers-more to v0.31 + + Upgrade fancyindex to v0.4.1 + + Upgrade upload-progress to v0.9.2 [ Michael Lustfield ] * debian/patches/0003-*.patch: From 3953784152f876fdcdf8e838651432d560aec031 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 31 Aug 2016 14:48:28 +0300 Subject: [PATCH 153/651] wrap-and-sort --- debian/control | 58 ++++++++++++++++++------------------- debian/nginx-common.dirs | 8 ++--- debian/nginx-common.install | 4 +-- debian/rules | 19 +++++++++++- 4 files changed, 52 insertions(+), 37 deletions(-) diff --git a/debian/control b/debian/control index c986066..cd18cbc 100644 --- a/debian/control +++ b/debian/control @@ -15,8 +15,9 @@ Build-Depends: autotools-dev, libexpat-dev, libgd-dev, libgeoip-dev, - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 armel armhf powerpc powerpcspe mips mipsel], + libhiredis-dev, liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !armel !armhf !powerpc !powerpcspe !mips !mipsel], + libluajit-5.1-dev [i386 amd64 kfreebsd-i386 armel armhf powerpc powerpcspe mips mipsel], libmhash-dev, libpam0g-dev, libpcre3-dev, @@ -24,8 +25,7 @@ Build-Depends: autotools-dev, libssl-dev, libxslt1-dev, po-debconf, - zlib1g-dev, - libhiredis-dev + zlib1g-dev Standards-Version: 3.9.8.0 Homepage: http://nginx.net Vcs-Git: https://anonscm.debian.org/cgit/collab-maint/nginx.git @@ -33,12 +33,8 @@ Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/nginx.git Package: nginx Architecture: all -Depends: nginx-full (>= ${source:Version}) | - nginx-light (>= ${source:Version}) | - nginx-extras (>= ${source:Version}) , - nginx-full (<< ${source:Version}.1~) | - nginx-light (<< ${source:Version}.1~) | - nginx-extras (<< ${source:Version}.1~) , +Depends: nginx-full (<< ${source:Version}.1~) | nginx-light (<< ${source:Version}.1~) | nginx-extras (<< ${source:Version}.1~), + nginx-full (>= ${source:Version}) | nginx-light (>= ${source:Version}) | nginx-extras (>= ${source:Version}), ${misc:Depends} Description: small, powerful, scalable web/proxy server Nginx ("engine X") is a high-performance web and reverse proxy server @@ -83,16 +79,16 @@ Description: small, powerful, scalable web/proxy server - common files Package: nginx-full Architecture: any -Depends: nginx-common (= ${source:Version}), +Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), + libnginx-mod-http-echo (= ${binary:Version}), libnginx-mod-http-geoip (= ${binary:Version}), libnginx-mod-http-image-filter (= ${binary:Version}), + libnginx-mod-http-subs-filter (= ${binary:Version}), + libnginx-mod-http-upstream-fair (= ${binary:Version}), libnginx-mod-http-xslt-filter (= ${binary:Version}), libnginx-mod-mail (= ${binary:Version}), libnginx-mod-stream (= ${binary:Version}), - libnginx-mod-http-auth-pam (= ${binary:Version}), - libnginx-mod-http-echo (= ${binary:Version}), - libnginx-mod-http-upstream-fair (= ${binary:Version}), - libnginx-mod-http-subs-filter (= ${binary:Version}), + nginx-common (= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} Breaks: nginx (<< 1.4.5-1) @@ -139,8 +135,8 @@ Description: nginx web/proxy server (standard version) - debugging symbols Package: nginx-light Architecture: any Priority: extra -Depends: nginx-common (= ${source:Version}), - libnginx-mod-http-echo (= ${binary:Version}), +Depends: libnginx-mod-http-echo (= ${binary:Version}), + nginx-common (= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} Breaks: nginx (<< 1.4.5-1) @@ -182,23 +178,23 @@ Description: nginx web/proxy server (basic version) - debugging symbols Package: nginx-extras Architecture: any Priority: extra -Depends: nginx-common (= ${source:Version}), +Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), + libnginx-mod-http-cache-purge (= ${binary:Version}), + libnginx-mod-http-echo (= ${binary:Version}), + libnginx-mod-http-fancyindex (= ${binary:Version}), libnginx-mod-http-geoip (= ${binary:Version}), + libnginx-mod-http-headers-more-filter (= ${binary:Version}), libnginx-mod-http-image-filter (= ${binary:Version}), - libnginx-mod-http-xslt-filter (= ${binary:Version}), - libnginx-mod-mail (= ${binary:Version}), - libnginx-mod-stream (= ${binary:Version}), - libnginx-mod-http-auth-pam (= ${binary:Version}), libnginx-mod-http-lua (= ${binary:Version}), libnginx-mod-http-perl (= ${binary:Version}), - libnginx-mod-nchan (= ${binary:Version}), - libnginx-mod-http-echo (= ${binary:Version}), - libnginx-mod-http-upstream-fair (= ${binary:Version}), - libnginx-mod-http-headers-more-filter (= ${binary:Version}), - libnginx-mod-http-cache-purge (= ${binary:Version}), - libnginx-mod-http-fancyindex (= ${binary:Version}), - libnginx-mod-http-uploadprogress (= ${binary:Version}), libnginx-mod-http-subs-filter (= ${binary:Version}), + libnginx-mod-http-uploadprogress (= ${binary:Version}), + libnginx-mod-http-upstream-fair (= ${binary:Version}), + libnginx-mod-http-xslt-filter (= ${binary:Version}), + libnginx-mod-mail (= ${binary:Version}), + libnginx-mod-nchan (= ${binary:Version}), + libnginx-mod-stream (= ${binary:Version}), + nginx-common (= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} Breaks: nginx (<< 1.4.5-1) @@ -295,7 +291,7 @@ Description: Stream module for Nginx Package: libnginx-mod-http-perl Architecture: any -Depends: ${perl:Depends}, ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${perl:Depends}, ${shlibs:Depends} Replaces: nginx-extras (<< 1.9.14-1) Description: Perl module for Nginx Embed Perl runtime into nginx. @@ -316,7 +312,9 @@ Description: PAM authentication module for Nginx Package: libnginx-mod-http-lua Architecture: any -Depends: libnginx-mod-http-ndk (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} +Depends: libnginx-mod-http-ndk (= ${binary:Version}), + ${misc:Depends}, + ${shlibs:Depends} Description: LUA module for Nginx Embed LUA runtime into nginx. . diff --git a/debian/nginx-common.dirs b/debian/nginx-common.dirs index 8ee01f5..65bb651 100644 --- a/debian/nginx-common.dirs +++ b/debian/nginx-common.dirs @@ -1,13 +1,13 @@ etc/nginx -etc/nginx/sites-available -etc/nginx/sites-enabled +etc/nginx/conf.d etc/nginx/modules-available etc/nginx/modules-enabled -etc/nginx/conf.d +etc/nginx/sites-available +etc/nginx/sites-enabled etc/ufw/applications.d usr/share/nginx usr/share/vim/addons usr/share/vim/registry -var/log/nginx var/lib/nginx +var/log/nginx var/www/html diff --git a/debian/nginx-common.install b/debian/nginx-common.install index a114903..90f173b 100644 --- a/debian/nginx-common.install +++ b/debian/nginx-common.install @@ -1,5 +1,5 @@ +contrib/vim/* usr/share/vim/addons debian/conf/* etc/nginx debian/ufw/nginx etc/ufw/applications.d -html/index.html usr/share/nginx/html/ debian/vim/nginx.yaml usr/share/vim/registry -contrib/vim/* usr/share/vim/addons +html/index.html usr/share/nginx/html/ diff --git a/debian/rules b/debian/rules index 8ae25ac..b453c47 100755 --- a/debian/rules +++ b/debian/rules @@ -11,7 +11,24 @@ DEBIAN_NGINX_PERL_LDFLAGS:= $(shell DEB_BUILD_MAINT_OPTIONS=hardening=+all,-pie export DEBIAN_NGINX_PERL_LDFLAGS FLAVOURS := full light extras -DYN_MODS := http-geoip http-image-filter http-xslt-filter mail stream http-auth-pam http-lua http-perl http-ndk nchan http-echo http-upstream-fair http-headers-more-filter http-cache-purge http-fancyindex http-uploadprogress http-subs-filter +DYN_MODS := \ + http-auth-pam \ + http-cache-purge \ + http-echo \ + http-fancyindex \ + http-geoip \ + http-headers-more-filter \ + http-image-filter \ + http-lua \ + http-ndk \ + http-perl \ + http-subs-filter \ + http-uploadprogress \ + http-upstream-fair \ + http-xslt-filter \ + mail \ + nchan \ + stream MODULESDIR = $(CURDIR)/debian/modules BASEDIR = $(CURDIR) From 3f6df9e7065699a77f247d3f73196c1313334b40 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 6 Sep 2016 11:07:34 +0300 Subject: [PATCH 154/651] Release 1.10.1-2 --- debian/changelog | 4 ++-- debian/nginx-extras.NEWS | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 9d34e8c..7022476 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.10.1-2) UNRELEASED; urgency=medium +nginx (1.10.1-2) unstable; urgency=medium [ Christos Trochalakis ] * debian/control: @@ -31,7 +31,7 @@ nginx (1.10.1-2) UNRELEASED; urgency=medium + Make nginx-*.postinst use invoke-rc.d. (Closes: #823435) Thanks Simon Deziel for the patch. - -- Michael Lustfield Sat, 16 Jul 2016 17:24:40 -0700 + -- Christos Trochalakis Tue, 06 Sep 2016 11:06:26 +0300 nginx (1.10.1-1) unstable; urgency=medium diff --git a/debian/nginx-extras.NEWS b/debian/nginx-extras.NEWS index 55c9701..d4fff37 100644 --- a/debian/nginx-extras.NEWS +++ b/debian/nginx-extras.NEWS @@ -1,4 +1,4 @@ -nginx-extras (1.10.1-2) UNRELEASED; urgency=medium +nginx-extras (1.10.1-2) unstable; urgency=medium Starting with this release the HTTP Push module has been replaced by Nchan. More info for the upgrade can be found at https://nchan.slact.net/upgrade. From 8b6e35fe350490f7ed6bed0477372cd5bfa8e6df Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 13 Sep 2016 14:21:06 +0300 Subject: [PATCH 155/651] Drop nginx-*-dbg packages Switch to autogenerated -dbgsym packages. --- debian/changelog | 7 +++++++ debian/control | 44 -------------------------------------------- debian/rules | 2 +- 3 files changed, 8 insertions(+), 45 deletions(-) diff --git a/debian/changelog b/debian/changelog index 7022476..9704e83 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.10.1-3) UNRELEASED; urgency=medium + + * debian/control: + + Drop nginx-*-dbg packages in favor of autogenerated -dbgsym packages. + + -- Christos Trochalakis Wed, 14 Sep 2016 10:43:41 +0300 + nginx (1.10.1-2) unstable; urgency=medium [ Christos Trochalakis ] diff --git a/debian/control b/debian/control index cd18cbc..64e219f 100644 --- a/debian/control +++ b/debian/control @@ -118,20 +118,6 @@ Description: nginx web/proxy server (standard version) THIRD PARTY MODULES: Auth PAM, DAV Ext, Echo, HTTP Substitutions, Upstream Fair Queue. -Package: nginx-full-dbg -Architecture: any -Section: debug -Priority: extra -Depends: nginx-full (= ${binary:Version}), ${misc:Depends} -Conflicts: nginx-extras-dbg, nginx-light-dbg -Description: nginx web/proxy server (standard version) - debugging symbols - Nginx ("engine X") is a high-performance web and reverse proxy server - created by Igor Sysoev. It can be used both as a standalone web server - and as a proxy to reduce the load on back-end HTTP or mail servers. - . - This package provides debugging symbols for nginx-full, to assist in debugging - issues that you may find. It should not be required for normal operation. - Package: nginx-light Architecture: any Priority: extra @@ -160,21 +146,6 @@ Description: nginx web/proxy server (basic version) . THIRD PARTY MODULES: Echo. -Package: nginx-light-dbg -Architecture: any -Section: debug -Priority: extra -Depends: nginx-light (= ${binary:Version}), ${misc:Depends} -Conflicts: nginx-extras-dbg, nginx-full-dbg -Description: nginx web/proxy server (basic version) - debugging symbols - Nginx ("engine X") is a high-performance web and reverse proxy server - created by Igor Sysoev. It can be used both as a standalone web server - and as a proxy to reduce the load on back-end HTTP or mail servers. - . - This package provides debugging symbols for nginx-light, to assist in - debugging issues that you may find. It should not be required for normal - operation. - Package: nginx-extras Architecture: any Priority: extra @@ -225,21 +196,6 @@ Description: nginx web/proxy server (extended version) Headers More, Embedded Lua, HTTP Substitutions, Nchan, Upload Progress, Upstream Fair Queue. -Package: nginx-extras-dbg -Architecture: any -Section: debug -Priority: extra -Depends: nginx-extras (= ${binary:Version}), ${misc:Depends} -Conflicts: nginx-full-dbg, nginx-light-dbg -Description: nginx web/proxy server (extended version) - debugging symbols - Nginx ("engine X") is a high-performance web and reverse proxy server - created by Igor Sysoev. It can be used both as a standalone web server - and as a proxy to reduce the load on back-end HTTP or mail servers. - . - This package provides debugging symbols for nginx-extras, to assist in - debugging issues that you may find. It should not be required for normal - operation. - Package: libnginx-mod-http-geoip Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends} diff --git a/debian/rules b/debian/rules index b453c47..7547660 100755 --- a/debian/rules +++ b/debian/rules @@ -161,7 +161,7 @@ build.arch.%: $(MAKE) -C $(BUILDDIR_$*) build strip.arch.%: - dh_strip --package=nginx-$(*) --dbg-package=nginx-$(*)-dbg + dh_strip --package=nginx-$(*) -O--dbgsym-migration='nginx-$(*)-dbg (<< 1.10.1-3~)' strip.mods.%: dh_strip --package=libnginx-mod-$(*) -O--automatic-dbgsym From 0570da941eed18d6e3ec8bcde591a8315931c470 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 14 Sep 2016 10:36:04 +0300 Subject: [PATCH 156/651] Remove relic Breaks/Replaces used for squeeze upgrades --- debian/changelog | 1 + debian/control | 8 -------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/debian/changelog b/debian/changelog index 9704e83..6220dea 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,7 @@ nginx (1.10.1-3) UNRELEASED; urgency=medium * debian/control: + Drop nginx-*-dbg packages in favor of autogenerated -dbgsym packages. + + Remove relic Breaks/Replaces from nginx-common. -- Christos Trochalakis Wed, 14 Sep 2016 10:43:41 +0300 diff --git a/debian/control b/debian/control index 64e219f..11198ca 100644 --- a/debian/control +++ b/debian/control @@ -60,14 +60,6 @@ Package: nginx-common Architecture: all Multi-Arch: foreign Depends: lsb-base (>= 3.2-14), ${misc:Depends} -Replaces: nginx (<< 0.8.54-4), - nginx-extras (<< 0.8.54-4), - nginx-full (<< 0.8.54-4), - nginx-light (<< 0.8.54-4) -Breaks: nginx (<< 0.8.54-4), - nginx-extras (<< 0.8.54-4), - nginx-full (<< 0.8.54-4), - nginx-light (<< 0.8.54-4) Suggests: fcgiwrap, nginx-doc, ssl-cert Description: small, powerful, scalable web/proxy server - common files Nginx ("engine X") is a high-performance web and reverse proxy server From b624187e45ce20790954e4bd24d61b6243538bd6 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 14 Sep 2016 10:37:47 +0300 Subject: [PATCH 157/651] Fix lsb-base deps o nginx-doc doesn't need lsb-base. o relax nginx-common dependency, any recent version should work. --- debian/changelog | 1 + debian/control | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 6220dea..8564a16 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,6 +3,7 @@ nginx (1.10.1-3) UNRELEASED; urgency=medium * debian/control: + Drop nginx-*-dbg packages in favor of autogenerated -dbgsym packages. + Remove relic Breaks/Replaces from nginx-common. + + Fix lsb-base dependencies. -- Christos Trochalakis Wed, 14 Sep 2016 10:43:41 +0300 diff --git a/debian/control b/debian/control index 11198ca..b08be6a 100644 --- a/debian/control +++ b/debian/control @@ -48,7 +48,7 @@ Package: nginx-doc Architecture: all Multi-Arch: foreign Section: doc -Depends: lsb-base (>= 3.2-14), ${misc:Depends} +Depends: ${misc:Depends} Description: small, powerful, scalable web/proxy server - documentation Nginx ("engine X") is a high-performance web and reverse proxy server created by Igor Sysoev. It can be used both as a standalone web server @@ -59,7 +59,7 @@ Description: small, powerful, scalable web/proxy server - documentation Package: nginx-common Architecture: all Multi-Arch: foreign -Depends: lsb-base (>= 3.2-14), ${misc:Depends} +Depends: lsb-base, ${misc:Depends} Suggests: fcgiwrap, nginx-doc, ssl-cert Description: small, powerful, scalable web/proxy server - common files Nginx ("engine X") is a high-performance web and reverse proxy server From 725adf41f2325c853914a2e2e029a22119e5eb93 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 7 Sep 2016 14:31:11 +0300 Subject: [PATCH 158/651] Switch Maintainer to the Debian Nginx Maintainers list Keep all active maintainers as Uploaders. --- debian/changelog | 5 ++++- debian/control | 7 ++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/debian/changelog b/debian/changelog index 8564a16..a787dc6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,8 +4,11 @@ nginx (1.10.1-3) UNRELEASED; urgency=medium + Drop nginx-*-dbg packages in favor of autogenerated -dbgsym packages. + Remove relic Breaks/Replaces from nginx-common. + Fix lsb-base dependencies. + + Switch Maintainer to the Nginx Packaging Team and keep active maintainers + as uploaders. Jose, Fabio, Dmitry & Cyril, thanks a lot for all your + contributions! - -- Christos Trochalakis Wed, 14 Sep 2016 10:43:41 +0300 + -- Christos Trochalakis Tue, 06 Sep 2016 15:06:47 +0300 nginx (1.10.1-2) unstable; urgency=medium diff --git a/debian/control b/debian/control index b08be6a..baa4b52 100644 --- a/debian/control +++ b/debian/control @@ -1,12 +1,9 @@ Source: nginx Section: httpd Priority: optional -Maintainer: Kartik Mistry -Uploaders: Jose Parrella , - Fabio Tranchitella , +Maintainer: Debian Nginx Maintainers +Uploaders: Kartik Mistry , Michael Lustfield , - Dmitry E. Oboukhov , - Cyril Lavier , Christos Trochalakis Build-Depends: autotools-dev, debhelper (>= 9), From 255d6d4e4a63e891153bc9bc7a9410351c39a639 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 15 Sep 2016 15:21:11 +0300 Subject: [PATCH 159/651] Release 1.10.1-3 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index a787dc6..0d59634 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.10.1-3) UNRELEASED; urgency=medium +nginx (1.10.1-3) unstable; urgency=medium * debian/control: + Drop nginx-*-dbg packages in favor of autogenerated -dbgsym packages. @@ -8,7 +8,7 @@ nginx (1.10.1-3) UNRELEASED; urgency=medium as uploaders. Jose, Fabio, Dmitry & Cyril, thanks a lot for all your contributions! - -- Christos Trochalakis Tue, 06 Sep 2016 15:06:47 +0300 + -- Christos Trochalakis Thu, 15 Sep 2016 15:20:58 +0300 nginx (1.10.1-2) unstable; urgency=medium From 42f5c9e7b475ee71e5bda337dd18474c54a101ac Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 16 Sep 2016 12:54:01 +0300 Subject: [PATCH 160/651] New upstream version 1.11.4 --- CHANGES | 30 + CHANGES.ru | 29 + auto/modules | 12 + auto/options | 3 + contrib/unicode2nginx/unicode-to-nginx.pl | 7 +- src/core/nginx.h | 4 +- src/core/ngx_inet.c | 87 + src/core/ngx_inet.h | 1 + src/core/ngx_thread_pool.c | 7 + src/event/ngx_event_connect.c | 2 +- src/event/ngx_event_openssl.c | 63 +- src/event/ngx_event_openssl_stapling.c | 3 + src/event/ngx_event_pipe.c | 12 +- src/http/modules/ngx_http_geo_module.c | 50 +- src/http/modules/ngx_http_limit_req_module.c | 14 +- src/http/modules/ngx_http_realip_module.c | 2 +- src/http/modules/ngx_http_ssi_filter_module.c | 10 +- src/http/ngx_http_core_module.c | 134 +- src/http/ngx_http_upstream.c | 22 +- src/http/ngx_http_upstream.h | 1 + src/mail/ngx_mail.h | 4 +- src/mail/ngx_mail_core_module.c | 9 + src/os/unix/ngx_posix_init.c | 6 +- src/os/unix/ngx_process_cycle.c | 4 +- src/stream/ngx_stream.c | 2 + src/stream/ngx_stream.h | 33 +- src/stream/ngx_stream_core_module.c | 31 + src/stream/ngx_stream_geo_module.c | 40 +- src/stream/ngx_stream_handler.c | 238 ++- src/stream/ngx_stream_log_module.c | 1474 +++++++++++++++++ src/stream/ngx_stream_proxy_module.c | 129 +- src/stream/ngx_stream_realip_module.c | 342 ++++ src/stream/ngx_stream_return_module.c | 14 +- src/stream/ngx_stream_script.c | 67 + src/stream/ngx_stream_script.h | 4 + src/stream/ngx_stream_upstream.c | 236 ++- src/stream/ngx_stream_upstream.h | 12 + src/stream/ngx_stream_variables.c | 143 +- 38 files changed, 3005 insertions(+), 276 deletions(-) create mode 100644 src/stream/ngx_stream_log_module.c create mode 100644 src/stream/ngx_stream_realip_module.c diff --git a/CHANGES b/CHANGES index a795ef2..2ea8d8d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,34 @@ +Changes with nginx 1.11.4 13 Sep 2016 + + *) Feature: the $upstream_bytes_received variable. + + *) Feature: the $bytes_received, $session_time, $protocol, $status, + $upstream_addr, $upstream_bytes_sent, $upstream_bytes_received, + $upstream_connect_time, $upstream_first_byte_time, and + $upstream_session_time variables in the stream module. + + *) Feature: the ngx_stream_log_module. + + *) Feature: the "proxy_protocol" parameter of the "listen" directive, + the $proxy_protocol_addr and $proxy_protocol_port variables in the + stream module. + + *) Feature: the ngx_stream_realip_module. + + *) Bugfix: nginx could not be built with the stream module and the + ngx_http_ssl_module, but without ngx_stream_ssl_module; the bug had + appeared in 1.11.3. + + *) Feature: the IP_BIND_ADDRESS_NO_PORT socket option was not used; the + bug had appeared in 1.11.2. + + *) Bugfix: in the "ranges" parameter of the "geo" directive. + + *) Bugfix: an incorrect response might be returned when using the "aio + threads" and "sendfile" directives; the bug had appeared in 1.9.13. + + Changes with nginx 1.11.3 26 Jul 2016 *) Change: now the "accept_mutex" directive is turned off by default. diff --git a/CHANGES.ru b/CHANGES.ru index cd424e9..28ac2d8 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,33 @@ +Изменения в nginx 1.11.4 13.09.2016 + + *) Добавление: переменная $upstream_bytes_received. + + *) Добавление: переменные $bytes_received, $session_time, $protocol, + $status, $upstream_addr, $upstream_bytes_sent, + $upstream_bytes_received, $upstream_connect_time, + $upstream_first_byte_time и $upstream_session_time в модуле stream. + + *) Добавление: модуль ngx_stream_log_module. + + *) Добавление: параметр proxy_protocol в директиве listen, переменные + $proxy_protocol_addr и $proxy_protocol_port в модуле stream. + + *) Добавление: модуль ngx_stream_realip_module. + + *) Исправление: nginx не собирался с модулем stream и модулем + ngx_http_ssl_module, но без модуля ngx_stream_ssl_module; ошибка + появилась в 1.11.3. + + *) Добавление: опция сокета IP_BIND_ADDRESS_NO_PORT не использовалась; + ошибка появилась в 1.11.2. + + *) Исправление: в параметре ranges директивы geo. + + *) Исправление: при использовании директив "aio threads" и sendfile мог + возвращаться некорректный ответ; ошибка появилась в 1.9.13. + + Изменения в nginx 1.11.3 26.07.2016 *) Изменение: теперь accept_mutex по умолчанию выключен. diff --git a/auto/modules b/auto/modules index 614037c..433767a 100644 --- a/auto/modules +++ b/auto/modules @@ -971,6 +971,7 @@ if [ $STREAM != NO ]; then ngx_module_name="ngx_stream_module \ ngx_stream_core_module \ + ngx_stream_log_module \ ngx_stream_proxy_module \ ngx_stream_upstream_module" ngx_module_incs="src/stream" @@ -984,6 +985,7 @@ if [ $STREAM != NO ]; then src/stream/ngx_stream_script.c \ src/stream/ngx_stream_handler.c \ src/stream/ngx_stream_core_module.c \ + src/stream/ngx_stream_log_module.c \ src/stream/ngx_stream_proxy_module.c \ src/stream/ngx_stream_upstream.c \ src/stream/ngx_stream_upstream_round_robin.c" @@ -1005,6 +1007,16 @@ if [ $STREAM != NO ]; then . auto/module fi + if [ $STREAM_REALIP = YES ]; then + ngx_module_name=ngx_stream_realip_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_realip_module.c + ngx_module_libs= + ngx_module_link=$STREAM_REALIP + + . auto/module + fi + if [ $STREAM_LIMIT_CONN = YES ]; then ngx_module_name=ngx_stream_limit_conn_module ngx_module_deps= diff --git a/auto/options b/auto/options index a8fce30..73149d9 100644 --- a/auto/options +++ b/auto/options @@ -115,6 +115,7 @@ MAIL_SMTP=YES STREAM=NO STREAM_SSL=NO +STREAM_REALIP=NO STREAM_LIMIT_CONN=YES STREAM_ACCESS=YES STREAM_GEO=YES @@ -296,6 +297,7 @@ use the \"--with-mail_ssl_module\" option instead" --with-stream) STREAM=YES ;; --with-stream=dynamic) STREAM=DYNAMIC ;; --with-stream_ssl_module) STREAM_SSL=YES ;; + --with-stream_realip_module) STREAM_REALIP=YES ;; --with-stream_geoip_module) STREAM_GEOIP=YES ;; --with-stream_geoip_module=dynamic) STREAM_GEOIP=DYNAMIC ;; @@ -503,6 +505,7 @@ cat << END --with-stream enable TCP/UDP proxy module --with-stream=dynamic enable dynamic TCP/UDP proxy module --with-stream_ssl_module enable ngx_stream_ssl_module + --with-stream_realip_module enable ngx_stream_realip_module --with-stream_geoip_module enable ngx_stream_geoip_module --with-stream_geoip_module=dynamic enable dynamic ngx_stream_geoip_module --without-stream_limit_conn_module disable ngx_stream_limit_conn_module diff --git a/contrib/unicode2nginx/unicode-to-nginx.pl b/contrib/unicode2nginx/unicode-to-nginx.pl index daaf354..d113fed 100755 --- a/contrib/unicode2nginx/unicode-to-nginx.pl +++ b/contrib/unicode2nginx/unicode-to-nginx.pl @@ -10,7 +10,7 @@ # Needs perl 5.6 or later. -# Written by Maxim Dounin, mdounin@rambler-co.ru +# Written by Maxim Dounin, mdounin@mdounin.ru ############################################################################### @@ -33,7 +33,10 @@ while (<>) { # Produce UTF-8 sequence from character code; - my $un_utf8 = join('', map { sprintf("%02X", $_) } unpack("C*", pack("U", hex($un_code)))); + my $un_utf8 = join('', + map { sprintf("%02X", $_) } + unpack("U0C*", pack("U", hex($un_code))) + ); print " $cs_code $un_utf8 ; $un_name\n"; diff --git a/src/core/nginx.h b/src/core/nginx.h index e303e66..7e9aae6 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1011003 -#define NGINX_VERSION "1.11.3" +#define nginx_version 1011004 +#define NGINX_VERSION "1.11.4" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c index c4aaf3a..dbd1f46 100644 --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -465,6 +465,93 @@ ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr) } +ngx_int_t +ngx_cidr_match(struct sockaddr *sa, ngx_array_t *cidrs) +{ +#if (NGX_HAVE_INET6) + u_char *p; +#endif + in_addr_t inaddr; + ngx_cidr_t *cidr; + ngx_uint_t family, i; +#if (NGX_HAVE_INET6) + ngx_uint_t n; + struct in6_addr *inaddr6; +#endif + +#if (NGX_SUPPRESS_WARN) + inaddr = 0; +#if (NGX_HAVE_INET6) + inaddr6 = NULL; +#endif +#endif + + family = sa->sa_family; + + if (family == AF_INET) { + inaddr = ((struct sockaddr_in *) sa)->sin_addr.s_addr; + } + +#if (NGX_HAVE_INET6) + else if (family == AF_INET6) { + inaddr6 = &((struct sockaddr_in6 *) sa)->sin6_addr; + + if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { + family = AF_INET; + + p = inaddr6->s6_addr; + + inaddr = p[12] << 24; + inaddr += p[13] << 16; + inaddr += p[14] << 8; + inaddr += p[15]; + + inaddr = htonl(inaddr); + } + } +#endif + + for (cidr = cidrs->elts, i = 0; i < cidrs->nelts; i++) { + if (cidr[i].family != family) { + goto next; + } + + switch (family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + for (n = 0; n < 16; n++) { + if ((inaddr6->s6_addr[n] & cidr[i].u.in6.mask.s6_addr[n]) + != cidr[i].u.in6.addr.s6_addr[n]) + { + goto next; + } + } + break; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + break; +#endif + + default: /* AF_INET */ + if ((inaddr & cidr[i].u.in.mask) != cidr[i].u.in.addr) { + goto next; + } + break; + } + + return NGX_OK; + + next: + continue; + } + + return NGX_DECLINED; +} + + ngx_int_t ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, size_t len) { diff --git a/src/core/ngx_inet.h b/src/core/ngx_inet.h index 97dc354..538771e 100644 --- a/src/core/ngx_inet.h +++ b/src/core/ngx_inet.h @@ -113,6 +113,7 @@ size_t ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text, size_t len, ngx_uint_t port); size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len); ngx_int_t ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr); +ngx_int_t ngx_cidr_match(struct sockaddr *sa, ngx_array_t *cidrs); ngx_int_t ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, size_t len); ngx_int_t ngx_parse_addr_port(ngx_pool_t *pool, ngx_addr_t *addr, diff --git a/src/core/ngx_thread_pool.c b/src/core/ngx_thread_pool.c index f3655aa..7fb0f7f 100644 --- a/src/core/ngx_thread_pool.c +++ b/src/core/ngx_thread_pool.c @@ -137,6 +137,13 @@ ngx_thread_pool_init(ngx_thread_pool_t *tp, ngx_log_t *log, ngx_pool_t *pool) return NGX_ERROR; } + err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if (err) { + ngx_log_error(NGX_LOG_ALERT, log, err, + "pthread_attr_setdetachstate() failed"); + return NGX_ERROR; + } + #if 0 err = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); if (err) { diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c index 30cb59a..06534ef 100644 --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -91,7 +91,7 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc) #endif #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX) - port = ngx_inet_get_port(pc->sockaddr); + port = ngx_inet_get_port(pc->local->sockaddr); #endif #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT) diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index bb9a900..1cbfdf2 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -118,9 +118,7 @@ ngx_ssl_init(ngx_log_t *log) #else -#ifndef OPENSSL_IS_BORINGSSL OPENSSL_config(NULL); -#endif SSL_library_init(); SSL_load_error_strings(); @@ -2023,7 +2021,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, || n == SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST /* 151 */ || n == SSL_R_EXCESSIVE_MESSAGE_SIZE /* 152 */ || n == SSL_R_LENGTH_MISMATCH /* 159 */ +#ifdef SSL_R_NO_CIPHERS_PASSED || n == SSL_R_NO_CIPHERS_PASSED /* 182 */ +#endif || n == SSL_R_NO_CIPHERS_SPECIFIED /* 183 */ || n == SSL_R_NO_COMPRESSION_SPECIFIED /* 187 */ || n == SSL_R_NO_SHARED_CIPHER /* 193 */ @@ -2941,13 +2941,6 @@ failed: } -#ifdef OPENSSL_NO_SHA256 -#define ngx_ssl_session_ticket_md EVP_sha1 -#else -#define ngx_ssl_session_ticket_md EVP_sha256 -#endif - - static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx, @@ -2958,6 +2951,8 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, ngx_array_t *keys; ngx_connection_t *c; ngx_ssl_session_ticket_key_t *key; + const EVP_MD *digest; + const EVP_CIPHER *cipher; #if (NGX_DEBUG) u_char buf[32]; #endif @@ -2965,6 +2960,13 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, c = ngx_ssl_get_connection(ssl_conn); ssl_ctx = c->ssl->session_ctx; + cipher = EVP_aes_128_cbc(); +#ifdef OPENSSL_NO_SHA256 + digest = EVP_sha1(); +#else + digest = EVP_sha256(); +#endif + keys = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_ticket_keys_index); if (keys == NULL) { return -1; @@ -2980,13 +2982,29 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, ngx_hex_dump(buf, key[0].name, 16) - buf, buf, SSL_session_reused(ssl_conn) ? "reused" : "new"); - RAND_bytes(iv, 16); - EVP_EncryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, key[0].aes_key, iv); - HMAC_Init_ex(hctx, key[0].hmac_key, 16, - ngx_ssl_session_ticket_md(), NULL); + if (RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)) != 1) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "RAND_bytes() failed"); + return -1; + } + + if (EVP_EncryptInit_ex(ectx, cipher, NULL, key[0].aes_key, iv) != 1) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, + "EVP_EncryptInit_ex() failed"); + return -1; + } + +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + if (HMAC_Init_ex(hctx, key[0].hmac_key, 16, digest, NULL) != 1) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "HMAC_Init_ex() failed"); + return -1; + } +#else + HMAC_Init_ex(hctx, key[0].hmac_key, 16, digest, NULL); +#endif + ngx_memcpy(name, key[0].name, 16); - return 0; + return 1; } else { /* decrypt session ticket */ @@ -3010,9 +3028,20 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, ngx_hex_dump(buf, key[i].name, 16) - buf, buf, (i == 0) ? " (default)" : ""); - HMAC_Init_ex(hctx, key[i].hmac_key, 16, - ngx_ssl_session_ticket_md(), NULL); - EVP_DecryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, key[i].aes_key, iv); +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + if (HMAC_Init_ex(hctx, key[i].hmac_key, 16, digest, NULL) != 1) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "HMAC_Init_ex() failed"); + return -1; + } +#else + HMAC_Init_ex(hctx, key[i].hmac_key, 16, digest, NULL); +#endif + + if (EVP_DecryptInit_ex(ectx, cipher, NULL, key[i].aes_key, iv) != 1) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, + "EVP_DecryptInit_ex() failed"); + return -1; + } return (i == 0) ? 1 : 2 /* renew */; } diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c index cce8e9e..09fab76 100644 --- a/src/event/ngx_event_openssl_stapling.c +++ b/src/event/ngx_event_openssl_stapling.c @@ -376,6 +376,7 @@ ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl, { ngx_url_t u; char *s; + ngx_str_t rsp; STACK_OF(OPENSSL_STRING) *aia; if (responder->len == 0) { @@ -403,6 +404,8 @@ ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl, return NGX_DECLINED; } + responder = &rsp; + responder->len = ngx_strlen(s); responder->data = ngx_palloc(cf->pool, responder->len); if (responder->data == NULL) { diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c index 5ce59ae..249433a 100644 --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -300,7 +300,7 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) if (n == NGX_ERROR) { p->upstream_error = 1; - return NGX_ERROR; + break; } if (n == NGX_AGAIN) { @@ -815,10 +815,12 @@ ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p) } #if (NGX_THREADS) - p->temp_file->thread_write = p->thread_handler ? 1 : 0; - p->temp_file->file.thread_task = p->thread_task; - p->temp_file->file.thread_handler = p->thread_handler; - p->temp_file->file.thread_ctx = p->thread_ctx; + if (p->thread_handler) { + p->temp_file->thread_write = 1; + p->temp_file->file.thread_task = p->thread_task; + p->temp_file->file.thread_handler = p->thread_handler; + p->temp_file->file.thread_ctx = p->thread_ctx; + } #endif n = ngx_write_chain_to_temp_file(p->temp_file, out); diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c index 9b3c6cb..46a8d7c 100644 --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -469,7 +469,12 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) for (i = 0; i < 0x10000; i++) { a = (ngx_array_t *) ctx.high.low[i]; - if (a == NULL || a->nelts == 0) { + if (a == NULL) { + continue; + } + + if (a->nelts == 0) { + ctx.high.low[i] = NULL; continue; } @@ -814,7 +819,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, range = a->elts; ngx_memmove(&range[i + 2], &range[i + 1], - (a->nelts - 2 - i) * sizeof(ngx_http_geo_range_t)); + (a->nelts - 2 - i) * sizeof(ngx_http_geo_range_t)); range[i + 1].start = (u_short) s; range[i + 1].end = (u_short) e; @@ -853,7 +858,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, range = a->elts; ngx_memmove(&range[i + 3], &range[i + 1], - (a->nelts - 3 - i) * sizeof(ngx_http_geo_range_t)); + (a->nelts - 3 - i) * sizeof(ngx_http_geo_range_t)); range[i + 2].start = (u_short) (e + 1); range[i + 2].end = range[i].end; @@ -881,7 +886,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, range = a->elts; ngx_memmove(&range[i + 1], &range[i], - (a->nelts - 1 - i) * sizeof(ngx_http_geo_range_t)); + (a->nelts - 1 - i) * sizeof(ngx_http_geo_range_t)); range[i + 1].start = (u_short) (e + 1); @@ -905,7 +910,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, range = a->elts; ngx_memmove(&range[i + 2], &range[i + 1], - (a->nelts - 2 - i) * sizeof(ngx_http_geo_range_t)); + (a->nelts - 2 - i) * sizeof(ngx_http_geo_range_t)); range[i + 1].start = (u_short) s; range[i + 1].end = (u_short) e; @@ -935,13 +940,20 @@ ngx_http_geo_add_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, return NGX_CONF_ERROR; } - range->start = (u_short) s; - range->end = (u_short) e; - range->value = ctx->value; + range = a->elts; + + ngx_memmove(&range[1], &range[0], + (a->nelts - 1) * sizeof(ngx_http_geo_range_t)); + + range[0].start = (u_short) s; + range[0].end = (u_short) e; + range[0].value = ctx->value; next: - continue; + if (h == 0xffff) { + break; + } } return NGX_CONF_OK; @@ -959,7 +971,7 @@ ngx_http_geo_delete_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, warn = 0; - for (n = start; n <= end; n += 0x10000) { + for (n = start; n <= end; n = (n + 0x10000) & 0xffff0000) { h = n >> 16; @@ -978,9 +990,9 @@ ngx_http_geo_delete_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, a = (ngx_array_t *) ctx->high.low[h]; - if (a == NULL) { + if (a == NULL || a->nelts == 0) { warn = 1; - continue; + goto next; } range = a->elts; @@ -990,20 +1002,22 @@ ngx_http_geo_delete_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, && e == (ngx_uint_t) range[i].end) { ngx_memmove(&range[i], &range[i + 1], - (a->nelts - 1 - i) * sizeof(ngx_http_geo_range_t)); + (a->nelts - 1 - i) * sizeof(ngx_http_geo_range_t)); a->nelts--; break; } - if (s != (ngx_uint_t) range[i].start - && e != (ngx_uint_t) range[i].end) - { - continue; + if (i == a->nelts - 1) { + warn = 1; } + } - warn = 1; + next: + + if (h == 0xffff) { + break; } } diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c index 9059ac3..2f695f2 100644 --- a/src/http/modules/ngx_http_limit_req_module.c +++ b/src/http/modules/ngx_http_limit_req_module.c @@ -362,15 +362,13 @@ ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, ngx_uint_t hash, { size_t size; ngx_int_t rc, excess; - ngx_time_t *tp; ngx_msec_t now; ngx_msec_int_t ms; ngx_rbtree_node_t *node, *sentinel; ngx_http_limit_req_ctx_t *ctx; ngx_http_limit_req_node_t *lr; - tp = ngx_timeofday(); - now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); + now = ngx_current_msec; ctx = limit->shm_zone->data; @@ -483,7 +481,6 @@ 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; @@ -509,9 +506,7 @@ ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits, ngx_uint_t n, ngx_shmtx_lock(&ctx->shpool->mutex); - tp = ngx_timeofday(); - - now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); + now = ngx_current_msec; ms = (ngx_msec_int_t) (now - lr->last); excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; @@ -549,16 +544,13 @@ static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n) { ngx_int_t excess; - ngx_time_t *tp; ngx_msec_t now; ngx_queue_t *q; ngx_msec_int_t ms; ngx_rbtree_node_t *node; ngx_http_limit_req_node_t *lr; - tp = ngx_timeofday(); - - now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); + now = ngx_current_msec; /* * n == 1 deletes one or two zero rate entries diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c index 490a53d..dba3c52 100644 --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -264,7 +264,6 @@ ngx_http_realip_set_addr(ngx_http_request_t *r, ngx_addr_t *addr) } ctx = cln->data; - ngx_http_set_ctx(r, ctx, ngx_http_realip_module); c = r->connection; @@ -282,6 +281,7 @@ ngx_http_realip_set_addr(ngx_http_request_t *r, ngx_addr_t *addr) ngx_memcpy(p, text, len); cln->handler = ngx_http_realip_cleanup; + ngx_http_set_ctx(r, ctx, ngx_http_realip_module); ctx->connection = c; ctx->sockaddr = c->sockaddr; diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index fc6e65b..6fb1fbe 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -2722,8 +2722,8 @@ static ngx_int_t ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t gmt) { + time_t now; ngx_http_ssi_ctx_t *ctx; - ngx_time_t *tp; ngx_str_t *timefmt; struct tm tm; char buf[NGX_HTTP_SSI_DATE_LEN]; @@ -2732,7 +2732,7 @@ ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, v->no_cacheable = 0; v->not_found = 0; - tp = ngx_timeofday(); + now = ngx_time(); ctx = ngx_http_get_module_ctx(r, ngx_http_ssi_filter_module); @@ -2746,15 +2746,15 @@ ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, return NGX_ERROR; } - v->len = ngx_sprintf(v->data, "%T", tp->sec) - v->data; + v->len = ngx_sprintf(v->data, "%T", now) - v->data; return NGX_OK; } if (gmt) { - ngx_libc_gmtime(tp->sec, &tm); + ngx_libc_gmtime(now, &tm); } else { - ngx_libc_localtime(tp->sec, &tm); + ngx_libc_localtime(now, &tm); } v->len = strftime(buf, NGX_HTTP_SSI_DATE_LEN, diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 76917bb..e26c3f7 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -2823,120 +2823,46 @@ static ngx_int_t ngx_http_get_forwarded_addr_internal(ngx_http_request_t *r, ngx_addr_t *addr, u_char *xff, size_t xfflen, ngx_array_t *proxies, int recursive) { - u_char *p; - in_addr_t inaddr; - ngx_int_t rc; - ngx_addr_t paddr; - ngx_cidr_t *cidr; - ngx_uint_t family, i; -#if (NGX_HAVE_INET6) - ngx_uint_t n; - struct in6_addr *inaddr6; -#endif + u_char *p; + ngx_int_t rc; + ngx_addr_t paddr; -#if (NGX_SUPPRESS_WARN) - inaddr = 0; -#if (NGX_HAVE_INET6) - inaddr6 = NULL; -#endif -#endif - - family = addr->sockaddr->sa_family; - - if (family == AF_INET) { - inaddr = ((struct sockaddr_in *) addr->sockaddr)->sin_addr.s_addr; + if (ngx_cidr_match(addr->sockaddr, proxies) != NGX_OK) { + return NGX_DECLINED; } -#if (NGX_HAVE_INET6) - else if (family == AF_INET6) { - inaddr6 = &((struct sockaddr_in6 *) addr->sockaddr)->sin6_addr; - - if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { - family = AF_INET; - - p = inaddr6->s6_addr; - - inaddr = p[12] << 24; - inaddr += p[13] << 16; - inaddr += p[14] << 8; - inaddr += p[15]; - - inaddr = htonl(inaddr); + for (p = xff + xfflen - 1; p > xff; p--, xfflen--) { + if (*p != ' ' && *p != ',') { + break; } } -#endif - for (cidr = proxies->elts, i = 0; i < proxies->nelts; i++) { - if (cidr[i].family != family) { - goto next; - } - - switch (family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - for (n = 0; n < 16; n++) { - if ((inaddr6->s6_addr[n] & cidr[i].u.in6.mask.s6_addr[n]) - != cidr[i].u.in6.addr.s6_addr[n]) - { - goto next; - } - } - break; -#endif - -#if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - break; -#endif - - default: /* AF_INET */ - if ((inaddr & cidr[i].u.in.mask) != cidr[i].u.in.addr) { - goto next; - } + for ( /* void */ ; p > xff; p--) { + if (*p == ' ' || *p == ',') { + p++; break; } - - for (p = xff + xfflen - 1; p > xff; p--, xfflen--) { - if (*p != ' ' && *p != ',') { - break; - } - } - - for ( /* void */ ; p > xff; p--) { - if (*p == ' ' || *p == ',') { - p++; - break; - } - } - - if (ngx_parse_addr_port(r->pool, &paddr, p, xfflen - (p - xff)) - != NGX_OK) - { - return NGX_DECLINED; - } - - *addr = paddr; - - if (recursive && p > xff) { - rc = ngx_http_get_forwarded_addr_internal(r, addr, xff, p - 1 - xff, - proxies, 1); - - if (rc == NGX_DECLINED) { - return NGX_DONE; - } - - /* rc == NGX_OK || rc == NGX_DONE */ - return rc; - } - - return NGX_OK; - - next: - continue; } - return NGX_DECLINED; + if (ngx_parse_addr_port(r->pool, &paddr, p, xfflen - (p - xff)) != NGX_OK) { + return NGX_DECLINED; + } + + *addr = paddr; + + if (recursive && p > xff) { + rc = ngx_http_get_forwarded_addr_internal(r, addr, xff, p - 1 - xff, + proxies, 1); + + if (rc == NGX_DECLINED) { + return NGX_DONE; + } + + /* rc == NGX_OK || rc == NGX_DONE */ + return rc; + } + + return NGX_OK; } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 0f6b3ae..7e4b3c5 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -391,6 +391,10 @@ static ngx_http_variable_t ngx_http_upstream_vars[] = { ngx_http_upstream_response_length_variable, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, + { ngx_string("upstream_bytes_received"), NULL, + ngx_http_upstream_response_length_variable, 1, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + #if (NGX_HTTP_CACHE) { ngx_string("upstream_cache_status"), NULL, @@ -2136,6 +2140,8 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u) return; } + u->state->bytes_received += n; + u->buffer.last += n; #if 0 @@ -2642,6 +2648,7 @@ ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r, return; } + u->state->bytes_received += n; u->state->response_length += n; if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) { @@ -3215,6 +3222,10 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, do_write = 1; b->last += n; + if (from_upstream) { + u->state->bytes_received += n; + } + continue; } @@ -3411,6 +3422,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, } if (n > 0) { + u->state->bytes_received += n; u->state->response_length += n; if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) { @@ -4095,6 +4107,8 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r, u->state->response_time = ngx_current_msec - u->state->response_time; if (u->pipe && u->pipe->read_length) { + u->state->bytes_received += u->pipe->read_length + - u->pipe->preread_size; u->state->response_length = u->pipe->read_length; } } @@ -5242,7 +5256,13 @@ ngx_http_upstream_response_length_variable(ngx_http_request_t *r, state = r->upstream_states->elts; for ( ;; ) { - p = ngx_sprintf(p, "%O", state[i].response_length); + + if (data == 1) { + p = ngx_sprintf(p, "%O", state[i].bytes_received); + + } else { + p = ngx_sprintf(p, "%O", state[i].response_length); + } if (++i == r->upstream_states->nelts) { break; diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index b288f28..ef861f4 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -63,6 +63,7 @@ typedef struct { ngx_msec_t connect_time; ngx_msec_t header_time; off_t response_length; + off_t bytes_received; ngx_str_t *peer; } ngx_http_upstream_state_t; diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index ae1aa41..1068bb3 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -117,13 +117,15 @@ typedef struct { ngx_str_t server_name; u_char *file_name; - ngx_int_t line; + ngx_uint_t line; ngx_resolver_t *resolver; ngx_log_t *error_log; /* server ctx */ ngx_mail_conf_ctx_t *ctx; + + ngx_uint_t listen; /* unsigned listen:1; */ } ngx_mail_core_srv_conf_t; diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index d992402..48eacfa 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -279,6 +279,13 @@ ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) *cf = pcf; + if (rv == NGX_CONF_OK && !cscf->listen) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"listen\" is defined for server in %s:%ui", + cscf->file_name, cscf->line); + return NGX_CONF_ERROR; + } + return rv; } @@ -295,6 +302,8 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_mail_module_t *module; ngx_mail_core_main_conf_t *cmcf; + cscf->listen = 1; + value = cf->args->elts; ngx_memzero(&u, sizeof(ngx_url_t)); diff --git a/src/os/unix/ngx_posix_init.c b/src/os/unix/ngx_posix_init.c index 76ed94e..7e6e79d 100644 --- a/src/os/unix/ngx_posix_init.c +++ b/src/os/unix/ngx_posix_init.c @@ -33,7 +33,8 @@ ngx_os_io_t ngx_os_io = { ngx_int_t ngx_os_init(ngx_log_t *log) { - ngx_uint_t n; + ngx_time_t *tp; + ngx_uint_t n; #if (NGX_HAVE_OS_SPECIFIC_INIT) if (ngx_os_specific_init(log) != NGX_OK) { @@ -76,7 +77,8 @@ ngx_os_init(ngx_log_t *log) ngx_inherited_nonblocking = 0; #endif - srandom(ngx_time()); + tp = ngx_timeofday(); + srandom(((unsigned) ngx_pid << 16) ^ tp->sec ^ tp->msec); return NGX_OK; } diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c index 7cee1c5..83b04ee 100644 --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -785,6 +785,7 @@ ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker) { sigset_t set; ngx_int_t n; + ngx_time_t *tp; ngx_uint_t i; ngx_cpuset_t *cpu_affinity; struct rlimit rlmt; @@ -884,7 +885,8 @@ ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker) "sigprocmask() failed"); } - srandom((ngx_pid << 16) ^ ngx_time()); + tp = ngx_timeofday(); + srandom(((unsigned) ngx_pid << 16) ^ tp->sec ^ tp->msec); /* * disable deleting previous events for the listening sockets because diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c index c195171..873e102 100644 --- a/src/stream/ngx_stream.c +++ b/src/stream/ngx_stream.c @@ -455,6 +455,7 @@ ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *stport, #if (NGX_STREAM_SSL) addrs[i].conf.ssl = addr[i].opt.ssl; #endif + addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; len = ngx_sock_ntop(&addr[i].opt.sockaddr.sockaddr, addr[i].opt.socklen, buf, NGX_SOCKADDR_STRLEN, 1); @@ -504,6 +505,7 @@ ngx_stream_add_addrs6(ngx_conf_t *cf, ngx_stream_port_t *stport, #if (NGX_STREAM_SSL) addrs6[i].conf.ssl = addr[i].opt.ssl; #endif + addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; len = ngx_sock_ntop(&addr[i].opt.sockaddr.sockaddr, addr[i].opt.socklen, buf, NGX_SOCKADDR_STRLEN, 1); diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h index 807ab5b..6251cc7 100644 --- a/src/stream/ngx_stream.h +++ b/src/stream/ngx_stream.h @@ -26,6 +26,14 @@ typedef struct ngx_stream_session_s ngx_stream_session_t; #include +#define NGX_STREAM_OK 200 +#define NGX_STREAM_BAD_REQUEST 400 +#define NGX_STREAM_FORBIDDEN 403 +#define NGX_STREAM_INTERNAL_SERVER_ERROR 500 +#define NGX_STREAM_BAD_GATEWAY 502 +#define NGX_STREAM_SERVICE_UNAVAILABLE 503 + + typedef struct { void **main_conf; void **srv_conf; @@ -51,6 +59,7 @@ typedef struct { unsigned reuseport:1; #endif unsigned so_keepalive:2; + unsigned proxy_protocol:1; #if (NGX_HAVE_KEEPALIVE_TUNABLE) int tcp_keepidle; int tcp_keepintvl; @@ -65,8 +74,9 @@ typedef struct { ngx_stream_conf_ctx_t *ctx; ngx_str_t addr_text; #if (NGX_STREAM_SSL) - ngx_uint_t ssl; /* unsigned ssl:1; */ + unsigned ssl:1; #endif + unsigned proxy_protocol:1; } ngx_stream_addr_conf_t; typedef struct { @@ -112,8 +122,10 @@ typedef struct { ngx_array_t servers; /* ngx_stream_core_srv_conf_t */ ngx_array_t listen; /* ngx_stream_listen_t */ + ngx_stream_access_pt realip_handler; ngx_stream_access_pt limit_conn_handler; ngx_stream_access_pt access_handler; + ngx_stream_access_pt access_log_handler; ngx_hash_t variables_hash; @@ -136,7 +148,7 @@ typedef struct { ngx_stream_conf_ctx_t *ctx; u_char *file_name; - ngx_int_t line; + ngx_uint_t line; ngx_flag_t tcp_nodelay; @@ -144,6 +156,10 @@ typedef struct { ngx_msec_t resolver_timeout; ngx_resolver_t *resolver; + + ngx_msec_t proxy_protocol_timeout; + + ngx_uint_t listen; /* unsigned listen:1; */ } ngx_stream_core_srv_conf_t; @@ -153,6 +169,8 @@ struct ngx_stream_session_s { ngx_connection_t *connection; off_t received; + time_t start_sec; + ngx_msec_t start_msec; ngx_log_handler_pt log_handler; @@ -161,7 +179,8 @@ struct ngx_stream_session_s { void **srv_conf; ngx_stream_upstream_t *upstream; - + ngx_array_t *upstream_states; + /* of ngx_stream_upstream_state_t */ ngx_stream_variable_value_t *variables; #if (NGX_PCRE) @@ -169,6 +188,12 @@ struct ngx_stream_session_s { int *captures; u_char *captures_data; #endif + + ngx_uint_t status; + +#if (NGX_STREAM_SSL) + ngx_uint_t ssl; /* unsigned ssl:1; */ +#endif }; @@ -219,7 +244,7 @@ typedef struct { void ngx_stream_init_connection(ngx_connection_t *c); -void ngx_stream_close_connection(ngx_connection_t *c); +void ngx_stream_finalize_session(ngx_stream_session_t *s, ngx_uint_t rc); extern ngx_module_t ngx_stream_module; diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c index 70b9e2d..1c808ad 100644 --- a/src/stream/ngx_stream_core_module.c +++ b/src/stream/ngx_stream_core_module.c @@ -77,6 +77,13 @@ static ngx_command_t ngx_stream_core_commands[] = { offsetof(ngx_stream_core_srv_conf_t, resolver_timeout), NULL }, + { ngx_string("proxy_protocol_timeout"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_core_srv_conf_t, proxy_protocol_timeout), + NULL }, + { ngx_string("tcp_nodelay"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -192,6 +199,7 @@ ngx_stream_core_create_srv_conf(ngx_conf_t *cf) cscf->file_name = cf->conf_file->file.name.data; cscf->line = cf->conf_file->line; cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; + cscf->proxy_protocol_timeout = NGX_CONF_UNSET_MSEC; cscf->tcp_nodelay = NGX_CONF_UNSET; return cscf; @@ -240,6 +248,9 @@ ngx_stream_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) } } + ngx_conf_merge_msec_value(conf->proxy_protocol_timeout, + prev->proxy_protocol_timeout, 30000); + ngx_conf_merge_value(conf->tcp_nodelay, prev->tcp_nodelay, 1); return NGX_CONF_OK; @@ -325,6 +336,13 @@ ngx_stream_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) *cf = pcf; + if (rv == NGX_CONF_OK && !cscf->listen) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"listen\" is defined for server in %s:%ui", + cscf->file_name, cscf->line); + return NGX_CONF_ERROR; + } + return rv; } @@ -332,12 +350,16 @@ ngx_stream_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) static char * ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_stream_core_srv_conf_t *cscf = conf; + ngx_str_t *value; ngx_url_t u; ngx_uint_t i, backlog; ngx_stream_listen_t *ls, *als; ngx_stream_core_main_conf_t *cmcf; + cscf->listen = 1; + value = cf->args->elts; ngx_memzero(&u, sizeof(ngx_url_t)); @@ -561,6 +583,11 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } + if (ngx_strcmp(value[i].data, "proxy_protocol") == 0) { + ls->proxy_protocol = 1; + continue; + } + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the invalid \"%V\" parameter", &value[i]); return NGX_CONF_ERROR; @@ -580,6 +607,10 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ls->so_keepalive) { return "\"so_keepalive\" parameter is incompatible with \"udp\""; } + + if (ls->proxy_protocol) { + return "\"proxy_protocol\" parameter is incompatible with \"udp\""; + } } als = cmcf->listen.elts; diff --git a/src/stream/ngx_stream_geo_module.c b/src/stream/ngx_stream_geo_module.c index ed1a488..2204546 100644 --- a/src/stream/ngx_stream_geo_module.c +++ b/src/stream/ngx_stream_geo_module.c @@ -436,7 +436,12 @@ ngx_stream_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) for (i = 0; i < 0x10000; i++) { a = (ngx_array_t *) ctx.high.low[i]; - if (a == NULL || a->nelts == 0) { + if (a == NULL) { + continue; + } + + if (a->nelts == 0) { + ctx.high.low[i] = NULL; continue; } @@ -885,13 +890,20 @@ ngx_stream_geo_add_range(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx, return NGX_CONF_ERROR; } - range->start = (u_short) s; - range->end = (u_short) e; - range->value = ctx->value; + range = a->elts; + + ngx_memmove(&range[1], &range[0], + (a->nelts - 1) * sizeof(ngx_stream_geo_range_t)); + + range[0].start = (u_short) s; + range[0].end = (u_short) e; + range[0].value = ctx->value; next: - continue; + if (h == 0xffff) { + break; + } } return NGX_CONF_OK; @@ -909,7 +921,7 @@ ngx_stream_geo_delete_range(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx, warn = 0; - for (n = start; n <= end; n += 0x10000) { + for (n = start; n <= end; n = (n + 0x10000) & 0xffff0000) { h = n >> 16; @@ -928,9 +940,9 @@ ngx_stream_geo_delete_range(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx, a = (ngx_array_t *) ctx->high.low[h]; - if (a == NULL) { + if (a == NULL || a->nelts == 0) { warn = 1; - continue; + goto next; } range = a->elts; @@ -947,13 +959,15 @@ ngx_stream_geo_delete_range(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx, break; } - if (s != (ngx_uint_t) range[i].start - && e != (ngx_uint_t) range[i].end) - { - continue; + if (i == a->nelts - 1) { + warn = 1; } + } - warn = 1; + next: + + if (h == 0xffff) { + break; } } diff --git a/src/stream/ngx_stream_handler.c b/src/stream/ngx_stream_handler.c index 61169e1..6e2ed82 100644 --- a/src/stream/ngx_stream_handler.c +++ b/src/stream/ngx_stream_handler.c @@ -11,8 +11,10 @@ #include +static void ngx_stream_close_connection(ngx_connection_t *c); static u_char *ngx_stream_log_error(ngx_log_t *log, u_char *buf, size_t len); -static void ngx_stream_init_session(ngx_connection_t *c); +static void ngx_stream_proxy_protocol_handler(ngx_event_t *rev); +static void ngx_stream_init_session_handler(ngx_event_t *rev); #if (NGX_STREAM_SSL) static void ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c); @@ -23,11 +25,11 @@ static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c); void ngx_stream_init_connection(ngx_connection_t *c) { - int tcp_nodelay; u_char text[NGX_SOCKADDR_STRLEN]; size_t len; - ngx_int_t rc; ngx_uint_t i; + ngx_time_t *tp; + ngx_event_t *rev; struct sockaddr *sa; ngx_stream_port_t *port; struct sockaddr_in *sin; @@ -128,6 +130,10 @@ ngx_stream_init_connection(ngx_connection_t *c) s->main_conf = addr_conf->ctx->main_conf; s->srv_conf = addr_conf->ctx->srv_conf; +#if (NGX_STREAM_SSL) + s->ssl = addr_conf->ssl; +#endif + s->connection = c; c->data = s; @@ -147,6 +153,12 @@ ngx_stream_init_connection(ngx_connection_t *c) c->log->action = "initializing connection"; c->log_error = NGX_ERROR_INFO; + s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_stream_max_module); + if (s->ctx == NULL) { + ngx_stream_close_connection(c); + return; + } + cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); s->variables = ngx_pcalloc(s->connection->pool, @@ -158,11 +170,151 @@ ngx_stream_init_connection(ngx_connection_t *c) return; } + tp = ngx_timeofday(); + s->start_sec = tp->sec; + s->start_msec = tp->msec; + + rev = c->read; + rev->handler = ngx_stream_init_session_handler; + + if (addr_conf->proxy_protocol) { + c->log->action = "reading PROXY protocol"; + + rev->handler = ngx_stream_proxy_protocol_handler; + + if (!rev->ready) { + ngx_add_timer(rev, cscf->proxy_protocol_timeout); + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_stream_finalize_session(s, + NGX_STREAM_INTERNAL_SERVER_ERROR); + } + + return; + } + } + + if (ngx_use_accept_mutex) { + ngx_post_event(rev, &ngx_posted_events); + return; + } + + rev->handler(rev); +} + + +static void +ngx_stream_proxy_protocol_handler(ngx_event_t *rev) +{ + u_char *p, buf[NGX_PROXY_PROTOCOL_MAX_HEADER]; + size_t size; + ssize_t n; + ngx_err_t err; + ngx_connection_t *c; + ngx_stream_session_t *s; + ngx_stream_core_srv_conf_t *cscf; + + c = rev->data; + s = c->data; + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream PROXY protocol handler"); + + if (rev->timedout) { + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); + ngx_stream_finalize_session(s, NGX_STREAM_OK); + return; + } + + n = recv(c->fd, (char *) buf, sizeof(buf), MSG_PEEK); + + err = ngx_socket_errno; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "recv(): %z", n); + + if (n == -1) { + if (err == NGX_EAGAIN) { + rev->ready = 0; + + if (!rev->timer_set) { + cscf = ngx_stream_get_module_srv_conf(s, + ngx_stream_core_module); + + ngx_add_timer(rev, cscf->proxy_protocol_timeout); + } + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_stream_finalize_session(s, + NGX_STREAM_INTERNAL_SERVER_ERROR); + } + + return; + } + + ngx_connection_error(c, err, "recv() failed"); + + ngx_stream_finalize_session(s, NGX_STREAM_OK); + return; + } + + if (rev->timer_set) { + ngx_del_timer(rev); + } + + p = ngx_proxy_protocol_read(c, buf, buf + n); + + if (p == NULL) { + ngx_stream_finalize_session(s, NGX_STREAM_BAD_REQUEST); + return; + } + + size = p - buf; + + if (c->recv(c, buf, size) != (ssize_t) size) { + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + + ngx_stream_init_session_handler(rev); +} + + +static void +ngx_stream_init_session_handler(ngx_event_t *rev) +{ + int tcp_nodelay; + ngx_int_t rc; + ngx_connection_t *c; + ngx_stream_session_t *s; + ngx_stream_core_srv_conf_t *cscf; + ngx_stream_core_main_conf_t *cmcf; + + c = rev->data; + s = c->data; + + c->log->action = "initializing session"; + + cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); + + if (cmcf->realip_handler) { + rc = cmcf->realip_handler(s); + + if (rc == NGX_ERROR) { + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + } + if (cmcf->limit_conn_handler) { rc = cmcf->limit_conn_handler(s); - if (rc != NGX_DECLINED) { - ngx_stream_close_connection(c); + if (rc == NGX_ERROR) { + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + + if (rc == NGX_ABORT) { + ngx_stream_finalize_session(s, NGX_STREAM_SERVICE_UNAVAILABLE); return; } } @@ -170,12 +322,19 @@ ngx_stream_init_connection(ngx_connection_t *c) if (cmcf->access_handler) { rc = cmcf->access_handler(s); - if (rc != NGX_OK && rc != NGX_DECLINED) { - ngx_stream_close_connection(c); + if (rc == NGX_ERROR) { + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + + if (rc == NGX_ABORT) { + ngx_stream_finalize_session(s, NGX_STREAM_FORBIDDEN); return; } } + cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); + if (c->type == SOCK_STREAM && cscf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) @@ -189,7 +348,7 @@ ngx_stream_init_connection(ngx_connection_t *c) { ngx_connection_error(c, ngx_socket_errno, "setsockopt(TCP_NODELAY) failed"); - ngx_stream_close_connection(c); + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -203,14 +362,14 @@ ngx_stream_init_connection(ngx_connection_t *c) sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); - if (addr_conf->ssl) { + if (s->ssl) { c->log->action = "SSL handshaking"; if (sslcf->ssl.ctx == NULL) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "no \"ssl_certificate\" is defined " "in server listening on SSL port"); - ngx_stream_close_connection(c); + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -220,27 +379,8 @@ ngx_stream_init_connection(ngx_connection_t *c) } #endif - ngx_stream_init_session(c); -} - - -static void -ngx_stream_init_session(ngx_connection_t *c) -{ - ngx_stream_session_t *s; - ngx_stream_core_srv_conf_t *cscf; - - s = c->data; c->log->action = "handling client connection"; - cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); - - s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_stream_max_module); - if (s->ctx == NULL) { - ngx_stream_close_connection(c); - return; - } - cscf->handler(s); } @@ -253,15 +393,14 @@ ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c) ngx_stream_session_t *s; ngx_stream_ssl_conf_t *sslcf; + s = c->data; + if (ngx_ssl_create_connection(ssl, c, 0) == NGX_ERROR) { - ngx_stream_close_connection(c); + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } if (ngx_ssl_handshake(c) == NGX_AGAIN) { - - s = c->data; - sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); ngx_add_timer(c->read, sslcf->handshake_timeout); @@ -278,8 +417,11 @@ ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c) static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c) { + ngx_stream_session_t *s; + ngx_stream_core_srv_conf_t *cscf; + if (!c->ssl->handshaked) { - ngx_stream_close_connection(c); + ngx_stream_finalize_session(c->data, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -287,13 +429,39 @@ ngx_stream_ssl_handshake_handler(ngx_connection_t *c) ngx_del_timer(c->read); } - ngx_stream_init_session(c); + c->log->action = "handling client connection"; + + s = c->data; + + cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); + + cscf->handler(s); } #endif void +ngx_stream_finalize_session(ngx_stream_session_t *s, ngx_uint_t rc) +{ + ngx_stream_core_main_conf_t *cmcf; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "finalize stream session: %i", rc); + + s->status = rc; + + cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); + + if (cmcf->access_log_handler) { + (void) cmcf->access_log_handler(s); + } + + ngx_stream_close_connection(s->connection); +} + + +static void ngx_stream_close_connection(ngx_connection_t *c) { ngx_pool_t *pool; diff --git a/src/stream/ngx_stream_log_module.c b/src/stream/ngx_stream_log_module.c new file mode 100644 index 0000000..4affbdf --- /dev/null +++ b/src/stream/ngx_stream_log_module.c @@ -0,0 +1,1474 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + +#if (NGX_ZLIB) +#include +#endif + + +typedef struct ngx_stream_log_op_s ngx_stream_log_op_t; + +typedef u_char *(*ngx_stream_log_op_run_pt) (ngx_stream_session_t *s, + u_char *buf, ngx_stream_log_op_t *op); + +typedef size_t (*ngx_stream_log_op_getlen_pt) (ngx_stream_session_t *s, + uintptr_t data); + + +struct ngx_stream_log_op_s { + size_t len; + ngx_stream_log_op_getlen_pt getlen; + ngx_stream_log_op_run_pt run; + uintptr_t data; +}; + + +typedef struct { + ngx_str_t name; + ngx_array_t *flushes; + ngx_array_t *ops; /* array of ngx_stream_log_op_t */ +} ngx_stream_log_fmt_t; + + +typedef struct { + ngx_array_t formats; /* array of ngx_stream_log_fmt_t */ +} ngx_stream_log_main_conf_t; + + +typedef struct { + u_char *start; + u_char *pos; + u_char *last; + + ngx_event_t *event; + ngx_msec_t flush; + ngx_int_t gzip; +} ngx_stream_log_buf_t; + + +typedef struct { + ngx_array_t *lengths; + ngx_array_t *values; +} ngx_stream_log_script_t; + + +typedef struct { + ngx_open_file_t *file; + ngx_stream_log_script_t *script; + time_t disk_full_time; + time_t error_log_time; + ngx_syslog_peer_t *syslog_peer; + ngx_stream_log_fmt_t *format; + ngx_stream_complex_value_t *filter; +} ngx_stream_log_t; + + +typedef struct { + ngx_array_t *logs; /* array of ngx_stream_log_t */ + + ngx_open_file_cache_t *open_file_cache; + time_t open_file_cache_valid; + ngx_uint_t open_file_cache_min_uses; + + ngx_uint_t off; /* unsigned off:1 */ +} ngx_stream_log_srv_conf_t; + + +typedef struct { + ngx_str_t name; + size_t len; + ngx_stream_log_op_run_pt run; +} ngx_stream_log_var_t; + + +static void ngx_stream_log_write(ngx_stream_session_t *s, ngx_stream_log_t *log, + u_char *buf, size_t len); +static ssize_t ngx_stream_log_script_write(ngx_stream_session_t *s, + ngx_stream_log_script_t *script, u_char **name, u_char *buf, size_t len); + +#if (NGX_ZLIB) +static ssize_t ngx_stream_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, + ngx_int_t level, ngx_log_t *log); + +static void *ngx_stream_log_gzip_alloc(void *opaque, u_int items, u_int size); +static void ngx_stream_log_gzip_free(void *opaque, void *address); +#endif + +static void ngx_stream_log_flush(ngx_open_file_t *file, ngx_log_t *log); +static void ngx_stream_log_flush_handler(ngx_event_t *ev); + +static ngx_int_t ngx_stream_log_variable_compile(ngx_conf_t *cf, + ngx_stream_log_op_t *op, ngx_str_t *value); +static size_t ngx_stream_log_variable_getlen(ngx_stream_session_t *s, + uintptr_t data); +static u_char *ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf, + ngx_stream_log_op_t *op); +static uintptr_t ngx_stream_log_escape(u_char *dst, u_char *src, size_t size); + + +static void *ngx_stream_log_create_main_conf(ngx_conf_t *cf); +static void *ngx_stream_log_create_srv_conf(ngx_conf_t *cf); +static char *ngx_stream_log_merge_srv_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_stream_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_log_compile_format(ngx_conf_t *cf, + ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s); +static char *ngx_stream_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_stream_log_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_stream_log_commands[] = { + + { ngx_string("log_format"), + NGX_STREAM_MAIN_CONF|NGX_CONF_2MORE, + ngx_stream_log_set_format, + NGX_STREAM_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("access_log"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE, + ngx_stream_log_set_log, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("open_log_file_cache"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1234, + ngx_stream_log_open_file_cache, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_log_module_ctx = { + NULL, /* preconfiguration */ + ngx_stream_log_init, /* postconfiguration */ + + ngx_stream_log_create_main_conf, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_stream_log_create_srv_conf, /* create server configuration */ + ngx_stream_log_merge_srv_conf /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_log_module = { + NGX_MODULE_V1, + &ngx_stream_log_module_ctx, /* module context */ + ngx_stream_log_commands, /* module directives */ + NGX_STREAM_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_stream_log_handler(ngx_stream_session_t *s) +{ + u_char *line, *p; + size_t len, size; + ssize_t n; + ngx_str_t val; + ngx_uint_t i, l; + ngx_stream_log_t *log; + ngx_stream_log_op_t *op; + ngx_stream_log_buf_t *buffer; + ngx_stream_log_srv_conf_t *lscf; + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream log handler"); + + lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_log_module); + + if (lscf->off || lscf->logs == NULL) { + return NGX_OK; + } + + log = lscf->logs->elts; + for (l = 0; l < lscf->logs->nelts; l++) { + + if (log[l].filter) { + if (ngx_stream_complex_value(s, log[l].filter, &val) != NGX_OK) { + return NGX_ERROR; + } + + if (val.len == 0 || (val.len == 1 && val.data[0] == '0')) { + continue; + } + } + + if (ngx_time() == log[l].disk_full_time) { + + /* + * on FreeBSD writing to a full filesystem with enabled softupdates + * may block process for much longer time than writing to non-full + * filesystem, so we skip writing to a log for one second + */ + + continue; + } + + ngx_stream_script_flush_no_cacheable_variables(s, + log[l].format->flushes); + + len = 0; + op = log[l].format->ops->elts; + for (i = 0; i < log[l].format->ops->nelts; i++) { + if (op[i].len == 0) { + len += op[i].getlen(s, op[i].data); + + } else { + len += op[i].len; + } + } + + if (log[l].syslog_peer) { + + /* length of syslog's PRI and HEADER message parts */ + len += sizeof("<255>Jan 01 00:00:00 ") - 1 + + ngx_cycle->hostname.len + 1 + + log[l].syslog_peer->tag.len + 2; + + goto alloc_line; + } + + len += NGX_LINEFEED_SIZE; + + buffer = log[l].file ? log[l].file->data : NULL; + + if (buffer) { + + if (len > (size_t) (buffer->last - buffer->pos)) { + + ngx_stream_log_write(s, &log[l], buffer->start, + buffer->pos - buffer->start); + + buffer->pos = buffer->start; + } + + if (len <= (size_t) (buffer->last - buffer->pos)) { + + p = buffer->pos; + + if (buffer->event && p == buffer->start) { + ngx_add_timer(buffer->event, buffer->flush); + } + + for (i = 0; i < log[l].format->ops->nelts; i++) { + p = op[i].run(s, p, &op[i]); + } + + ngx_linefeed(p); + + buffer->pos = p; + + continue; + } + + if (buffer->event && buffer->event->timer_set) { + ngx_del_timer(buffer->event); + } + } + + alloc_line: + + line = ngx_pnalloc(s->connection->pool, len); + if (line == NULL) { + return NGX_ERROR; + } + + p = line; + + if (log[l].syslog_peer) { + p = ngx_syslog_add_header(log[l].syslog_peer, line); + } + + for (i = 0; i < log[l].format->ops->nelts; i++) { + p = op[i].run(s, p, &op[i]); + } + + if (log[l].syslog_peer) { + + size = p - line; + + n = ngx_syslog_send(log[l].syslog_peer, line, size); + + if (n < 0) { + ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, + "send() to syslog failed"); + + } else if ((size_t) n != size) { + ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, + "send() to syslog has written only %z of %uz", + n, size); + } + + continue; + } + + ngx_linefeed(p); + + ngx_stream_log_write(s, &log[l], line, p - line); + } + + return NGX_OK; +} + + +static void +ngx_stream_log_write(ngx_stream_session_t *s, ngx_stream_log_t *log, + u_char *buf, size_t len) +{ + u_char *name; + time_t now; + ssize_t n; + ngx_err_t err; +#if (NGX_ZLIB) + ngx_stream_log_buf_t *buffer; +#endif + + if (log->script == NULL) { + name = log->file->name.data; + +#if (NGX_ZLIB) + buffer = log->file->data; + + if (buffer && buffer->gzip) { + n = ngx_stream_log_gzip(log->file->fd, buf, len, buffer->gzip, + s->connection->log); + } else { + n = ngx_write_fd(log->file->fd, buf, len); + } +#else + n = ngx_write_fd(log->file->fd, buf, len); +#endif + + } else { + name = NULL; + n = ngx_stream_log_script_write(s, log->script, &name, buf, len); + } + + if (n == (ssize_t) len) { + return; + } + + now = ngx_time(); + + if (n == -1) { + err = ngx_errno; + + if (err == NGX_ENOSPC) { + log->disk_full_time = now; + } + + if (now - log->error_log_time > 59) { + ngx_log_error(NGX_LOG_ALERT, s->connection->log, err, + ngx_write_fd_n " to \"%s\" failed", name); + + log->error_log_time = now; + } + + return; + } + + if (now - log->error_log_time > 59) { + ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0, + ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz", + name, n, len); + + log->error_log_time = now; + } +} + + +static ssize_t +ngx_stream_log_script_write(ngx_stream_session_t *s, + ngx_stream_log_script_t *script, u_char **name, u_char *buf, size_t len) +{ + ssize_t n; + ngx_str_t log; + ngx_open_file_info_t of; + ngx_stream_log_srv_conf_t *lscf; + + if (ngx_stream_script_run(s, &log, script->lengths->elts, 1, + script->values->elts) + == NULL) + { + /* simulate successful logging */ + return len; + } + + log.data[log.len - 1] = '\0'; + *name = log.data; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream log \"%s\"", log.data); + + lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_log_module); + + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + + of.log = 1; + of.valid = lscf->open_file_cache_valid; + of.min_uses = lscf->open_file_cache_min_uses; + of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; + + if (ngx_open_cached_file(lscf->open_file_cache, &log, &of, + s->connection->pool) + != NGX_OK) + { + ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno, + "%s \"%s\" failed", of.failed, log.data); + /* simulate successful logging */ + return len; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream log #%d", of.fd); + + n = ngx_write_fd(of.fd, buf, len); + + return n; +} + + +#if (NGX_ZLIB) + +static ssize_t +ngx_stream_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level, + ngx_log_t *log) +{ + int rc, wbits, memlevel; + u_char *out; + size_t size; + ssize_t n; + z_stream zstream; + ngx_err_t err; + ngx_pool_t *pool; + + wbits = MAX_WBITS; + memlevel = MAX_MEM_LEVEL - 1; + + while ((ssize_t) len < ((1 << (wbits - 1)) - 262)) { + wbits--; + memlevel--; + } + + /* + * This is a formula from deflateBound() for conservative upper bound of + * compressed data plus 18 bytes of gzip wrapper. + */ + + size = len + ((len + 7) >> 3) + ((len + 63) >> 6) + 5 + 18; + + ngx_memzero(&zstream, sizeof(z_stream)); + + pool = ngx_create_pool(256, log); + if (pool == NULL) { + /* simulate successful logging */ + return len; + } + + pool->log = log; + + zstream.zalloc = ngx_stream_log_gzip_alloc; + zstream.zfree = ngx_stream_log_gzip_free; + zstream.opaque = pool; + + out = ngx_pnalloc(pool, size); + if (out == NULL) { + goto done; + } + + zstream.next_in = buf; + zstream.avail_in = len; + zstream.next_out = out; + zstream.avail_out = size; + + rc = deflateInit2(&zstream, (int) level, Z_DEFLATED, wbits + 16, memlevel, + Z_DEFAULT_STRATEGY); + + if (rc != Z_OK) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateInit2() failed: %d", rc); + goto done; + } + + ngx_log_debug4(NGX_LOG_DEBUG_STREAM, log, 0, + "deflate in: ni:%p no:%p ai:%ud ao:%ud", + zstream.next_in, zstream.next_out, + zstream.avail_in, zstream.avail_out); + + rc = deflate(&zstream, Z_FINISH); + + if (rc != Z_STREAM_END) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "deflate(Z_FINISH) failed: %d", rc); + goto done; + } + + ngx_log_debug5(NGX_LOG_DEBUG_STREAM, log, 0, + "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d", + zstream.next_in, zstream.next_out, + zstream.avail_in, zstream.avail_out, + rc); + + size -= zstream.avail_out; + + rc = deflateEnd(&zstream); + + if (rc != Z_OK) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateEnd() failed: %d", rc); + goto done; + } + + n = ngx_write_fd(fd, out, size); + + if (n != (ssize_t) size) { + err = (n == -1) ? ngx_errno : 0; + + ngx_destroy_pool(pool); + + ngx_set_errno(err); + return -1; + } + +done: + + ngx_destroy_pool(pool); + + /* simulate successful logging */ + return len; +} + + +static void * +ngx_stream_log_gzip_alloc(void *opaque, u_int items, u_int size) +{ + ngx_pool_t *pool = opaque; + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pool->log, 0, + "gzip alloc: n:%ud s:%ud", items, size); + + return ngx_palloc(pool, items * size); +} + + +static void +ngx_stream_log_gzip_free(void *opaque, void *address) +{ +#if 0 + ngx_pool_t *pool = opaque; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pool->log, 0, + "gzip free: %p", address); +#endif +} + +#endif + + +static void +ngx_stream_log_flush(ngx_open_file_t *file, ngx_log_t *log) +{ + size_t len; + ssize_t n; + ngx_stream_log_buf_t *buffer; + + buffer = file->data; + + len = buffer->pos - buffer->start; + + if (len == 0) { + return; + } + +#if (NGX_ZLIB) + if (buffer->gzip) { + n = ngx_stream_log_gzip(file->fd, buffer->start, len, buffer->gzip, + log); + } else { + n = ngx_write_fd(file->fd, buffer->start, len); + } +#else + n = ngx_write_fd(file->fd, buffer->start, len); +#endif + + if (n == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_write_fd_n " to \"%s\" failed", + file->name.data); + + } else if ((size_t) n != len) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz", + file->name.data, n, len); + } + + buffer->pos = buffer->start; + + if (buffer->event && buffer->event->timer_set) { + ngx_del_timer(buffer->event); + } +} + + +static void +ngx_stream_log_flush_handler(ngx_event_t *ev) +{ + ngx_open_file_t *file; + ngx_stream_log_buf_t *buffer; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "stream log buffer flush handler"); + + if (ev->timedout) { + ngx_stream_log_flush(ev->data, ev->log); + return; + } + + /* cancel the flush timer for graceful shutdown */ + + file = ev->data; + buffer = file->data; + + buffer->event = NULL; +} + + +static u_char * +ngx_stream_log_copy_short(ngx_stream_session_t *s, u_char *buf, + ngx_stream_log_op_t *op) +{ + size_t len; + uintptr_t data; + + len = op->len; + data = op->data; + + while (len--) { + *buf++ = (u_char) (data & 0xff); + data >>= 8; + } + + return buf; +} + + +static u_char * +ngx_stream_log_copy_long(ngx_stream_session_t *s, u_char *buf, + ngx_stream_log_op_t *op) +{ + return ngx_cpymem(buf, (u_char *) op->data, op->len); +} + + +static ngx_int_t +ngx_stream_log_variable_compile(ngx_conf_t *cf, ngx_stream_log_op_t *op, + ngx_str_t *value) +{ + ngx_int_t index; + + index = ngx_stream_get_variable_index(cf, value); + if (index == NGX_ERROR) { + return NGX_ERROR; + } + + op->len = 0; + op->getlen = ngx_stream_log_variable_getlen; + op->run = ngx_stream_log_variable; + op->data = index; + + return NGX_OK; +} + + +static size_t +ngx_stream_log_variable_getlen(ngx_stream_session_t *s, uintptr_t data) +{ + uintptr_t len; + ngx_stream_variable_value_t *value; + + value = ngx_stream_get_indexed_variable(s, data); + + if (value == NULL || value->not_found) { + return 1; + } + + len = ngx_stream_log_escape(NULL, value->data, value->len); + + value->escape = len ? 1 : 0; + + return value->len + len * 3; +} + + +static u_char * +ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf, + ngx_stream_log_op_t *op) +{ + ngx_stream_variable_value_t *value; + + value = ngx_stream_get_indexed_variable(s, op->data); + + if (value == NULL || value->not_found) { + *buf = '-'; + return buf + 1; + } + + if (value->escape == 0) { + return ngx_cpymem(buf, value->data, value->len); + + } else { + return (u_char *) ngx_stream_log_escape(buf, value->data, value->len); + } +} + + +static uintptr_t +ngx_stream_log_escape(u_char *dst, u_char *src, size_t size) +{ + ngx_uint_t n; + static u_char hex[] = "0123456789ABCDEF"; + + static uint32_t escape[] = { + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0x00000004, /* 0000 0000 0000 0000 0000 0000 0000 0100 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x10000000, /* 0001 0000 0000 0000 0000 0000 0000 0000 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + }; + + + if (dst == NULL) { + + /* find the number of the characters to be escaped */ + + n = 0; + + while (size) { + if (escape[*src >> 5] & (1U << (*src & 0x1f))) { + n++; + } + src++; + size--; + } + + return (uintptr_t) n; + } + + while (size) { + if (escape[*src >> 5] & (1U << (*src & 0x1f))) { + *dst++ = '\\'; + *dst++ = 'x'; + *dst++ = hex[*src >> 4]; + *dst++ = hex[*src & 0xf]; + src++; + + } else { + *dst++ = *src++; + } + size--; + } + + return (uintptr_t) dst; +} + + +static void * +ngx_stream_log_create_main_conf(ngx_conf_t *cf) +{ + ngx_stream_log_main_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_main_conf_t)); + if (conf == NULL) { + return NULL; + } + + if (ngx_array_init(&conf->formats, cf->pool, 4, + sizeof(ngx_stream_log_fmt_t)) + != NGX_OK) + { + return NULL; + } + + return conf; +} + + +static void * +ngx_stream_log_create_srv_conf(ngx_conf_t *cf) +{ + ngx_stream_log_srv_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + conf->open_file_cache = NGX_CONF_UNSET_PTR; + + return conf; +} + + +static char * +ngx_stream_log_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_stream_log_srv_conf_t *prev = parent; + ngx_stream_log_srv_conf_t *conf = child; + + if (conf->open_file_cache == NGX_CONF_UNSET_PTR) { + + conf->open_file_cache = prev->open_file_cache; + conf->open_file_cache_valid = prev->open_file_cache_valid; + conf->open_file_cache_min_uses = prev->open_file_cache_min_uses; + + if (conf->open_file_cache == NGX_CONF_UNSET_PTR) { + conf->open_file_cache = NULL; + } + } + + if (conf->logs || conf->off) { + return NGX_CONF_OK; + } + + conf->logs = prev->logs; + conf->off = prev->off; + + return NGX_CONF_OK; +} + + +static char * +ngx_stream_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_log_srv_conf_t *lscf = conf; + + ssize_t size; + ngx_int_t gzip; + ngx_uint_t i, n; + ngx_msec_t flush; + ngx_str_t *value, name, s; + ngx_stream_log_t *log; + ngx_syslog_peer_t *peer; + ngx_stream_log_buf_t *buffer; + ngx_stream_log_fmt_t *fmt; + ngx_stream_script_compile_t sc; + ngx_stream_log_main_conf_t *lmcf; + ngx_stream_compile_complex_value_t ccv; + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "off") == 0) { + lscf->off = 1; + if (cf->args->nelts == 2) { + return NGX_CONF_OK; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + + if (lscf->logs == NULL) { + lscf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_stream_log_t)); + if (lscf->logs == NULL) { + return NGX_CONF_ERROR; + } + } + + lmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_log_module); + + log = ngx_array_push(lscf->logs); + if (log == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(log, sizeof(ngx_stream_log_t)); + + + if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) { + + peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t)); + if (peer == NULL) { + return NGX_CONF_ERROR; + } + + if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) { + return NGX_CONF_ERROR; + } + + log->syslog_peer = peer; + + goto process_formats; + } + + n = ngx_stream_script_variables_count(&value[1]); + + if (n == 0) { + log->file = ngx_conf_open_file(cf->cycle, &value[1]); + if (log->file == NULL) { + return NGX_CONF_ERROR; + } + + } else { + if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) { + return NGX_CONF_ERROR; + } + + log->script = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_script_t)); + if (log->script == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(&sc, sizeof(ngx_stream_script_compile_t)); + + sc.cf = cf; + sc.source = &value[1]; + sc.lengths = &log->script->lengths; + sc.values = &log->script->values; + sc.variables = n; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_stream_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + +process_formats: + + if (cf->args->nelts >= 3) { + name = value[2]; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "log format is not specified"); + return NGX_CONF_ERROR; + } + + fmt = lmcf->formats.elts; + for (i = 0; i < lmcf->formats.nelts; i++) { + if (fmt[i].name.len == name.len + && ngx_strcasecmp(fmt[i].name.data, name.data) == 0) + { + log->format = &fmt[i]; + break; + } + } + + if (log->format == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unknown log format \"%V\"", &name); + return NGX_CONF_ERROR; + } + + size = 0; + flush = 0; + gzip = 0; + + for (i = 3; i < cf->args->nelts; i++) { + + if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) { + s.len = value[i].len - 7; + s.data = value[i].data + 7; + + size = ngx_parse_size(&s); + + if (size == NGX_ERROR || size == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid buffer size \"%V\"", &s); + return NGX_CONF_ERROR; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "flush=", 6) == 0) { + s.len = value[i].len - 6; + s.data = value[i].data + 6; + + flush = ngx_parse_time(&s, 0); + + if (flush == (ngx_msec_t) NGX_ERROR || flush == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid flush time \"%V\"", &s); + return NGX_CONF_ERROR; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "gzip", 4) == 0 + && (value[i].len == 4 || value[i].data[4] == '=')) + { +#if (NGX_ZLIB) + if (size == 0) { + size = 64 * 1024; + } + + if (value[i].len == 4) { + gzip = Z_BEST_SPEED; + continue; + } + + s.len = value[i].len - 5; + s.data = value[i].data + 5; + + gzip = ngx_atoi(s.data, s.len); + + if (gzip < 1 || gzip > 9) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid compression level \"%V\"", &s); + return NGX_CONF_ERROR; + } + + continue; + +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "nginx was built without zlib support"); + return NGX_CONF_ERROR; +#endif + } + + if (ngx_strncmp(value[i].data, "if=", 3) == 0) { + s.len = value[i].len - 3; + s.data = value[i].data + 3; + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &s; + ccv.complex_value = ngx_palloc(cf->pool, + sizeof(ngx_stream_complex_value_t)); + if (ccv.complex_value == NULL) { + return NGX_CONF_ERROR; + } + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + log->filter = ccv.complex_value; + + continue; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (flush && size == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "no buffer is defined for access_log \"%V\"", + &value[1]); + return NGX_CONF_ERROR; + } + + if (size) { + + if (log->script) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "buffered logs cannot have variables in name"); + return NGX_CONF_ERROR; + } + + if (log->syslog_peer) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "logs to syslog cannot be buffered"); + return NGX_CONF_ERROR; + } + + if (log->file->data) { + buffer = log->file->data; + + if (buffer->last - buffer->start != size + || buffer->flush != flush + || buffer->gzip != gzip) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "access_log \"%V\" already defined " + "with conflicting parameters", + &value[1]); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; + } + + buffer = ngx_pcalloc(cf->pool, sizeof(ngx_stream_log_buf_t)); + if (buffer == NULL) { + return NGX_CONF_ERROR; + } + + buffer->start = ngx_pnalloc(cf->pool, size); + if (buffer->start == NULL) { + return NGX_CONF_ERROR; + } + + buffer->pos = buffer->start; + buffer->last = buffer->start + size; + + if (flush) { + buffer->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t)); + if (buffer->event == NULL) { + return NGX_CONF_ERROR; + } + + buffer->event->data = log->file; + buffer->event->handler = ngx_stream_log_flush_handler; + buffer->event->log = &cf->cycle->new_log; + buffer->event->cancelable = 1; + + buffer->flush = flush; + } + + buffer->gzip = gzip; + + log->file->flush = ngx_stream_log_flush; + log->file->data = buffer; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_stream_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_log_main_conf_t *lmcf = conf; + + ngx_str_t *value; + ngx_uint_t i; + ngx_stream_log_fmt_t *fmt; + + value = cf->args->elts; + + fmt = lmcf->formats.elts; + for (i = 0; i < lmcf->formats.nelts; i++) { + if (fmt[i].name.len == value[1].len + && ngx_strcmp(fmt[i].name.data, value[1].data) == 0) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate \"log_format\" name \"%V\"", + &value[1]); + return NGX_CONF_ERROR; + } + } + + fmt = ngx_array_push(&lmcf->formats); + if (fmt == NULL) { + return NGX_CONF_ERROR; + } + + fmt->name = value[1]; + + fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t)); + if (fmt->flushes == NULL) { + return NGX_CONF_ERROR; + } + + fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_stream_log_op_t)); + if (fmt->ops == NULL) { + return NGX_CONF_ERROR; + } + + return ngx_stream_log_compile_format(cf, fmt->flushes, fmt->ops, + cf->args, 2); +} + + +static char * +ngx_stream_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes, + ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s) +{ + u_char *data, *p, ch; + size_t i, len; + ngx_str_t *value, var; + ngx_int_t *flush; + ngx_uint_t bracket; + ngx_stream_log_op_t *op; + + value = args->elts; + + for ( /* void */ ; s < args->nelts; s++) { + + i = 0; + + while (i < value[s].len) { + + op = ngx_array_push(ops); + if (op == NULL) { + return NGX_CONF_ERROR; + } + + data = &value[s].data[i]; + + if (value[s].data[i] == '$') { + + if (++i == value[s].len) { + goto invalid; + } + + if (value[s].data[i] == '{') { + bracket = 1; + + if (++i == value[s].len) { + goto invalid; + } + + var.data = &value[s].data[i]; + + } else { + bracket = 0; + var.data = &value[s].data[i]; + } + + for (var.len = 0; i < value[s].len; i++, var.len++) { + ch = value[s].data[i]; + + if (ch == '}' && bracket) { + i++; + bracket = 0; + break; + } + + if ((ch >= 'A' && ch <= 'Z') + || (ch >= 'a' && ch <= 'z') + || (ch >= '0' && ch <= '9') + || ch == '_') + { + continue; + } + + break; + } + + if (bracket) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the closing bracket in \"%V\" " + "variable is missing", &var); + return NGX_CONF_ERROR; + } + + if (var.len == 0) { + goto invalid; + } + + if (ngx_stream_log_variable_compile(cf, op, &var) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (flushes) { + + flush = ngx_array_push(flushes); + if (flush == NULL) { + return NGX_CONF_ERROR; + } + + *flush = op->data; /* variable index */ + } + + continue; + } + + i++; + + while (i < value[s].len && value[s].data[i] != '$') { + i++; + } + + len = &value[s].data[i] - data; + + if (len) { + + op->len = len; + op->getlen = NULL; + + if (len <= sizeof(uintptr_t)) { + op->run = ngx_stream_log_copy_short; + op->data = 0; + + while (len--) { + op->data <<= 8; + op->data |= data[len]; + } + + } else { + op->run = ngx_stream_log_copy_long; + + p = ngx_pnalloc(cf->pool, len); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memcpy(p, data, len); + op->data = (uintptr_t) p; + } + } + } + } + + return NGX_CONF_OK; + +invalid: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data); + + return NGX_CONF_ERROR; +} + + +static char * +ngx_stream_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_log_srv_conf_t *lscf = conf; + + time_t inactive, valid; + ngx_str_t *value, s; + ngx_int_t max, min_uses; + ngx_uint_t i; + + if (lscf->open_file_cache != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + max = 0; + inactive = 10; + valid = 60; + min_uses = 1; + + for (i = 1; i < cf->args->nelts; i++) { + + if (ngx_strncmp(value[i].data, "max=", 4) == 0) { + + max = ngx_atoi(value[i].data + 4, value[i].len - 4); + if (max == NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) { + + s.len = value[i].len - 9; + s.data = value[i].data + 9; + + inactive = ngx_parse_time(&s, 1); + if (inactive == (time_t) NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "min_uses=", 9) == 0) { + + min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9); + if (min_uses == NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "valid=", 6) == 0) { + + s.len = value[i].len - 6; + s.data = value[i].data + 6; + + valid = ngx_parse_time(&s, 1); + if (valid == (time_t) NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strcmp(value[i].data, "off") == 0) { + + lscf->open_file_cache = NULL; + + continue; + } + + failed: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid \"open_log_file_cache\" parameter \"%V\"", + &value[i]); + return NGX_CONF_ERROR; + } + + if (lscf->open_file_cache == NULL) { + return NGX_CONF_OK; + } + + if (max == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"open_log_file_cache\" must have \"max\" parameter"); + return NGX_CONF_ERROR; + } + + lscf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive); + + if (lscf->open_file_cache) { + + lscf->open_file_cache_valid = valid; + lscf->open_file_cache_min_uses = min_uses; + + return NGX_CONF_OK; + } + + return NGX_CONF_ERROR; +} + + +static ngx_int_t +ngx_stream_log_init(ngx_conf_t *cf) +{ + ngx_stream_core_main_conf_t *cmcf; + + cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); + + cmcf->access_log_handler = ngx_stream_log_handler; + + return NGX_OK; +} diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 9d43109..ed802e7 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -73,7 +73,7 @@ static ngx_int_t ngx_stream_proxy_test_connect(ngx_connection_t *c); static void ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, ngx_uint_t do_write); static void ngx_stream_proxy_next_upstream(ngx_stream_session_t *s); -static void ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_int_t rc); +static void ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_uint_t rc); static u_char *ngx_stream_proxy_log_error(ngx_log_t *log, u_char *buf, size_t len); @@ -368,7 +368,7 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) u = ngx_pcalloc(c->pool, sizeof(ngx_stream_upstream_t)); if (u == NULL) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -380,7 +380,7 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) u->peer.log_error = NGX_ERROR_ERR; if (ngx_stream_proxy_set_local(s, u, pscf->local) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -392,10 +392,17 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) c->write->handler = ngx_stream_proxy_downstream_handler; c->read->handler = ngx_stream_proxy_downstream_handler; + s->upstream_states = ngx_array_create(c->pool, 1, + sizeof(ngx_stream_upstream_state_t)); + if (s->upstream_states == NULL) { + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + if (c->type == SOCK_STREAM) { p = ngx_pnalloc(c->pool, pscf->buffer_size); if (p == NULL) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -418,7 +425,7 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) p = ngx_proxy_protocol_write(c, u->downstream_buf.last, u->downstream_buf.end); if (p == NULL) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -433,7 +440,7 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) if (pscf->upstream_value) { if (ngx_stream_proxy_eval(s, pscf) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } } @@ -457,14 +464,14 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "no port in upstream \"%V\"", host); - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } if (ngx_stream_upstream_create_round_robin_peer(s, u->resolved) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -493,7 +500,7 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) if (u->resolved->port == 0) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "no port in upstream \"%V\"", host); - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -503,14 +510,14 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) ctx = ngx_resolve_start(cscf->resolver, &temp); if (ctx == NULL) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } if (ctx == NGX_NO_RESOLVER) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "no resolver defined to resolve %V", host); - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -523,7 +530,7 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) if (ngx_resolve_name(ctx) != NGX_OK) { u->resolved->ctx = NULL; - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -534,16 +541,16 @@ found: if (uscf == NULL) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "no upstream configuration"); - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } -#if (NGX_HTTP_SSL) +#if (NGX_STREAM_SSL) u->ssl_name = uscf->host; #endif if (uscf->peer.init(s, uscf) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -677,18 +684,36 @@ ngx_stream_proxy_connect(ngx_stream_session_t *s) u = s->upstream; + if (u->state) { + u->state->response_time = ngx_current_msec - u->state->response_time; + } + + u->state = ngx_array_push(s->upstream_states); + if (u->state == NULL) { + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + + ngx_memzero(u->state, sizeof(ngx_stream_upstream_state_t)); + + u->state->connect_time = (ngx_msec_t) -1; + u->state->first_byte_time = (ngx_msec_t) -1; + u->state->response_time = ngx_current_msec; + rc = ngx_event_connect_peer(&u->peer); ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "proxy connect: %i", rc); if (rc == NGX_ERROR) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } + u->state->peer = u->peer.name; + if (rc == NGX_BUSY) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "no live upstreams"); - ngx_stream_proxy_finalize(s, NGX_DECLINED); + ngx_stream_proxy_finalize(s, NGX_STREAM_BAD_GATEWAY); return; } @@ -796,12 +821,14 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) } } + u->state->connect_time = ngx_current_msec - u->state->response_time; + c->log->action = "proxying connection"; if (u->upstream_buf.start == NULL) { p = ngx_pnalloc(c->pool, pscf->buffer_size); if (p == NULL) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -851,7 +878,7 @@ ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s) p = ngx_proxy_protocol_write(c, buf, buf + NGX_PROXY_PROTOCOL_MAX_HEADER); if (p == NULL) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return NGX_ERROR; } @@ -865,7 +892,7 @@ ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s) if (n == NGX_AGAIN) { if (ngx_handle_write_event(pc->write, 0) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return NGX_ERROR; } @@ -879,7 +906,7 @@ ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s) } if (n == NGX_ERROR) { - ngx_stream_proxy_finalize(s, NGX_DECLINED); + ngx_stream_proxy_finalize(s, NGX_STREAM_OK); return NGX_ERROR; } @@ -895,7 +922,7 @@ ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s) ngx_log_error(NGX_LOG_ERR, c->log, 0, "could not send PROXY protocol header at once"); - ngx_stream_proxy_finalize(s, NGX_DECLINED); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return NGX_ERROR; } @@ -947,20 +974,20 @@ ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s) if (ngx_ssl_create_connection(pscf->ssl, pc, NGX_SSL_BUFFER|NGX_SSL_CLIENT) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } if (pscf->ssl_server_name || pscf->ssl_verify) { if (ngx_stream_proxy_ssl_name(s) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } } if (pscf->ssl_session_reuse) { if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } } @@ -1157,7 +1184,7 @@ ngx_stream_proxy_resolve_handler(ngx_resolver_ctx_t *ctx) u = s->upstream; ur = u->resolved; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, s->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "stream upstream resolve"); if (ctx->state) { @@ -1166,7 +1193,7 @@ ngx_stream_proxy_resolve_handler(ngx_resolver_ctx_t *ctx) &ctx->name, ctx->state, ngx_resolver_strerror(ctx->state)); - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -1192,7 +1219,7 @@ ngx_stream_proxy_resolve_handler(ngx_resolver_ctx_t *ctx) #endif if (ngx_stream_upstream_create_round_robin_peer(s, ur) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -1245,7 +1272,8 @@ ngx_stream_proxy_process_connection(ngx_event_t *ev, ngx_uint_t from_upstream) if (!ev->ready) { if (ngx_handle_read_event(ev, 0) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, + NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -1279,7 +1307,7 @@ ngx_stream_proxy_process_connection(ngx_event_t *ev, ngx_uint_t from_upstream) } ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); - ngx_stream_proxy_finalize(s, NGX_DECLINED); + ngx_stream_proxy_finalize(s, NGX_STREAM_OK); return; } @@ -1289,7 +1317,7 @@ ngx_stream_proxy_process_connection(ngx_event_t *ev, ngx_uint_t from_upstream) "stream connection delayed"); if (ngx_handle_read_event(ev, 0) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); } return; @@ -1407,7 +1435,7 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, c->log->handler = handler; - ngx_stream_proxy_finalize(s, NGX_OK); + ngx_stream_proxy_finalize(s, NGX_STREAM_OK); return; } @@ -1449,7 +1477,7 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, return; } - ngx_stream_proxy_finalize(s, NGX_DECLINED); + ngx_stream_proxy_finalize(s, NGX_STREAM_OK); return; } @@ -1500,6 +1528,13 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, } } + if (from_upstream) { + if (u->state->first_byte_time == (ngx_msec_t) -1) { + u->state->first_byte_time = ngx_current_msec + - u->state->response_time; + } + } + if (c->type == SOCK_DGRAM && ++u->responses == pscf->responses) { src->read->ready = 0; @@ -1540,20 +1575,20 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, c->log->handler = handler; - ngx_stream_proxy_finalize(s, NGX_OK); + ngx_stream_proxy_finalize(s, NGX_STREAM_OK); return; } flags = src->read->eof ? NGX_CLOSE_EVENT : 0; if (!src->shared && ngx_handle_read_event(src->read, flags) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } if (dst) { if (!dst->shared && ngx_handle_write_event(dst->write, 0) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_ERROR); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -1593,7 +1628,7 @@ ngx_stream_proxy_next_upstream(ngx_stream_session_t *s) || !pscf->next_upstream || (timeout && ngx_current_msec - u->peer.start_time >= timeout)) { - ngx_stream_proxy_finalize(s, NGX_DECLINED); + ngx_stream_proxy_finalize(s, NGX_STREAM_BAD_GATEWAY); return; } @@ -1612,6 +1647,9 @@ ngx_stream_proxy_next_upstream(ngx_stream_session_t *s) } #endif + u->state->bytes_received = u->received; + u->state->bytes_sent = pc->sent; + ngx_close_connection(pc); u->peer.connection = NULL; } @@ -1621,7 +1659,7 @@ ngx_stream_proxy_next_upstream(ngx_stream_session_t *s) static void -ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_int_t rc) +ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_uint_t rc) { ngx_connection_t *pc; ngx_stream_upstream_t *u; @@ -1640,13 +1678,22 @@ ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_int_t rc) u->resolved->ctx = NULL; } + pc = u->peer.connection; + + if (u->state) { + u->state->response_time = ngx_current_msec - u->state->response_time; + + if (pc) { + u->state->bytes_received = u->received; + u->state->bytes_sent = pc->sent; + } + } + if (u->peer.free && u->peer.sockaddr) { u->peer.free(&u->peer, u->peer.data, 0); u->peer.sockaddr = NULL; } - pc = u->peer.connection; - if (pc) { ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "close stream proxy upstream connection: %d", pc->fd); @@ -1664,7 +1711,7 @@ ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_int_t rc) noupstream: - ngx_stream_close_connection(s->connection); + ngx_stream_finalize_session(s, rc); } diff --git a/src/stream/ngx_stream_realip_module.c b/src/stream/ngx_stream_realip_module.c new file mode 100644 index 0000000..8ce05a0 --- /dev/null +++ b/src/stream/ngx_stream_realip_module.c @@ -0,0 +1,342 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_array_t *from; /* array of ngx_cidr_t */ +} ngx_stream_realip_srv_conf_t; + + +typedef struct { + struct sockaddr *sockaddr; + socklen_t socklen; + ngx_str_t addr_text; +} ngx_stream_realip_ctx_t; + + +static ngx_int_t ngx_stream_realip_handler(ngx_stream_session_t *s); +static ngx_int_t ngx_stream_realip_set_addr(ngx_stream_session_t *s, + ngx_addr_t *addr); +static char *ngx_stream_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void *ngx_stream_realip_create_srv_conf(ngx_conf_t *cf); +static char *ngx_stream_realip_merge_srv_conf(ngx_conf_t *cf, void *parent, + void *child); +static ngx_int_t ngx_stream_realip_add_variables(ngx_conf_t *cf); +static ngx_int_t ngx_stream_realip_init(ngx_conf_t *cf); + + +static ngx_int_t ngx_stream_realip_remote_addr_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_realip_remote_port_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); + + +static ngx_command_t ngx_stream_realip_commands[] = { + + { ngx_string("set_real_ip_from"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_stream_realip_from, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_realip_module_ctx = { + ngx_stream_realip_add_variables, /* preconfiguration */ + ngx_stream_realip_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_stream_realip_create_srv_conf, /* create server configuration */ + ngx_stream_realip_merge_srv_conf /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_realip_module = { + NGX_MODULE_V1, + &ngx_stream_realip_module_ctx, /* module context */ + ngx_stream_realip_commands, /* module directives */ + NGX_STREAM_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_stream_variable_t ngx_stream_realip_vars[] = { + + { ngx_string("realip_remote_addr"), NULL, + ngx_stream_realip_remote_addr_variable, 0, 0, 0 }, + + { ngx_string("realip_remote_port"), NULL, + ngx_stream_realip_remote_port_variable, 0, 0, 0 }, + + { ngx_null_string, NULL, NULL, 0, 0, 0 } +}; + + +static ngx_int_t +ngx_stream_realip_handler(ngx_stream_session_t *s) +{ + ngx_addr_t addr; + ngx_connection_t *c; + ngx_stream_realip_srv_conf_t *rscf; + + rscf = ngx_stream_get_module_srv_conf(s, ngx_stream_realip_module); + + if (rscf->from == NULL) { + return NGX_DECLINED; + } + + c = s->connection; + + if (c->proxy_protocol_addr.len == 0) { + return NGX_DECLINED; + } + + if (ngx_cidr_match(c->sockaddr, rscf->from) != NGX_OK) { + return NGX_DECLINED; + } + + if (ngx_parse_addr(c->pool, &addr, c->proxy_protocol_addr.data, + c->proxy_protocol_addr.len) + != NGX_OK) + { + return NGX_DECLINED; + } + + ngx_inet_set_port(addr.sockaddr, c->proxy_protocol_port); + + return ngx_stream_realip_set_addr(s, &addr); +} + + +static ngx_int_t +ngx_stream_realip_set_addr(ngx_stream_session_t *s, ngx_addr_t *addr) +{ + size_t len; + u_char *p; + u_char text[NGX_SOCKADDR_STRLEN]; + ngx_connection_t *c; + ngx_stream_realip_ctx_t *ctx; + + c = s->connection; + + ctx = ngx_palloc(c->pool, sizeof(ngx_stream_realip_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + len = ngx_sock_ntop(addr->sockaddr, addr->socklen, text, + NGX_SOCKADDR_STRLEN, 0); + if (len == 0) { + return NGX_ERROR; + } + + p = ngx_pnalloc(c->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, text, len); + + ngx_stream_set_ctx(s, ctx, ngx_stream_realip_module); + + ctx->sockaddr = c->sockaddr; + ctx->socklen = c->socklen; + ctx->addr_text = c->addr_text; + + c->sockaddr = addr->sockaddr; + c->socklen = addr->socklen; + c->addr_text.len = len; + c->addr_text.data = p; + + return NGX_DECLINED; +} + + +static char * +ngx_stream_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_realip_srv_conf_t *rscf = conf; + + ngx_int_t rc; + ngx_str_t *value; + ngx_cidr_t *cidr; + + value = cf->args->elts; + + if (rscf->from == NULL) { + rscf->from = ngx_array_create(cf->pool, 2, + sizeof(ngx_cidr_t)); + if (rscf->from == NULL) { + return NGX_CONF_ERROR; + } + } + + cidr = ngx_array_push(rscf->from); + if (cidr == NULL) { + return NGX_CONF_ERROR; + } + +#if (NGX_HAVE_UNIX_DOMAIN) + + if (ngx_strcmp(value[1].data, "unix:") == 0) { + cidr->family = AF_UNIX; + return NGX_CONF_OK; + } + +#endif + + rc = ngx_ptocidr(&value[1], cidr); + + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", + &value[1]); + return NGX_CONF_ERROR; + } + + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", &value[1]); + } + + return NGX_CONF_OK; +} + + +static void * +ngx_stream_realip_create_srv_conf(ngx_conf_t *cf) +{ + ngx_stream_realip_srv_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_realip_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->from = NULL; + */ + + return conf; +} + + +static char * +ngx_stream_realip_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_stream_realip_srv_conf_t *prev = parent; + ngx_stream_realip_srv_conf_t *conf = child; + + if (conf->from == NULL) { + conf->from = prev->from; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_stream_realip_add_variables(ngx_conf_t *cf) +{ + ngx_stream_variable_t *var, *v; + + for (v = ngx_stream_realip_vars; v->name.len; v++) { + var = ngx_stream_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = v->get_handler; + var->data = v->data; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_realip_init(ngx_conf_t *cf) +{ + ngx_stream_core_main_conf_t *cmcf; + + cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); + + cmcf->realip_handler = ngx_stream_realip_handler; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_realip_remote_addr_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_str_t *addr_text; + ngx_stream_realip_ctx_t *ctx; + + ctx = ngx_stream_get_module_ctx(s, ngx_stream_realip_module); + + addr_text = ctx ? &ctx->addr_text : &s->connection->addr_text; + + v->len = addr_text->len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = addr_text->data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_realip_remote_port_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_uint_t port; + struct sockaddr *sa; + ngx_stream_realip_ctx_t *ctx; + + ctx = ngx_stream_get_module_ctx(s, ngx_stream_realip_module); + + sa = ctx ? ctx->sockaddr : s->connection->sockaddr; + + v->len = 0; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1); + if (v->data == NULL) { + return NGX_ERROR; + } + + port = ngx_inet_get_port(sa); + + if (port > 0 && port < 65536) { + v->len = ngx_sprintf(v->data, "%ui", port) - v->data; + } + + return NGX_OK; +} diff --git a/src/stream/ngx_stream_return_module.c b/src/stream/ngx_stream_return_module.c index 3ab9bdf..c22087f 100644 --- a/src/stream/ngx_stream_return_module.c +++ b/src/stream/ngx_stream_return_module.c @@ -83,7 +83,7 @@ ngx_stream_return_handler(ngx_stream_session_t *s) rscf = ngx_stream_get_module_srv_conf(s, ngx_stream_return_module); if (ngx_stream_complex_value(s, &rscf->text, &text) != NGX_OK) { - ngx_stream_close_connection(c); + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -91,13 +91,13 @@ ngx_stream_return_handler(ngx_stream_session_t *s) "stream return text: \"%V\"", &text); if (text.len == 0) { - ngx_stream_close_connection(c); + ngx_stream_finalize_session(s, NGX_STREAM_OK); return; } ctx = ngx_pcalloc(c->pool, sizeof(ngx_stream_return_ctx_t)); if (ctx == NULL) { - ngx_stream_close_connection(c); + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -126,7 +126,7 @@ ngx_stream_return_write_handler(ngx_event_t *ev) if (ev->timedout) { ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); - ngx_stream_close_connection(c); + ngx_stream_finalize_session(s, NGX_STREAM_OK); return; } @@ -137,7 +137,7 @@ ngx_stream_return_write_handler(ngx_event_t *ev) n = c->send(c, b->pos, b->last - b->pos); if (n == NGX_ERROR) { - ngx_stream_close_connection(c); + ngx_stream_finalize_session(s, NGX_STREAM_OK); return; } @@ -145,14 +145,14 @@ ngx_stream_return_write_handler(ngx_event_t *ev) b->pos += n; if (b->pos == b->last) { - ngx_stream_close_connection(c); + ngx_stream_finalize_session(s, NGX_STREAM_OK); return; } } } if (ngx_handle_write_event(ev, 0) != NGX_OK) { - ngx_stream_close_connection(c); + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } diff --git a/src/stream/ngx_stream_script.c b/src/stream/ngx_stream_script.c index 8130f92..ff8e655 100644 --- a/src/stream/ngx_stream_script.c +++ b/src/stream/ngx_stream_script.c @@ -388,6 +388,73 @@ invalid_variable: } +u_char * +ngx_stream_script_run(ngx_stream_session_t *s, ngx_str_t *value, + void *code_lengths, size_t len, void *code_values) +{ + ngx_uint_t i; + ngx_stream_script_code_pt code; + ngx_stream_script_engine_t e; + ngx_stream_core_main_conf_t *cmcf; + ngx_stream_script_len_code_pt lcode; + + cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); + + for (i = 0; i < cmcf->variables.nelts; i++) { + if (s->variables[i].no_cacheable) { + s->variables[i].valid = 0; + s->variables[i].not_found = 0; + } + } + + ngx_memzero(&e, sizeof(ngx_stream_script_engine_t)); + + e.ip = code_lengths; + e.session = s; + e.flushed = 1; + + while (*(uintptr_t *) e.ip) { + lcode = *(ngx_stream_script_len_code_pt *) e.ip; + len += lcode(&e); + } + + + value->len = len; + value->data = ngx_pnalloc(s->connection->pool, len); + if (value->data == NULL) { + return NULL; + } + + e.ip = code_values; + e.pos = value->data; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_stream_script_code_pt *) e.ip; + code((ngx_stream_script_engine_t *) &e); + } + + return e.pos; +} + + +void +ngx_stream_script_flush_no_cacheable_variables(ngx_stream_session_t *s, + ngx_array_t *indices) +{ + ngx_uint_t n, *index; + + if (indices) { + index = indices->elts; + for (n = 0; n < indices->nelts; n++) { + if (s->variables[index[n]].no_cacheable) { + s->variables[index[n]].valid = 0; + s->variables[index[n]].not_found = 0; + } + } + } +} + + static ngx_int_t ngx_stream_script_init_arrays(ngx_stream_script_compile_t *sc) { diff --git a/src/stream/ngx_stream_script.h b/src/stream/ngx_stream_script.h index 0abe50e..25a450d 100644 --- a/src/stream/ngx_stream_script.h +++ b/src/stream/ngx_stream_script.h @@ -110,6 +110,10 @@ char *ngx_stream_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, ngx_uint_t ngx_stream_script_variables_count(ngx_str_t *value); ngx_int_t ngx_stream_script_compile(ngx_stream_script_compile_t *sc); +u_char *ngx_stream_script_run(ngx_stream_session_t *s, ngx_str_t *value, + void *code_lengths, size_t reserved, void *code_values); +void ngx_stream_script_flush_no_cacheable_variables(ngx_stream_session_t *s, + ngx_array_t *indices); void *ngx_stream_script_add_code(ngx_array_t *codes, size_t size, void *code); diff --git a/src/stream/ngx_stream_upstream.c b/src/stream/ngx_stream_upstream.c index 2ea5eeb..0c59780 100644 --- a/src/stream/ngx_stream_upstream.c +++ b/src/stream/ngx_stream_upstream.c @@ -10,6 +10,14 @@ #include +static ngx_int_t ngx_stream_upstream_add_variables(ngx_conf_t *cf); +static ngx_int_t ngx_stream_upstream_addr_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_upstream_response_time_variable( + ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_upstream_bytes_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); + static char *ngx_stream_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy); static char *ngx_stream_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, @@ -39,7 +47,7 @@ static ngx_command_t ngx_stream_upstream_commands[] = { static ngx_stream_module_t ngx_stream_upstream_module_ctx = { - NULL, /* preconfiguration */ + ngx_stream_upstream_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ ngx_stream_upstream_create_main_conf, /* create main configuration */ @@ -66,6 +74,232 @@ ngx_module_t ngx_stream_upstream_module = { }; +static ngx_stream_variable_t ngx_stream_upstream_vars[] = { + + { ngx_string("upstream_addr"), NULL, + ngx_stream_upstream_addr_variable, 0, + NGX_STREAM_VAR_NOCACHEABLE, 0 }, + + { ngx_string("upstream_bytes_sent"), NULL, + ngx_stream_upstream_bytes_variable, 0, + NGX_STREAM_VAR_NOCACHEABLE, 0 }, + + { ngx_string("upstream_connect_time"), NULL, + ngx_stream_upstream_response_time_variable, 2, + NGX_STREAM_VAR_NOCACHEABLE, 0 }, + + { ngx_string("upstream_first_byte_time"), NULL, + ngx_stream_upstream_response_time_variable, 1, + NGX_STREAM_VAR_NOCACHEABLE, 0 }, + + { ngx_string("upstream_session_time"), NULL, + ngx_stream_upstream_response_time_variable, 0, + NGX_STREAM_VAR_NOCACHEABLE, 0 }, + + { ngx_string("upstream_bytes_received"), NULL, + ngx_stream_upstream_bytes_variable, 1, + NGX_STREAM_VAR_NOCACHEABLE, 0 }, + + { ngx_null_string, NULL, NULL, 0, 0, 0 } +}; + + +static ngx_int_t +ngx_stream_upstream_add_variables(ngx_conf_t *cf) +{ + ngx_stream_variable_t *var, *v; + + for (v = ngx_stream_upstream_vars; v->name.len; v++) { + var = ngx_stream_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = v->get_handler; + var->data = v->data; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_upstream_addr_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + size_t len; + ngx_uint_t i; + ngx_stream_upstream_state_t *state; + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + if (s->upstream_states == NULL || s->upstream_states->nelts == 0) { + v->not_found = 1; + return NGX_OK; + } + + len = 0; + state = s->upstream_states->elts; + + for (i = 0; i < s->upstream_states->nelts; i++) { + if (state[i].peer) { + len += state[i].peer->len; + } + + len += 2; + } + + p = ngx_pnalloc(s->connection->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + v->data = p; + + i = 0; + + for ( ;; ) { + if (state[i].peer) { + p = ngx_cpymem(p, state[i].peer->data, state[i].peer->len); + } + + if (++i == s->upstream_states->nelts) { + break; + } + + *p++ = ','; + *p++ = ' '; + } + + v->len = p - v->data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_upstream_bytes_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + size_t len; + ngx_uint_t i; + ngx_stream_upstream_state_t *state; + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + if (s->upstream_states == NULL || s->upstream_states->nelts == 0) { + v->not_found = 1; + return NGX_OK; + } + + len = s->upstream_states->nelts * (NGX_OFF_T_LEN + 2); + + p = ngx_pnalloc(s->connection->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + v->data = p; + + i = 0; + state = s->upstream_states->elts; + + for ( ;; ) { + + if (data == 1) { + p = ngx_sprintf(p, "%O", state[i].bytes_received); + + } else { + p = ngx_sprintf(p, "%O", state[i].bytes_sent); + } + + if (++i == s->upstream_states->nelts) { + break; + } + + *p++ = ','; + *p++ = ' '; + } + + v->len = p - v->data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_upstream_response_time_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + size_t len; + ngx_uint_t i; + ngx_msec_int_t ms; + ngx_stream_upstream_state_t *state; + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + if (s->upstream_states == NULL || s->upstream_states->nelts == 0) { + v->not_found = 1; + return NGX_OK; + } + + len = s->upstream_states->nelts * (NGX_TIME_T_LEN + 4 + 2); + + p = ngx_pnalloc(s->connection->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + v->data = p; + + i = 0; + state = s->upstream_states->elts; + + for ( ;; ) { + + if (data == 1) { + if (state[i].first_byte_time == (ngx_msec_t) -1) { + *p++ = '-'; + goto next; + } + + ms = state[i].first_byte_time; + + } else if (data == 2 && state[i].connect_time != (ngx_msec_t) -1) { + ms = state[i].connect_time; + + } else { + ms = state[i].response_time; + } + + ms = ngx_max(ms, 0); + p = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000); + + next: + + if (++i == s->upstream_states->nelts) { + break; + } + + *p++ = ','; + *p++ = ' '; + } + + v->len = p - v->data; + + return NGX_OK; +} + + static char * ngx_stream_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) { diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h index 5f067c0..f83b5ba 100644 --- a/src/stream/ngx_stream_upstream.h +++ b/src/stream/ngx_stream_upstream.h @@ -78,6 +78,17 @@ struct ngx_stream_upstream_srv_conf_s { }; +typedef struct { + ngx_msec_t response_time; + ngx_msec_t connect_time; + ngx_msec_t first_byte_time; + off_t bytes_sent; + off_t bytes_received; + + ngx_str_t *peer; +} ngx_stream_upstream_state_t; + + typedef struct { ngx_str_t host; in_port_t port; @@ -104,6 +115,7 @@ typedef struct { ngx_str_t ssl_name; #endif ngx_stream_upstream_resolved_t *resolved; + ngx_stream_upstream_state_t *state; unsigned connected:1; unsigned proxy_protocol:1; } ngx_stream_upstream_t; diff --git a/src/stream/ngx_stream_variables.c b/src/stream/ngx_stream_variables.c index 10f9c7e..aa5361d 100644 --- a/src/stream/ngx_stream_variables.c +++ b/src/stream/ngx_stream_variables.c @@ -17,11 +17,19 @@ static ngx_int_t ngx_stream_variable_remote_addr(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_remote_port(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_proxy_protocol_addr( + ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_proxy_protocol_port( + ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_server_addr(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_server_port(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); -static ngx_int_t ngx_stream_variable_bytes_sent(ngx_stream_session_t *s, +static ngx_int_t ngx_stream_variable_bytes(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_session_time(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_status(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_connection(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); @@ -38,6 +46,8 @@ static ngx_int_t ngx_stream_variable_time_iso8601(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_time_local(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_protocol(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); static ngx_stream_variable_t ngx_stream_core_variables[] = { @@ -51,15 +61,30 @@ static ngx_stream_variable_t ngx_stream_core_variables[] = { { ngx_string("remote_port"), NULL, ngx_stream_variable_remote_port, 0, 0, 0 }, + { ngx_string("proxy_protocol_addr"), NULL, + ngx_stream_variable_proxy_protocol_addr, 0, 0, 0 }, + + { ngx_string("proxy_protocol_port"), NULL, + ngx_stream_variable_proxy_protocol_port, 0, 0, 0 }, + { ngx_string("server_addr"), NULL, ngx_stream_variable_server_addr, 0, 0, 0 }, { ngx_string("server_port"), NULL, ngx_stream_variable_server_port, 0, 0, 0 }, - { ngx_string("bytes_sent"), NULL, ngx_stream_variable_bytes_sent, + { ngx_string("bytes_sent"), NULL, ngx_stream_variable_bytes, 0, 0, 0 }, + { ngx_string("bytes_received"), NULL, ngx_stream_variable_bytes, + 1, 0, 0 }, + + { ngx_string("session_time"), NULL, ngx_stream_variable_session_time, + 0, NGX_STREAM_VAR_NOCACHEABLE, 0 }, + + { ngx_string("status"), NULL, ngx_stream_variable_status, + 0, NGX_STREAM_VAR_NOCACHEABLE, 0 }, + { ngx_string("connection"), NULL, ngx_stream_variable_connection, 0, 0, 0 }, @@ -81,6 +106,9 @@ static ngx_stream_variable_t ngx_stream_core_variables[] = { { ngx_string("time_local"), NULL, ngx_stream_variable_time_local, 0, NGX_STREAM_VAR_NOCACHEABLE, 0 }, + { ngx_string("protocol"), NULL, + ngx_stream_variable_protocol, 0, 0, 0 }, + { ngx_null_string, NULL, NULL, 0, 0, 0 } }; @@ -399,6 +427,46 @@ ngx_stream_variable_remote_port(ngx_stream_session_t *s, } +static ngx_int_t +ngx_stream_variable_proxy_protocol_addr(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + v->len = s->connection->proxy_protocol_addr.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = s->connection->proxy_protocol_addr.data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_proxy_protocol_port(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_uint_t port; + + v->len = 0; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1); + if (v->data == NULL) { + return NGX_ERROR; + } + + port = s->connection->proxy_protocol_port; + + if (port > 0 && port < 65536) { + v->len = ngx_sprintf(v->data, "%ui", port) - v->data; + } + + return NGX_OK; +} + + static ngx_int_t ngx_stream_variable_server_addr(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) @@ -461,7 +529,7 @@ ngx_stream_variable_server_port(ngx_stream_session_t *s, static ngx_int_t -ngx_stream_variable_bytes_sent(ngx_stream_session_t *s, +ngx_stream_variable_bytes(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) { u_char *p; @@ -471,7 +539,13 @@ ngx_stream_variable_bytes_sent(ngx_stream_session_t *s, return NGX_ERROR; } - v->len = ngx_sprintf(p, "%O", s->connection->sent) - p; + if (data == 1) { + v->len = ngx_sprintf(p, "%O", s->received) - p; + + } else { + v->len = ngx_sprintf(p, "%O", s->connection->sent) - p; + } + v->valid = 1; v->no_cacheable = 0; v->not_found = 0; @@ -481,6 +555,53 @@ ngx_stream_variable_bytes_sent(ngx_stream_session_t *s, } +static ngx_int_t +ngx_stream_variable_session_time(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + ngx_time_t *tp; + ngx_msec_int_t ms; + + p = ngx_pnalloc(s->connection->pool, NGX_TIME_T_LEN + 4); + if (p == NULL) { + return NGX_ERROR; + } + + tp = ngx_timeofday(); + + ms = (ngx_msec_int_t) + ((tp->sec - s->start_sec) * 1000 + (tp->msec - s->start_msec)); + ms = ngx_max(ms, 0); + + v->len = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000) - p; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_status(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + v->data = ngx_pnalloc(s->connection->pool, NGX_INT_T_LEN); + if (v->data == NULL) { + return NGX_ERROR; + } + + v->len = ngx_sprintf(v->data, "%03ui", s->status) - v->data; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; +} + + static ngx_int_t ngx_stream_variable_connection(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) @@ -622,6 +743,20 @@ ngx_stream_variable_time_local(ngx_stream_session_t *s, } +static ngx_int_t +ngx_stream_variable_protocol(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + v->len = 3; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = (u_char *) (s->connection->type == SOCK_DGRAM ? "UDP" : "TCP"); + + return NGX_OK; +} + + void * ngx_stream_map_find(ngx_stream_session_t *s, ngx_stream_map_t *map, ngx_str_t *match) From 5692397ea12c468deaf6abc3ad453b557f4fce10 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 4 Oct 2016 19:52:52 +0300 Subject: [PATCH 161/651] debian/control: Reference nginx-extras in nginx meta-package --- debian/control | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/control b/debian/control index baa4b52..131872b 100644 --- a/debian/control +++ b/debian/control @@ -38,8 +38,8 @@ Description: small, powerful, scalable web/proxy server created by Igor Sysoev. It can be used both as a standalone web server and as a proxy to reduce the load on back-end HTTP or mail servers. . - This is a dependency package to install either nginx-full (by default) or - nginx-light. + This is a dependency package to install either nginx-full (by default), + nginx-light or nginx-extras. Package: nginx-doc Architecture: all From d045f9b328d77d85e2fdf3c9c6f8d5febe2c19e5 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 10 Oct 2016 16:57:12 +0300 Subject: [PATCH 162/651] Strict version depend on lsb-base version >= 3.0-6 Fixes lintian error init.d-script-needs-depends-on-lsb-base that strict checks the version. --- debian/changelog | 8 ++++++++ debian/control | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 0d59634..40a7cf4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +nginx (1.10.1-4) UNRELEASED; urgency=medium + + * debian/control: + + Version depend on lsb-base (>= 3.0-6). + Fixes lintian init.d-script-needs-depends-on-lsb-base. + + -- Christos Trochalakis Tue, 11 Oct 2016 10:00:23 +0300 + nginx (1.10.1-3) unstable; urgency=medium * debian/control: diff --git a/debian/control b/debian/control index 131872b..ec867ae 100644 --- a/debian/control +++ b/debian/control @@ -56,7 +56,7 @@ Description: small, powerful, scalable web/proxy server - documentation Package: nginx-common Architecture: all Multi-Arch: foreign -Depends: lsb-base, ${misc:Depends} +Depends: lsb-base (>= 3.0-6), ${misc:Depends} Suggests: fcgiwrap, nginx-doc, ssl-cert Description: small, powerful, scalable web/proxy server - common files Nginx ("engine X") is a high-performance web and reverse proxy server From 646704e9fbeace3af6be908c8148c045ad6eca25 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 12 Oct 2016 08:07:21 +0300 Subject: [PATCH 163/651] New upstream version 1.11.5 --- CHANGES | 39 ++ CHANGES.ru | 39 ++ auto/lib/geoip/conf | 20 +- auto/lib/perl/conf | 4 +- auto/lib/perl/make | 1 + auto/make | 1 + auto/modules | 28 +- auto/options | 18 +- auto/os/win32 | 4 +- auto/sources | 1 + auto/unix | 26 +- src/core/nginx.h | 4 +- src/core/ngx_buf.h | 12 +- src/core/ngx_conf_file.c | 4 +- src/core/ngx_config.h | 13 + src/core/ngx_connection.c | 5 +- src/core/ngx_connection.h | 14 +- src/core/ngx_core.h | 31 +- src/core/ngx_file.c | 8 +- src/core/ngx_file.h | 8 +- src/core/ngx_inet.c | 19 +- src/core/ngx_module.h | 37 +- src/core/ngx_resolver.c | 1 + src/core/ngx_resolver.h | 1 + src/event/ngx_event.h | 3 +- src/event/ngx_event_accept.c | 1 + src/event/ngx_event_connect.c | 1 + src/event/ngx_event_connect.h | 13 +- src/event/ngx_event_openssl.c | 10 +- src/event/ngx_event_openssl.h | 8 +- src/event/ngx_event_pipe.h | 2 +- .../modules/ngx_http_addition_filter_module.c | 1 + src/http/modules/ngx_http_mp4_module.c | 2 +- .../modules/ngx_http_range_filter_module.c | 3 +- src/http/modules/ngx_http_realip_module.c | 12 +- .../modules/ngx_http_upstream_hash_module.c | 11 +- .../ngx_http_upstream_ip_hash_module.c | 5 + .../ngx_http_upstream_least_conn_module.c | 16 +- src/http/modules/perl/Makefile.PL | 2 + src/http/ngx_http.c | 2 +- src/http/ngx_http.h | 3 - src/http/ngx_http_cache.h | 11 +- src/http/ngx_http_core_module.c | 4 +- src/http/ngx_http_core_module.h | 22 +- src/http/ngx_http_file_cache.c | 103 +++- src/http/ngx_http_parse.c | 4 +- src/http/ngx_http_request.h | 14 +- src/http/ngx_http_special_response.c | 2 +- src/http/ngx_http_upstream.c | 26 +- src/http/ngx_http_upstream.h | 18 +- src/http/ngx_http_upstream_round_robin.c | 22 +- src/http/ngx_http_upstream_round_robin.h | 15 +- src/http/v2/ngx_http_v2.c | 2 +- src/mail/ngx_mail.c | 2 +- src/mail/ngx_mail.h | 6 +- src/mail/ngx_mail_core_module.c | 2 +- src/mail/ngx_mail_ssl_module.c | 4 +- src/os/unix/ngx_darwin_init.c | 1 + src/os/unix/ngx_freebsd_init.c | 1 + src/os/unix/ngx_linux_init.c | 1 + src/os/unix/ngx_os.h | 3 + src/os/unix/ngx_posix_init.c | 1 + src/os/unix/ngx_process_cycle.c | 6 +- src/os/unix/ngx_solaris_init.c | 1 + src/os/unix/ngx_udp_sendmsg_chain.c | 245 ++++++++++ src/stream/ngx_stream.c | 124 ++++- src/stream/ngx_stream.h | 86 +++- src/stream/ngx_stream_access_module.c | 11 +- src/stream/ngx_stream_core_module.c | 232 ++++++++- src/stream/ngx_stream_handler.c | 204 ++------ src/stream/ngx_stream_limit_conn_module.c | 12 +- src/stream/ngx_stream_log_module.c | 8 +- src/stream/ngx_stream_proxy_module.c | 218 ++++++--- src/stream/ngx_stream_realip_module.c | 8 +- src/stream/ngx_stream_return_module.c | 55 ++- src/stream/ngx_stream_ssl_module.c | 108 ++++- src/stream/ngx_stream_ssl_preread_module.c | 449 ++++++++++++++++++ src/stream/ngx_stream_upstream.c | 24 +- src/stream/ngx_stream_upstream.h | 19 +- src/stream/ngx_stream_upstream_hash_module.c | 11 +- .../ngx_stream_upstream_least_conn_module.c | 16 +- src/stream/ngx_stream_upstream_round_robin.c | 22 +- src/stream/ngx_stream_upstream_round_robin.h | 15 +- src/stream/ngx_stream_write_filter_module.c | 273 +++++++++++ 84 files changed, 2297 insertions(+), 547 deletions(-) create mode 100644 src/os/unix/ngx_udp_sendmsg_chain.c create mode 100644 src/stream/ngx_stream_ssl_preread_module.c create mode 100644 src/stream/ngx_stream_write_filter_module.c diff --git a/CHANGES b/CHANGES index 2ea8d8d..6a88ce4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,43 @@ +Changes with nginx 1.11.5 11 Oct 2016 + + *) Change: the --with-ipv6 configure option was removed, now IPv6 + support is configured automatically. + + *) Change: now if there are no available servers in an upstream, nginx + will not reset number of failures of all servers as it previously + did, but will wait for fail_timeout to expire. + + *) Feature: the ngx_stream_ssl_preread_module. + + *) Feature: the "server" directive in the "upstream" context supports + the "max_conns" parameter. + + *) Feature: the --with-compat configure option. + + *) Feature: "manager_files", "manager_threshold", and "manager_sleep" + parameters of the "proxy_cache_path", "fastcgi_cache_path", + "scgi_cache_path", and "uwsgi_cache_path" directives. + + *) Bugfix: flags passed by the --with-ld-opt configure option were not + used while building perl module. + + *) Bugfix: in the "add_after_body" directive when used with the + "sub_filter" directive. + + *) Bugfix: in the $realip_remote_addr variable. + + *) Bugfix: the "dav_access", "proxy_store_access", + "fastcgi_store_access", "scgi_store_access", and "uwsgi_store_access" + directives ignored permissions specified for user. + + *) Bugfix: unix domain listen sockets might not be inherited during + binary upgrade on Linux. + + *) Bugfix: nginx returned the 400 response on requests with the "-" + character in the HTTP method. + + Changes with nginx 1.11.4 13 Sep 2016 *) Feature: the $upstream_bytes_received variable. diff --git a/CHANGES.ru b/CHANGES.ru index 28ac2d8..f0bdaf5 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,43 @@ +Изменения в nginx 1.11.5 11.10.2016 + + *) Изменение: параметр configure --with-ipv6 упразднён, поддержка IPv6 + теперь собирается автоматически. + + *) Изменение: теперь, если в блоке upstream не оказалось доступных + серверов, nginx не сбрасывает статистику ошибок всех серверов, как + делал ранее, а ожидает истечения fail_timeout. + + *) Добавление: модуль ngx_stream_ssl_preread_module. + + *) Добавление: директива server в блоке upstream поддерживает параметр + max_conns. + + *) Добавление: параметр configure --with-compat. + + *) Добавление: параметры manager_files, manager_threshold и + manager_sleep директив proxy_cache_path, fastcgi_cache_path, + scgi_cache_path и uwsgi_cache_path. + + *) Исправление: при сборке perl-модуля не использовались флаги, заданные + с помощью параметра configure --with-ld-opt. + + *) Исправление: в директиве add_after_body при использовании совместно с + директивой sub_filter. + + *) Исправление: в переменной $realip_remote_addr. + + *) Исправление: директивы dav_access, proxy_store_access, + fastcgi_store_access, scgi_store_access и uwsgi_store_access + игнорировали права, заданные для пользователя. + + *) Исправление: unix domain listen-сокеты могли не наследоваться при + обновлении исполняемого файла на Linux. + + *) Исправление: nginx возвращал ошибку 400 на запросы с символом "-" в + HTTP-методе. + + Изменения в nginx 1.11.4 13.09.2016 *) Добавление: переменная $upstream_bytes_received. diff --git a/auto/lib/geoip/conf b/auto/lib/geoip/conf index ebd2e15..8302aae 100644 --- a/auto/lib/geoip/conf +++ b/auto/lib/geoip/conf @@ -74,17 +74,15 @@ if [ $ngx_found = yes ]; then NGX_LIB_GEOIP=$ngx_feature_libs - if [ $NGX_IPV6 = YES ]; then - ngx_feature="GeoIP IPv6 support" - ngx_feature_name="NGX_HAVE_GEOIP_V6" - ngx_feature_run=no - ngx_feature_incs="#include - #include " - #ngx_feature_path= - #ngx_feature_libs= - ngx_feature_test="printf(\"%d\", GEOIP_CITY_EDITION_REV0_V6);" - . auto/feature - fi + ngx_feature="GeoIP IPv6 support" + ngx_feature_name="NGX_HAVE_GEOIP_V6" + ngx_feature_run=no + ngx_feature_incs="#include + #include " + #ngx_feature_path= + #ngx_feature_libs= + ngx_feature_test="printf(\"%d\", GEOIP_CITY_EDITION_REV0_V6);" + . auto/feature else diff --git a/auto/lib/perl/conf b/auto/lib/perl/conf index f5f5d3e..d891d82 100644 --- a/auto/lib/perl/conf +++ b/auto/lib/perl/conf @@ -28,8 +28,10 @@ if test -n "$NGX_PERL_VER"; then exit 1; fi - NGX_PERL_CFLAGS="$CFLAGS `$NGX_PERL -MExtUtils::Embed -e ccopts`" NGX_PM_CFLAGS=`$NGX_PERL -MExtUtils::Embed -e ccopts` + NGX_PM_LDFLAGS=`$NGX_PERL -MConfig -e 'print $Config{lddlflags}'` + + NGX_PERL_CFLAGS="$CFLAGS `$NGX_PERL -MExtUtils::Embed -e ccopts`" # gcc 4.1/4.2 warn about unused values in pTHX_ NGX_PERL_CFLAGS=`echo $NGX_PERL_CFLAGS \ diff --git a/auto/lib/perl/make b/auto/lib/perl/make index 8af8902..350090c 100644 --- a/auto/lib/perl/make +++ b/auto/lib/perl/make @@ -35,6 +35,7 @@ $NGX_OBJS/src/http/modules/perl/Makefile: \\ cd $NGX_OBJS/src/http/modules/perl \\ && NGX_PM_CFLAGS="\$(NGX_PM_CFLAGS) -g $NGX_CC_OPT" \\ + NGX_PM_LDFLAGS="$NGX_LD_OPT \$(NGX_PM_LDFLAGS)" \\ NGX_INCS="$CORE_INCS $NGX_OBJS $HTTP_INCS" \\ NGX_DEPS="\$(CORE_DEPS) \$(HTTP_DEPS)" \\ $NGX_PERL Makefile.PL \\ diff --git a/auto/make b/auto/make index 5589bee..84d2668 100644 --- a/auto/make +++ b/auto/make @@ -31,6 +31,7 @@ END if test -n "$NGX_PERL_CFLAGS"; then echo NGX_PERL_CFLAGS = $NGX_PERL_CFLAGS >> $NGX_MAKEFILE echo NGX_PM_CFLAGS = $NGX_PM_CFLAGS >> $NGX_MAKEFILE + echo NGX_PM_LDFLAGS = $NGX_PM_LDFLAGS >> $NGX_MAKEFILE fi diff --git a/auto/modules b/auto/modules index 433767a..89377bf 100644 --- a/auto/modules +++ b/auto/modules @@ -973,7 +973,8 @@ if [ $STREAM != NO ]; then ngx_stream_core_module \ ngx_stream_log_module \ ngx_stream_proxy_module \ - ngx_stream_upstream_module" + ngx_stream_upstream_module \ + ngx_stream_write_filter_module" ngx_module_incs="src/stream" ngx_module_deps="src/stream/ngx_stream.h \ src/stream/ngx_stream_variables.h \ @@ -988,7 +989,8 @@ if [ $STREAM != NO ]; then src/stream/ngx_stream_log_module.c \ src/stream/ngx_stream_proxy_module.c \ src/stream/ngx_stream_upstream.c \ - src/stream/ngx_stream_upstream_round_robin.c" + src/stream/ngx_stream_upstream_round_robin.c \ + src/stream/ngx_stream_write_filter_module.c" . auto/module @@ -1118,6 +1120,16 @@ if [ $STREAM != NO ]; then . auto/module fi + + if [ $STREAM_SSL_PREREAD = YES ]; then + ngx_module_name=ngx_stream_ssl_preread_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_ssl_preread_module.c + ngx_module_libs= + ngx_module_link=$STREAM_SSL_PREREAD + + . auto/module + fi fi @@ -1300,6 +1312,18 @@ fi modules="$modules $MISC_MODULES" +if [ $NGX_COMPAT = YES ]; then + have=NGX_COMPAT . auto/have + have=NGX_HTTP_GZIP . auto/have + have=NGX_HTTP_DAV . auto/have + have=NGX_HTTP_REALIP . auto/have + have=NGX_HTTP_X_FORWARDED_FOR . auto/have + have=NGX_HTTP_HEADERS . auto/have + have=NGX_HTTP_UPSTREAM_ZONE . auto/have + have=NGX_STREAM_UPSTREAM_ZONE . auto/have +fi + + cat << END > $NGX_MODULES_C #include diff --git a/auto/options b/auto/options index 73149d9..43724b1 100644 --- a/auto/options +++ b/auto/options @@ -44,7 +44,6 @@ EVENT_POLL=NO USE_THREADS=NO NGX_FILE_AIO=NO -NGX_IPV6=NO HTTP=YES @@ -126,6 +125,7 @@ STREAM_RETURN=YES STREAM_UPSTREAM_HASH=YES STREAM_UPSTREAM_LEAST_CONN=YES STREAM_UPSTREAM_ZONE=YES +STREAM_SSL_PREREAD=NO DYNAMIC_MODULES= @@ -133,6 +133,8 @@ NGX_ADDONS= NGX_ADDON_DEPS= DYNAMIC_ADDONS= +NGX_COMPAT=NO + USE_PCRE=NO PCRE=NONE PCRE_OPT= @@ -201,7 +203,11 @@ do --with-threads) USE_THREADS=YES ;; --with-file-aio) NGX_FILE_AIO=YES ;; - --with-ipv6) NGX_IPV6=YES ;; + + --with-ipv6) + NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG +$0: warning: the \"--with-ipv6\" option is deprecated" + ;; --without-http) HTTP=NO ;; --without-http-cache) HTTP_CACHE=NO ;; @@ -301,6 +307,8 @@ use the \"--with-mail_ssl_module\" option instead" --with-stream_geoip_module) STREAM_GEOIP=YES ;; --with-stream_geoip_module=dynamic) STREAM_GEOIP=DYNAMIC ;; + --with-stream_ssl_preread_module) + STREAM_SSL_PREREAD=YES ;; --without-stream_limit_conn_module) STREAM_LIMIT_CONN=NO ;; --without-stream_access_module) STREAM_ACCESS=NO ;; @@ -322,6 +330,8 @@ use the \"--with-mail_ssl_module\" option instead" --add-module=*) NGX_ADDONS="$NGX_ADDONS $value" ;; --add-dynamic-module=*) DYNAMIC_ADDONS="$DYNAMIC_ADDONS $value" ;; + --with-compat) NGX_COMPAT=YES ;; + --with-cc=*) CC="$value" ;; --with-cpp=*) CPP="$value" ;; --with-cc-opt=*) NGX_CC_OPT="$value" ;; @@ -417,7 +427,6 @@ cat << END --with-threads enable thread pool support --with-file-aio enable file AIO support - --with-ipv6 enable IPv6 support --with-http_ssl_module enable ngx_http_ssl_module --with-http_v2_module enable ngx_http_v2_module @@ -508,6 +517,7 @@ cat << END --with-stream_realip_module enable ngx_stream_realip_module --with-stream_geoip_module enable ngx_stream_geoip_module --with-stream_geoip_module=dynamic enable dynamic ngx_stream_geoip_module + --with-stream_ssl_preread_module enable ngx_stream_ssl_preread_module --without-stream_limit_conn_module disable ngx_stream_limit_conn_module --without-stream_access_module disable ngx_stream_access_module --without-stream_geo_module disable ngx_stream_geo_module @@ -528,6 +538,8 @@ cat << END --add-module=PATH enable external module --add-dynamic-module=PATH enable dynamic external module + --with-compat dynamic modules compatibility + --with-cc=PATH set C compiler pathname --with-cpp=PATH set C preprocessor pathname --with-cc-opt=OPTIONS set additional C compiler options diff --git a/auto/os/win32 b/auto/os/win32 index 14ae3b8..650cf49 100644 --- a/auto/os/win32 +++ b/auto/os/win32 @@ -37,8 +37,6 @@ if [ $EVENT_SELECT = NO ]; then EVENT_MODULES="$EVENT_MODULES $SELECT_MODULE" fi -if [ $NGX_IPV6 = YES ]; then - have=NGX_HAVE_INET6 . auto/have -fi +have=NGX_HAVE_INET6 . auto/have have=NGX_HAVE_IOCP . auto/have diff --git a/auto/sources b/auto/sources index 216e900..1398147 100644 --- a/auto/sources +++ b/auto/sources @@ -167,6 +167,7 @@ UNIX_SRCS="$CORE_SRCS $EVENT_SRCS \ src/os/unix/ngx_send.c \ src/os/unix/ngx_writev_chain.c \ src/os/unix/ngx_udp_send.c \ + src/os/unix/ngx_udp_sendmsg_chain.c \ src/os/unix/ngx_channel.c \ src/os/unix/ngx_shmem.c \ src/os/unix/ngx_process.c \ diff --git a/auto/unix b/auto/unix index dbc0f0e..5ef74d4 100755 --- a/auto/unix +++ b/auto/unix @@ -637,20 +637,18 @@ ngx_param=NGX_MAX_TIME_T_VALUE; ngx_value=$ngx_max_value; . auto/types/value # syscalls, libc calls and some features -if [ $NGX_IPV6 = YES ]; then - ngx_feature="AF_INET6" - ngx_feature_name="NGX_HAVE_INET6" - ngx_feature_run=no - ngx_feature_incs="#include - #include - #include " - ngx_feature_path= - ngx_feature_libs= - ngx_feature_test="struct sockaddr_in6 sin6; - sin6.sin6_family = AF_INET6; - (void) sin6" - . auto/feature -fi +ngx_feature="AF_INET6" +ngx_feature_name="NGX_HAVE_INET6" +ngx_feature_run=no +ngx_feature_incs="#include + #include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="struct sockaddr_in6 sin6; + sin6.sin6_family = AF_INET6; + (void) sin6" +. auto/feature ngx_feature="setproctitle()" diff --git a/src/core/nginx.h b/src/core/nginx.h index 7e9aae6..1446251 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1011004 -#define NGINX_VERSION "1.11.4" +#define nginx_version 1011005 +#define NGINX_VERSION "1.11.5" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h index f652b20..12781a7 100644 --- a/src/core/ngx_buf.h +++ b/src/core/ngx_buf.h @@ -72,10 +72,8 @@ typedef struct ngx_output_chain_ctx_s ngx_output_chain_ctx_t; typedef ngx_int_t (*ngx_output_chain_filter_pt)(void *ctx, ngx_chain_t *in); -#if (NGX_HAVE_FILE_AIO) typedef void (*ngx_output_chain_aio_pt)(ngx_output_chain_ctx_t *ctx, ngx_file_t *file); -#endif struct ngx_output_chain_ctx_s { ngx_buf_t *buf; @@ -85,23 +83,19 @@ struct ngx_output_chain_ctx_s { unsigned sendfile:1; unsigned directio:1; -#if (NGX_HAVE_ALIGNED_DIRECTIO) unsigned unaligned:1; -#endif unsigned need_in_memory:1; unsigned need_in_temp:1; -#if (NGX_HAVE_FILE_AIO || NGX_THREADS) unsigned aio:1; -#endif -#if (NGX_HAVE_FILE_AIO) +#if (NGX_HAVE_FILE_AIO || NGX_COMPAT) ngx_output_chain_aio_pt aio_handler; -#if (NGX_HAVE_AIO_SENDFILE) +#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) ssize_t (*aio_preload)(ngx_buf_t *file); #endif #endif -#if (NGX_THREADS) +#if (NGX_THREADS || NGX_COMPAT) ngx_int_t (*thread_handler)(ngx_thread_task_t *task, ngx_file_t *file); ngx_thread_task_t *thread_task; diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c index c60d5fb..ea1dceb 100644 --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -1336,7 +1336,7 @@ ngx_conf_set_enum_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_OK; } - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid value \"%s\"", value[1].data); return NGX_CONF_ERROR; @@ -1378,7 +1378,7 @@ ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } if (mask[m].name.len == 0) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid value \"%s\"", value[i].data); return NGX_CONF_ERROR; diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h index a0bfa63..1861be6 100644 --- a/src/core/ngx_config.h +++ b/src/core/ngx_config.h @@ -129,4 +129,17 @@ typedef intptr_t ngx_flag_t; #define NGX_MAX_INT32_VALUE (uint32_t) 0x7fffffff +#if (NGX_COMPAT) + +#define NGX_COMPAT_BEGIN(slots) uint64_t spare[slots]; +#define NGX_COMPAT_END + +#else + +#define NGX_COMPAT_BEGIN(slots) +#define NGX_COMPAT_END + +#endif + + #endif /* _NGX_CONFIG_H_INCLUDED_ */ diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 16ba630..a789d8c 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -1191,10 +1191,7 @@ ngx_close_connection(ngx_connection_t *c) level = NGX_LOG_CRIT; } - /* we use ngx_cycle->log because c->log was in c->pool */ - - ngx_log_error(level, ngx_cycle->log, err, - ngx_close_socket_n " %d failed", fd); + ngx_log_error(level, c->log, err, ngx_close_socket_n " %d failed", fd); } } diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index e484c81..1d3e3a3 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -66,23 +66,19 @@ struct ngx_listening_s { unsigned addr_ntop:1; unsigned wildcard:1; -#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) +#if (NGX_HAVE_INET6) unsigned ipv6only:1; #endif -#if (NGX_HAVE_REUSEPORT) unsigned reuseport:1; unsigned add_reuseport:1; -#endif unsigned keepalive:2; -#if (NGX_HAVE_DEFERRED_ACCEPT) unsigned deferred_accept:1; unsigned delete_deferred:1; unsigned add_deferred:1; -#ifdef SO_ACCEPTFILTER +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) char *accept_filter; #endif -#endif #if (NGX_HAVE_SETFIB) int setfib; #endif @@ -151,7 +147,7 @@ struct ngx_connection_s { ngx_str_t proxy_protocol_addr; in_port_t proxy_protocol_port; -#if (NGX_SSL) +#if (NGX_SSL || NGX_COMPAT) ngx_ssl_connection_t *ssl; #endif @@ -186,11 +182,11 @@ struct ngx_connection_s { unsigned need_last_buf:1; -#if (NGX_HAVE_AIO_SENDFILE) +#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) unsigned busy_count:2; #endif -#if (NGX_THREADS) +#if (NGX_THREADS || NGX_COMPAT) ngx_thread_task_t *sendfile_task; #endif }; diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h index 2819c1a..2069373 100644 --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -12,22 +12,21 @@ #include -typedef struct ngx_module_s ngx_module_t; -typedef struct ngx_conf_s ngx_conf_t; -typedef struct ngx_cycle_s ngx_cycle_t; -typedef struct ngx_pool_s ngx_pool_t; -typedef struct ngx_chain_s ngx_chain_t; -typedef struct ngx_log_s ngx_log_t; -typedef struct ngx_open_file_s ngx_open_file_t; -typedef struct ngx_command_s ngx_command_t; -typedef struct ngx_file_s ngx_file_t; -typedef struct ngx_event_s ngx_event_t; -typedef struct ngx_event_aio_s ngx_event_aio_t; -typedef struct ngx_connection_s ngx_connection_t; - -#if (NGX_THREADS) -typedef struct ngx_thread_task_s ngx_thread_task_t; -#endif +typedef struct ngx_module_s ngx_module_t; +typedef struct ngx_conf_s ngx_conf_t; +typedef struct ngx_cycle_s ngx_cycle_t; +typedef struct ngx_pool_s ngx_pool_t; +typedef struct ngx_chain_s ngx_chain_t; +typedef struct ngx_log_s ngx_log_t; +typedef struct ngx_open_file_s ngx_open_file_t; +typedef struct ngx_command_s ngx_command_t; +typedef struct ngx_file_s ngx_file_t; +typedef struct ngx_event_s ngx_event_t; +typedef struct ngx_event_aio_s ngx_event_aio_t; +typedef struct ngx_connection_s ngx_connection_t; +typedef struct ngx_thread_task_s ngx_thread_task_t; +typedef struct ngx_ssl_s ngx_ssl_t; +typedef struct ngx_ssl_connection_s ngx_ssl_connection_t; typedef void (*ngx_event_handler_pt)(ngx_event_t *ev); typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c); diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c index c1137cc..8359c0f 100644 --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -441,7 +441,7 @@ ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) u_char *p; ngx_str_t *value; - ngx_uint_t i, right, shift, *access; + ngx_uint_t i, right, shift, *access, user; access = (ngx_uint_t *) (confp + cmd->offset); @@ -451,7 +451,8 @@ ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) value = cf->args->elts; - *access = 0600; + *access = 0; + user = 0600; for (i = 1; i < cf->args->nelts; i++) { @@ -460,6 +461,7 @@ ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strncmp(p, "user:", sizeof("user:") - 1) == 0) { shift = 6; p += sizeof("user:") - 1; + user = 0; } else if (ngx_strncmp(p, "group:", sizeof("group:") - 1) == 0) { shift = 3; @@ -486,6 +488,8 @@ ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) *access |= right << shift; } + *access |= user; + return NGX_CONF_OK; invalid: diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h index a723c3d..320adc2 100644 --- a/src/core/ngx_file.h +++ b/src/core/ngx_file.h @@ -23,14 +23,14 @@ struct ngx_file_s { ngx_log_t *log; -#if (NGX_THREADS) +#if (NGX_THREADS || NGX_COMPAT) ngx_int_t (*thread_handler)(ngx_thread_task_t *task, ngx_file_t *file); void *thread_ctx; ngx_thread_task_t *thread_task; #endif -#if (NGX_HAVE_FILE_AIO) +#if (NGX_HAVE_FILE_AIO || NGX_COMPAT) ngx_event_aio_t *aio; #endif @@ -42,7 +42,8 @@ struct ngx_file_s { #define NGX_MAX_PATH_LEVEL 3 -typedef time_t (*ngx_path_manager_pt) (void *data); +typedef ngx_msec_t (*ngx_path_manager_pt) (void *data); +typedef ngx_msec_t (*ngx_path_purger_pt) (void *data); typedef void (*ngx_path_loader_pt) (void *data); @@ -52,6 +53,7 @@ typedef struct { size_t level[NGX_MAX_PATH_LEVEL]; ngx_path_manager_pt manager; + ngx_path_purger_pt purger; ngx_path_loader_pt loader; void *data; diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c index dbd1f46..3bcd3e7 100644 --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -1364,6 +1364,7 @@ ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1, struct sockaddr_in6 *sin61, *sin62; #endif #if (NGX_HAVE_UNIX_DOMAIN) + size_t len; struct sockaddr_un *saun1, *saun2; #endif @@ -1393,15 +1394,21 @@ ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1, #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: - /* TODO length */ - saun1 = (struct sockaddr_un *) sa1; saun2 = (struct sockaddr_un *) sa2; - if (ngx_memcmp(&saun1->sun_path, &saun2->sun_path, - sizeof(saun1->sun_path)) - != 0) - { + if (slen1 < slen2) { + len = slen1 - offsetof(struct sockaddr_un, sun_path); + + } else { + len = slen2 - offsetof(struct sockaddr_un, sun_path); + } + + if (len > sizeof(saun1->sun_path)) { + len = sizeof(saun1->sun_path); + } + + if (ngx_memcmp(&saun1->sun_path, &saun2->sun_path, len) != 0) { return NGX_DECLINED; } diff --git a/src/core/ngx_module.h b/src/core/ngx_module.h index a1a0d6c..8cf3210 100644 --- a/src/core/ngx_module.h +++ b/src/core/ngx_module.h @@ -35,13 +35,13 @@ #define NGX_MODULE_SIGNATURE_2 "0" #endif -#if (NGX_HAVE_FILE_AIO) +#if (NGX_HAVE_FILE_AIO || NGX_COMPAT) #define NGX_MODULE_SIGNATURE_3 "1" #else #define NGX_MODULE_SIGNATURE_3 "0" #endif -#if (NGX_HAVE_AIO_SENDFILE) +#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) #define NGX_MODULE_SIGNATURE_4 "1" #else #define NGX_MODULE_SIGNATURE_4 "0" @@ -71,17 +71,8 @@ #define NGX_MODULE_SIGNATURE_8 "0" #endif -#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) #define NGX_MODULE_SIGNATURE_9 "1" -#else -#define NGX_MODULE_SIGNATURE_9 "0" -#endif - -#if (NGX_HAVE_REUSEPORT) #define NGX_MODULE_SIGNATURE_10 "1" -#else -#define NGX_MODULE_SIGNATURE_10 "0" -#endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) #define NGX_MODULE_SIGNATURE_11 "1" @@ -89,11 +80,7 @@ #define NGX_MODULE_SIGNATURE_11 "0" #endif -#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) #define NGX_MODULE_SIGNATURE_12 "1" -#else -#define NGX_MODULE_SIGNATURE_12 "0" -#endif #if (NGX_HAVE_SETFIB) #define NGX_MODULE_SIGNATURE_13 "1" @@ -140,7 +127,7 @@ #define NGX_MODULE_SIGNATURE_21 "0" #endif -#if (NGX_THREADS) +#if (NGX_THREADS || NGX_COMPAT) #define NGX_MODULE_SIGNATURE_22 "1" #else #define NGX_MODULE_SIGNATURE_22 "0" @@ -152,17 +139,13 @@ #define NGX_MODULE_SIGNATURE_23 "0" #endif -#if (NGX_HTTP_SSL) +#if (NGX_HTTP_SSL || NGX_COMPAT) #define NGX_MODULE_SIGNATURE_24 "1" #else #define NGX_MODULE_SIGNATURE_24 "0" #endif -#if (NGX_HTTP_V2) #define NGX_MODULE_SIGNATURE_25 "1" -#else -#define NGX_MODULE_SIGNATURE_25 "0" -#endif #if (NGX_HTTP_GZIP) #define NGX_MODULE_SIGNATURE_26 "1" @@ -170,11 +153,7 @@ #define NGX_MODULE_SIGNATURE_26 "0" #endif -#if (NGX_HTTP_DEGRADATION) #define NGX_MODULE_SIGNATURE_27 "1" -#else -#define NGX_MODULE_SIGNATURE_27 "0" -#endif #if (NGX_HTTP_X_FORWARDED_FOR) #define NGX_MODULE_SIGNATURE_28 "1" @@ -212,6 +191,12 @@ #define NGX_MODULE_SIGNATURE_33 "0" #endif +#if (NGX_COMPAT) +#define NGX_MODULE_SIGNATURE_34 "1" +#else +#define NGX_MODULE_SIGNATURE_34 "0" +#endif + #define NGX_MODULE_SIGNATURE \ NGX_MODULE_SIGNATURE_0 NGX_MODULE_SIGNATURE_1 NGX_MODULE_SIGNATURE_2 \ NGX_MODULE_SIGNATURE_3 NGX_MODULE_SIGNATURE_4 NGX_MODULE_SIGNATURE_5 \ @@ -224,7 +209,7 @@ NGX_MODULE_SIGNATURE_24 NGX_MODULE_SIGNATURE_25 NGX_MODULE_SIGNATURE_26 \ NGX_MODULE_SIGNATURE_27 NGX_MODULE_SIGNATURE_28 NGX_MODULE_SIGNATURE_29 \ NGX_MODULE_SIGNATURE_30 NGX_MODULE_SIGNATURE_31 NGX_MODULE_SIGNATURE_32 \ - NGX_MODULE_SIGNATURE_33 + NGX_MODULE_SIGNATURE_33 NGX_MODULE_SIGNATURE_34 #define NGX_MODULE_V1 \ diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index 53dae6b..bdfed88 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -3006,6 +3006,7 @@ ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx) ctx->count--; srv->ctx = NULL; + srv->state = cctx->state; if (cctx->naddrs) { diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h index e36cfdc..a0d6fc3 100644 --- a/src/core/ngx_resolver.h +++ b/src/core/ngx_resolver.h @@ -82,6 +82,7 @@ typedef struct { u_short port; ngx_resolver_ctx_t *ctx; + ngx_int_t state; ngx_uint_t naddrs; ngx_addr_t *addrs; diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index 27139ee..053bd16 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -152,7 +152,7 @@ struct ngx_event_aio_s { ngx_event_handler_pt handler; ngx_file_t *file; -#if (NGX_HAVE_AIO_SENDFILE) +#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) ssize_t (*preload_handler)(ngx_buf_t *file); #endif @@ -430,6 +430,7 @@ extern ngx_os_io_t ngx_io; #define ngx_send ngx_io.send #define ngx_send_chain ngx_io.send_chain #define ngx_udp_send ngx_io.udp_send +#define ngx_udp_send_chain ngx_io.udp_send_chain #define NGX_EVENT_MODULE 0x544E5645 /* "EVNT" */ diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index 4445adc..1fce2e8 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -467,6 +467,7 @@ ngx_event_recvmsg(ngx_event_t *ev) *log = ls->log; c->send = ngx_udp_send; + c->send_chain = ngx_udp_send_chain; c->log = log; c->pool->log = log; diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c index 06534ef..c5bb806 100644 --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -166,6 +166,7 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc) } else { /* type == SOCK_DGRAM */ c->recv = ngx_udp_recv; c->send = ngx_send; + c->send_chain = ngx_udp_send_chain; } c->log_error = pc->log_error; diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h index 10b72a1..72d21d7 100644 --- a/src/event/ngx_event_connect.h +++ b/src/event/ngx_event_connect.h @@ -25,13 +25,12 @@ typedef ngx_int_t (*ngx_event_get_peer_pt)(ngx_peer_connection_t *pc, void *data); typedef void (*ngx_event_free_peer_pt)(ngx_peer_connection_t *pc, void *data, ngx_uint_t state); -#if (NGX_SSL) - +typedef void (*ngx_event_notify_peer_pt)(ngx_peer_connection_t *pc, + void *data, ngx_uint_t type); typedef ngx_int_t (*ngx_event_set_peer_session_pt)(ngx_peer_connection_t *pc, void *data); typedef void (*ngx_event_save_peer_session_pt)(ngx_peer_connection_t *pc, void *data); -#endif struct ngx_peer_connection_s { @@ -46,9 +45,10 @@ struct ngx_peer_connection_s { ngx_event_get_peer_pt get; ngx_event_free_peer_pt free; + ngx_event_notify_peer_pt notify; void *data; -#if (NGX_SSL) +#if (NGX_SSL || NGX_COMPAT) ngx_event_set_peer_session_pt set_session; ngx_event_save_peer_session_pt save_session; #endif @@ -61,12 +61,13 @@ struct ngx_peer_connection_s { ngx_log_t *log; unsigned cached:1; -#if (NGX_HAVE_TRANSPARENT_PROXY) unsigned transparent:1; -#endif /* ngx_connection_log_error_e */ unsigned log_error:2; + + NGX_COMPAT_BEGIN(2) + NGX_COMPAT_END }; diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 1cbfdf2..68d02bf 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -55,7 +55,7 @@ static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, HMAC_CTX *hctx, int enc); #endif -#if OPENSSL_VERSION_NUMBER < 0x10002002L +#ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT static ngx_int_t ngx_ssl_check_name(ngx_str_t *name, ASN1_STRING *str); #endif @@ -3092,7 +3092,7 @@ ngx_ssl_check_host(ngx_connection_t *c, ngx_str_t *name) return NGX_ERROR; } -#if OPENSSL_VERSION_NUMBER >= 0x10002002L +#ifdef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT /* X509_check_host() is only available in OpenSSL 1.0.2+ */ @@ -3209,7 +3209,7 @@ found: } -#if OPENSSL_VERSION_NUMBER < 0x10002002L +#ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT static ngx_int_t ngx_ssl_check_name(ngx_str_t *name, ASN1_STRING *pattern) @@ -3656,13 +3656,13 @@ ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) engine = ENGINE_by_id((char *) value[1].data); if (engine == NULL) { - ngx_ssl_error(NGX_LOG_WARN, cf->log, 0, + ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, "ENGINE_by_id(\"%V\") failed", &value[1]); return NGX_CONF_ERROR; } if (ENGINE_set_default(engine, ENGINE_METHOD_ALL) == 0) { - ngx_ssl_error(NGX_LOG_WARN, cf->log, 0, + ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, "ENGINE_set_default(\"%V\", ENGINE_METHOD_ALL) failed", &value[1]); diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 3367d10..24b812f 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -54,14 +54,14 @@ #define ngx_ssl_conn_t SSL -typedef struct { +struct ngx_ssl_s { SSL_CTX *ctx; ngx_log_t *log; size_t buffer_size; -} ngx_ssl_t; +}; -typedef struct { +struct ngx_ssl_connection_s { ngx_ssl_conn_t *connection; SSL_CTX *session_ctx; @@ -80,7 +80,7 @@ typedef struct { unsigned no_wait_shutdown:1; unsigned no_send_shutdown:1; unsigned handshake_buffer_set:1; -} ngx_ssl_connection_t; +}; #define NGX_SSL_NO_SCACHE -2 diff --git a/src/event/ngx_event_pipe.h b/src/event/ngx_event_pipe.h index ef2e7a0..10a3340 100644 --- a/src/event/ngx_event_pipe.h +++ b/src/event/ngx_event_pipe.h @@ -47,7 +47,7 @@ struct ngx_event_pipe_s { ngx_event_pipe_output_filter_pt output_filter; void *output_ctx; -#if (NGX_THREADS) +#if (NGX_THREADS || NGX_COMPAT) ngx_int_t (*thread_handler)(ngx_thread_task_t *task, ngx_file_t *file); void *thread_ctx; diff --git a/src/http/modules/ngx_http_addition_filter_module.c b/src/http/modules/ngx_http_addition_filter_module.c index db4970b..2fad0e5 100644 --- a/src/http/modules/ngx_http_addition_filter_module.c +++ b/src/http/modules/ngx_http_addition_filter_module.c @@ -171,6 +171,7 @@ ngx_http_addition_body_filter(ngx_http_request_t *r, ngx_chain_t *in) for (cl = in; cl; cl = cl->next) { if (cl->buf->last_buf) { cl->buf->last_buf = 0; + cl->buf->last_in_chain = 1; cl->buf->sync = 1; last = 1; } diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index 16ef83c..2a68bae 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -1144,7 +1144,7 @@ ngx_http_mp4_read_mdat_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) data = &mp4->mdat_data_buf; data->file = &mp4->file; data->in_file = 1; - data->last_buf = 1; + data->last_buf = (mp4->request == mp4->request->main) ? 1 : 0; data->last_in_chain = 1; data->file_last = mp4->offset + atom_data_size; diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index 57065e1..095ef06 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -750,7 +750,8 @@ ngx_http_range_singlepart_body(ngx_http_request_t *r, buf->last -= (size_t) (last - range->end); } - buf->last_buf = 1; + buf->last_buf = (r == r->main) ? 1 : 0; + buf->last_in_chain = 1; *ll = cl; cl->next = NULL; diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c index dba3c52..5e3355c 100644 --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -141,18 +141,18 @@ ngx_http_realip_handler(ngx_http_request_t *r) ngx_http_realip_ctx_t *ctx; ngx_http_realip_loc_conf_t *rlcf; - ctx = ngx_http_get_module_ctx(r, ngx_http_realip_module); - - if (ctx) { - return NGX_DECLINED; - } - rlcf = ngx_http_get_module_loc_conf(r, ngx_http_realip_module); if (rlcf->from == NULL) { return NGX_DECLINED; } + ctx = ngx_http_realip_get_module_ctx(r); + + if (ctx) { + return NGX_DECLINED; + } + switch (rlcf->type) { case NGX_HTTP_REALIP_XREALIP: diff --git a/src/http/modules/ngx_http_upstream_hash_module.c b/src/http/modules/ngx_http_upstream_hash_module.c index 1e2e05c..6c28c64 100644 --- a/src/http/modules/ngx_http_upstream_hash_module.c +++ b/src/http/modules/ngx_http_upstream_hash_module.c @@ -242,6 +242,10 @@ ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) goto next; } + if (peer->max_conns && peer->conns >= peer->max_conns) { + goto next; + } + break; next: @@ -523,7 +527,6 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) peer; peer = peer->next, i++) { - n = i / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); @@ -549,6 +552,10 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) continue; } + if (peer->max_conns && peer->conns >= peer->max_conns) { + continue; + } + peer->current_weight += peer->effective_weight; total += peer->effective_weight; @@ -571,6 +578,7 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) hp->tries++; if (hp->tries >= points->number) { + pc->name = hp->rrp.peers->name; ngx_http_upstream_rr_peers_unlock(hp->rrp.peers); return NGX_BUSY; } @@ -647,6 +655,7 @@ ngx_http_upstream_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) uscf->flags = NGX_HTTP_UPSTREAM_CREATE |NGX_HTTP_UPSTREAM_WEIGHT + |NGX_HTTP_UPSTREAM_MAX_CONNS |NGX_HTTP_UPSTREAM_MAX_FAILS |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT |NGX_HTTP_UPSTREAM_DOWN; diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c index 8a5f0fa..296108f 100644 --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c @@ -212,6 +212,10 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) goto next; } + if (peer->max_conns && peer->conns >= peer->max_conns) { + goto next; + } + break; next: @@ -259,6 +263,7 @@ ngx_http_upstream_ip_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) uscf->flags = NGX_HTTP_UPSTREAM_CREATE |NGX_HTTP_UPSTREAM_WEIGHT + |NGX_HTTP_UPSTREAM_MAX_CONNS |NGX_HTTP_UPSTREAM_MAX_FAILS |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT |NGX_HTTP_UPSTREAM_DOWN; diff --git a/src/http/modules/ngx_http_upstream_least_conn_module.c b/src/http/modules/ngx_http_upstream_least_conn_module.c index 8a300c1..ebe0627 100644 --- a/src/http/modules/ngx_http_upstream_least_conn_module.c +++ b/src/http/modules/ngx_http_upstream_least_conn_module.c @@ -136,7 +136,6 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) peer; peer = peer->next, i++) { - n = i / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); @@ -155,6 +154,10 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) continue; } + if (peer->max_conns && peer->conns >= peer->max_conns) { + continue; + } + /* * select peer with least number of connections; if there are * multiple peers with the same number of connections, select @@ -210,6 +213,10 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) continue; } + if (peer->max_conns && peer->conns >= peer->max_conns) { + continue; + } + peer->current_weight += peer->effective_weight; total += peer->effective_weight; @@ -273,12 +280,6 @@ failed: ngx_http_upstream_rr_peers_wlock(peers); } - /* all peers failed, mark them as live for quick recovery */ - - for (peer = peers->peer; peer; peer = peer->next) { - peer->fails = 0; - } - ngx_http_upstream_rr_peers_unlock(peers); pc->name = peers->name; @@ -303,6 +304,7 @@ ngx_http_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) uscf->flags = NGX_HTTP_UPSTREAM_CREATE |NGX_HTTP_UPSTREAM_WEIGHT + |NGX_HTTP_UPSTREAM_MAX_CONNS |NGX_HTTP_UPSTREAM_MAX_FAILS |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT |NGX_HTTP_UPSTREAM_DOWN diff --git a/src/http/modules/perl/Makefile.PL b/src/http/modules/perl/Makefile.PL index 03348b5..7edadcb 100644 --- a/src/http/modules/perl/Makefile.PL +++ b/src/http/modules/perl/Makefile.PL @@ -16,6 +16,8 @@ WriteMakefile( CCFLAGS => "$ENV{NGX_PM_CFLAGS}", OPTIMIZE => '-O', + LDDLFLAGS => "$ENV{NGX_PM_LDFLAGS}", + INC => join(" ", map { m#^/# ? "-I $_" : "-I ../../../../../$_" } (split /\s+/, $ENV{NGX_INCS})), diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index 7a46b3e..ba559f2 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1756,7 +1756,7 @@ ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) ls->deferred_accept = addr->opt.deferred_accept; #endif -#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) +#if (NGX_HAVE_INET6) ls->ipv6only = addr->opt.ipv6only; #endif diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index 19cb680..afab4f6 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -19,10 +19,7 @@ typedef struct ngx_http_cache_s ngx_http_cache_t; typedef struct ngx_http_file_cache_s ngx_http_file_cache_t; typedef struct ngx_http_log_ctx_s ngx_http_log_ctx_t; typedef struct ngx_http_chunked_s ngx_http_chunked_t; - -#if (NGX_HTTP_V2) typedef struct ngx_http_v2_stream_s ngx_http_v2_stream_t; -#endif typedef ngx_int_t (*ngx_http_header_handler_pt)(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h index 2667cbb..70342d0 100644 --- a/src/http/ngx_http_cache.h +++ b/src/http/ngx_http_cache.h @@ -50,7 +50,8 @@ typedef struct { unsigned exists:1; unsigned updating:1; unsigned deleting:1; - /* 11 unused bits */ + unsigned purged:1; + /* 10 unused bits */ ngx_file_uniq_t uniq; time_t expire; @@ -85,13 +86,14 @@ struct ngx_http_cache_s { ngx_uint_t min_uses; ngx_uint_t error; ngx_uint_t valid_msec; + ngx_uint_t vary_tag; ngx_buf_t *buf; ngx_http_file_cache_t *file_cache; ngx_http_file_cache_node_t *node; -#if (NGX_THREADS) +#if (NGX_THREADS || NGX_COMPAT) ngx_thread_task_t *thread_task; #endif @@ -109,6 +111,7 @@ struct ngx_http_cache_s { unsigned updating:1; unsigned exists:1; unsigned temp_file:1; + unsigned purged:1; unsigned reading:1; unsigned secondary:1; }; @@ -163,6 +166,10 @@ struct ngx_http_file_cache_s { ngx_msec_t loader_sleep; ngx_msec_t loader_threshold; + ngx_uint_t manager_files; + ngx_msec_t manager_sleep; + ngx_msec_t manager_threshold; + ngx_shm_zone_t *shm_zone; }; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index e26c3f7..9da5d10 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -3760,10 +3760,8 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0); ngx_conf_merge_size_value(conf->sendfile_max_chunk, prev->sendfile_max_chunk, 0); -#if (NGX_HAVE_FILE_AIO || NGX_THREADS) ngx_conf_merge_value(conf->aio, prev->aio, NGX_HTTP_AIO_OFF); ngx_conf_merge_value(conf->aio_write, prev->aio_write, 0); -#endif #if (NGX_THREADS) ngx_conf_merge_ptr_value(conf->thread_pool, prev->thread_pool, NULL); ngx_conf_merge_ptr_value(conf->thread_pool_value, prev->thread_pool_value, @@ -3939,7 +3937,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) lsopt.fastopen = -1; #endif lsopt.wildcard = u.wildcard; -#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) +#if (NGX_HAVE_INET6) lsopt.ipv6only = 1; #endif diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 773c215..ade9abb 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -15,6 +15,8 @@ #if (NGX_THREADS) #include +#elif (NGX_COMPAT) +typedef struct ngx_thread_pool_s ngx_thread_pool_t; #endif @@ -65,18 +67,13 @@ typedef struct { unsigned default_server:1; unsigned bind:1; unsigned wildcard:1; -#if (NGX_HTTP_SSL) unsigned ssl:1; -#endif -#if (NGX_HTTP_V2) unsigned http2:1; -#endif -#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) +#if (NGX_HAVE_INET6) unsigned ipv6only:1; #endif -#if (NGX_HAVE_REUSEPORT) + unsigned deferred_accept:1; unsigned reuseport:1; -#endif unsigned so_keepalive:2; unsigned proxy_protocol:1; @@ -98,9 +95,6 @@ typedef struct { #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) char *accept_filter; #endif -#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) - ngx_uint_t deferred_accept; -#endif u_char addr[NGX_SOCKADDR_STRLEN + 1]; } ngx_http_listen_opt_t; @@ -234,12 +228,8 @@ struct ngx_http_addr_conf_s { ngx_http_virtual_names_t *virtual_names; -#if (NGX_HTTP_SSL) unsigned ssl:1; -#endif -#if (NGX_HTTP_V2) unsigned http2:1; -#endif unsigned proxy_protocol:1; }; @@ -327,9 +317,7 @@ struct ngx_http_core_loc_conf_s { unsigned auto_redirect:1; #if (NGX_HTTP_GZIP) unsigned gzip_disable_msie6:2; -#if (NGX_HTTP_DEGRADATION) unsigned gzip_disable_degradation:2; -#endif #endif ngx_http_location_tree_node_t *static_locations; @@ -419,7 +407,7 @@ struct ngx_http_core_loc_conf_s { #endif #endif -#if (NGX_THREADS) +#if (NGX_THREADS || NGX_COMPAT) ngx_thread_pool_t *thread_pool; ngx_http_complex_value_t *thread_pool_value; #endif diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index 4bf0f7f..199a901 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -1759,6 +1759,7 @@ ngx_http_file_cache_expire(ngx_http_file_cache_t *cache) size_t len; time_t now, wait; ngx_path_t *path; + ngx_msec_t elapsed; ngx_queue_t *q; ngx_http_file_cache_node_t *fcn; u_char key[2 * NGX_HTTP_CACHE_KEY_LEN]; @@ -1810,7 +1811,7 @@ ngx_http_file_cache_expire(ngx_http_file_cache_t *cache) if (fcn->count == 0) { ngx_http_file_cache_delete(cache, q, name); - continue; + goto next; } if (fcn->deleting) { @@ -1836,6 +1837,22 @@ ngx_http_file_cache_expire(ngx_http_file_cache_t *cache) ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "ignore long locked inactive cache entry %*s, count:%d", (size_t) 2 * NGX_HTTP_CACHE_KEY_LEN, key, fcn->count); + +next: + + if (++cache->files >= cache->manager_files) { + wait = 0; + break; + } + + ngx_time_update(); + + elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last)); + + if (elapsed >= cache->manager_threshold) { + wait = 0; + break; + } } ngx_shmtx_unlock(&cache->shpool->mutex); @@ -1897,20 +1914,25 @@ ngx_http_file_cache_delete(ngx_http_file_cache_t *cache, ngx_queue_t *q, } -static time_t +static ngx_msec_t ngx_http_file_cache_manager(void *data) { ngx_http_file_cache_t *cache = data; off_t size; time_t next, wait; + ngx_msec_t elapsed; ngx_uint_t count, watermark; - next = ngx_http_file_cache_expire(cache); - cache->last = ngx_current_msec; cache->files = 0; + next = ngx_http_file_cache_expire(cache); + + if (next == 0) { + return cache->manager_sleep; + } + for ( ;; ) { ngx_shmtx_lock(&cache->shpool->mutex); @@ -1925,17 +1947,29 @@ ngx_http_file_cache_manager(void *data) size, count, (ngx_int_t) watermark); if (size < cache->max_size && count < watermark) { - return next; + return (ngx_msec_t) next * 1000; } wait = ngx_http_file_cache_forced_expire(cache); if (wait > 0) { - return wait; + return (ngx_msec_t) wait * 1000; } if (ngx_quit || ngx_terminate) { - return next; + return (ngx_msec_t) next * 1000; + } + + if (++cache->files >= cache->manager_files) { + return cache->manager_sleep; + } + + ngx_time_update(); + + elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last)); + + if (elapsed >= cache->manager_threshold) { + return cache->manager_sleep; } } } @@ -2211,8 +2245,9 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) size_t len; ssize_t size; ngx_str_t s, name, *value; - ngx_int_t loader_files; - ngx_msec_t loader_sleep, loader_threshold; + ngx_int_t loader_files, manager_files; + ngx_msec_t loader_sleep, manager_sleep, loader_threshold, + manager_threshold; ngx_uint_t i, n, use_temp_path; ngx_array_t *caches; ngx_http_file_cache_t *cache, **ce; @@ -2230,10 +2265,15 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) use_temp_path = 1; inactive = 600; + loader_files = 100; loader_sleep = 50; loader_threshold = 200; + manager_files = 100; + manager_sleep = 50; + manager_threshold = 200; + name.len = 0; size = 0; max_size = NGX_MAX_OFF_T_VALUE; @@ -2405,6 +2445,48 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } + if (ngx_strncmp(value[i].data, "manager_files=", 14) == 0) { + + manager_files = ngx_atoi(value[i].data + 14, value[i].len - 14); + if (manager_files == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid manager_files value \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "manager_sleep=", 14) == 0) { + + s.len = value[i].len - 14; + s.data = value[i].data + 14; + + manager_sleep = ngx_parse_time(&s, 0); + if (manager_sleep == (ngx_msec_t) NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid manager_sleep value \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "manager_threshold=", 18) == 0) { + + s.len = value[i].len - 18; + s.data = value[i].data + 18; + + manager_threshold = ngx_parse_time(&s, 0); + if (manager_threshold == (ngx_msec_t) NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid manager_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; @@ -2425,6 +2507,9 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) cache->loader_files = loader_files; cache->loader_sleep = loader_sleep; cache->loader_threshold = loader_threshold; + cache->manager_files = manager_files; + cache->manager_sleep = manager_sleep; + cache->manager_threshold = manager_threshold; if (ngx_add_path(cf, &cache->path) != NGX_OK) { return NGX_CONF_ERROR; diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index bd6c9c9..9f99473 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -149,7 +149,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) break; } - if ((ch < 'A' || ch > 'Z') && ch != '_') { + if ((ch < 'A' || ch > 'Z') && ch != '_' && ch != '-') { return NGX_HTTP_PARSE_INVALID_METHOD; } @@ -270,7 +270,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) break; } - if ((ch < 'A' || ch > 'Z') && ch != '_') { + if ((ch < 'A' || ch > 'Z') && ch != '_' && ch != '-') { return NGX_HTTP_PARSE_INVALID_METHOD; } diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 499c1ef..cf9ee3c 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -286,9 +286,7 @@ typedef struct { ngx_chain_t *bufs; ngx_buf_t *buf; off_t rest; -#if (NGX_HTTP_V2) off_t received; -#endif ngx_chain_t *free; ngx_chain_t *busy; ngx_http_chunked_t *chunked; @@ -302,7 +300,7 @@ typedef struct { ngx_http_addr_conf_t *addr_conf; ngx_http_conf_ctx_t *conf_ctx; -#if (NGX_HTTP_SSL && defined SSL_CTRL_SET_TLSEXT_HOSTNAME) +#if (NGX_HTTP_SSL || NGX_COMPAT) ngx_str_t *ssl_servername; #if (NGX_PCRE) ngx_http_regex_t *ssl_servername_regex; @@ -315,9 +313,7 @@ typedef struct { ngx_buf_t **free; ngx_int_t nfree; -#if (NGX_HTTP_SSL) unsigned ssl:1; -#endif unsigned proxy_protocol:1; } ngx_http_connection_t; @@ -438,9 +434,7 @@ struct ngx_http_request_s { ngx_uint_t err_status; ngx_http_connection_t *http_connection; -#if (NGX_HTTP_V2) ngx_http_v2_stream_t *stream; -#endif ngx_http_log_handler_pt log_handler; @@ -539,11 +533,11 @@ struct ngx_http_request_s { unsigned subrequest_ranges:1; unsigned single_range:1; unsigned disable_not_modified:1; - -#if (NGX_STAT_STUB) unsigned stat_reading:1; unsigned stat_writing:1; -#endif + unsigned stat_processing:1; + + unsigned health_check:1; /* used to parse HTTP headers */ diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c index 64e5acd..7692f80 100644 --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -792,7 +792,7 @@ ngx_http_send_refresh(ngx_http_request_t *r) b->last = ngx_cpymem(p, ngx_http_msie_refresh_tail, sizeof(ngx_http_msie_refresh_tail) - 1); - b->last_buf = 1; + b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; out.buf = b; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 7e4b3c5..ceb798f 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -748,6 +748,8 @@ found: return; } + u->upstream = uscf; + #if (NGX_HTTP_SSL) u->ssl_name = uscf->host; #endif @@ -5442,6 +5444,7 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) uscf = ngx_http_upstream_add(cf, &u, NGX_HTTP_UPSTREAM_CREATE |NGX_HTTP_UPSTREAM_WEIGHT + |NGX_HTTP_UPSTREAM_MAX_CONNS |NGX_HTTP_UPSTREAM_MAX_FAILS |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT |NGX_HTTP_UPSTREAM_DOWN @@ -5543,7 +5546,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) time_t fail_timeout; ngx_str_t *value, s; ngx_url_t u; - ngx_int_t weight, max_fails; + ngx_int_t weight, max_conns, max_fails; ngx_uint_t i; ngx_http_upstream_server_t *us; @@ -5557,6 +5560,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) value = cf->args->elts; weight = 1; + max_conns = 0; max_fails = 1; fail_timeout = 10; @@ -5577,6 +5581,21 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } + if (ngx_strncmp(value[i].data, "max_conns=", 10) == 0) { + + if (!(uscf->flags & NGX_HTTP_UPSTREAM_MAX_CONNS)) { + goto not_supported; + } + + max_conns = ngx_atoi(&value[i].data[10], value[i].len - 10); + + if (max_conns == NGX_ERROR) { + goto invalid; + } + + continue; + } + if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) { if (!(uscf->flags & NGX_HTTP_UPSTREAM_MAX_FAILS)) { @@ -5653,6 +5672,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) us->addrs = u.addrs; us->naddrs = u.naddrs; us->weight = weight; + us->max_conns = max_conns; us->max_fails = max_fails; us->fail_timeout = fail_timeout; @@ -5717,14 +5737,14 @@ ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags) } if ((uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE) && !u->no_port) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "upstream \"%V\" may not have port %d", &u->host, u->port); return NULL; } if ((flags & NGX_HTTP_UPSTREAM_CREATE) && !uscfp[i]->no_port) { - ngx_log_error(NGX_LOG_WARN, cf->log, 0, + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "upstream \"%V\" may not have port %d in %s:%ui", &u->host, uscfp[i]->port, uscfp[i]->file_name, uscfp[i]->line); diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index ef861f4..3d521f2 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -95,11 +95,16 @@ typedef struct { ngx_addr_t *addrs; ngx_uint_t naddrs; ngx_uint_t weight; + ngx_uint_t max_conns; ngx_uint_t max_fails; time_t fail_timeout; + ngx_msec_t slow_start; unsigned down:1; unsigned backup:1; + + NGX_COMPAT_BEGIN(6) + NGX_COMPAT_END } ngx_http_upstream_server_t; @@ -109,6 +114,7 @@ typedef struct { #define NGX_HTTP_UPSTREAM_FAIL_TIMEOUT 0x0008 #define NGX_HTTP_UPSTREAM_DOWN 0x0010 #define NGX_HTTP_UPSTREAM_BACKUP 0x0020 +#define NGX_HTTP_UPSTREAM_MAX_CONNS 0x0100 struct ngx_http_upstream_srv_conf_s { @@ -202,6 +208,7 @@ typedef struct { ngx_array_t *cache_valid; ngx_array_t *cache_bypass; + ngx_array_t *cache_purge; ngx_array_t *no_cache; #endif @@ -215,7 +222,7 @@ typedef struct { unsigned intercept_404:1; unsigned change_buffering:1; -#if (NGX_HTTP_SSL) +#if (NGX_HTTP_SSL || NGX_COMPAT) ngx_ssl_t *ssl; ngx_flag_t ssl_session_reuse; @@ -225,6 +232,9 @@ typedef struct { #endif ngx_str_t module; + + NGX_COMPAT_BEGIN(2) + NGX_COMPAT_END } ngx_http_upstream_conf_t; @@ -313,6 +323,7 @@ struct ngx_http_upstream_s { ngx_chain_writer_ctx_t writer; ngx_http_upstream_conf_t *conf; + ngx_http_upstream_srv_conf_t *upstream; #if (NGX_HTTP_CACHE) ngx_array_t *caches; #endif @@ -356,7 +367,7 @@ struct ngx_http_upstream_s { ngx_str_t schema; ngx_str_t uri; -#if (NGX_HTTP_SSL) +#if (NGX_HTTP_SSL || NGX_COMPAT) ngx_str_t ssl_name; #endif @@ -377,6 +388,9 @@ struct ngx_http_upstream_s { unsigned request_sent:1; unsigned request_body_sent:1; unsigned header_sent:1; + + NGX_COMPAT_BEGIN(1) + NGX_COMPAT_END }; diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c index 8479c42..0137bf6 100644 --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -92,6 +92,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, peer[n].weight = server[i].weight; peer[n].effective_weight = server[i].weight; peer[n].current_weight = 0; + peer[n].max_conns = server[i].max_conns; peer[n].max_fails = server[i].max_fails; peer[n].fail_timeout = server[i].fail_timeout; peer[n].down = server[i].down; @@ -155,6 +156,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, peer[n].weight = server[i].weight; peer[n].effective_weight = server[i].weight; peer[n].current_weight = 0; + peer[n].max_conns = server[i].max_conns; peer[n].max_fails = server[i].max_fails; peer[n].fail_timeout = server[i].fail_timeout; peer[n].down = server[i].down; @@ -223,6 +225,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, peer[i].weight = 1; peer[i].effective_weight = 1; peer[i].current_weight = 0; + peer[i].max_conns = 0; peer[i].max_fails = 1; peer[i].fail_timeout = 10; *peerp = &peer[i]; @@ -257,6 +260,7 @@ ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r, rrp->peers = us->peer.data; rrp->current = NULL; + rrp->config = 0; n = rrp->peers->number; @@ -337,6 +341,7 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, peer[0].weight = 1; peer[0].effective_weight = 1; peer[0].current_weight = 0; + peer[0].max_conns = 0; peer[0].max_fails = 1; peer[0].fail_timeout = 10; peers->peer = peer; @@ -370,6 +375,7 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, peer[i].weight = 1; peer[i].effective_weight = 1; peer[i].current_weight = 0; + peer[i].max_conns = 0; peer[i].max_fails = 1; peer[i].fail_timeout = 10; *peerp = &peer[i]; @@ -379,6 +385,7 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, rrp->peers = peers; rrp->current = NULL; + rrp->config = 0; if (rrp->peers->number <= 8 * sizeof(uintptr_t)) { rrp->tried = &rrp->data; @@ -432,6 +439,10 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) goto failed; } + if (peer->max_conns && peer->conns >= peer->max_conns) { + goto failed; + } + rrp->current = peer; } else { @@ -485,12 +496,6 @@ failed: ngx_http_upstream_rr_peers_wlock(peers); } - /* all peers failed, mark them as live for quick recovery */ - - for (peer = peers->peer; peer; peer = peer->next) { - peer->fails = 0; - } - ngx_http_upstream_rr_peers_unlock(peers); pc->name = peers->name; @@ -521,7 +526,6 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp) peer; peer = peer->next, i++) { - n = i / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); @@ -540,6 +544,10 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp) continue; } + if (peer->max_conns && peer->conns >= peer->max_conns) { + continue; + } + peer->current_weight += peer->effective_weight; total += peer->effective_weight; diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h index f2c573f..45f258d 100644 --- a/src/http/ngx_http_upstream_round_robin.h +++ b/src/http/ngx_http_upstream_round_robin.h @@ -27,6 +27,7 @@ struct ngx_http_upstream_rr_peer_s { ngx_int_t weight; ngx_uint_t conns; + ngx_uint_t max_conns; ngx_uint_t fails; time_t accessed; @@ -34,19 +35,24 @@ struct ngx_http_upstream_rr_peer_s { ngx_uint_t max_fails; time_t fail_timeout; + ngx_msec_t slow_start; + ngx_msec_t start_time; - ngx_uint_t down; /* unsigned down:1; */ + ngx_uint_t down; -#if (NGX_HTTP_SSL) +#if (NGX_HTTP_SSL || NGX_COMPAT) void *ssl_session; int ssl_session_len; #endif - ngx_http_upstream_rr_peer_t *next; - #if (NGX_HTTP_UPSTREAM_ZONE) ngx_atomic_t lock; #endif + + ngx_http_upstream_rr_peer_t *next; + + NGX_COMPAT_BEGIN(32) + NGX_COMPAT_END }; @@ -119,6 +125,7 @@ struct ngx_http_upstream_rr_peers_s { typedef struct { + ngx_uint_t config; ngx_http_upstream_rr_peers_t *peers; ngx_http_upstream_rr_peer_t *current; uintptr_t *tried; diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index d0cd2ab..235092b 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -3178,7 +3178,7 @@ ngx_http_v2_parse_method(ngx_http_request_t *r, ngx_http_v2_header_t *header) p = r->method_name.data; do { - if ((*p < 'A' || *p > 'Z') && *p != '_') { + if ((*p < 'A' || *p > 'Z') && *p != '_' && *p != '-') { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client sent invalid method: \"%V\"", &r->method_name); diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c index e5a77b0..9e560bb 100644 --- a/src/mail/ngx_mail.c +++ b/src/mail/ngx_mail.c @@ -341,7 +341,7 @@ ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) ls->keepcnt = addr[i].opt.tcp_keepcnt; #endif -#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) +#if (NGX_HAVE_INET6) ls->ipv6only = addr[i].opt.ipv6only; #endif diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index 1068bb3..c30af35 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -35,10 +35,8 @@ typedef struct { unsigned bind:1; unsigned wildcard:1; -#if (NGX_MAIL_SSL) unsigned ssl:1; -#endif -#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) +#if (NGX_HAVE_INET6) unsigned ipv6only:1; #endif unsigned so_keepalive:2; @@ -54,9 +52,7 @@ typedef struct { typedef struct { ngx_mail_conf_ctx_t *ctx; ngx_str_t addr_text; -#if (NGX_MAIL_SSL) ngx_uint_t ssl; /* unsigned ssl:1; */ -#endif } ngx_mail_addr_conf_t; typedef struct { diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index 48eacfa..b974d90 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -353,7 +353,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ls->wildcard = u.wildcard; ls->ctx = cf->ctx; -#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) +#if (NGX_HAVE_INET6) ls->ipv6only = 1; #endif diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c index 11e428c..fbc9bc7 100644 --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -488,7 +488,7 @@ ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } if (scf->enable && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"starttls\" directive conflicts with \"ssl on\""); return NGX_CONF_ERROR; } @@ -514,7 +514,7 @@ ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } if (scf->enable == 1 && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"ssl\" directive conflicts with \"starttls\""); return NGX_CONF_ERROR; } diff --git a/src/os/unix/ngx_darwin_init.c b/src/os/unix/ngx_darwin_init.c index a9d12a8..aabe02f 100644 --- a/src/os/unix/ngx_darwin_init.c +++ b/src/os/unix/ngx_darwin_init.c @@ -24,6 +24,7 @@ static ngx_os_io_t ngx_darwin_io = { ngx_udp_unix_recv, ngx_unix_send, ngx_udp_unix_send, + ngx_udp_unix_sendmsg_chain, #if (NGX_HAVE_SENDFILE) ngx_darwin_sendfile_chain, NGX_IO_SENDFILE diff --git a/src/os/unix/ngx_freebsd_init.c b/src/os/unix/ngx_freebsd_init.c index 71672c7..1823f02 100644 --- a/src/os/unix/ngx_freebsd_init.c +++ b/src/os/unix/ngx_freebsd_init.c @@ -33,6 +33,7 @@ static ngx_os_io_t ngx_freebsd_io = { ngx_udp_unix_recv, ngx_unix_send, ngx_udp_unix_send, + ngx_udp_unix_sendmsg_chain, #if (NGX_HAVE_SENDFILE) ngx_freebsd_sendfile_chain, NGX_IO_SENDFILE diff --git a/src/os/unix/ngx_linux_init.c b/src/os/unix/ngx_linux_init.c index a1372e9..a8cf6a0 100644 --- a/src/os/unix/ngx_linux_init.c +++ b/src/os/unix/ngx_linux_init.c @@ -19,6 +19,7 @@ static ngx_os_io_t ngx_linux_io = { ngx_udp_unix_recv, ngx_unix_send, ngx_udp_unix_send, + ngx_udp_unix_sendmsg_chain, #if (NGX_HAVE_SENDFILE) ngx_linux_sendfile_chain, NGX_IO_SENDFILE diff --git a/src/os/unix/ngx_os.h b/src/os/unix/ngx_os.h index e22f07c..3b32819 100644 --- a/src/os/unix/ngx_os.h +++ b/src/os/unix/ngx_os.h @@ -29,6 +29,7 @@ typedef struct { ngx_recv_pt udp_recv; ngx_send_pt send; ngx_send_pt udp_send; + ngx_send_chain_pt udp_send_chain; ngx_send_chain_pt send_chain; ngx_uint_t flags; } ngx_os_io_t; @@ -49,6 +50,8 @@ ssize_t ngx_unix_send(ngx_connection_t *c, u_char *buf, size_t size); ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); ssize_t ngx_udp_unix_send(ngx_connection_t *c, u_char *buf, size_t size); +ngx_chain_t *ngx_udp_unix_sendmsg_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); #if (IOV_MAX > 64) diff --git a/src/os/unix/ngx_posix_init.c b/src/os/unix/ngx_posix_init.c index 7e6e79d..583ea4f 100644 --- a/src/os/unix/ngx_posix_init.c +++ b/src/os/unix/ngx_posix_init.c @@ -25,6 +25,7 @@ ngx_os_io_t ngx_os_io = { ngx_udp_unix_recv, ngx_unix_send, ngx_udp_unix_send, + ngx_udp_unix_sendmsg_chain, ngx_writev_chain, 0 }; diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c index 83b04ee..5c4e21d 100644 --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -1148,11 +1148,11 @@ ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data) static void ngx_cache_manager_process_handler(ngx_event_t *ev) { - time_t next, n; ngx_uint_t i; + ngx_msec_t next, n; ngx_path_t **path; - next = 60 * 60; + next = 60 * 60 * 1000; path = ngx_cycle->paths.elts; for (i = 0; i < ngx_cycle->paths.nelts; i++) { @@ -1170,7 +1170,7 @@ ngx_cache_manager_process_handler(ngx_event_t *ev) next = 1; } - ngx_add_timer(ev, next * 1000); + ngx_add_timer(ev, next); } diff --git a/src/os/unix/ngx_solaris_init.c b/src/os/unix/ngx_solaris_init.c index 83acae1..65d7875 100644 --- a/src/os/unix/ngx_solaris_init.c +++ b/src/os/unix/ngx_solaris_init.c @@ -20,6 +20,7 @@ static ngx_os_io_t ngx_solaris_io = { ngx_udp_unix_recv, ngx_unix_send, ngx_udp_unix_send, + ngx_udp_unix_sendmsg_chain, #if (NGX_HAVE_SENDFILE) ngx_solaris_sendfilev_chain, NGX_IO_SENDFILE diff --git a/src/os/unix/ngx_udp_sendmsg_chain.c b/src/os/unix/ngx_udp_sendmsg_chain.c new file mode 100644 index 0000000..65bde6f --- /dev/null +++ b/src/os/unix/ngx_udp_sendmsg_chain.c @@ -0,0 +1,245 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +static ngx_chain_t *ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec, + ngx_chain_t *in, ngx_log_t *log); +static ssize_t ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec); + + +ngx_chain_t * +ngx_udp_unix_sendmsg_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) +{ + ssize_t n; + off_t send; + ngx_chain_t *cl; + ngx_event_t *wev; + ngx_iovec_t vec; + struct iovec iovs[NGX_IOVS_PREALLOCATE]; + + wev = c->write; + + if (!wev->ready) { + return in; + } + +#if (NGX_HAVE_KQUEUE) + + if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) { + (void) ngx_connection_error(c, wev->kq_errno, + "kevent() reported about an closed connection"); + wev->error = 1; + return NGX_CHAIN_ERROR; + } + +#endif + + /* the maximum limit size is the maximum size_t value - the page size */ + + if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) { + limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize; + } + + send = 0; + + vec.iovs = iovs; + vec.nalloc = NGX_IOVS_PREALLOCATE; + + for ( ;; ) { + + /* create the iovec and coalesce the neighbouring bufs */ + + cl = ngx_udp_output_chain_to_iovec(&vec, in, c->log); + + if (cl == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; + } + + if (cl && cl->buf->in_file) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "file buf in sendmsg " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); + + ngx_debug_point(); + + return NGX_CHAIN_ERROR; + } + + if (cl == in) { + return in; + } + + send += vec.size; + + n = ngx_sendmsg(c, &vec); + + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + if (n == NGX_AGAIN) { + wev->ready = 0; + return in; + } + + c->sent += n; + + in = ngx_chain_update_sent(in, n); + + if (send >= limit || in == NULL) { + return in; + } + } +} + + +static ngx_chain_t * +ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, ngx_log_t *log) +{ + size_t total, size; + u_char *prev; + ngx_uint_t n, flush; + ngx_chain_t *cl; + struct iovec *iov; + + cl = in; + iov = NULL; + prev = NULL; + total = 0; + n = 0; + flush = 0; + + for ( /* void */ ; in && !flush; in = in->next) { + + if (in->buf->flush || in->buf->last_buf) { + flush = 1; + } + + if (ngx_buf_special(in->buf)) { + continue; + } + + if (in->buf->in_file) { + break; + } + + if (!ngx_buf_in_memory(in->buf)) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "bad buf in output chain " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + in->buf->temporary, + in->buf->recycled, + in->buf->in_file, + in->buf->start, + in->buf->pos, + in->buf->last, + in->buf->file, + in->buf->file_pos, + in->buf->file_last); + + ngx_debug_point(); + + return NGX_CHAIN_ERROR; + } + + size = in->buf->last - in->buf->pos; + + if (prev == in->buf->pos) { + iov->iov_len += size; + + } else { + if (n == vec->nalloc) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "too many parts in a datagram"); + return NGX_CHAIN_ERROR; + } + + iov = &vec->iovs[n++]; + + iov->iov_base = (void *) in->buf->pos; + iov->iov_len = size; + } + + prev = in->buf->pos + size; + total += size; + } + + if (!flush) { +#if (NGX_SUPPRESS_WARN) + vec->size = 0; + vec->count = 0; +#endif + return cl; + } + + vec->count = n; + vec->size = total; + + return in; +} + + +static ssize_t +ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec) +{ + ssize_t n; + ngx_err_t err; + struct msghdr msg; + + ngx_memzero(&msg, sizeof(struct msghdr)); + + if (c->socklen) { + msg.msg_name = c->sockaddr; + msg.msg_namelen = c->socklen; + } + + msg.msg_iov = vec->iovs; + msg.msg_iovlen = vec->count; + +eintr: + + n = sendmsg(c->fd, &msg, 0); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendmsg: %z of %uz", n, vec->size); + + if (n == -1) { + err = ngx_errno; + + switch (err) { + case NGX_EAGAIN: + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "sendmsg() not ready"); + return NGX_AGAIN; + + case NGX_EINTR: + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "sendmsg() was interrupted"); + goto eintr; + + default: + c->write->error = 1; + ngx_connection_error(c, err, "sendmsg() failed"); + return NGX_ERROR; + } + } + + return n; +} diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c index 873e102..4a394d7 100644 --- a/src/stream/ngx_stream.c +++ b/src/stream/ngx_stream.c @@ -12,6 +12,10 @@ static char *ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static ngx_int_t ngx_stream_init_phases(ngx_conf_t *cf, + ngx_stream_core_main_conf_t *cmcf); +static ngx_int_t ngx_stream_init_phase_handlers(ngx_conf_t *cf, + ngx_stream_core_main_conf_t *cmcf); static ngx_int_t ngx_stream_add_ports(ngx_conf_t *cf, ngx_array_t *ports, ngx_stream_listen_t *listen); static char *ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports); @@ -27,6 +31,9 @@ static ngx_int_t ngx_stream_cmp_conf_addrs(const void *one, const void *two); ngx_uint_t ngx_stream_max_module; +ngx_stream_filter_pt ngx_stream_top_filter; + + static ngx_command_t ngx_stream_commands[] = { { ngx_string("stream"), @@ -216,6 +223,10 @@ ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } + if (ngx_stream_init_phases(cf, cmcf) != NGX_OK) { + return NGX_CONF_ERROR; + } + for (m = 0; cf->cycle->modules[m]; m++) { if (cf->cycle->modules[m]->type != NGX_STREAM_MODULE) { continue; @@ -236,6 +247,9 @@ ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) *cf = pcf; + if (ngx_stream_init_phase_handlers(cf, cmcf) != NGX_OK) { + return NGX_CONF_ERROR; + } if (ngx_array_init(&ports, cf->temp_pool, 4, sizeof(ngx_stream_conf_port_t)) != NGX_OK) @@ -255,6 +269,114 @@ ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +static ngx_int_t +ngx_stream_init_phases(ngx_conf_t *cf, ngx_stream_core_main_conf_t *cmcf) +{ + if (ngx_array_init(&cmcf->phases[NGX_STREAM_POST_ACCEPT_PHASE].handlers, + cf->pool, 1, sizeof(ngx_stream_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&cmcf->phases[NGX_STREAM_PREACCESS_PHASE].handlers, + cf->pool, 1, sizeof(ngx_stream_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&cmcf->phases[NGX_STREAM_ACCESS_PHASE].handlers, + cf->pool, 1, sizeof(ngx_stream_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&cmcf->phases[NGX_STREAM_SSL_PHASE].handlers, + cf->pool, 1, sizeof(ngx_stream_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&cmcf->phases[NGX_STREAM_PREREAD_PHASE].handlers, + cf->pool, 1, sizeof(ngx_stream_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&cmcf->phases[NGX_STREAM_LOG_PHASE].handlers, + cf->pool, 1, sizeof(ngx_stream_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_init_phase_handlers(ngx_conf_t *cf, + ngx_stream_core_main_conf_t *cmcf) +{ + ngx_int_t j; + ngx_uint_t i, n; + ngx_stream_handler_pt *h; + ngx_stream_phase_handler_t *ph; + ngx_stream_phase_handler_pt checker; + + n = 1 /* content phase */; + + for (i = 0; i < NGX_STREAM_LOG_PHASE; i++) { + n += cmcf->phases[i].handlers.nelts; + } + + ph = ngx_pcalloc(cf->pool, + n * sizeof(ngx_stream_phase_handler_t) + sizeof(void *)); + if (ph == NULL) { + return NGX_ERROR; + } + + cmcf->phase_engine.handlers = ph; + n = 0; + + for (i = 0; i < NGX_STREAM_LOG_PHASE; i++) { + h = cmcf->phases[i].handlers.elts; + + switch (i) { + + case NGX_STREAM_PREREAD_PHASE: + checker = ngx_stream_core_preread_phase; + break; + + case NGX_STREAM_CONTENT_PHASE: + ph->checker = ngx_stream_core_content_phase; + n++; + ph++; + + continue; + + default: + checker = ngx_stream_core_generic_phase; + } + + n += cmcf->phases[i].handlers.nelts; + + for (j = cmcf->phases[i].handlers.nelts - 1; j >= 0; j--) { + ph->checker = checker; + ph->handler = h[j]; + ph->next = n; + ph++; + } + } + + return NGX_OK; +} + + static ngx_int_t ngx_stream_add_ports(ngx_conf_t *cf, ngx_array_t *ports, ngx_stream_listen_t *listen) @@ -382,7 +504,7 @@ ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) ls->keepcnt = addr[i].opt.tcp_keepcnt; #endif -#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) +#if (NGX_HAVE_INET6) ls->ipv6only = addr[i].opt.ipv6only; #endif diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h index 6251cc7..9e4169c 100644 --- a/src/stream/ngx_stream.h +++ b/src/stream/ngx_stream.h @@ -49,15 +49,11 @@ typedef struct { unsigned bind:1; unsigned wildcard:1; -#if (NGX_STREAM_SSL) unsigned ssl:1; -#endif -#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) +#if (NGX_HAVE_INET6) unsigned ipv6only:1; #endif -#if (NGX_HAVE_REUSEPORT) unsigned reuseport:1; -#endif unsigned so_keepalive:2; unsigned proxy_protocol:1; #if (NGX_HAVE_KEEPALIVE_TUNABLE) @@ -73,9 +69,7 @@ typedef struct { typedef struct { ngx_stream_conf_ctx_t *ctx; ngx_str_t addr_text; -#if (NGX_STREAM_SSL) unsigned ssl:1; -#endif unsigned proxy_protocol:1; } ngx_stream_addr_conf_t; @@ -115,17 +109,47 @@ typedef struct { } ngx_stream_conf_addr_t; -typedef ngx_int_t (*ngx_stream_access_pt)(ngx_stream_session_t *s); +typedef enum { + NGX_STREAM_POST_ACCEPT_PHASE = 0, + NGX_STREAM_PREACCESS_PHASE, + NGX_STREAM_ACCESS_PHASE, + NGX_STREAM_SSL_PHASE, + NGX_STREAM_PREREAD_PHASE, + NGX_STREAM_CONTENT_PHASE, + NGX_STREAM_LOG_PHASE +} ngx_stream_phases; + + +typedef struct ngx_stream_phase_handler_s ngx_stream_phase_handler_t; + +typedef ngx_int_t (*ngx_stream_phase_handler_pt)(ngx_stream_session_t *s, + ngx_stream_phase_handler_t *ph); +typedef ngx_int_t (*ngx_stream_handler_pt)(ngx_stream_session_t *s); +typedef void (*ngx_stream_content_handler_pt)(ngx_stream_session_t *s); + + +struct ngx_stream_phase_handler_s { + ngx_stream_phase_handler_pt checker; + ngx_stream_handler_pt handler; + ngx_uint_t next; +}; + + +typedef struct { + ngx_stream_phase_handler_t *handlers; +} ngx_stream_phase_engine_t; + + +typedef struct { + ngx_array_t handlers; +} ngx_stream_phase_t; typedef struct { ngx_array_t servers; /* ngx_stream_core_srv_conf_t */ ngx_array_t listen; /* ngx_stream_listen_t */ - ngx_stream_access_pt realip_handler; - ngx_stream_access_pt limit_conn_handler; - ngx_stream_access_pt access_handler; - ngx_stream_access_pt access_log_handler; + ngx_stream_phase_engine_t phase_engine; ngx_hash_t variables_hash; @@ -136,14 +160,13 @@ typedef struct { ngx_uint_t variables_hash_bucket_size; ngx_hash_keys_arrays_t *variables_keys; + + ngx_stream_phase_t phases[NGX_STREAM_LOG_PHASE + 1]; } ngx_stream_core_main_conf_t; -typedef void (*ngx_stream_handler_pt)(ngx_stream_session_t *s); - - typedef struct { - ngx_stream_handler_pt handler; + ngx_stream_content_handler_pt handler; ngx_stream_conf_ctx_t *ctx; @@ -151,6 +174,8 @@ typedef struct { ngx_uint_t line; ngx_flag_t tcp_nodelay; + size_t preread_buffer_size; + ngx_msec_t preread_timeout; ngx_log_t *error_log; @@ -189,11 +214,14 @@ struct ngx_stream_session_s { u_char *captures_data; #endif + ngx_int_t phase_handler; ngx_uint_t status; -#if (NGX_STREAM_SSL) - ngx_uint_t ssl; /* unsigned ssl:1; */ -#endif + unsigned ssl:1; + + unsigned stat_processing:1; + + unsigned health_check:1; }; @@ -243,7 +271,20 @@ typedef struct { NULL) +#define NGX_STREAM_WRITE_BUFFERED 0x10 + + +void ngx_stream_core_run_phases(ngx_stream_session_t *s); +ngx_int_t ngx_stream_core_generic_phase(ngx_stream_session_t *s, + ngx_stream_phase_handler_t *ph); +ngx_int_t ngx_stream_core_preread_phase(ngx_stream_session_t *s, + ngx_stream_phase_handler_t *ph); +ngx_int_t ngx_stream_core_content_phase(ngx_stream_session_t *s, + ngx_stream_phase_handler_t *ph); + + void ngx_stream_init_connection(ngx_connection_t *c); +void ngx_stream_session_handler(ngx_event_t *rev); void ngx_stream_finalize_session(ngx_stream_session_t *s, ngx_uint_t rc); @@ -252,4 +293,11 @@ extern ngx_uint_t ngx_stream_max_module; extern ngx_module_t ngx_stream_core_module; +typedef ngx_int_t (*ngx_stream_filter_pt)(ngx_stream_session_t *s, + ngx_chain_t *chain, ngx_uint_t from_upstream); + + +extern ngx_stream_filter_pt ngx_stream_top_filter; + + #endif /* _NGX_STREAM_H_INCLUDED_ */ diff --git a/src/stream/ngx_stream_access_module.c b/src/stream/ngx_stream_access_module.c index 6985d36..1745cdf 100644 --- a/src/stream/ngx_stream_access_module.c +++ b/src/stream/ngx_stream_access_module.c @@ -275,7 +275,7 @@ ngx_stream_access_found(ngx_stream_session_t *s, ngx_uint_t deny) if (deny) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "access forbidden by rule"); - return NGX_ABORT; + return NGX_STREAM_FORBIDDEN; } return NGX_OK; @@ -443,10 +443,17 @@ ngx_stream_access_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) static ngx_int_t ngx_stream_access_init(ngx_conf_t *cf) { + ngx_stream_handler_pt *h; ngx_stream_core_main_conf_t *cmcf; cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); - cmcf->access_handler = ngx_stream_access_handler; + + h = ngx_array_push(&cmcf->phases[NGX_STREAM_ACCESS_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_stream_access_handler; return NGX_OK; } diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c index 1c808ad..f7870ee 100644 --- a/src/stream/ngx_stream_core_module.c +++ b/src/stream/ngx_stream_core_module.c @@ -91,6 +91,20 @@ static ngx_command_t ngx_stream_core_commands[] = { offsetof(ngx_stream_core_srv_conf_t, tcp_nodelay), NULL }, + { ngx_string("preread_buffer_size"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_core_srv_conf_t, preread_buffer_size), + NULL }, + + { ngx_string("preread_timeout"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_core_srv_conf_t, preread_timeout), + NULL }, + ngx_null_command }; @@ -123,6 +137,214 @@ ngx_module_t ngx_stream_core_module = { }; +void +ngx_stream_core_run_phases(ngx_stream_session_t *s) +{ + ngx_int_t rc; + ngx_stream_phase_handler_t *ph; + ngx_stream_core_main_conf_t *cmcf; + + cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); + + ph = cmcf->phase_engine.handlers; + + while (ph[s->phase_handler].checker) { + + rc = ph[s->phase_handler].checker(s, &ph[s->phase_handler]); + + if (rc == NGX_OK) { + return; + } + } +} + + +ngx_int_t +ngx_stream_core_generic_phase(ngx_stream_session_t *s, + ngx_stream_phase_handler_t *ph) +{ + ngx_int_t rc; + + /* + * generic phase checker, + * used by all phases, except for preread and content + */ + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "generic phase: %ui", s->phase_handler); + + rc = ph->handler(s); + + if (rc == NGX_OK) { + s->phase_handler = ph->next; + return NGX_AGAIN; + } + + if (rc == NGX_DECLINED) { + s->phase_handler++; + return NGX_AGAIN; + } + + if (rc == NGX_AGAIN || rc == NGX_DONE) { + return NGX_OK; + } + + if (rc == NGX_ERROR) { + rc = NGX_STREAM_INTERNAL_SERVER_ERROR; + } + + ngx_stream_finalize_session(s, rc); + + return NGX_OK; +} + + +ngx_int_t +ngx_stream_core_preread_phase(ngx_stream_session_t *s, + ngx_stream_phase_handler_t *ph) +{ + size_t size; + ssize_t n; + ngx_int_t rc; + ngx_connection_t *c; + ngx_stream_core_srv_conf_t *cscf; + + c = s->connection; + + c->log->action = "prereading client data"; + + cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); + + if (c->read->timedout) { + rc = NGX_STREAM_OK; + + } else if (c->read->timer_set) { + rc = NGX_AGAIN; + + } else { + rc = ph->handler(s); + } + + while (rc == NGX_AGAIN) { + + if (c->buffer == NULL) { + c->buffer = ngx_create_temp_buf(c->pool, cscf->preread_buffer_size); + if (c->buffer == NULL) { + rc = NGX_ERROR; + break; + } + } + + size = c->buffer->end - c->buffer->last; + + if (size == 0) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, "preread buffer full"); + rc = NGX_STREAM_BAD_REQUEST; + break; + } + + if (c->read->eof) { + rc = NGX_STREAM_OK; + break; + } + + if (!c->read->ready) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + rc = NGX_ERROR; + break; + } + + if (!c->read->timer_set) { + ngx_add_timer(c->read, cscf->preread_timeout); + } + + c->read->handler = ngx_stream_session_handler; + + return NGX_OK; + } + + n = c->recv(c, c->buffer->last, size); + + if (n == NGX_ERROR) { + rc = NGX_STREAM_OK; + break; + } + + if (n > 0) { + c->buffer->last += n; + } + + rc = ph->handler(s); + } + + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + if (rc == NGX_OK) { + s->phase_handler = ph->next; + return NGX_AGAIN; + } + + if (rc == NGX_DECLINED) { + s->phase_handler++; + return NGX_AGAIN; + } + + if (rc == NGX_DONE) { + return NGX_OK; + } + + if (rc == NGX_ERROR) { + rc = NGX_STREAM_INTERNAL_SERVER_ERROR; + } + + ngx_stream_finalize_session(s, rc); + + return NGX_OK; +} + + +ngx_int_t +ngx_stream_core_content_phase(ngx_stream_session_t *s, + ngx_stream_phase_handler_t *ph) +{ + int tcp_nodelay; + ngx_connection_t *c; + ngx_stream_core_srv_conf_t *cscf; + + c = s->connection; + + c->log->action = NULL; + + cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); + + if (c->type == SOCK_STREAM + && cscf->tcp_nodelay + && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) + { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "tcp_nodelay"); + + tcp_nodelay = 1; + + if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, + (const void *) &tcp_nodelay, sizeof(int)) == -1) + { + ngx_connection_error(c, ngx_socket_errno, + "setsockopt(TCP_NODELAY) failed"); + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return NGX_OK; + } + + c->tcp_nodelay = NGX_TCP_NODELAY_SET; + } + + cscf->handler(s); + + return NGX_OK; +} + + static ngx_int_t ngx_stream_core_preconfiguration(ngx_conf_t *cf) { @@ -201,6 +423,8 @@ ngx_stream_core_create_srv_conf(ngx_conf_t *cf) cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; cscf->proxy_protocol_timeout = NGX_CONF_UNSET_MSEC; cscf->tcp_nodelay = NGX_CONF_UNSET; + cscf->preread_buffer_size = NGX_CONF_UNSET_SIZE; + cscf->preread_timeout = NGX_CONF_UNSET_MSEC; return cscf; } @@ -253,6 +477,12 @@ ngx_stream_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->tcp_nodelay, prev->tcp_nodelay, 1); + ngx_conf_merge_size_value(conf->preread_buffer_size, + prev->preread_buffer_size, 16384); + + ngx_conf_merge_msec_value(conf->preread_timeout, + prev->preread_timeout, 30000); + return NGX_CONF_OK; } @@ -394,7 +624,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ls->wildcard = u.wildcard; ls->ctx = cf->ctx; -#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) +#if (NGX_HAVE_INET6) ls->ipv6only = 1; #endif diff --git a/src/stream/ngx_stream_handler.c b/src/stream/ngx_stream_handler.c index 6e2ed82..669b6a1 100644 --- a/src/stream/ngx_stream_handler.c +++ b/src/stream/ngx_stream_handler.c @@ -11,15 +11,10 @@ #include +static void ngx_stream_log_session(ngx_stream_session_t *s); static void ngx_stream_close_connection(ngx_connection_t *c); static u_char *ngx_stream_log_error(ngx_log_t *log, u_char *buf, size_t len); static void ngx_stream_proxy_protocol_handler(ngx_event_t *rev); -static void ngx_stream_init_session_handler(ngx_event_t *rev); - -#if (NGX_STREAM_SSL) -static void ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c); -static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c); -#endif void @@ -134,6 +129,10 @@ ngx_stream_init_connection(ngx_connection_t *c) s->ssl = addr_conf->ssl; #endif + if (c->buffer) { + s->received += c->buffer->last - c->buffer->pos; + } + s->connection = c; c->data = s; @@ -150,7 +149,7 @@ ngx_stream_init_connection(ngx_connection_t *c) c->log->connection = c->number; c->log->handler = ngx_stream_log_error; c->log->data = s; - c->log->action = "initializing connection"; + c->log->action = "initializing session"; c->log_error = NGX_ERROR_INFO; s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_stream_max_module); @@ -175,7 +174,7 @@ ngx_stream_init_connection(ngx_connection_t *c) s->start_msec = tp->msec; rev = c->read; - rev->handler = ngx_stream_init_session_handler; + rev->handler = ngx_stream_session_handler; if (addr_conf->proxy_protocol) { c->log->action = "reading PROXY protocol"; @@ -275,192 +274,57 @@ ngx_stream_proxy_protocol_handler(ngx_event_t *rev) return; } - ngx_stream_init_session_handler(rev); + c->log->action = "initializing session"; + + ngx_stream_session_handler(rev); } -static void -ngx_stream_init_session_handler(ngx_event_t *rev) +void +ngx_stream_session_handler(ngx_event_t *rev) { - int tcp_nodelay; - ngx_int_t rc; - ngx_connection_t *c; - ngx_stream_session_t *s; - ngx_stream_core_srv_conf_t *cscf; - ngx_stream_core_main_conf_t *cmcf; + ngx_connection_t *c; + ngx_stream_session_t *s; c = rev->data; s = c->data; - c->log->action = "initializing session"; - - cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); - - if (cmcf->realip_handler) { - rc = cmcf->realip_handler(s); - - if (rc == NGX_ERROR) { - ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - } - - if (cmcf->limit_conn_handler) { - rc = cmcf->limit_conn_handler(s); - - if (rc == NGX_ERROR) { - ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - if (rc == NGX_ABORT) { - ngx_stream_finalize_session(s, NGX_STREAM_SERVICE_UNAVAILABLE); - return; - } - } - - if (cmcf->access_handler) { - rc = cmcf->access_handler(s); - - if (rc == NGX_ERROR) { - ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - if (rc == NGX_ABORT) { - ngx_stream_finalize_session(s, NGX_STREAM_FORBIDDEN); - return; - } - } - - cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); - - if (c->type == SOCK_STREAM - && cscf->tcp_nodelay - && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) - { - ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "tcp_nodelay"); - - tcp_nodelay = 1; - - if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, - (const void *) &tcp_nodelay, sizeof(int)) == -1) - { - ngx_connection_error(c, ngx_socket_errno, - "setsockopt(TCP_NODELAY) failed"); - ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - c->tcp_nodelay = NGX_TCP_NODELAY_SET; - } - - -#if (NGX_STREAM_SSL) - { - ngx_stream_ssl_conf_t *sslcf; - - sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); - - if (s->ssl) { - c->log->action = "SSL handshaking"; - - if (sslcf->ssl.ctx == NULL) { - ngx_log_error(NGX_LOG_ERR, c->log, 0, - "no \"ssl_certificate\" is defined " - "in server listening on SSL port"); - ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - ngx_stream_ssl_init_connection(&sslcf->ssl, c); - return; - } - } -#endif - - c->log->action = "handling client connection"; - - cscf->handler(s); + ngx_stream_core_run_phases(s); } -#if (NGX_STREAM_SSL) - -static void -ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c) -{ - ngx_stream_session_t *s; - ngx_stream_ssl_conf_t *sslcf; - - s = c->data; - - if (ngx_ssl_create_connection(ssl, c, 0) == NGX_ERROR) { - ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - if (ngx_ssl_handshake(c) == NGX_AGAIN) { - sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); - - ngx_add_timer(c->read, sslcf->handshake_timeout); - - c->ssl->handler = ngx_stream_ssl_handshake_handler; - - return; - } - - ngx_stream_ssl_handshake_handler(c); -} - - -static void -ngx_stream_ssl_handshake_handler(ngx_connection_t *c) -{ - ngx_stream_session_t *s; - ngx_stream_core_srv_conf_t *cscf; - - if (!c->ssl->handshaked) { - ngx_stream_finalize_session(c->data, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - if (c->read->timer_set) { - ngx_del_timer(c->read); - } - - c->log->action = "handling client connection"; - - s = c->data; - - cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); - - cscf->handler(s); -} - -#endif - - void ngx_stream_finalize_session(ngx_stream_session_t *s, ngx_uint_t rc) { - ngx_stream_core_main_conf_t *cmcf; - ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "finalize stream session: %i", rc); s->status = rc; - cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); - - if (cmcf->access_log_handler) { - (void) cmcf->access_log_handler(s); - } + ngx_stream_log_session(s); ngx_stream_close_connection(s->connection); } +static void +ngx_stream_log_session(ngx_stream_session_t *s) +{ + ngx_uint_t i, n; + ngx_stream_handler_pt *log_handler; + ngx_stream_core_main_conf_t *cmcf; + + cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); + + log_handler = cmcf->phases[NGX_STREAM_LOG_PHASE].handlers.elts; + n = cmcf->phases[NGX_STREAM_LOG_PHASE].handlers.nelts; + + for (i = 0; i < n; i++) { + log_handler[i](s); + } +} + + static void ngx_stream_close_connection(ngx_connection_t *c) { diff --git a/src/stream/ngx_stream_limit_conn_module.c b/src/stream/ngx_stream_limit_conn_module.c index 40eca94..b64a426 100644 --- a/src/stream/ngx_stream_limit_conn_module.c +++ b/src/stream/ngx_stream_limit_conn_module.c @@ -178,7 +178,7 @@ ngx_stream_limit_conn_handler(ngx_stream_session_t *s) if (node == NULL) { ngx_shmtx_unlock(&shpool->mutex); ngx_stream_limit_conn_cleanup_all(s->connection->pool); - return NGX_ABORT; + return NGX_STREAM_SERVICE_UNAVAILABLE; } lc = (ngx_stream_limit_conn_node_t *) &node->color; @@ -203,7 +203,7 @@ ngx_stream_limit_conn_handler(ngx_stream_session_t *s) &limits[i].shm_zone->shm.name); ngx_stream_limit_conn_cleanup_all(s->connection->pool); - return NGX_ABORT; + return NGX_STREAM_SERVICE_UNAVAILABLE; } lc->conn++; @@ -630,11 +630,17 @@ ngx_stream_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) static ngx_int_t ngx_stream_limit_conn_init(ngx_conf_t *cf) { + ngx_stream_handler_pt *h; ngx_stream_core_main_conf_t *cmcf; cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); - cmcf->limit_conn_handler = ngx_stream_limit_conn_handler; + h = ngx_array_push(&cmcf->phases[NGX_STREAM_PREACCESS_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_stream_limit_conn_handler; return NGX_OK; } diff --git a/src/stream/ngx_stream_log_module.c b/src/stream/ngx_stream_log_module.c index 4affbdf..26e6d22 100644 --- a/src/stream/ngx_stream_log_module.c +++ b/src/stream/ngx_stream_log_module.c @@ -1464,11 +1464,17 @@ ngx_stream_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) static ngx_int_t ngx_stream_log_init(ngx_conf_t *cf) { + ngx_stream_handler_pt *h; ngx_stream_core_main_conf_t *cmcf; cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); - cmcf->access_log_handler = ngx_stream_log_handler; + h = ngx_array_push(&cmcf->phases[NGX_STREAM_LOG_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_stream_log_handler; return NGX_OK; } diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index ed802e7..4231f97 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -84,10 +84,10 @@ static char *ngx_stream_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_stream_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static ngx_int_t ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s); #if (NGX_STREAM_SSL) +static ngx_int_t ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s); static char *ngx_stream_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s); @@ -385,8 +385,6 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) } u->peer.type = c->type; - - u->proxy_protocol = pscf->proxy_protocol; u->start_sec = ngx_time(); c->write->handler = ngx_stream_proxy_downstream_handler; @@ -411,28 +409,6 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) u->downstream_buf.pos = p; u->downstream_buf.last = p; - if (u->proxy_protocol -#if (NGX_STREAM_SSL) - && pscf->ssl == NULL -#endif - && pscf->buffer_size >= NGX_PROXY_PROTOCOL_MAX_HEADER) - { - /* optimization for a typical case */ - - ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, - "stream proxy send PROXY protocol header"); - - p = ngx_proxy_protocol_write(c, u->downstream_buf.last, - u->downstream_buf.end); - if (p == NULL) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - u->downstream_buf.last = p; - u->proxy_protocol = 0; - } - if (c->read->ready) { ngx_post_event(c->read, &ngx_posted_events); } @@ -545,6 +521,8 @@ found: return; } + u->upstream = uscf; + #if (NGX_STREAM_SSL) u->ssl_name = uscf->host; #endif @@ -682,8 +660,13 @@ ngx_stream_proxy_connect(ngx_stream_session_t *s) c->log->action = "connecting to upstream"; + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + u = s->upstream; + u->connected = 0; + u->proxy_protocol = pscf->proxy_protocol; + if (u->state) { u->state->response_time = ngx_current_msec - u->state->response_time; } @@ -740,8 +723,6 @@ ngx_stream_proxy_connect(ngx_stream_session_t *s) pc->read->handler = ngx_stream_proxy_connect_handler; pc->write->handler = ngx_stream_proxy_connect_handler; - pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); - ngx_add_timer(pc->write, pscf->connect_timeout); } @@ -751,6 +732,7 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) { int tcp_nodelay; u_char *p; + ngx_chain_t *cl; ngx_connection_t *c, *pc; ngx_log_handler_pt handler; ngx_stream_upstream_t *u; @@ -782,21 +764,26 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) pc->tcp_nodelay = NGX_TCP_NODELAY_SET; } - if (u->proxy_protocol) { - if (ngx_stream_proxy_send_proxy_protocol(s) != NGX_OK) { - return; - } - - u->proxy_protocol = 0; - } - pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); #if (NGX_STREAM_SSL) - if (pc->type == SOCK_STREAM && pscf->ssl && pc->ssl == NULL) { - ngx_stream_proxy_ssl_init_connection(s); - return; + + if (pc->type == SOCK_STREAM && pscf->ssl) { + + if (u->proxy_protocol) { + if (ngx_stream_proxy_send_proxy_protocol(s) != NGX_OK) { + return; + } + + u->proxy_protocol = 0; + } + + if (pc->ssl == NULL) { + ngx_stream_proxy_ssl_init_connection(s); + return; + } } + #endif c = s->connection; @@ -838,14 +825,66 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) u->upstream_buf.last = p; } - if (c->type == SOCK_DGRAM) { - s->received = c->buffer->last - c->buffer->pos; - u->downstream_buf = *c->buffer; + if (c->buffer && c->buffer->pos < c->buffer->last) { + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream proxy add preread buffer: %uz", + c->buffer->last - c->buffer->pos); - if (pscf->responses == 0) { - pc->read->ready = 0; - pc->read->eof = 1; + cl = ngx_chain_get_free_buf(c->pool, &u->free); + if (cl == NULL) { + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; } + + *cl->buf = *c->buffer; + + cl->buf->tag = (ngx_buf_tag_t) &ngx_stream_proxy_module; + cl->buf->flush = 1; + cl->buf->last_buf = (c->type == SOCK_DGRAM); + + cl->next = u->upstream_out; + u->upstream_out = cl; + } + + if (u->proxy_protocol) { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream proxy add PROXY protocol header"); + + cl = ngx_chain_get_free_buf(c->pool, &u->free); + if (cl == NULL) { + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + + p = ngx_pnalloc(c->pool, NGX_PROXY_PROTOCOL_MAX_HEADER); + if (p == NULL) { + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + + cl->buf->pos = p; + + p = ngx_proxy_protocol_write(c, p, p + NGX_PROXY_PROTOCOL_MAX_HEADER); + if (p == NULL) { + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + + cl->buf->last = p; + cl->buf->temporary = 1; + cl->buf->flush = 0; + cl->buf->last_buf = 0; + cl->buf->tag = (ngx_buf_tag_t) &ngx_stream_proxy_module; + + cl->next = u->upstream_out; + u->upstream_out = cl; + + u->proxy_protocol = 0; + } + + if (c->type == SOCK_DGRAM && pscf->responses == 0) { + pc->read->ready = 0; + pc->read->eof = 1; } u->connected = 1; @@ -861,6 +900,8 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) } +#if (NGX_STREAM_SSL) + static ngx_int_t ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s) { @@ -931,8 +972,6 @@ ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s) } -#if (NGX_STREAM_SSL) - static char * ngx_stream_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) @@ -1412,8 +1451,10 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, size_t size, limit_rate; ssize_t n; ngx_buf_t *b; + ngx_int_t rc; ngx_uint_t flags; ngx_msec_t delay; + ngx_chain_t *cl, **ll, **out, **busy; ngx_connection_t *c, *pc, *src, *dst; ngx_log_handler_pt handler; ngx_stream_upstream_t *u; @@ -1447,6 +1488,8 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, b = &u->upstream_buf; limit_rate = pscf->download_rate; received = &u->received; + out = &u->downstream_out; + busy = &u->downstream_busy; } else { src = c; @@ -1454,24 +1497,18 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, b = &u->downstream_buf; limit_rate = pscf->upload_rate; received = &s->received; + out = &u->upstream_out; + busy = &u->upstream_busy; } for ( ;; ) { - if (do_write) { + if (do_write && dst) { - size = b->last - b->pos; + if (*out || *busy || dst->buffered) { + rc = ngx_stream_top_filter(s, *out, from_upstream); - if (size && dst && dst->write->ready) { - - n = dst->send(dst, b->pos, size); - - if (n == NGX_AGAIN && dst->shared) { - /* cannot wait on a shared socket */ - n = NGX_ERROR; - } - - if (n == NGX_ERROR) { + if (rc == NGX_ERROR) { if (c->type == SOCK_DGRAM && !from_upstream) { ngx_stream_proxy_next_upstream(s); return; @@ -1481,13 +1518,12 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, return; } - if (n > 0) { - b->pos += n; + ngx_chain_update_chains(c->pool, &u->free, busy, out, + (ngx_buf_tag_t) &ngx_stream_proxy_module); - if (b->pos == b->last) { - b->pos = b->start; - b->last = b->start; - } + if (*busy == NULL) { + b->pos = b->start; + b->last = b->start; } } } @@ -1514,11 +1550,21 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, n = src->recv(src, b->last, size); - if (n == NGX_AGAIN || n == 0) { + if (n == NGX_AGAIN) { break; } - if (n > 0) { + if (n == NGX_ERROR) { + if (c->type == SOCK_DGRAM && u->received == 0) { + ngx_stream_proxy_next_upstream(s); + return; + } + + src->read->eof = 1; + n = 0; + } + + if (n >= 0) { if (limit_rate) { delay = (ngx_msec_t) (n * 1000 / limit_rate); @@ -1541,27 +1587,37 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, src->read->eof = 1; } + for (ll = out; *ll; ll = &(*ll)->next) { /* void */ } + + cl = ngx_chain_get_free_buf(c->pool, &u->free); + if (cl == NULL) { + ngx_stream_proxy_finalize(s, + NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + + *ll = cl; + + cl->buf->pos = b->last; + cl->buf->last = b->last + n; + cl->buf->tag = (ngx_buf_tag_t) &ngx_stream_proxy_module; + + cl->buf->temporary = (n ? 1 : 0); + cl->buf->last_buf = src->read->eof; + cl->buf->flush = 1; + *received += n; b->last += n; do_write = 1; continue; } - - if (n == NGX_ERROR) { - if (c->type == SOCK_DGRAM && u->received == 0) { - ngx_stream_proxy_next_upstream(s); - return; - } - - src->read->eof = 1; - } } break; } - if (src->read->eof && (b->pos == b->last || (dst && dst->read->eof))) { + if (src->read->eof && dst && (dst->read->eof || !dst->buffered)) { handler = c->log->handler; c->log->handler = NULL; @@ -1614,6 +1670,14 @@ ngx_stream_proxy_next_upstream(ngx_stream_session_t *s) "stream proxy next upstream"); u = s->upstream; + pc = u->peer.connection; + + if (u->upstream_out || u->upstream_busy || (pc && pc->buffered)) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "pending buffers on next upstream"); + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } if (u->peer.sockaddr) { u->peer.free(&u->peer, u->peer.data, NGX_PEER_FAILED); @@ -1632,8 +1696,6 @@ ngx_stream_proxy_next_upstream(ngx_stream_session_t *s) return; } - pc = u->peer.connection; - if (pc) { ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "close proxy upstream connection: %d", pc->fd); diff --git a/src/stream/ngx_stream_realip_module.c b/src/stream/ngx_stream_realip_module.c index 8ce05a0..0740431 100644 --- a/src/stream/ngx_stream_realip_module.c +++ b/src/stream/ngx_stream_realip_module.c @@ -279,11 +279,17 @@ ngx_stream_realip_add_variables(ngx_conf_t *cf) static ngx_int_t ngx_stream_realip_init(ngx_conf_t *cf) { + ngx_stream_handler_pt *h; ngx_stream_core_main_conf_t *cmcf; cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); - cmcf->realip_handler = ngx_stream_realip_handler; + h = ngx_array_push(&cmcf->phases[NGX_STREAM_POST_ACCEPT_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_stream_realip_handler; return NGX_OK; } diff --git a/src/stream/ngx_stream_return_module.c b/src/stream/ngx_stream_return_module.c index c22087f..9301b02 100644 --- a/src/stream/ngx_stream_return_module.c +++ b/src/stream/ngx_stream_return_module.c @@ -11,12 +11,12 @@ typedef struct { - ngx_stream_complex_value_t text; + ngx_stream_complex_value_t text; } ngx_stream_return_srv_conf_t; typedef struct { - ngx_buf_t buf; + ngx_chain_t *out; } ngx_stream_return_ctx_t; @@ -72,6 +72,7 @@ static void ngx_stream_return_handler(ngx_stream_session_t *s) { ngx_str_t text; + ngx_buf_t *b; ngx_connection_t *c; ngx_stream_return_ctx_t *ctx; ngx_stream_return_srv_conf_t *rscf; @@ -103,8 +104,25 @@ ngx_stream_return_handler(ngx_stream_session_t *s) ngx_stream_set_ctx(s, ctx, ngx_stream_return_module); - ctx->buf.pos = text.data; - ctx->buf.last = text.data + text.len; + b = ngx_calloc_buf(c->pool); + if (b == NULL) { + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + + b->memory = 1; + b->pos = text.data; + b->last = text.data + text.len; + b->last_buf = 1; + + ctx->out = ngx_alloc_chain_link(c->pool); + if (ctx->out == NULL) { + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + + ctx->out->buf = b; + ctx->out->next = NULL; c->write->handler = ngx_stream_return_write_handler; @@ -115,8 +133,6 @@ ngx_stream_return_handler(ngx_stream_session_t *s) static void ngx_stream_return_write_handler(ngx_event_t *ev) { - ssize_t n; - ngx_buf_t *b; ngx_connection_t *c; ngx_stream_session_t *s; ngx_stream_return_ctx_t *ctx; @@ -130,25 +146,20 @@ ngx_stream_return_write_handler(ngx_event_t *ev) return; } - if (ev->ready) { - ctx = ngx_stream_get_module_ctx(s, ngx_stream_return_module); + ctx = ngx_stream_get_module_ctx(s, ngx_stream_return_module); - b = &ctx->buf; + if (ngx_stream_top_filter(s, ctx->out, 1) == NGX_ERROR) { + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } - n = c->send(c, b->pos, b->last - b->pos); - if (n == NGX_ERROR) { - ngx_stream_finalize_session(s, NGX_STREAM_OK); - return; - } + ctx->out = NULL; - if (n > 0) { - b->pos += n; - - if (b->pos == b->last) { - ngx_stream_finalize_session(s, NGX_STREAM_OK); - return; - } - } + if (!c->buffered) { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream return done sending"); + ngx_stream_finalize_session(s, NGX_STREAM_OK); + return; } if (ngx_handle_write_event(ev, 0) != NGX_OK) { diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index 2661220..d00718b 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -18,6 +18,10 @@ typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c, #define NGX_DEFAULT_ECDH_CURVE "auto" +static ngx_int_t ngx_stream_ssl_handler(ngx_stream_session_t *s); +static ngx_int_t ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, + ngx_connection_t *c); +static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c); static ngx_int_t ngx_stream_ssl_static_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_ssl_variable(ngx_stream_session_t *s, @@ -32,6 +36,7 @@ static char *ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static ngx_int_t ngx_stream_ssl_init(ngx_conf_t *cf); static ngx_conf_bitmask_t ngx_stream_ssl_protocols[] = { @@ -143,7 +148,7 @@ static ngx_command_t ngx_stream_ssl_commands[] = { static ngx_stream_module_t ngx_stream_ssl_module_ctx = { ngx_stream_ssl_add_variables, /* preconfiguration */ - NULL, /* postconfiguration */ + ngx_stream_ssl_init, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -193,6 +198,88 @@ static ngx_stream_variable_t ngx_stream_ssl_vars[] = { static ngx_str_t ngx_stream_ssl_sess_id_ctx = ngx_string("STREAM"); +static ngx_int_t +ngx_stream_ssl_handler(ngx_stream_session_t *s) +{ + ngx_connection_t *c; + ngx_stream_ssl_conf_t *sslcf; + + c = s->connection; + + sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); + + if (s->ssl && c->ssl == NULL) { + c->log->action = "SSL handshaking"; + + if (sslcf->ssl.ctx == NULL) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no \"ssl_certificate\" is defined " + "in server listening on SSL port"); + return NGX_ERROR; + } + + return ngx_stream_ssl_init_connection(&sslcf->ssl, c); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c) +{ + ngx_int_t rc; + ngx_stream_session_t *s; + ngx_stream_ssl_conf_t *sslcf; + + s = c->data; + + if (ngx_ssl_create_connection(ssl, c, 0) == NGX_ERROR) { + return NGX_ERROR; + } + + rc = ngx_ssl_handshake(c); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_AGAIN) { + sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); + + ngx_add_timer(c->read, sslcf->handshake_timeout); + + c->ssl->handler = ngx_stream_ssl_handshake_handler; + + return NGX_AGAIN; + } + + /* rc == NGX_OK */ + + return NGX_OK; +} + + +static void +ngx_stream_ssl_handshake_handler(ngx_connection_t *c) +{ + ngx_stream_session_t *s; + + s = c->data; + + if (!c->ssl->handshaked) { + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + ngx_stream_core_run_phases(s); +} + + static ngx_int_t ngx_stream_ssl_static_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) @@ -565,3 +652,22 @@ invalid: return NGX_CONF_ERROR; } + + +static ngx_int_t +ngx_stream_ssl_init(ngx_conf_t *cf) +{ + ngx_stream_handler_pt *h; + ngx_stream_core_main_conf_t *cmcf; + + cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_STREAM_SSL_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_stream_ssl_handler; + + return NGX_OK; +} diff --git a/src/stream/ngx_stream_ssl_preread_module.c b/src/stream/ngx_stream_ssl_preread_module.c new file mode 100644 index 0000000..e26c518 --- /dev/null +++ b/src/stream/ngx_stream_ssl_preread_module.c @@ -0,0 +1,449 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_flag_t enabled; +} ngx_stream_ssl_preread_srv_conf_t; + + +typedef struct { + size_t left; + size_t size; + u_char *pos; + u_char *dst; + u_char buf[4]; + ngx_str_t host; + ngx_log_t *log; + ngx_pool_t *pool; + ngx_uint_t state; +} ngx_stream_ssl_preread_ctx_t; + + +static ngx_int_t ngx_stream_ssl_preread_handler(ngx_stream_session_t *s); +static ngx_int_t ngx_stream_ssl_preread_parse_record( + ngx_stream_ssl_preread_ctx_t *ctx, u_char *pos, u_char *last); +static ngx_int_t ngx_stream_ssl_preread_server_name_variable( + ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf); +static void *ngx_stream_ssl_preread_create_srv_conf(ngx_conf_t *cf); +static char *ngx_stream_ssl_preread_merge_srv_conf(ngx_conf_t *cf, void *parent, + void *child); +static ngx_int_t ngx_stream_ssl_preread_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_stream_ssl_preread_commands[] = { + + { ngx_string("ssl_preread"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_ssl_preread_srv_conf_t, enabled), + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_ssl_preread_module_ctx = { + ngx_stream_ssl_preread_add_variables, /* preconfiguration */ + ngx_stream_ssl_preread_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_stream_ssl_preread_create_srv_conf, /* create server configuration */ + ngx_stream_ssl_preread_merge_srv_conf /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_ssl_preread_module = { + NGX_MODULE_V1, + &ngx_stream_ssl_preread_module_ctx, /* module context */ + ngx_stream_ssl_preread_commands, /* module directives */ + NGX_STREAM_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_stream_variable_t ngx_stream_ssl_preread_vars[] = { + + { ngx_string("ssl_preread_server_name"), NULL, + ngx_stream_ssl_preread_server_name_variable, 0, 0, 0 }, + + { ngx_null_string, NULL, NULL, 0, 0, 0 } +}; + + +static ngx_int_t +ngx_stream_ssl_preread_handler(ngx_stream_session_t *s) +{ + u_char *last, *p; + size_t len; + ngx_int_t rc; + ngx_connection_t *c; + ngx_stream_ssl_preread_ctx_t *ctx; + ngx_stream_ssl_preread_srv_conf_t *sscf; + + c = s->connection; + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "ssl preread handler"); + + sscf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_preread_module); + + if (!sscf->enabled) { + return NGX_DECLINED; + } + + if (c->type != SOCK_STREAM) { + return NGX_DECLINED; + } + + if (c->buffer == NULL) { + return NGX_AGAIN; + } + + ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module); + if (ctx == NULL) { + ctx = ngx_pcalloc(c->pool, sizeof(ngx_stream_ssl_preread_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_stream_set_ctx(s, ctx, ngx_stream_ssl_preread_module); + + ctx->pool = c->pool; + ctx->log = c->log; + ctx->pos = c->buffer->pos; + } + + p = ctx->pos; + last = c->buffer->last; + + while (last - p >= 5) { + + if (p[0] != 0x16) { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, + "ssl preread: not a handshake"); + return NGX_DECLINED; + } + + if (p[1] != 3 || p[2] == 0) { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, + "ssl preread: unsupported SSL version"); + return NGX_DECLINED; + } + + len = (p[3] << 8) + p[4]; + + /* read the whole record before parsing */ + if ((size_t) (last - p) < len + 5) { + break; + } + + p += 5; + + rc = ngx_stream_ssl_preread_parse_record(ctx, p, p + len); + if (rc != NGX_AGAIN) { + return rc; + } + + p += len; + } + + ctx->pos = p; + + return NGX_AGAIN; +} + + +static ngx_int_t +ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx, + u_char *pos, u_char *last) +{ + size_t left, n, size; + u_char *dst, *p; + + enum { + sw_start = 0, + sw_header, /* handshake msg_type, length */ + sw_head_tail, /* version, random */ + sw_sid_len, /* session_id length */ + sw_sid, /* session_id */ + sw_cs_len, /* cipher_suites length */ + sw_cs, /* cipher_suites */ + sw_cm_len, /* compression_methods length */ + sw_cm, /* compression_methods */ + sw_ext, /* extension */ + sw_ext_header, /* extension_type, extension_data length */ + sw_sni_len, /* SNI length */ + sw_sni_host_head, /* SNI name_type, host_name length */ + sw_sni_host /* SNI host_name */ + } state; + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0, + "ssl preread: state %ui left %z", ctx->state, ctx->left); + + state = ctx->state; + size = ctx->size; + left = ctx->left; + dst = ctx->dst; + p = ctx->buf; + + for ( ;; ) { + n = ngx_min((size_t) (last - pos), size); + + if (dst) { + dst = ngx_cpymem(dst, pos, n); + } + + pos += n; + size -= n; + left -= n; + + if (size != 0) { + break; + } + + switch (state) { + + case sw_start: + state = sw_header; + dst = p; + size = 4; + left = size; + break; + + case sw_header: + if (p[0] != 1) { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, + "ssl preread: not a client hello"); + return NGX_DECLINED; + } + + state = sw_head_tail; + dst = NULL; + size = 34; + left = (p[1] << 16) + (p[2] << 8) + p[3]; + break; + + case sw_head_tail: + state = sw_sid_len; + dst = p; + size = 1; + break; + + case sw_sid_len: + state = sw_sid; + dst = NULL; + size = p[0]; + break; + + case sw_sid: + state = sw_cs_len; + dst = p; + size = 2; + break; + + case sw_cs_len: + state = sw_cs; + dst = NULL; + size = (p[0] << 8) + p[1]; + break; + + case sw_cs: + state = sw_cm_len; + dst = p; + size = 1; + break; + + case sw_cm_len: + state = sw_cm; + dst = NULL; + size = p[0]; + break; + + case sw_cm: + if (left == 0) { + /* no extensions */ + return NGX_OK; + } + + state = sw_ext; + dst = p; + size = 2; + break; + + case sw_ext: + if (left == 0) { + return NGX_OK; + } + + state = sw_ext_header; + dst = p; + size = 4; + break; + + case sw_ext_header: + if (p[0] == 0 && p[1] == 0) { + /* SNI extension */ + state = sw_sni_len; + dst = NULL; + size = 2; + break; + } + + state = sw_ext; + dst = NULL; + size = (p[2] << 8) + p[3]; + break; + + case sw_sni_len: + state = sw_sni_host_head; + dst = p; + size = 3; + break; + + case sw_sni_host_head: + if (p[0] != 0) { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, + "ssl preread: SNI hostname type is not DNS"); + return NGX_DECLINED; + } + + state = sw_sni_host; + size = (p[1] << 8) + p[2]; + + ctx->host.data = ngx_pnalloc(ctx->pool, size); + if (ctx->host.data == NULL) { + return NGX_ERROR; + } + + dst = ctx->host.data; + break; + + case sw_sni_host: + ctx->host.len = (p[1] << 8) + p[2]; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0, + "ssl preread: SNI hostname \"%V\"", &ctx->host); + return NGX_OK; + } + + if (left < size) { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, + "ssl preread: failed to parse handshake"); + return NGX_DECLINED; + } + } + + ctx->state = state; + ctx->size = size; + ctx->left = left; + ctx->dst = dst; + + return NGX_AGAIN; +} + + +static ngx_int_t +ngx_stream_ssl_preread_server_name_variable(ngx_stream_session_t *s, + ngx_variable_value_t *v, uintptr_t data) +{ + ngx_stream_ssl_preread_ctx_t *ctx; + + ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module); + + if (ctx == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->len = ctx->host.len; + v->data = ctx->host.data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf) +{ + ngx_stream_variable_t *var, *v; + + for (v = ngx_stream_ssl_preread_vars; v->name.len; v++) { + var = ngx_stream_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = v->get_handler; + var->data = v->data; + } + + return NGX_OK; +} + + +static void * +ngx_stream_ssl_preread_create_srv_conf(ngx_conf_t *cf) +{ + ngx_stream_ssl_preread_srv_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_ssl_preread_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + conf->enabled = NGX_CONF_UNSET; + + return conf; +} + + +static char * +ngx_stream_ssl_preread_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_stream_ssl_preread_srv_conf_t *prev = parent; + ngx_stream_ssl_preread_srv_conf_t *conf = child; + + ngx_conf_merge_value(conf->enabled, prev->enabled, 0); + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_stream_ssl_preread_init(ngx_conf_t *cf) +{ + ngx_stream_handler_pt *h; + ngx_stream_core_main_conf_t *cmcf; + + cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_STREAM_PREREAD_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_stream_ssl_preread_handler; + + return NGX_OK; +} diff --git a/src/stream/ngx_stream_upstream.c b/src/stream/ngx_stream_upstream.c index 0c59780..c9e1784 100644 --- a/src/stream/ngx_stream_upstream.c +++ b/src/stream/ngx_stream_upstream.c @@ -322,6 +322,7 @@ ngx_stream_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) uscf = ngx_stream_upstream_add(cf, &u, NGX_STREAM_UPSTREAM_CREATE |NGX_STREAM_UPSTREAM_WEIGHT + |NGX_STREAM_UPSTREAM_MAX_CONNS |NGX_STREAM_UPSTREAM_MAX_FAILS |NGX_STREAM_UPSTREAM_FAIL_TIMEOUT |NGX_STREAM_UPSTREAM_DOWN @@ -407,7 +408,7 @@ ngx_stream_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) time_t fail_timeout; ngx_str_t *value, s; ngx_url_t u; - ngx_int_t weight, max_fails; + ngx_int_t weight, max_conns, max_fails; ngx_uint_t i; ngx_stream_upstream_server_t *us; @@ -421,6 +422,7 @@ ngx_stream_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) value = cf->args->elts; weight = 1; + max_conns = 0; max_fails = 1; fail_timeout = 10; @@ -441,6 +443,21 @@ ngx_stream_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } + if (ngx_strncmp(value[i].data, "max_conns=", 10) == 0) { + + if (!(uscf->flags & NGX_STREAM_UPSTREAM_MAX_CONNS)) { + goto not_supported; + } + + max_conns = ngx_atoi(&value[i].data[10], value[i].len - 10); + + if (max_conns == NGX_ERROR) { + goto invalid; + } + + continue; + } + if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) { if (!(uscf->flags & NGX_STREAM_UPSTREAM_MAX_FAILS)) { @@ -522,6 +539,7 @@ ngx_stream_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) us->addrs = u.addrs; us->naddrs = u.naddrs; us->weight = weight; + us->max_conns = max_conns; us->max_fails = max_fails; us->fail_timeout = fail_timeout; @@ -586,14 +604,14 @@ ngx_stream_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags) } if ((uscfp[i]->flags & NGX_STREAM_UPSTREAM_CREATE) && !u->no_port) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "upstream \"%V\" may not have port %d", &u->host, u->port); return NULL; } if ((flags & NGX_STREAM_UPSTREAM_CREATE) && !uscfp[i]->no_port) { - ngx_log_error(NGX_LOG_WARN, cf->log, 0, + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "upstream \"%V\" may not have port %d in %s:%ui", &u->host, uscfp[i]->port, uscfp[i]->file_name, uscfp[i]->line); diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h index f83b5ba..764a340 100644 --- a/src/stream/ngx_stream_upstream.h +++ b/src/stream/ngx_stream_upstream.h @@ -21,6 +21,7 @@ #define NGX_STREAM_UPSTREAM_FAIL_TIMEOUT 0x0008 #define NGX_STREAM_UPSTREAM_DOWN 0x0010 #define NGX_STREAM_UPSTREAM_BACKUP 0x0020 +#define NGX_STREAM_UPSTREAM_MAX_CONNS 0x0100 typedef struct { @@ -50,11 +51,16 @@ typedef struct { ngx_addr_t *addrs; ngx_uint_t naddrs; ngx_uint_t weight; + ngx_uint_t max_conns; ngx_uint_t max_fails; time_t fail_timeout; + ngx_msec_t slow_start; unsigned down:1; unsigned backup:1; + + NGX_COMPAT_BEGIN(4) + NGX_COMPAT_END } ngx_stream_upstream_server_t; @@ -106,14 +112,23 @@ typedef struct { typedef struct { ngx_peer_connection_t peer; + ngx_buf_t downstream_buf; ngx_buf_t upstream_buf; + + ngx_chain_t *free; + ngx_chain_t *upstream_out; + ngx_chain_t *upstream_busy; + ngx_chain_t *downstream_out; + ngx_chain_t *downstream_busy; + off_t received; time_t start_sec; ngx_uint_t responses; -#if (NGX_STREAM_SSL) + ngx_str_t ssl_name; -#endif + + ngx_stream_upstream_srv_conf_t *upstream; ngx_stream_upstream_resolved_t *resolved; ngx_stream_upstream_state_t *state; unsigned connected:1; diff --git a/src/stream/ngx_stream_upstream_hash_module.c b/src/stream/ngx_stream_upstream_hash_module.c index 88185eb..cb44fcd 100644 --- a/src/stream/ngx_stream_upstream_hash_module.c +++ b/src/stream/ngx_stream_upstream_hash_module.c @@ -241,6 +241,10 @@ ngx_stream_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) goto next; } + if (peer->max_conns && peer->conns >= peer->max_conns) { + goto next; + } + break; next: @@ -524,7 +528,6 @@ ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) peer; peer = peer->next, i++) { - n = i / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); @@ -550,6 +553,10 @@ ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) continue; } + if (peer->max_conns && peer->conns >= peer->max_conns) { + continue; + } + peer->current_weight += peer->effective_weight; total += peer->effective_weight; @@ -572,6 +579,7 @@ ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) hp->tries++; if (hp->tries >= points->number) { + pc->name = hp->rrp.peers->name; ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers); return NGX_BUSY; } @@ -646,6 +654,7 @@ ngx_stream_upstream_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) uscf->flags = NGX_STREAM_UPSTREAM_CREATE |NGX_STREAM_UPSTREAM_WEIGHT + |NGX_STREAM_UPSTREAM_MAX_CONNS |NGX_STREAM_UPSTREAM_MAX_FAILS |NGX_STREAM_UPSTREAM_FAIL_TIMEOUT |NGX_STREAM_UPSTREAM_DOWN; diff --git a/src/stream/ngx_stream_upstream_least_conn_module.c b/src/stream/ngx_stream_upstream_least_conn_module.c index e884975..739b20a 100644 --- a/src/stream/ngx_stream_upstream_least_conn_module.c +++ b/src/stream/ngx_stream_upstream_least_conn_module.c @@ -132,7 +132,6 @@ ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) peer; peer = peer->next, i++) { - n = i / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); @@ -151,6 +150,10 @@ ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) continue; } + if (peer->max_conns && peer->conns >= peer->max_conns) { + continue; + } + /* * select peer with least number of connections; if there are * multiple peers with the same number of connections, select @@ -206,6 +209,10 @@ ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) continue; } + if (peer->max_conns && peer->conns >= peer->max_conns) { + continue; + } + peer->current_weight += peer->effective_weight; total += peer->effective_weight; @@ -269,12 +276,6 @@ failed: ngx_stream_upstream_rr_peers_wlock(peers); } - /* all peers failed, mark them as live for quick recovery */ - - for (peer = peers->peer; peer; peer = peer->next) { - peer->fails = 0; - } - ngx_stream_upstream_rr_peers_unlock(peers); pc->name = peers->name; @@ -299,6 +300,7 @@ ngx_stream_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) uscf->flags = NGX_STREAM_UPSTREAM_CREATE |NGX_STREAM_UPSTREAM_WEIGHT + |NGX_STREAM_UPSTREAM_MAX_CONNS |NGX_STREAM_UPSTREAM_MAX_FAILS |NGX_STREAM_UPSTREAM_FAIL_TIMEOUT |NGX_STREAM_UPSTREAM_DOWN diff --git a/src/stream/ngx_stream_upstream_round_robin.c b/src/stream/ngx_stream_upstream_round_robin.c index 7aced0f..3a62501 100644 --- a/src/stream/ngx_stream_upstream_round_robin.c +++ b/src/stream/ngx_stream_upstream_round_robin.c @@ -96,6 +96,7 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, peer[n].weight = server[i].weight; peer[n].effective_weight = server[i].weight; peer[n].current_weight = 0; + peer[n].max_conns = server[i].max_conns; peer[n].max_fails = server[i].max_fails; peer[n].fail_timeout = server[i].fail_timeout; peer[n].down = server[i].down; @@ -159,6 +160,7 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, peer[n].weight = server[i].weight; peer[n].effective_weight = server[i].weight; peer[n].current_weight = 0; + peer[n].max_conns = server[i].max_conns; peer[n].max_fails = server[i].max_fails; peer[n].fail_timeout = server[i].fail_timeout; peer[n].down = server[i].down; @@ -227,6 +229,7 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, peer[i].weight = 1; peer[i].effective_weight = 1; peer[i].current_weight = 0; + peer[i].max_conns = 0; peer[i].max_fails = 1; peer[i].fail_timeout = 10; *peerp = &peer[i]; @@ -262,6 +265,7 @@ ngx_stream_upstream_init_round_robin_peer(ngx_stream_session_t *s, rrp->peers = us->peer.data; rrp->current = NULL; + rrp->config = 0; n = rrp->peers->number; @@ -344,6 +348,7 @@ ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, peer[0].weight = 1; peer[0].effective_weight = 1; peer[0].current_weight = 0; + peer[0].max_conns = 0; peer[0].max_fails = 1; peer[0].fail_timeout = 10; peers->peer = peer; @@ -377,6 +382,7 @@ ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, peer[i].weight = 1; peer[i].effective_weight = 1; peer[i].current_weight = 0; + peer[i].max_conns = 0; peer[i].max_fails = 1; peer[i].fail_timeout = 10; *peerp = &peer[i]; @@ -386,6 +392,7 @@ ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, rrp->peers = peers; rrp->current = NULL; + rrp->config = 0; if (rrp->peers->number <= 8 * sizeof(uintptr_t)) { rrp->tried = &rrp->data; @@ -438,6 +445,10 @@ ngx_stream_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) goto failed; } + if (peer->max_conns && peer->conns >= peer->max_conns) { + goto failed; + } + rrp->current = peer; } else { @@ -491,12 +502,6 @@ failed: ngx_stream_upstream_rr_peers_wlock(peers); } - /* all peers failed, mark them as live for quick recovery */ - - for (peer = peers->peer; peer; peer = peer->next) { - peer->fails = 0; - } - ngx_stream_upstream_rr_peers_unlock(peers); pc->name = peers->name; @@ -527,7 +532,6 @@ ngx_stream_upstream_get_peer(ngx_stream_upstream_rr_peer_data_t *rrp) peer; peer = peer->next, i++) { - n = i / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); @@ -546,6 +550,10 @@ ngx_stream_upstream_get_peer(ngx_stream_upstream_rr_peer_data_t *rrp) continue; } + if (peer->max_conns && peer->conns >= peer->max_conns) { + continue; + } + peer->current_weight += peer->effective_weight; total += peer->effective_weight; diff --git a/src/stream/ngx_stream_upstream_round_robin.h b/src/stream/ngx_stream_upstream_round_robin.h index 452c2e9..35d9fce 100644 --- a/src/stream/ngx_stream_upstream_round_robin.h +++ b/src/stream/ngx_stream_upstream_round_robin.h @@ -27,6 +27,7 @@ struct ngx_stream_upstream_rr_peer_s { ngx_int_t weight; ngx_uint_t conns; + ngx_uint_t max_conns; ngx_uint_t fails; time_t accessed; @@ -34,19 +35,22 @@ struct ngx_stream_upstream_rr_peer_s { ngx_uint_t max_fails; time_t fail_timeout; + ngx_msec_t slow_start; + ngx_msec_t start_time; - ngx_uint_t down; /* unsigned down:1; */ + ngx_uint_t down; -#if (NGX_STREAM_SSL) void *ssl_session; int ssl_session_len; -#endif - - ngx_stream_upstream_rr_peer_t *next; #if (NGX_STREAM_UPSTREAM_ZONE) ngx_atomic_t lock; #endif + + ngx_stream_upstream_rr_peer_t *next; + + NGX_COMPAT_BEGIN(25) + NGX_COMPAT_END }; @@ -119,6 +123,7 @@ struct ngx_stream_upstream_rr_peers_s { typedef struct { + ngx_uint_t config; ngx_stream_upstream_rr_peers_t *peers; ngx_stream_upstream_rr_peer_t *current; uintptr_t *tried; diff --git a/src/stream/ngx_stream_write_filter_module.c b/src/stream/ngx_stream_write_filter_module.c new file mode 100644 index 0000000..8fdcd37 --- /dev/null +++ b/src/stream/ngx_stream_write_filter_module.c @@ -0,0 +1,273 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_chain_t *from_upstream; + ngx_chain_t *from_downstream; +} ngx_stream_write_filter_ctx_t; + + +static ngx_int_t ngx_stream_write_filter(ngx_stream_session_t *s, + ngx_chain_t *in, ngx_uint_t from_upstream); +static ngx_int_t ngx_stream_write_filter_init(ngx_conf_t *cf); + + +static ngx_stream_module_t ngx_stream_write_filter_module_ctx = { + NULL, /* preconfiguration */ + ngx_stream_write_filter_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_write_filter_module = { + NGX_MODULE_V1, + &ngx_stream_write_filter_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_STREAM_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_stream_write_filter(ngx_stream_session_t *s, ngx_chain_t *in, + ngx_uint_t from_upstream) +{ + off_t size; + ngx_uint_t last, flush, sync; + ngx_chain_t *cl, *ln, **ll, **out, *chain; + ngx_connection_t *c; + ngx_stream_write_filter_ctx_t *ctx; + + ctx = ngx_stream_get_module_ctx(s, ngx_stream_write_filter_module); + + if (ctx == NULL) { + ctx = ngx_pcalloc(s->connection->pool, + sizeof(ngx_stream_write_filter_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_stream_set_ctx(s, ctx, ngx_stream_write_filter_module); + } + + if (from_upstream) { + c = s->connection; + out = &ctx->from_upstream; + + } else { + c = s->upstream->peer.connection; + out = &ctx->from_downstream; + } + + if (c->error) { + return NGX_ERROR; + } + + size = 0; + flush = 0; + sync = 0; + last = 0; + ll = out; + + /* find the size, the flush point and the last link of the saved chain */ + + for (cl = *out; cl; cl = cl->next) { + ll = &cl->next; + + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0, + "write old buf t:%d f:%d %p, pos %p, size: %z " + "file: %O, size: %O", + cl->buf->temporary, cl->buf->in_file, + cl->buf->start, cl->buf->pos, + cl->buf->last - cl->buf->pos, + cl->buf->file_pos, + cl->buf->file_last - cl->buf->file_pos); + +#if 1 + if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "zero size buf in writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); + + ngx_debug_point(); + return NGX_ERROR; + } +#endif + + size += ngx_buf_size(cl->buf); + + if (cl->buf->flush || cl->buf->recycled) { + flush = 1; + } + + if (cl->buf->sync) { + sync = 1; + } + + if (cl->buf->last_buf) { + last = 1; + } + } + + /* add the new chain to the existent one */ + + for (ln = in; ln; ln = ln->next) { + cl = ngx_alloc_chain_link(c->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf = ln->buf; + *ll = cl; + ll = &cl->next; + + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0, + "write new buf t:%d f:%d %p, pos %p, size: %z " + "file: %O, size: %O", + cl->buf->temporary, cl->buf->in_file, + cl->buf->start, cl->buf->pos, + cl->buf->last - cl->buf->pos, + cl->buf->file_pos, + cl->buf->file_last - cl->buf->file_pos); + +#if 1 + if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "zero size buf in writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); + + ngx_debug_point(); + return NGX_ERROR; + } +#endif + + size += ngx_buf_size(cl->buf); + + if (cl->buf->flush || cl->buf->recycled) { + flush = 1; + } + + if (cl->buf->sync) { + sync = 1; + } + + if (cl->buf->last_buf) { + last = 1; + } + } + + *ll = NULL; + + ngx_log_debug3(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream write filter: l:%ui f:%ui s:%O", last, flush, size); + + if (size == 0 + && !(c->buffered & NGX_LOWLEVEL_BUFFERED) + && !(last && c->need_last_buf)) + { + if (last || flush || sync) { + for (cl = *out; cl; /* void */) { + ln = cl; + cl = cl->next; + ngx_free_chain(c->pool, ln); + } + + *out = NULL; + c->buffered &= ~NGX_STREAM_WRITE_BUFFERED; + + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "the stream output chain is empty"); + + ngx_debug_point(); + + return NGX_ERROR; + } + + chain = c->send_chain(c, *out, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream write filter %p", chain); + + if (chain == NGX_CHAIN_ERROR) { + c->error = 1; + return NGX_ERROR; + } + + for (cl = *out; cl && cl != chain; /* void */) { + ln = cl; + cl = cl->next; + ngx_free_chain(c->pool, ln); + } + + *out = chain; + + if (chain) { + if (c->shared) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "shared connection is busy"); + return NGX_ERROR; + } + + c->buffered |= NGX_STREAM_WRITE_BUFFERED; + return NGX_AGAIN; + } + + c->buffered &= ~NGX_STREAM_WRITE_BUFFERED; + + if (c->buffered & NGX_LOWLEVEL_BUFFERED) { + return NGX_AGAIN; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_write_filter_init(ngx_conf_t *cf) +{ + ngx_stream_top_filter = ngx_stream_write_filter; + + return NGX_OK; +} From 7bfa979832b01ccb4afd02aae0f5bb3e9c863b74 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Wed, 19 Oct 2016 04:36:34 +0000 Subject: [PATCH 164/651] Updated PHP sample configuration block. #841230 --- debian/changelog | 9 +++++++-- debian/conf/sites-available/default | 8 ++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/debian/changelog b/debian/changelog index 40a7cf4..e616576 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,10 +1,15 @@ -nginx (1.10.1-4) UNRELEASED; urgency=medium +nginx (1.10.1-5) UNRELEASED; urgency=medium + [ Christos Trochalakis ] * debian/control: + Version depend on lsb-base (>= 3.0-6). Fixes lintian init.d-script-needs-depends-on-lsb-base. - -- Christos Trochalakis Tue, 11 Oct 2016 10:00:23 +0300 + [ Michael Lustfield ] + * debian/conf/sites-available/default: + + Updated PHP sample configuration block. (Closes: #841230) + + -- Michael Lustfield Wed, 19 Oct 2016 04:34:08 +0000 nginx (1.10.1-3) unstable; urgency=medium diff --git a/debian/conf/sites-available/default b/debian/conf/sites-available/default index 79e41e8..5073cc4 100644 --- a/debian/conf/sites-available/default +++ b/debian/conf/sites-available/default @@ -46,15 +46,15 @@ server { try_files $uri $uri/ =404; } - # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + # pass PHP scripts to FastCGI server # #location ~ \.php$ { # include snippets/fastcgi-php.conf; # - # # With php5-cgi alone: + # # With php5-fpm (or other unix sockets): + # fastcgi_pass unix:/var/run/php7-fpm.sock; + # # With php5-cgi (or other tcp sockets): # fastcgi_pass 127.0.0.1:9000; - # # With php5-fpm: - # fastcgi_pass unix:/var/run/php5-fpm.sock; #} # deny access to .htaccess files, if Apache's document root From 8c5b5c4f670fb860599b0eb0e6fb0c1aebdcf625 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Wed, 19 Oct 2016 06:49:34 +0000 Subject: [PATCH 165/651] More documentation updates. --- debian/conf/sites-available/default | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/debian/conf/sites-available/default b/debian/conf/sites-available/default index 5073cc4..bfb7f0c 100644 --- a/debian/conf/sites-available/default +++ b/debian/conf/sites-available/default @@ -1,12 +1,17 @@ ## # You should look at the following URL's in order to grasp a solid understanding # of Nginx configuration files in order to fully unleash the power of Nginx. -# http://wiki.nginx.org/Pitfalls -# http://wiki.nginx.org/QuickStart -# http://wiki.nginx.org/Configuration +# https://www.nginx.com/resources/wiki/start/ +# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/ +# https://wiki.debian.org/Nginx/DirectoryStructure # -# Generally, you will want to move this file somewhere, and start with a clean -# file but keep this around for reference. Or just disable in sites-enabled. +# In most cases, administrators will remove this file from sites-enabled/ and +# leave it as reference inside of sites-available where it will continue to be +# updated by the nginx packaging team. +# +# This file will automatically load configuration files provided by other +# applications, such as Drupal or Wordpress. These applications will be made +# available underneath a path with that package name, such as /drupal8. # # Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples. ## @@ -52,7 +57,7 @@ server { # include snippets/fastcgi-php.conf; # # # With php5-fpm (or other unix sockets): - # fastcgi_pass unix:/var/run/php7-fpm.sock; + # fastcgi_pass unix:/var/run/php7.0-fpm.sock; # # With php5-cgi (or other tcp sockets): # fastcgi_pass 127.0.0.1:9000; #} From 5d09382c825202bf2b28ae16b6dbfb9485d3c67b Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Wed, 19 Oct 2016 06:56:25 +0000 Subject: [PATCH 166/651] Adding support for packaged application configurations. --- debian/changelog | 7 +++++-- debian/conf/sites-available/default | 4 ++++ debian/nginx-common.dirs | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index e616576..a678a83 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.10.1-5) UNRELEASED; urgency=medium +nginx (1.10.1-6) UNRELEASED; urgency=medium [ Christos Trochalakis ] * debian/control: @@ -8,8 +8,11 @@ nginx (1.10.1-5) UNRELEASED; urgency=medium [ Michael Lustfield ] * debian/conf/sites-available/default: + Updated PHP sample configuration block. (Closes: #841230) + + Adding include default-server.d/pkg_*.conf. (Closes: #822792) + * debian/nginx-common.dirs: + + Adding support for packaged application configurations. - -- Michael Lustfield Wed, 19 Oct 2016 04:34:08 +0000 + -- Michael Lustfield Wed, 19 Oct 2016 06:51:46 +0000 nginx (1.10.1-3) unstable; urgency=medium diff --git a/debian/conf/sites-available/default b/debian/conf/sites-available/default index bfb7f0c..cca2b9a 100644 --- a/debian/conf/sites-available/default +++ b/debian/conf/sites-available/default @@ -68,6 +68,10 @@ server { #location ~ /\.ht { # deny all; #} + + # load package-maintained configuration files + # https://wiki.debian.org/Nginx/DirectoryStructure#Packaged_Applications + include default-server.d/pkg_*.conf; } diff --git a/debian/nginx-common.dirs b/debian/nginx-common.dirs index 65bb651..b674397 100644 --- a/debian/nginx-common.dirs +++ b/debian/nginx-common.dirs @@ -4,6 +4,7 @@ etc/nginx/modules-available etc/nginx/modules-enabled etc/nginx/sites-available etc/nginx/sites-enabled +etc/nginx/default-server.d etc/ufw/applications.d usr/share/nginx usr/share/vim/addons From 8bf94db95d9d75e4887947628744ea6d8719ec92 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 20 Oct 2016 09:47:41 +0300 Subject: [PATCH 167/651] Follow the 1.10.x stable branch --- debian/watch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/watch b/debian/watch index 2cb0678..d54dab0 100644 --- a/debian/watch +++ b/debian/watch @@ -1,3 +1,3 @@ version=3 opts=pgpsigurlmangle=s/$/.asc/ \ -http://nginx.org/download/nginx-(\d\.\d+\.\d+)\.tar\.gz +http://nginx.org/download/nginx-(1.10\.\d+)\.tar\.gz From a8a1325840eae9d93c5b05e66151eba362dd99c7 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 20 Oct 2016 09:48:27 +0300 Subject: [PATCH 168/651] New upstream version 1.10.2 --- CHANGES | 32 +++ CHANGES.ru | 34 +++ src/core/nginx.h | 4 +- src/event/ngx_event_openssl.c | 23 +- src/event/ngx_event_pipe.c | 10 +- src/http/modules/ngx_http_sub_filter_module.c | 124 +++++++--- src/http/ngx_http_header_filter_module.c | 14 +- src/http/ngx_http_request.c | 2 +- src/http/ngx_http_request.h | 1 + src/http/ngx_http_special_response.c | 15 +- src/http/v2/ngx_http_v2.c | 220 +++++++++++++----- src/http/v2/ngx_http_v2.h | 5 + src/http/v2/ngx_http_v2_filter_module.c | 22 +- src/http/v2/ngx_http_v2_module.c | 31 +++ src/http/v2/ngx_http_v2_module.h | 1 + 15 files changed, 417 insertions(+), 121 deletions(-) diff --git a/CHANGES b/CHANGES index 4396472..209da02 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,36 @@ +Changes with nginx 1.10.2 18 Oct 2016 + + *) Change: the "421 Misdirected Request" response now used when + rejecting requests to a virtual server different from one negotiated + during an SSL handshake; this improves interoperability with some + HTTP/2 clients when using client certificates. + + *) Change: HTTP/2 clients can now start sending request body + immediately; the "http2_body_preread_size" directive controls size of + the buffer used before nginx will start reading client request body. + + *) Bugfix: a segmentation fault might occur in a worker process when + using HTTP/2 and the "proxy_request_buffering" directive. + + *) Bugfix: the "Content-Length" request header line was always added to + requests passed to backends, including requests without body, when + using HTTP/2. + + *) Bugfix: "http request count is zero" alerts might appear in logs when + using HTTP/2. + + *) Bugfix: unnecessary buffering might occur when using the "sub_filter" + directive; the issue had appeared in 1.9.4. + + *) Bugfix: socket leak when using HTTP/2. + + *) Bugfix: an incorrect response might be returned when using the "aio + threads" and "sendfile" directives; the bug had appeared in 1.9.13. + + *) Workaround: OpenSSL 1.1.0 compatibility. + + Changes with nginx 1.10.1 31 May 2016 *) Security: a segmentation fault might occur in a worker process while diff --git a/CHANGES.ru b/CHANGES.ru index c96cf93..ea46689 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,38 @@ +Изменения в nginx 1.10.2 18.10.2016 + + *) Изменение: при попытке запросить виртуальный сервер, отличающийся от + согласованного в процессе SSL handshake, теперь возвращается ответ + "421 Misdirected Request"; это улучшает совместимость с некоторыми + HTTP/2-клиентами в случае использования клиентских сертификатов. + + *) Изменение: HTTP/2-клиенты теперь могут сразу присылать тело запроса; + директива http2_body_preread_size позволяет указать размер буфера, + который будет использоваться до того, как nginx начнёт читать тело. + + *) Исправление: при использовании HTTP/2 и директивы + proxy_request_buffering в рабочем процессе мог произойти segmentation + fault. + + *) Исправление: при использовании HTTP/2 к запросам, передаваемым на + бэкенд, всегда добавлялась строка заголовка "Content-Length", даже + если у запроса не было тела. + + *) Исправление: при использовании HTTP/2 в логах могли появляться + сообщения "http request count is zero". + + *) Исправление: при использовании директивы sub_filter могло + буферизироваться больше данных, чем это необходимо; проблема + появилась в 1.9.4. + + *) Исправление: утечки сокетов при использовании HTTP/2. + + *) Исправление: при использовании директив "aio threads" и sendfile мог + возвращаться некорректный ответ; ошибка появилась в 1.9.13. + + *) Изменение: совместимость с OpenSSL 1.1.0. + + Изменения в nginx 1.10.1 31.05.2016 *) Безопасность: при записи тела специально созданного запроса во diff --git a/src/core/nginx.h b/src/core/nginx.h index e2b8005..95123f1 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1010001 -#define NGINX_VERSION "1.10.1" +#define nginx_version 1010002 +#define NGINX_VERSION "1.10.2" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index de10296..a3160b4 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -951,6 +951,8 @@ ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) return NGX_ERROR; } +#if OPENSSL_VERSION_NUMBER < 0x10100005L + dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL); dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL); @@ -960,6 +962,23 @@ ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) return NGX_ERROR; } +#else + { + BIGNUM *p, *g; + + p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL); + g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL); + + if (p == NULL || g == NULL || !DH_set0_pqg(dh, p, NULL, g)) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "BN_bin2bn() failed"); + DH_free(dh); + BN_free(p); + BN_free(g); + return NGX_ERROR; + } + } +#endif + SSL_CTX_set_tmp_dh(ssl->ctx, dh); DH_free(dh); @@ -1938,7 +1957,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, || n == SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST /* 151 */ || n == SSL_R_EXCESSIVE_MESSAGE_SIZE /* 152 */ || n == SSL_R_LENGTH_MISMATCH /* 159 */ +#ifdef SSL_R_NO_CIPHERS_PASSED || n == SSL_R_NO_CIPHERS_PASSED /* 182 */ +#endif || n == SSL_R_NO_CIPHERS_SPECIFIED /* 183 */ || n == SSL_R_NO_COMPRESSION_SPECIFIED /* 187 */ || n == SSL_R_NO_SHARED_CIPHER /* 193 */ @@ -2898,7 +2919,7 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_ticket_md(), NULL); ngx_memcpy(name, key[0].name, 16); - return 0; + return 1; } else { /* decrypt session ticket */ diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c index 5ce59ae..be1b475 100644 --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -815,10 +815,12 @@ ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p) } #if (NGX_THREADS) - p->temp_file->thread_write = p->thread_handler ? 1 : 0; - p->temp_file->file.thread_task = p->thread_task; - p->temp_file->file.thread_handler = p->thread_handler; - p->temp_file->file.thread_ctx = p->thread_ctx; + if (p->thread_handler) { + p->temp_file->thread_write = 1; + p->temp_file->file.thread_task = p->thread_task; + p->temp_file->file.thread_handler = p->thread_handler; + p->temp_file->file.thread_ctx = p->thread_ctx; + } #endif n = ngx_write_chain_to_temp_file(p->temp_file, out); diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c index bb1c50b..e8d1d80 100644 --- a/src/http/modules/ngx_http_sub_filter_module.c +++ b/src/http/modules/ngx_http_sub_filter_module.c @@ -83,7 +83,9 @@ static ngx_uint_t ngx_http_sub_cmp_index; static ngx_int_t ngx_http_sub_output(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx); static ngx_int_t ngx_http_sub_parse(ngx_http_request_t *r, - ngx_http_sub_ctx_t *ctx); + ngx_http_sub_ctx_t *ctx, ngx_uint_t flush); +static ngx_int_t ngx_http_sub_match(ngx_http_sub_ctx_t *ctx, ngx_int_t start, + ngx_str_t *m); static char * ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -285,6 +287,7 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_int_t rc; ngx_buf_t *b; ngx_str_t *sub; + ngx_uint_t flush, last; ngx_chain_t *cl; ngx_http_sub_ctx_t *ctx; ngx_http_sub_match_t *match; @@ -326,6 +329,9 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http sub filter \"%V\"", &r->uri); + flush = 0; + last = 0; + while (ctx->in || ctx->buf) { if (ctx->buf == NULL) { @@ -334,11 +340,19 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ctx->pos = ctx->buf->pos; } + if (ctx->buf->flush || ctx->buf->recycled) { + flush = 1; + } + + if (ctx->in == NULL) { + last = flush; + } + b = NULL; while (ctx->pos < ctx->buf->last) { - rc = ngx_http_sub_parse(r, ctx); + rc = ngx_http_sub_parse(r, ctx, last); ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "parse: %i, looked: \"%V\" %p-%p", @@ -590,9 +604,10 @@ ngx_http_sub_output(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) static ngx_int_t -ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) +ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx, + ngx_uint_t flush) { - u_char *p, *last, *pat, *pat_end, c; + u_char *p, c; ngx_str_t *m; ngx_int_t offset, start, next, end, len, rc; ngx_uint_t shift, i, j; @@ -602,6 +617,7 @@ ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module); tables = ctx->tables; + match = ctx->matches->elts; offset = ctx->offset; end = ctx->buf->last - ctx->pos; @@ -628,7 +644,6 @@ ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) /* a potential match */ start = offset - (ngx_int_t) tables->min_match_len + 1; - match = ctx->matches->elts; i = ngx_max(tables->index[c], ctx->index); j = tables->index[c + 1]; @@ -641,41 +656,15 @@ ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) m = &match[i].match; - pat = m->data; - pat_end = m->data + m->len; + rc = ngx_http_sub_match(ctx, start, m); - if (start >= 0) { - p = ctx->pos + start; - - } else { - last = ctx->looked.data + ctx->looked.len; - p = last + start; - - while (p < last && pat < pat_end) { - if (ngx_tolower(*p) != *pat) { - goto next; - } - - p++; - pat++; - } - - p = ctx->pos; - } - - while (p < ctx->buf->last && pat < pat_end) { - if (ngx_tolower(*p) != *pat) { - goto next; - } - - p++; - pat++; + if (rc == NGX_DECLINED) { + goto next; } ctx->index = i; - if (pat != pat_end) { - /* partial match */ + if (rc == NGX_AGAIN) { goto again; } @@ -695,6 +684,26 @@ ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) ctx->index = 0; } + if (flush) { + for ( ;; ) { + start = offset - (ngx_int_t) tables->min_match_len + 1; + + if (start >= end) { + break; + } + + for (i = 0; i < ctx->matches->nelts; i++) { + m = &match[i].match; + + if (ngx_http_sub_match(ctx, start, m) == NGX_AGAIN) { + goto again; + } + } + + offset++; + } + } + again: ctx->offset = offset; @@ -731,6 +740,51 @@ done: } +static ngx_int_t +ngx_http_sub_match(ngx_http_sub_ctx_t *ctx, ngx_int_t start, ngx_str_t *m) +{ + u_char *p, *last, *pat, *pat_end; + + pat = m->data; + pat_end = m->data + m->len; + + if (start >= 0) { + p = ctx->pos + start; + + } else { + last = ctx->looked.data + ctx->looked.len; + p = last + start; + + while (p < last && pat < pat_end) { + if (ngx_tolower(*p) != *pat) { + return NGX_DECLINED; + } + + p++; + pat++; + } + + p = ctx->pos; + } + + while (p < ctx->buf->last && pat < pat_end) { + if (ngx_tolower(*p) != *pat) { + return NGX_DECLINED; + } + + p++; + pat++; + } + + if (pat != pat_end) { + /* partial match */ + return NGX_AGAIN; + } + + return NGX_OK; +} + + static char * ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c index 507dc93..2cf1205 100644 --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -95,17 +95,17 @@ static ngx_str_t ngx_http_status_lines[] = { ngx_string("414 Request-URI Too Large"), ngx_string("415 Unsupported Media Type"), ngx_string("416 Requested Range Not Satisfiable"), + ngx_null_string, /* "417 Expectation Failed" */ + ngx_null_string, /* "418 unused" */ + ngx_null_string, /* "419 unused" */ + ngx_null_string, /* "420 unused" */ + ngx_string("421 Misdirected Request"), - /* ngx_null_string, */ /* "417 Expectation Failed" */ - /* ngx_null_string, */ /* "418 unused" */ - /* ngx_null_string, */ /* "419 unused" */ - /* ngx_null_string, */ /* "420 unused" */ - /* ngx_null_string, */ /* "421 unused" */ /* ngx_null_string, */ /* "422 Unprocessable Entity" */ /* ngx_null_string, */ /* "423 Locked" */ /* ngx_null_string, */ /* "424 Failed Dependency" */ -#define NGX_HTTP_LAST_4XX 417 +#define NGX_HTTP_LAST_4XX 422 #define NGX_HTTP_OFF_5XX (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX) ngx_string("500 Internal Server Error"), @@ -113,10 +113,10 @@ static ngx_str_t ngx_http_status_lines[] = { ngx_string("502 Bad Gateway"), ngx_string("503 Service Temporarily Unavailable"), ngx_string("504 Gateway Time-out"), - ngx_null_string, /* "505 HTTP Version Not Supported" */ ngx_null_string, /* "506 Variant Also Negotiates" */ ngx_string("507 Insufficient Storage"), + /* ngx_null_string, */ /* "508 unused" */ /* ngx_null_string, */ /* "509 unused" */ /* ngx_null_string, */ /* "510 Not Extended" */ diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 7d6cada..c2ce222 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -2065,7 +2065,7 @@ ngx_http_set_virtual_server(ngx_http_request_t *r, ngx_str_t *host) ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client attempted to request the server name " "different from that one was negotiated"); - ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + ngx_http_finalize_request(r, NGX_HTTP_MISDIRECTED_REQUEST); return NGX_ERROR; } } diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index cfde7dc..57f8583 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -95,6 +95,7 @@ #define NGX_HTTP_REQUEST_URI_TOO_LARGE 414 #define NGX_HTTP_UNSUPPORTED_MEDIA_TYPE 415 #define NGX_HTTP_RANGE_NOT_SATISFIABLE 416 +#define NGX_HTTP_MISDIRECTED_REQUEST 421 /* Our own HTTP codes */ diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c index 2771e58..64e5acd 100644 --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -210,6 +210,14 @@ static char ngx_http_error_416_page[] = ; +static char ngx_http_error_421_page[] = +"" CRLF +"421 Misdirected Request" CRLF +"" CRLF +"

421 Misdirected Request

" CRLF +; + + static char ngx_http_error_494_page[] = "" CRLF "400 Request Header Or Cookie Too Large" @@ -334,8 +342,13 @@ static ngx_str_t ngx_http_error_pages[] = { ngx_string(ngx_http_error_414_page), ngx_string(ngx_http_error_415_page), ngx_string(ngx_http_error_416_page), + ngx_null_string, /* 417 */ + ngx_null_string, /* 418 */ + ngx_null_string, /* 419 */ + ngx_null_string, /* 420 */ + ngx_string(ngx_http_error_421_page), -#define NGX_HTTP_LAST_4XX 417 +#define NGX_HTTP_LAST_4XX 422 #define NGX_HTTP_OFF_5XX (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX) ngx_string(ngx_http_error_494_page), /* 494, request header too large */ diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 278c9ab..d0cd2ab 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -48,11 +48,6 @@ #define NGX_HTTP_V2_DEFAULT_FRAME_SIZE (1 << 14) -#define NGX_HTTP_V2_MAX_WINDOW ((1U << 31) - 1) -#define NGX_HTTP_V2_DEFAULT_WINDOW 65535 - -#define NGX_HTTP_V2_INITIAL_WINDOW 0 - #define NGX_HTTP_V2_ROOT (void *) -1 @@ -415,6 +410,16 @@ ngx_http_v2_write_handler(ngx_event_t *wev) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 write handler"); + if (h2c->last_out == NULL && !c->buffered) { + + if (wev->timer_set) { + ngx_del_timer(wev); + } + + ngx_http_v2_handle_connection(h2c); + return; + } + h2c->blocked = 1; rc = ngx_http_v2_send_output_queue(h2c); @@ -473,7 +478,7 @@ ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c) wev = c->write; if (!wev->ready) { - return NGX_OK; + return NGX_AGAIN; } cl = NULL; @@ -544,15 +549,6 @@ ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c) c->tcp_nodelay = NGX_TCP_NODELAY_SET; } - if (cl) { - ngx_add_timer(wev, clcf->send_timeout); - - } else { - if (wev->timer_set) { - ngx_del_timer(wev); - } - } - for ( /* void */ ; out; out = fn) { fn = out->next; @@ -577,6 +573,15 @@ ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c) h2c->last_out = frame; + if (!wev->ready) { + ngx_add_timer(wev, clcf->send_timeout); + return NGX_AGAIN; + } + + if (wev->timer_set) { + ngx_del_timer(wev); + } + return NGX_OK; error: @@ -594,7 +599,8 @@ error: static void ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) { - ngx_connection_t *c; + ngx_int_t rc; + ngx_connection_t *c; ngx_http_v2_srv_conf_t *h2scf; if (h2c->last_out || h2c->processing) { @@ -609,7 +615,22 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) } if (c->buffered) { - return; + h2c->blocked = 1; + + rc = ngx_http_v2_send_output_queue(h2c); + + h2c->blocked = 0; + + if (rc == NGX_ERROR) { + ngx_http_close_connection(c); + return; + } + + if (rc == NGX_AGAIN) { + return; + } + + /* rc == NGX_OK */ } h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, @@ -620,7 +641,7 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) } if (ngx_terminate || ngx_exiting) { - ngx_http_close_connection(c); + ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR); return; } @@ -879,8 +900,6 @@ ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) return ngx_http_v2_state_skip_padded(h2c, pos, end); } - stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; - h2c->state.stream = stream; return ngx_http_v2_state_read_data(h2c, pos, end); @@ -891,10 +910,12 @@ static u_char * ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) { - size_t size; - ngx_int_t rc; - ngx_uint_t last; - ngx_http_v2_stream_t *stream; + size_t size; + ngx_buf_t *buf; + ngx_int_t rc; + ngx_http_request_t *r; + ngx_http_v2_stream_t *stream; + ngx_http_v2_srv_conf_t *h2scf; stream = h2c->state.stream; @@ -913,17 +934,42 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, if (size >= h2c->state.length) { size = h2c->state.length; - last = stream->in_closed; - - } else { - last = 0; + stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; } - rc = ngx_http_v2_process_request_body(stream->request, pos, size, last); + r = stream->request; - if (rc != NGX_OK) { - stream->skip_data = 1; - ngx_http_finalize_request(stream->request, rc); + if (r->request_body) { + rc = ngx_http_v2_process_request_body(r, pos, size, stream->in_closed); + + if (rc != NGX_OK) { + stream->skip_data = 1; + ngx_http_finalize_request(r, rc); + } + + } else if (size) { + buf = stream->preread; + + if (buf == NULL) { + h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module); + + buf = ngx_create_temp_buf(r->pool, h2scf->preread_size); + if (buf == NULL) { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + stream->preread = buf; + } + + if (size > (size_t) (buf->end - buf->last)) { + ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, + "http2 preread buffer overflow"); + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + buf->last = ngx_cpymem(buf->last, pos, size); } pos += size; @@ -1058,7 +1104,9 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, goto rst_stream; } - if (!h2c->settings_ack && !(h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG)) + if (!h2c->settings_ack + && !(h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG) + && h2scf->preread_size < NGX_HTTP_V2_DEFAULT_WINDOW) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, "client sent stream with data " @@ -2434,8 +2482,7 @@ ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, ngx_uint_t ack) buf->last = ngx_http_v2_write_uint16(buf->last, NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING); - buf->last = ngx_http_v2_write_uint32(buf->last, - NGX_HTTP_V2_INITIAL_WINDOW); + buf->last = ngx_http_v2_write_uint32(buf->last, h2scf->preread_size); buf->last = ngx_http_v2_write_uint16(buf->last, NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING); @@ -2643,6 +2690,7 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c) ngx_http_log_ctx_t *ctx; ngx_http_request_t *r; ngx_http_v2_stream_t *stream; + ngx_http_v2_srv_conf_t *h2scf; ngx_http_core_srv_conf_t *cscf; fc = h2c->free_fake_connections; @@ -2756,8 +2804,10 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c) stream->request = r; stream->connection = h2c; + h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module); + stream->send_window = h2c->init_window; - stream->recv_window = NGX_HTTP_V2_INITIAL_WINDOW; + stream->recv_window = h2scf->preread_size; h2c->processing++; @@ -3400,7 +3450,9 @@ ngx_http_v2_run_request(ngx_http_request_t *r) return; } - r->headers_in.chunked = (r->headers_in.content_length_n == -1); + if (r->headers_in.content_length_n == -1 && !r->stream->in_closed) { + r->headers_in.chunked = 1; + } ngx_http_process_request(r); } @@ -3411,7 +3463,11 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler) { off_t len; + size_t size; + ngx_buf_t *buf; + ngx_int_t rc; ngx_http_v2_stream_t *stream; + ngx_http_v2_srv_conf_t *h2scf; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; ngx_http_v2_connection_t *h2c; @@ -3444,24 +3500,34 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r, r->request_body = rb; + h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); len = r->headers_in.content_length_n; if (r->request_body_no_buffering && !stream->in_closed) { - r->request_body_in_file_only = 0; if (len < 0 || len > (off_t) clcf->client_body_buffer_size) { len = clcf->client_body_buffer_size; } + /* + * We need a room to store data up to the stream's initial window size, + * at least until this window will be exhausted. + */ + + if (len < (off_t) h2scf->preread_size) { + len = h2scf->preread_size; + } + if (len > NGX_HTTP_V2_MAX_WINDOW) { len = NGX_HTTP_V2_MAX_WINDOW; } - } - if (len >= 0 && len <= (off_t) clcf->client_body_buffer_size - && !r->request_body_in_file_only) + rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); + + } else if (len >= 0 && len <= (off_t) clcf->client_body_buffer_size + && !r->request_body_in_file_only) { rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); @@ -3478,22 +3544,44 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r, return NGX_HTTP_INTERNAL_SERVER_ERROR; } + buf = stream->preread; + if (stream->in_closed) { r->request_body_no_buffering = 0; + + if (buf) { + rc = ngx_http_v2_process_request_body(r, buf->pos, + buf->last - buf->pos, 1); + ngx_pfree(r->pool, buf->start); + return rc; + } + return ngx_http_v2_process_request_body(r, NULL, 0, 1); } - if (len) { - if (r->request_body_no_buffering) { - stream->recv_window = (size_t) len; + if (buf) { + rc = ngx_http_v2_process_request_body(r, buf->pos, + buf->last - buf->pos, 0); - } else { - stream->no_flow_control = 1; - stream->recv_window = NGX_HTTP_V2_MAX_WINDOW; + ngx_pfree(r->pool, buf->start); + + if (rc != NGX_OK) { + stream->skip_data = 1; + return rc; } + } - if (ngx_http_v2_send_window_update(stream->connection, stream->node->id, - stream->recv_window) + if (r->request_body_no_buffering) { + size = (size_t) len - h2scf->preread_size; + + } else { + stream->no_flow_control = 1; + size = NGX_HTTP_V2_MAX_WINDOW - stream->recv_window; + } + + if (size) { + if (ngx_http_v2_send_window_update(stream->connection, + stream->node->id, size) == NGX_ERROR) { stream->skip_data = 1; @@ -3508,9 +3596,13 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r, return NGX_HTTP_INTERNAL_SERVER_ERROR; } } + + stream->recv_window += size; } - ngx_add_timer(r->connection->read, clcf->client_body_timeout); + if (!buf) { + ngx_add_timer(r->connection->read, clcf->client_body_timeout); + } r->read_event_handler = ngx_http_v2_read_client_request_body_handler; r->write_event_handler = ngx_http_request_empty_handler; @@ -3529,13 +3621,8 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; - rb = r->request_body; - - if (rb == NULL) { - return NGX_OK; - } - fc = r->connection; + rb = r->request_body; buf = rb->buf; if (size) { @@ -3579,7 +3666,7 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, rb->buf = NULL; } - if (r->headers_in.content_length_n == -1) { + if (r->headers_in.chunked) { r->headers_in.content_length_n = rb->received; } @@ -3789,7 +3876,14 @@ ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r) window -= h2c->state.length; } - if (window == stream->recv_window) { + if (window <= stream->recv_window) { + if (window < stream->recv_window) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "http2 negative window update"); + stream->skip_data = 1; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + return NGX_AGAIN; } @@ -3824,6 +3918,10 @@ ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, ngx_event_t *rev; ngx_connection_t *fc; + if (stream->rst_sent) { + return NGX_OK; + } + if (ngx_http_v2_send_rst_stream(h2c, stream->node->id, status) == NGX_ERROR) { @@ -3831,6 +3929,7 @@ ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, } stream->rst_sent = 1; + stream->skip_data = 1; fc = stream->request->connection; fc->error = 1; @@ -3862,6 +3961,7 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) if (stream->queued) { fc->write->handler = ngx_http_v2_close_stream_handler; + fc->read->handler = ngx_http_empty_handler; return; } @@ -4103,10 +4203,6 @@ ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c, c->error = 1; - if (h2c->state.stream) { - ngx_http_v2_close_stream(h2c->state.stream, NGX_HTTP_BAD_REQUEST); - } - if (!h2c->processing) { ngx_http_close_connection(c); return; diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 1adf8de..9e738aa 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -46,6 +46,9 @@ #define NGX_HTTP_V2_PADDED_FLAG 0x08 #define NGX_HTTP_V2_PRIORITY_FLAG 0x20 +#define NGX_HTTP_V2_MAX_WINDOW ((1U << 31) - 1) +#define NGX_HTTP_V2_DEFAULT_WINDOW 65535 + typedef struct ngx_http_v2_connection_s ngx_http_v2_connection_t; typedef struct ngx_http_v2_node_s ngx_http_v2_node_t; @@ -174,6 +177,8 @@ struct ngx_http_v2_stream_s { ssize_t send_window; size_t recv_window; + ngx_buf_t *preread; + ngx_http_v2_out_frame_t *free_frames; ngx_chain_t *free_frame_headers; ngx_chain_t *free_bufs; diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index caa835d..09ce3f6 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -169,6 +169,12 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) return NGX_OK; } + fc = r->connection; + + if (fc->error) { + return NGX_ERROR; + } + if (r->method == NGX_HTTP_HEAD) { r->header_only = 1; } @@ -259,8 +265,6 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) len += 1 + ngx_http_v2_literal_size("Wed, 31 Dec 1986 18:00:00 GMT"); } - fc = r->connection; - if (r->headers_out.location && r->headers_out.location->value.len) { if (r->headers_out.location->value.data[0] == '/') { @@ -1313,18 +1317,20 @@ static ngx_inline void ngx_http_v2_handle_stream(ngx_http_v2_connection_t *h2c, ngx_http_v2_stream_t *stream) { - ngx_event_t *wev; + ngx_connection_t *fc; - if (stream->handled || stream->blocked || stream->exhausted) { + if (stream->handled || stream->blocked) { return; } - wev = stream->request->connection->write; + fc = stream->request->connection; - if (!wev->delayed) { - stream->handled = 1; - ngx_queue_insert_tail(&h2c->posted, &stream->queue); + if (!fc->error && (stream->exhausted || fc->write->delayed)) { + return; } + + stream->handled = 1; + ngx_queue_insert_tail(&h2c->posted, &stream->queue); } diff --git a/src/http/v2/ngx_http_v2_module.c b/src/http/v2/ngx_http_v2_module.c index 5a4561c..b7d99e0 100644 --- a/src/http/v2/ngx_http_v2_module.c +++ b/src/http/v2/ngx_http_v2_module.c @@ -30,6 +30,7 @@ static char *ngx_http_v2_merge_loc_conf(ngx_conf_t *cf, void *parent, static char *ngx_http_v2_recv_buffer_size(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_v2_pool_size(ngx_conf_t *cf, void *post, void *data); +static char *ngx_http_v2_preread_size(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_v2_streams_index_mask(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_v2_chunk_size(ngx_conf_t *cf, void *post, void *data); @@ -41,6 +42,8 @@ static ngx_conf_post_t ngx_http_v2_recv_buffer_size_post = { ngx_http_v2_recv_buffer_size }; static ngx_conf_post_t ngx_http_v2_pool_size_post = { ngx_http_v2_pool_size }; +static ngx_conf_post_t ngx_http_v2_preread_size_post = + { ngx_http_v2_preread_size }; static ngx_conf_post_t ngx_http_v2_streams_index_mask_post = { ngx_http_v2_streams_index_mask }; static ngx_conf_post_t ngx_http_v2_chunk_size_post = @@ -84,6 +87,13 @@ static ngx_command_t ngx_http_v2_commands[] = { offsetof(ngx_http_v2_srv_conf_t, max_header_size), NULL }, + { ngx_string("http2_body_preread_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v2_srv_conf_t, preread_size), + &ngx_http_v2_preread_size_post }, + { ngx_string("http2_streams_index_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, @@ -316,6 +326,8 @@ ngx_http_v2_create_srv_conf(ngx_conf_t *cf) h2scf->max_field_size = NGX_CONF_UNSET_SIZE; h2scf->max_header_size = NGX_CONF_UNSET_SIZE; + h2scf->preread_size = NGX_CONF_UNSET_SIZE; + h2scf->streams_index_mask = NGX_CONF_UNSET_UINT; h2scf->recv_timeout = NGX_CONF_UNSET_MSEC; @@ -341,6 +353,8 @@ ngx_http_v2_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_size_value(conf->max_header_size, prev->max_header_size, 16384); + ngx_conf_merge_size_value(conf->preread_size, prev->preread_size, 65536); + ngx_conf_merge_uint_value(conf->streams_index_mask, prev->streams_index_mask, 32 - 1); @@ -419,6 +433,23 @@ ngx_http_v2_pool_size(ngx_conf_t *cf, void *post, void *data) } +static char * +ngx_http_v2_preread_size(ngx_conf_t *cf, void *post, void *data) +{ + size_t *sp = data; + + if (*sp > NGX_HTTP_V2_MAX_WINDOW) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the maximum body preread buffer size is %uz", + NGX_HTTP_V2_MAX_WINDOW); + + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + static char * ngx_http_v2_streams_index_mask(ngx_conf_t *cf, void *post, void *data) { diff --git a/src/http/v2/ngx_http_v2_module.h b/src/http/v2/ngx_http_v2_module.h index 95cc7d8..91f97c2 100644 --- a/src/http/v2/ngx_http_v2_module.h +++ b/src/http/v2/ngx_http_v2_module.h @@ -25,6 +25,7 @@ typedef struct { ngx_uint_t concurrent_streams; size_t max_field_size; size_t max_header_size; + size_t preread_size; ngx_uint_t streams_index_mask; ngx_msec_t recv_timeout; ngx_msec_t idle_timeout; From 6a025de47dcd08d6a937fed6ba3b3f131d23d059 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 20 Oct 2016 09:49:53 +0300 Subject: [PATCH 169/651] New upstream release --- debian/changelog | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index a678a83..1274498 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,7 @@ -nginx (1.10.1-6) UNRELEASED; urgency=medium +nginx (1.10.2-1) UNRELEASED; urgency=medium [ Christos Trochalakis ] + * New upstream release. * debian/control: + Version depend on lsb-base (>= 3.0-6). Fixes lintian init.d-script-needs-depends-on-lsb-base. @@ -12,7 +13,7 @@ nginx (1.10.1-6) UNRELEASED; urgency=medium * debian/nginx-common.dirs: + Adding support for packaged application configurations. - -- Michael Lustfield Wed, 19 Oct 2016 06:51:46 +0000 + -- Christos Trochalakis Thu, 20 Oct 2016 09:49:25 +0300 nginx (1.10.1-3) unstable; urgency=medium From 1e6e4c88cf4cadc27f5d6b4ecb1d6cd2a73e93f3 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 20 Oct 2016 09:58:54 +0300 Subject: [PATCH 170/651] Drop unused lintian overrides (spelling-error-in-binary) --- debian/changelog | 2 ++ debian/nginx-extras.lintian-overrides | 1 - debian/nginx-full.lintian-overrides | 1 - debian/nginx-light.lintian-overrides | 1 - 4 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 debian/nginx-extras.lintian-overrides delete mode 100644 debian/nginx-full.lintian-overrides delete mode 100644 debian/nginx-light.lintian-overrides diff --git a/debian/changelog b/debian/changelog index 1274498..c79b10a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -5,6 +5,8 @@ nginx (1.10.2-1) UNRELEASED; urgency=medium * debian/control: + Version depend on lsb-base (>= 3.0-6). Fixes lintian init.d-script-needs-depends-on-lsb-base. + * debian/nginx-*.lintian-overrides: + + Drop unused spelling-error-in-binary override. [ Michael Lustfield ] * debian/conf/sites-available/default: diff --git a/debian/nginx-extras.lintian-overrides b/debian/nginx-extras.lintian-overrides deleted file mode 100644 index a90c2bf..0000000 --- a/debian/nginx-extras.lintian-overrides +++ /dev/null @@ -1 +0,0 @@ -nginx-extras: spelling-error-in-binary usr/sbin/nginx tEH the diff --git a/debian/nginx-full.lintian-overrides b/debian/nginx-full.lintian-overrides deleted file mode 100644 index 4e6e3ed..0000000 --- a/debian/nginx-full.lintian-overrides +++ /dev/null @@ -1 +0,0 @@ -nginx-full: spelling-error-in-binary usr/sbin/nginx tEH the diff --git a/debian/nginx-light.lintian-overrides b/debian/nginx-light.lintian-overrides deleted file mode 100644 index 3ba2609..0000000 --- a/debian/nginx-light.lintian-overrides +++ /dev/null @@ -1 +0,0 @@ -nginx-light: spelling-error-in-binary usr/sbin/nginx tEH the From 37b847285aa31501fe7a58135ab783c845791c40 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 28 Oct 2016 09:31:11 +0300 Subject: [PATCH 171/651] Revert "Adding support for packaged application configurations." This reverts commit 5d09382c825202bf2b28ae16b6dbfb9485d3c67b. We will include it in a later release (-2) and perhaps adjust the paths involved. --- debian/changelog | 3 --- debian/conf/sites-available/default | 4 ---- debian/nginx-common.dirs | 1 - 3 files changed, 8 deletions(-) diff --git a/debian/changelog b/debian/changelog index c79b10a..3671be9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,9 +11,6 @@ nginx (1.10.2-1) UNRELEASED; urgency=medium [ Michael Lustfield ] * debian/conf/sites-available/default: + Updated PHP sample configuration block. (Closes: #841230) - + Adding include default-server.d/pkg_*.conf. (Closes: #822792) - * debian/nginx-common.dirs: - + Adding support for packaged application configurations. -- Christos Trochalakis Thu, 20 Oct 2016 09:49:25 +0300 diff --git a/debian/conf/sites-available/default b/debian/conf/sites-available/default index cca2b9a..bfb7f0c 100644 --- a/debian/conf/sites-available/default +++ b/debian/conf/sites-available/default @@ -68,10 +68,6 @@ server { #location ~ /\.ht { # deny all; #} - - # load package-maintained configuration files - # https://wiki.debian.org/Nginx/DirectoryStructure#Packaged_Applications - include default-server.d/pkg_*.conf; } diff --git a/debian/nginx-common.dirs b/debian/nginx-common.dirs index b674397..65bb651 100644 --- a/debian/nginx-common.dirs +++ b/debian/nginx-common.dirs @@ -4,7 +4,6 @@ etc/nginx/modules-available etc/nginx/modules-enabled etc/nginx/sites-available etc/nginx/sites-enabled -etc/nginx/default-server.d etc/ufw/applications.d usr/share/nginx usr/share/vim/addons From 333595dc8382e728bc9d57c1e533fa656b2fd6b3 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 14 Sep 2016 12:23:49 +0300 Subject: [PATCH 172/651] CVE-2016-1247: Secure log file handling Backporting patches from 1.6.2-5+deb8u{3,4} and adjusting the compare-versions check to 1.10.2-1~. --- debian/changelog | 8 ++++++ debian/control | 1 + debian/nginx-common.NEWS | 15 +++++++++++ debian/nginx-common.config | 36 +++++++++++++++++++++++++ debian/nginx-common.postinst | 35 ++++++++++++++++++------- debian/nginx-common.templates | 13 ++++++++++ debian/po/POTFILES.in | 1 + debian/po/templates.pot | 49 +++++++++++++++++++++++++++++++++++ 8 files changed, 148 insertions(+), 10 deletions(-) create mode 100755 debian/nginx-common.config create mode 100644 debian/nginx-common.templates create mode 100644 debian/po/POTFILES.in create mode 100644 debian/po/templates.pot diff --git a/debian/changelog b/debian/changelog index 3671be9..d36950e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,14 @@ nginx (1.10.2-1) UNRELEASED; urgency=medium [ Christos Trochalakis ] * New upstream release. + * debian/nginx-common.postinst: + + CVE-2016-1247: Secure log file handling (owner & permissions) + against privilege escalation attacks. /var/log/nginx is now owned + by root:adm. Thanks ro Dawid Golunski for the report. + Changing /var/log/nginx permissions effectively reopens #701112, + since log files can be world-readable. This is a trade-off until + a better log opening solution is implemented upstream (trac:376). + (Closes: #842295) * debian/control: + Version depend on lsb-base (>= 3.0-6). Fixes lintian init.d-script-needs-depends-on-lsb-base. diff --git a/debian/control b/debian/control index ec867ae..c9b5ab5 100644 --- a/debian/control +++ b/debian/control @@ -7,6 +7,7 @@ Uploaders: Kartik Mistry , Christos Trochalakis Build-Depends: autotools-dev, debhelper (>= 9), + po-debconf, dh-systemd (>= 1.5), dpkg-dev (>= 1.15.5), libexpat-dev, diff --git a/debian/nginx-common.NEWS b/debian/nginx-common.NEWS index 3d06e67..fd8e57a 100644 --- a/debian/nginx-common.NEWS +++ b/debian/nginx-common.NEWS @@ -1,3 +1,18 @@ +nginx-common (1.10.2-1) UNRELEASED; urgency=medium + + In order to secure nginx against privilege escalation attacks, we are + changing the way log file owners & permissions are handled so that www-data + is not allowed to symlink a logfile. /var/log/nginx is now owned by root:adm + and its permissions are changed to 0755. The package checks for such symlinks + on existing installations and informs the admin using debconf. + + That unfortunately may come at a cost in terms of privacy. /var/log/nginx is + now world-readable, and nginx hardcodes permissions of non-existing logs to + 0644. On systems running logrotate log files are private after the first + logrotate run, since the new log files are created with 0640 permissions. + + -- Christos Trochalakis Tue, 04 Oct 2016 15:20:33 +0300 + nginx-common (1.9.9-1) unstable; urgency=medium Starting with this release we are changing the default logrotate rule to keep diff --git a/debian/nginx-common.config b/debian/nginx-common.config new file mode 100755 index 0000000..27cb92f --- /dev/null +++ b/debian/nginx-common.config @@ -0,0 +1,36 @@ +#!/bin/sh + +set -e + +. /usr/share/debconf/confmodule + +logdir="/var/log/nginx" + +log_symlinks_check() { + # Skip new installations + [ -z "$1" ] && return + + # Skip unaffected installations + dpkg --compare-versions "$1" lt-nl "1.10.2-1~" || return 0 + + # Check for unsecure symlinks + linked_logfiles="` find "$logdir" -type l -user www-data -name '*.log' `" + + # Skip if nothing is found + [ -z "$linked_logfiles" ] && return + + db_subst nginx/log-symlinks logfiles $linked_logfiles + db_input high nginx/log-symlinks || true + db_go || true +} + +case "$1" in + configure|reconfigure) + log_symlinks_check "$2" + ;; + *) + ;; +esac + +# vim: set ts=4 sts=4 sw=4 et sta ai : + diff --git a/debian/nginx-common.postinst b/debian/nginx-common.postinst index 351bdf9..2b176f8 100644 --- a/debian/nginx-common.postinst +++ b/debian/nginx-common.postinst @@ -1,6 +1,8 @@ #!/bin/sh set -e +. /usr/share/debconf/confmodule + # Handle naxsi removal dpkg-maintscript-helper rm_conffile \ /etc/nginx/naxsi.rules 1.6.2-2~ -- "$@" @@ -14,18 +16,31 @@ dpkg-maintscript-helper rm_conffile \ case "$1" in configure) logdir="/var/log/nginx" - # Ensure secure permissions (CVE-2013-0337) - # http://bugs.debian.org/701112 - # - # nginx uses 0755 for log files making them world readable, - # we fix that by using 0750 for the log directory. - # - # Allow local admin to override: - # e.g. dpkg-statoverride --add root adm 0755 /var/log/nginx + + # Allow local admin to override if ! dpkg-statoverride --list "$logdir" >/dev/null; then - chown www-data:adm $logdir - chmod 0750 $logdir + chown root:adm $logdir + chmod 0755 $logdir fi + + # Secure default logfiles on fresh installations + if [ -z "$2" ]; then + access_log="$logdir/access.log" + error_log="$logdir/error.log" + + if [ ! -e "$access_log" ]; then + touch "$access_log" + chmod 640 "$access_log" + chown www-data:adm "$access_log" + fi + + if [ ! -e "$error_log" ]; then + touch "$error_log" + chmod 640 "$error_log" + chown www-data:adm "$error_log" + fi + fi + # If a symlink doesn't exist and can be created, then create it. if [ -z $2 ] && [ ! -e /etc/nginx/sites-enabled/default ] && [ -d /etc/nginx/sites-enabled ] && [ -d /etc/nginx/sites-available ]; then diff --git a/debian/nginx-common.templates b/debian/nginx-common.templates new file mode 100644 index 0000000..225762c --- /dev/null +++ b/debian/nginx-common.templates @@ -0,0 +1,13 @@ +Template: nginx/log-symlinks +Type: note +_Description: Possible insecure nginx log files + The following log files under /var/log/nginx directory are symlinks + owned by www-data: + . + ${logfiles} + . + Since nginx 1.4.4-4 /var/log/nginx was owned by www-data. As a result + www-data could symlink log files to sensitive locations, which in turn + could lead to privilege escalation attacks. Although /var/log/nginx + permissions are now fixed it is possible that such insecure links + already exist. So, please make sure to check the above locations. diff --git a/debian/po/POTFILES.in b/debian/po/POTFILES.in new file mode 100644 index 0000000..dcbe15b --- /dev/null +++ b/debian/po/POTFILES.in @@ -0,0 +1 @@ +[type: gettext/rfc822deb] nginx-common.templates diff --git a/debian/po/templates.pot b/debian/po/templates.pot new file mode 100644 index 0000000..bb72383 --- /dev/null +++ b/debian/po/templates.pot @@ -0,0 +1,49 @@ +# Nginx debconf translations +# Copyright (C) 2016 Christos Trochalakis +# This file is distributed under the same license as the nginx package. +# Chrirtos Trochalakis , 2016. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: nginx\n" +"Report-Msgid-Bugs-To: nginx@packages.debian.org\n" +"POT-Creation-Date: 2016-10-04 20:03+0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: note +#. Description +#: ../nginx-common.templates:1001 +msgid "Possible insecure nginx log files" +msgstr "" + +#. Type: note +#. Description +#: ../nginx-common.templates:1001 +msgid "" +"The following log files under /var/log/nginx directory are symlinks owned by " +"www-data:" +msgstr "" + +#. Type: note +#. Description +#: ../nginx-common.templates:1001 +msgid "${logfiles}" +msgstr "" + +#. Type: note +#. Description +#: ../nginx-common.templates:1001 +msgid "" +"Since nginx 1.4.4-4 /var/log/nginx was owned by www-data. As a result www-" +"data could symlink log files to sensitive locations, which in turn could " +"lead to privilege escalation attacks. Although /var/log/nginx permissions " +"are now fixed it is possible that such insecure links already exist. So, " +"please make sure to check the above locations." +msgstr "" From 7f827f420adfcfeeb6c9a08aba3f006ad39e7d79 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Sat, 29 Oct 2016 08:45:31 +0300 Subject: [PATCH 173/651] Release 1.10.2-1 --- debian/changelog | 4 ++-- debian/nginx-common.NEWS | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index d36950e..03d1afb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.10.2-1) UNRELEASED; urgency=medium +nginx (1.10.2-1) unstable; urgency=high [ Christos Trochalakis ] * New upstream release. @@ -20,7 +20,7 @@ nginx (1.10.2-1) UNRELEASED; urgency=medium * debian/conf/sites-available/default: + Updated PHP sample configuration block. (Closes: #841230) - -- Christos Trochalakis Thu, 20 Oct 2016 09:49:25 +0300 + -- Christos Trochalakis Sat, 29 Oct 2016 08:45:09 +0300 nginx (1.10.1-3) unstable; urgency=medium diff --git a/debian/nginx-common.NEWS b/debian/nginx-common.NEWS index fd8e57a..da94a4c 100644 --- a/debian/nginx-common.NEWS +++ b/debian/nginx-common.NEWS @@ -1,4 +1,4 @@ -nginx-common (1.10.2-1) UNRELEASED; urgency=medium +nginx-common (1.10.2-1) unstable; urgency=high In order to secure nginx against privilege escalation attacks, we are changing the way log file owners & permissions are handled so that www-data From 4cf05a14a9a87a97daa9017cd3d577fc07cd7507 Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Sat, 29 Oct 2016 20:48:02 +0000 Subject: [PATCH 174/651] Removing php major version number from comment --- debian/conf/sites-available/default | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/conf/sites-available/default b/debian/conf/sites-available/default index bfb7f0c..890f572 100644 --- a/debian/conf/sites-available/default +++ b/debian/conf/sites-available/default @@ -56,9 +56,9 @@ server { #location ~ \.php$ { # include snippets/fastcgi-php.conf; # - # # With php5-fpm (or other unix sockets): + # # With php-fpm (or other unix sockets): # fastcgi_pass unix:/var/run/php7.0-fpm.sock; - # # With php5-cgi (or other tcp sockets): + # # With php-cgi (or other tcp sockets): # fastcgi_pass 127.0.0.1:9000; #} From 62276a745b977df88a9a8e7d02bd0ed9e3d27d8b Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Sat, 29 Oct 2016 17:27:05 +0300 Subject: [PATCH 175/651] mod: Convert dav-ext to dynamic module Patch by Florian Kinder --- debian/changelog | 8 ++++++++ debian/control | 11 +++++++++++ debian/libnginx-mod-http-dav-ext.nginx | 13 +++++++++++++ debian/libnginx-mod.conf/mod-http-dav-ext.conf | 1 + debian/modules/README.Modules-versions | 3 +-- debian/modules/nginx-dav-ext-module/config | 16 ++++++++++++---- debian/rules | 5 +++-- debian/tests/control | 3 +++ 8 files changed, 52 insertions(+), 8 deletions(-) create mode 100755 debian/libnginx-mod-http-dav-ext.nginx create mode 100644 debian/libnginx-mod.conf/mod-http-dav-ext.conf diff --git a/debian/changelog b/debian/changelog index 03d1afb..a8ec36c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +nginx (1.10.2-2) UNRELEASED; urgency=medium + + * debian/modules: + + Convert dav-ext to a dynamic module package: + o libnginx-mod-http-dav-ext + + -- Christos Trochalakis Sat, 29 Oct 2016 17:26:04 +0300 + nginx (1.10.2-1) unstable; urgency=high [ Christos Trochalakis ] diff --git a/debian/control b/debian/control index c9b5ab5..704c309 100644 --- a/debian/control +++ b/debian/control @@ -70,6 +70,7 @@ Description: small, powerful, scalable web/proxy server - common files Package: nginx-full Architecture: any Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), + libnginx-mod-http-dav-ext (= ${binary:Version}), libnginx-mod-http-echo (= ${binary:Version}), libnginx-mod-http-geoip (= ${binary:Version}), libnginx-mod-http-image-filter (= ${binary:Version}), @@ -141,6 +142,7 @@ Architecture: any Priority: extra Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), libnginx-mod-http-cache-purge (= ${binary:Version}), + libnginx-mod-http-dav-ext (= ${binary:Version}), libnginx-mod-http-echo (= ${binary:Version}), libnginx-mod-http-fancyindex (= ${binary:Version}), libnginx-mod-http-geoip (= ${binary:Version}), @@ -371,3 +373,12 @@ Description: Substitution filter module for Nginx substitutions on response bodies. The module is quite different from Nginx's native Substitution module. It scans the output chains buffer and matches string line by line, just like Apache's mod_substitute. + +Package: libnginx-mod-http-dav-ext +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: WebDAV missing commands support for Nginx + WebDAV Ext module complements the Nginx WebDAV module to provide a full + WebDAV support. + . + WebDAV Ext provides the missing PROPFIND & OPTIONS methods. diff --git a/debian/libnginx-mod-http-dav-ext.nginx b/debian/libnginx-mod-http-dav-ext.nginx new file mode 100755 index 0000000..78c206f --- /dev/null +++ b/debian/libnginx-mod-http-dav-ext.nginx @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use File::Basename; + +# Guess module name +$module = basename($0, '.nginx'); +$module =~ s/^libnginx-mod-//; + +$modulepath = $module; +$modulepath =~ s/-/_/g; + +print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod.conf/mod-http-dav-ext.conf b/debian/libnginx-mod.conf/mod-http-dav-ext.conf new file mode 100644 index 0000000..e852329 --- /dev/null +++ b/debian/libnginx-mod.conf/mod-http-dav-ext.conf @@ -0,0 +1 @@ +load_module modules/ngx_http_dav_ext_module.so; diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index a87f25d..33135ac 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -43,8 +43,7 @@ README for Modules versions nginx-dav-ext-module Homepage: https://github.com/arut/nginx-dav-ext-module - Version: v0.0.3 - Dynamic: No, https://github.com/arut/nginx-dav-ext-module/issues/21 + Version: v0.0.3+pull/22 ngx-fancyindex Homepage: https://github.com/aperezdc/ngx-fancyindex diff --git a/debian/modules/nginx-dav-ext-module/config b/debian/modules/nginx-dav-ext-module/config index 98b2b7a..b7aeb7a 100644 --- a/debian/modules/nginx-dav-ext-module/config +++ b/debian/modules/nginx-dav-ext-module/config @@ -1,9 +1,17 @@ ngx_addon_name="ngx_http_dav_ext_module" -HTTP_MODULES="$HTTP_MODULES \ +CORE_LIBS="$CORE_LIBS -lexpat" + +if test -n "$ngx_module_link"; then + ngx_module_type=HTTP + ngx_module_name=ngx_http_dav_ext_module + ngx_module_srcs="$ngx_addon_dir/ngx_http_dav_ext_module.c" + + . auto/module +else + HTTP_MODULES="$HTTP_MODULES \ ngx_http_dav_ext_module" -NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ + NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ $ngx_addon_dir/ngx_http_dav_ext_module.c" - -CORE_LIBS="$CORE_LIBS -lexpat" +fi diff --git a/debian/rules b/debian/rules index 7547660..3194993 100755 --- a/debian/rules +++ b/debian/rules @@ -14,6 +14,7 @@ FLAVOURS := full light extras DYN_MODS := \ http-auth-pam \ http-cache-purge \ + http-dav-ext \ http-echo \ http-fancyindex \ http-geoip \ @@ -99,7 +100,7 @@ full_configure_flags := \ --with-mail=dynamic \ --with-mail_ssl_module \ --add-dynamic-module=$(MODULESDIR)/nginx-auth-pam \ - --add-module=$(MODULESDIR)/nginx-dav-ext-module \ + --add-dynamic-module=$(MODULESDIR)/nginx-dav-ext-module \ --add-dynamic-module=$(MODULESDIR)/nginx-echo \ --add-dynamic-module=$(MODULESDIR)/nginx-upstream-fair \ --add-dynamic-module=$(MODULESDIR)/ngx_http_substitutions_filter_module @@ -125,7 +126,7 @@ extras_configure_flags := \ --add-dynamic-module=$(MODULESDIR)/headers-more-nginx-module \ --add-dynamic-module=$(MODULESDIR)/nginx-auth-pam \ --add-dynamic-module=$(MODULESDIR)/nginx-cache-purge \ - --add-module=$(MODULESDIR)/nginx-dav-ext-module \ + --add-dynamic-module=$(MODULESDIR)/nginx-dav-ext-module \ --add-dynamic-module=$(MODULESDIR)/nginx-development-kit \ --add-dynamic-module=$(MODULESDIR)/nginx-echo \ --add-dynamic-module=$(MODULESDIR)/ngx-fancyindex \ diff --git a/debian/tests/control b/debian/tests/control index 86a0da7..2bc571a 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -16,6 +16,7 @@ Depends: nginx-full, curl, libnginx-mod-http-auth-pam, libnginx-mod-http-cache-purge, + libnginx-mod-http-dav-ext, libnginx-mod-http-echo, libnginx-mod-http-fancyindex, libnginx-mod-http-geoip, @@ -37,6 +38,7 @@ Depends: nginx-light, curl, libnginx-mod-http-auth-pam, libnginx-mod-http-cache-purge, + libnginx-mod-http-dav-ext, libnginx-mod-http-echo, libnginx-mod-http-fancyindex, libnginx-mod-http-geoip, @@ -58,6 +60,7 @@ Depends: nginx-extras, curl, libnginx-mod-http-auth-pam, libnginx-mod-http-cache-purge, + libnginx-mod-http-dav-ext, libnginx-mod-http-echo, libnginx-mod-http-fancyindex, libnginx-mod-http-geoip, From 340b30f10ca4b6765f30e88804887deabee3752d Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Sun, 30 Oct 2016 12:25:28 +0200 Subject: [PATCH 176/651] Rethink module patches logic Collect all patches under debian/patches/modules so they can be easily tracked and apply them before configure. --- debian/changelog | 1 + debian/control | 1 + debian/modules/README.Modules-versions | 12 ++++-- debian/modules/nginx-cache-purge/config | 14 +------ debian/modules/nginx-dav-ext-module/config | 16 ++------ debian/modules/nginx-upstream-fair/config | 13 +----- .../config | 16 +------- .../nginx-cache-purge/dynamic-module.patch | 34 +++++++++++++++ .../patches/modules/nginx-cache-purge/series | 1 + .../nginx-dav-ext-module/dynamic-module.patch | 41 +++++++++++++++++++ .../modules/nginx-dav-ext-module/series | 1 + .../nginx-upstream-fair/dynamic-module.patch | 29 +++++++++++++ .../modules/nginx-upstream-fair/series | 1 + .../dynamic-module.patch | 32 +++++++++++++++ .../series | 1 + debian/rules | 11 ++++- 16 files changed, 170 insertions(+), 54 deletions(-) create mode 100644 debian/patches/modules/nginx-cache-purge/dynamic-module.patch create mode 100644 debian/patches/modules/nginx-cache-purge/series create mode 100644 debian/patches/modules/nginx-dav-ext-module/dynamic-module.patch create mode 100644 debian/patches/modules/nginx-dav-ext-module/series create mode 100644 debian/patches/modules/nginx-upstream-fair/dynamic-module.patch create mode 100644 debian/patches/modules/nginx-upstream-fair/series create mode 100644 debian/patches/modules/ngx_http_substitutions_filter_module/dynamic-module.patch create mode 100644 debian/patches/modules/ngx_http_substitutions_filter_module/series diff --git a/debian/changelog b/debian/changelog index a8ec36c..5101bbb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,7 @@ nginx (1.10.2-2) UNRELEASED; urgency=medium * debian/modules: + + Rethink module patching logic. + Convert dav-ext to a dynamic module package: o libnginx-mod-http-dav-ext diff --git a/debian/control b/debian/control index 704c309..e553a8a 100644 --- a/debian/control +++ b/debian/control @@ -23,6 +23,7 @@ Build-Depends: autotools-dev, libssl-dev, libxslt1-dev, po-debconf, + quilt, zlib1g-dev Standards-Version: 3.9.8.0 Homepage: http://nginx.net diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index 33135ac..e999b41 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -26,7 +26,8 @@ README for Modules versions nginx-upstream-fair Homepage: https://github.com/gnosek/nginx-upstream-fair - Version: a18b409+pull/21 + Version: a18b409 + Patch: dynamic-module.patch nchan Homepage: https://github.com/slact/nchan @@ -39,11 +40,13 @@ README for Modules versions nginx-cache-purge Homepage: https://github.com/FRiCKLE/ngx_cache_purge/ - Version: 2.3+pull/45 + Version: 2.3 + Patch: dynamic-module.patch nginx-dav-ext-module Homepage: https://github.com/arut/nginx-dav-ext-module - Version: v0.0.3+pull/22 + Version: v0.0.3 + Patch: dynamic-module.patch ngx-fancyindex Homepage: https://github.com/aperezdc/ngx-fancyindex @@ -51,4 +54,5 @@ README for Modules versions ngx_http_substitutions_filter_module Homepage: https://github.com/yaoweibin/ngx_http_substitutions_filter_module - Version: v0.6.4+pull/19 + Version: v0.6.4 + Patch: dynamic-module.patch diff --git a/debian/modules/nginx-cache-purge/config b/debian/modules/nginx-cache-purge/config index b900680..34f42ec 100644 --- a/debian/modules/nginx-cache-purge/config +++ b/debian/modules/nginx-cache-purge/config @@ -15,17 +15,7 @@ if [ "$HTTP_UWSGI" = "YES" ]; then fi ngx_addon_name=ngx_http_cache_purge_module -CACHE_PURGE_SRCS="$ngx_addon_dir/ngx_cache_purge_module.c" - -if [ -n "$ngx_module_link" ]; then - ngx_module_type=HTTP - ngx_module_name="$ngx_addon_name" - ngx_module_srcs="$CACHE_PURGE_SRCS" - - . auto/module -else - HTTP_MODULES="$HTTP_MODULES $ngx_addon_name" - NGX_ADDON_SRCS="$NGX_ADDON_SRCS $CACHE_PURGE_SRCS" -fi +HTTP_MODULES="$HTTP_MODULES ngx_http_cache_purge_module" +NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_cache_purge_module.c" have=NGX_CACHE_PURGE_MODULE . auto/have diff --git a/debian/modules/nginx-dav-ext-module/config b/debian/modules/nginx-dav-ext-module/config index b7aeb7a..98b2b7a 100644 --- a/debian/modules/nginx-dav-ext-module/config +++ b/debian/modules/nginx-dav-ext-module/config @@ -1,17 +1,9 @@ ngx_addon_name="ngx_http_dav_ext_module" -CORE_LIBS="$CORE_LIBS -lexpat" - -if test -n "$ngx_module_link"; then - ngx_module_type=HTTP - ngx_module_name=ngx_http_dav_ext_module - ngx_module_srcs="$ngx_addon_dir/ngx_http_dav_ext_module.c" - - . auto/module -else - HTTP_MODULES="$HTTP_MODULES \ +HTTP_MODULES="$HTTP_MODULES \ ngx_http_dav_ext_module" - NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ +NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ $ngx_addon_dir/ngx_http_dav_ext_module.c" -fi + +CORE_LIBS="$CORE_LIBS -lexpat" diff --git a/debian/modules/nginx-upstream-fair/config b/debian/modules/nginx-upstream-fair/config index d8d478b..ff351b7 100644 --- a/debian/modules/nginx-upstream-fair/config +++ b/debian/modules/nginx-upstream-fair/config @@ -1,12 +1,3 @@ ngx_addon_name=ngx_http_upstream_fair_module - -if test -n "$ngx_module_link"; then - ngx_module_type=HTTP - ngx_module_name=ngx_http_upstream_fair_module - ngx_module_srcs="$ngx_addon_dir/ngx_http_upstream_fair_module.c" - - . auto/module -else - HTTP_MODULES="$HTTP_MODULES ngx_http_upstream_fair_module" - NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_upstream_fair_module.c" -fi +HTTP_MODULES="$HTTP_MODULES ngx_http_upstream_fair_module" +NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_upstream_fair_module.c" diff --git a/debian/modules/ngx_http_substitutions_filter_module/config b/debian/modules/ngx_http_substitutions_filter_module/config index f1de029..fdb016c 100644 --- a/debian/modules/ngx_http_substitutions_filter_module/config +++ b/debian/modules/ngx_http_substitutions_filter_module/config @@ -1,15 +1,3 @@ ngx_addon_name=ngx_http_subs_filter_module - -if test -n "$ngx_module_link"; then - ngx_module_type=HTTP_FILTER - ngx_module_name=ngx_http_subs_filter_module - ngx_module_incs= - ngx_module_deps= - ngx_module_srcs="$ngx_addon_dir/ngx_http_subs_filter_module.c" - ngx_module_libs="" - - . auto/module -else - HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_subs_filter_module" - NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_subs_filter_module.c" -fi +HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_subs_filter_module" +NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_subs_filter_module.c" diff --git a/debian/patches/modules/nginx-cache-purge/dynamic-module.patch b/debian/patches/modules/nginx-cache-purge/dynamic-module.patch new file mode 100644 index 0000000..58dc77c --- /dev/null +++ b/debian/patches/modules/nginx-cache-purge/dynamic-module.patch @@ -0,0 +1,34 @@ +From 26d7114ac82195cd4f7db606d7762a6cff9132ad Mon Sep 17 00:00:00 2001 +From: Hiroaki Nakamura +Date: Fri, 12 Feb 2016 09:03:35 +0900 +Subject: [PATCH] Convert a config file to build a dynamic module +Origin: other, https://github.com/FRiCKLE/ngx_cache_purge/pull/45 + +--- + config | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/config b/config +index 34f42ec..b900680 100644 +--- a/config ++++ b/config +@@ -15,7 +15,17 @@ if [ "$HTTP_UWSGI" = "YES" ]; then + fi + + ngx_addon_name=ngx_http_cache_purge_module +-HTTP_MODULES="$HTTP_MODULES ngx_http_cache_purge_module" +-NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_cache_purge_module.c" ++CACHE_PURGE_SRCS="$ngx_addon_dir/ngx_cache_purge_module.c" ++ ++if [ -n "$ngx_module_link" ]; then ++ ngx_module_type=HTTP ++ ngx_module_name="$ngx_addon_name" ++ ngx_module_srcs="$CACHE_PURGE_SRCS" ++ ++ . auto/module ++else ++ HTTP_MODULES="$HTTP_MODULES $ngx_addon_name" ++ NGX_ADDON_SRCS="$NGX_ADDON_SRCS $CACHE_PURGE_SRCS" ++fi + + have=NGX_CACHE_PURGE_MODULE . auto/have diff --git a/debian/patches/modules/nginx-cache-purge/series b/debian/patches/modules/nginx-cache-purge/series new file mode 100644 index 0000000..f9b9360 --- /dev/null +++ b/debian/patches/modules/nginx-cache-purge/series @@ -0,0 +1 @@ +dynamic-module.patch diff --git a/debian/patches/modules/nginx-dav-ext-module/dynamic-module.patch b/debian/patches/modules/nginx-dav-ext-module/dynamic-module.patch new file mode 100644 index 0000000..c865460 --- /dev/null +++ b/debian/patches/modules/nginx-dav-ext-module/dynamic-module.patch @@ -0,0 +1,41 @@ +From 0473d8d1bb63a14afe608ecf46bfc933234e3048 Mon Sep 17 00:00:00 2001 +From: Florian Kinder +Date: Fri, 28 Oct 2016 13:34:21 +0200 +Subject: [PATCH] Added dynamic module support +Origin: other, https://github.com/Fank/nginx-dav-ext-module/pull/1 + +--- + config | 22 +++++++++++++++++----- + 1 file changed, 17 insertions(+), 5 deletions(-) + +diff --git a/config b/config +index 98b2b7a..b6b65de 100644 +--- a/config ++++ b/config +@@ -1,9 +1,21 @@ + ngx_addon_name="ngx_http_dav_ext_module" + +-HTTP_MODULES="$HTTP_MODULES \ +- ngx_http_dav_ext_module" + +-NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ +- $ngx_addon_dir/ngx_http_dav_ext_module.c" ++if test -n "$ngx_module_link"; then ++ ngx_module_type=HTTP ++ ngx_module_name=ngx_http_dav_ext_module ++ ngx_module_incs= ++ ngx_module_deps= ++ ngx_module_srcs="$ngx_addon_dir/ngx_http_dav_ext_module.c" ++ ngx_module_libs="-lexpat" ++ ++ . auto/module ++else ++ CORE_LIBS="$CORE_LIBS -lexpat" + +-CORE_LIBS="$CORE_LIBS -lexpat" ++ HTTP_MODULES="$HTTP_MODULES \ ++ ngx_http_dav_ext_module" ++ ++ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ ++ $ngx_addon_dir/ngx_http_dav_ext_module.c" ++fi diff --git a/debian/patches/modules/nginx-dav-ext-module/series b/debian/patches/modules/nginx-dav-ext-module/series new file mode 100644 index 0000000..f9b9360 --- /dev/null +++ b/debian/patches/modules/nginx-dav-ext-module/series @@ -0,0 +1 @@ +dynamic-module.patch diff --git a/debian/patches/modules/nginx-upstream-fair/dynamic-module.patch b/debian/patches/modules/nginx-upstream-fair/dynamic-module.patch new file mode 100644 index 0000000..0e00466 --- /dev/null +++ b/debian/patches/modules/nginx-upstream-fair/dynamic-module.patch @@ -0,0 +1,29 @@ +From 725c58638f5d1921ad5d4a39274edb81bc5b47e6 Mon Sep 17 00:00:00 2001 +From: 99999 +Date: Sat, 30 Apr 2016 23:56:19 +1000 +Subject: [PATCH] nginx-upstream-fair can now be compiled as a dynamic module +Origin: other, https://github.com/gnosek/nginx-upstream-fair/pull/21 + +--- + config | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/config b/config +index ff351b7..d8d478b 100644 +--- a/config ++++ b/config +@@ -1,3 +1,12 @@ + ngx_addon_name=ngx_http_upstream_fair_module +-HTTP_MODULES="$HTTP_MODULES ngx_http_upstream_fair_module" +-NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_upstream_fair_module.c" ++ ++if test -n "$ngx_module_link"; then ++ ngx_module_type=HTTP ++ ngx_module_name=ngx_http_upstream_fair_module ++ ngx_module_srcs="$ngx_addon_dir/ngx_http_upstream_fair_module.c" ++ ++ . auto/module ++else ++ HTTP_MODULES="$HTTP_MODULES ngx_http_upstream_fair_module" ++ NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_upstream_fair_module.c" ++fi diff --git a/debian/patches/modules/nginx-upstream-fair/series b/debian/patches/modules/nginx-upstream-fair/series new file mode 100644 index 0000000..f9b9360 --- /dev/null +++ b/debian/patches/modules/nginx-upstream-fair/series @@ -0,0 +1 @@ +dynamic-module.patch diff --git a/debian/patches/modules/ngx_http_substitutions_filter_module/dynamic-module.patch b/debian/patches/modules/ngx_http_substitutions_filter_module/dynamic-module.patch new file mode 100644 index 0000000..2001ff7 --- /dev/null +++ b/debian/patches/modules/ngx_http_substitutions_filter_module/dynamic-module.patch @@ -0,0 +1,32 @@ +From b157ed379c3c9c5c1846caa594d6733e88406863 Mon Sep 17 00:00:00 2001 +From: Jeffrey Kriegsman +Date: Mon, 15 Feb 2016 15:36:21 +0100 +Subject: [PATCH] Feature: nginx dynamic module support +Origin: other, https://github.com/yaoweibin/ngx_http_substitutions_filter_module/pull/19 + +--- + config | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/config b/config +index fdb016c..f1de029 100644 +--- a/config ++++ b/config +@@ -1,3 +1,15 @@ + ngx_addon_name=ngx_http_subs_filter_module +-HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_subs_filter_module" +-NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_subs_filter_module.c" ++ ++if test -n "$ngx_module_link"; then ++ ngx_module_type=HTTP_FILTER ++ ngx_module_name=ngx_http_subs_filter_module ++ ngx_module_incs= ++ ngx_module_deps= ++ ngx_module_srcs="$ngx_addon_dir/ngx_http_subs_filter_module.c" ++ ngx_module_libs="" ++ ++ . auto/module ++else ++ HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_subs_filter_module" ++ NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_subs_filter_module.c" ++fi diff --git a/debian/patches/modules/ngx_http_substitutions_filter_module/series b/debian/patches/modules/ngx_http_substitutions_filter_module/series new file mode 100644 index 0000000..f9b9360 --- /dev/null +++ b/debian/patches/modules/ngx_http_substitutions_filter_module/series @@ -0,0 +1 @@ +dynamic-module.patch diff --git a/debian/rules b/debian/rules index 3194993..f1806b1 100755 --- a/debian/rules +++ b/debian/rules @@ -45,6 +45,9 @@ ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) MAKEFLAGS += -j$(NUMJOBS) endif +MODULESPATCHDIR = $(CURDIR)/debian/patches/modules +modules_with_patches := $(notdir $(wildcard $(CURDIR)/debian/patches/modules/*)) + # configure flags common_configure_flags := \ --with-cc-opt="$(debian_cflags)" \ @@ -139,7 +142,7 @@ extras_configure_flags := \ %: dh $@ --with systemd -override_dh_auto_configure: $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) +override_dh_auto_configure: config_patch_modules $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) override_dh_auto_build: $(foreach flavour,$(FLAVOURS),build.arch.$(flavour)) override_dh_strip: $(foreach flavour,$(FLAVOURS),strip.arch.$(flavour)) $(foreach mod,$(DYN_MODS),strip.mods.$(mod)) override_dh_clean: $(foreach flavour,$(FLAVOURS),clean.$(flavour)) @@ -167,6 +170,10 @@ strip.arch.%: strip.mods.%: dh_strip --package=libnginx-mod-$(*) -O--automatic-dbgsym +config_patch_modules: $(foreach mod,$(modules_with_patches),config.patch.$(mod)) +config.patch.%: + cd $(MODULESDIR)/$* && QUILT_PATCHES=$(MODULESPATCHDIR)/$* quilt push -a + config.arch.%: dh_testdir mkdir -p $(BUILDDIR_$*) @@ -180,3 +187,5 @@ config.arch.%: clean.%: rm -rf $(BUILDDIR_$*) + +.PHONY: config_patch_modules From 2a4f3717931bea9ee2090a9e5f260dbdf1acc149 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 5 Sep 2016 16:55:33 +0300 Subject: [PATCH 177/651] upstream-fair: Apply OpenSSL 1.1.0 FTBFS https://github.com/gnosek/nginx-upstream-fair/pull/22 --- debian/modules/README.Modules-versions | 1 + .../nginx-upstream-fair/openssl-1.1.0.patch | 50 +++++++++++++++++++ .../modules/nginx-upstream-fair/series | 1 + 3 files changed, 52 insertions(+) create mode 100644 debian/patches/modules/nginx-upstream-fair/openssl-1.1.0.patch diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index e999b41..2ac5f96 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -28,6 +28,7 @@ README for Modules versions Homepage: https://github.com/gnosek/nginx-upstream-fair Version: a18b409 Patch: dynamic-module.patch + Patch: openssl-1.1.0.patch nchan Homepage: https://github.com/slact/nchan diff --git a/debian/patches/modules/nginx-upstream-fair/openssl-1.1.0.patch b/debian/patches/modules/nginx-upstream-fair/openssl-1.1.0.patch new file mode 100644 index 0000000..c154daa --- /dev/null +++ b/debian/patches/modules/nginx-upstream-fair/openssl-1.1.0.patch @@ -0,0 +1,50 @@ +From cfdf4ffa18e812cbbff3872c1026c3c072d22c09 Mon Sep 17 00:00:00 2001 +From: Kurt Roeckx +Date: Fri, 2 Sep 2016 23:04:36 +0200 +Subject: [PATCH] Make it build using OpenSSL 1.1.0 +Origin: other, https://github.com/gnosek/nginx-upstream-fair/pull/22 + +The reference counter is now internal in OpenSSL and not accessible any more. +--- + ngx_http_upstream_fair_module.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +diff --git a/ngx_http_upstream_fair_module.c b/ngx_http_upstream_fair_module.c +index a4419ca..6353f1b 100644 +--- a/ngx_http_upstream_fair_module.c ++++ b/ngx_http_upstream_fair_module.c +@@ -1174,9 +1174,8 @@ ngx_http_upstream_fair_set_session(ngx_peer_connection_t *pc, void *data) + + rc = ngx_ssl_set_session(pc->connection, ssl_session); + +- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, +- "set session: %p:%d", +- ssl_session, ssl_session ? ssl_session->references : 0); ++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, ++ "set session: %p", ssl_session); + + /* ngx_unlock_mutex(fp->peers->mutex); */ + +@@ -1200,8 +1199,8 @@ ngx_http_upstream_fair_save_session(ngx_peer_connection_t *pc, void *data) + return; + } + +- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, +- "save session: %p:%d", ssl_session, ssl_session->references); ++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, ++ "save session: %p", ssl_session); + + peer = &fp->peers->peer[fp->current]; + +@@ -1215,9 +1214,8 @@ ngx_http_upstream_fair_save_session(ngx_peer_connection_t *pc, void *data) + + if (old_ssl_session) { + +- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, +- "old session: %p:%d", +- old_ssl_session, old_ssl_session->references); ++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, ++ "old session: %p", old_ssl_session); + + /* TODO: may block */ + diff --git a/debian/patches/modules/nginx-upstream-fair/series b/debian/patches/modules/nginx-upstream-fair/series index f9b9360..373a826 100644 --- a/debian/patches/modules/nginx-upstream-fair/series +++ b/debian/patches/modules/nginx-upstream-fair/series @@ -1 +1,2 @@ dynamic-module.patch +openssl-1.1.0.patch From 0ec83a636e60da5434b36c6c3b07570c71e79208 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 3 Nov 2016 15:12:22 +0200 Subject: [PATCH 178/651] lua: Apply OpenSSL 1.1.0 FTBFS https://github.com/openresty/lua-nginx-module/pull/761 --- debian/modules/README.Modules-versions | 1 + .../modules/nginx-lua/openssl-1.1.0.patch | 799 ++++++++++++++++++ debian/patches/modules/nginx-lua/series | 1 + 3 files changed, 801 insertions(+) create mode 100644 debian/patches/modules/nginx-lua/openssl-1.1.0.patch create mode 100644 debian/patches/modules/nginx-lua/series diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index 2ac5f96..a8b93ff 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -23,6 +23,7 @@ README for Modules versions nginx-lua Homepage: https://github.com/openresty/lua-nginx-module Version: v0.10.6 + Patch: openssl-1.1.0.patch nginx-upstream-fair Homepage: https://github.com/gnosek/nginx-upstream-fair diff --git a/debian/patches/modules/nginx-lua/openssl-1.1.0.patch b/debian/patches/modules/nginx-lua/openssl-1.1.0.patch new file mode 100644 index 0000000..e3d0a92 --- /dev/null +++ b/debian/patches/modules/nginx-lua/openssl-1.1.0.patch @@ -0,0 +1,799 @@ +From 61301109f812bc8af0e731cea90ed89e03b7b4aa Mon Sep 17 00:00:00 2001 +From: Alessandro Ghedini +Date: Tue, 13 Sep 2016 22:31:32 +0100 +Subject: [PATCH 1/5] bugfix: ssl: use TLV1.2 in tests + +--- + t/142-ssl-session-store.t | 20 ++++++++++---------- + t/143-ssl-session-fetch.t | 24 ++++++++++++------------ + 2 files changed, 22 insertions(+), 22 deletions(-) + +diff --git a/t/142-ssl-session-store.t b/t/142-ssl-session-store.t +index da84a8d..d0d6080 100644 +--- a/t/142-ssl-session-store.t ++++ b/t/142-ssl-session-store.t +@@ -32,7 +32,7 @@ __DATA__ + ssl_session_store_by_lua_block { print("ssl session store by lua is running!") } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + + server_tokens off; + } +@@ -102,7 +102,7 @@ ssl_session_store_by_lua_block:1: ssl session store by lua is running! + } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + + server_tokens off; + } +@@ -177,7 +177,7 @@ API disabled in the context of ssl_session_store_by_lua* + return + end + } +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + + server_tokens off; + } +@@ -266,7 +266,7 @@ my timer run! + print("received memc reply: ", res) + } + +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + +@@ -334,7 +334,7 @@ API disabled in the context of ssl_session_store_by_lua* + ssl_session_store_by_lua_block { + ngx.exit(0) + } +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + +@@ -406,7 +406,7 @@ ngx.exit does not yield and the error code is eaten. + ssl_session_store_by_lua_block { + ngx.exit(ngx.ERROR) + } +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + +@@ -479,7 +479,7 @@ ssl_session_store_by_lua*: handler return value: 0, sess new cb exit code: 0 + error("bad bad bad") + ngx.log(ngx.ERR, "should never reached here...") + } +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + +@@ -547,7 +547,7 @@ should never reached here + ssl_session_store_by_lua_block { + print("get_phase: ", ngx.get_phase()) + } +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + +@@ -620,7 +620,7 @@ get_phase: ssl_session_store + ssl_session_store_by_lua_block { print("ssl store session by lua is running!") } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + + server_tokens off; + } +@@ -689,7 +689,7 @@ qr/elapsed in ssl cert by lua: 0.(?:09|1[01])\d+,/, + ssl_session_store_by_lua_file html/a.lua; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + + server_tokens off; + } +diff --git a/t/143-ssl-session-fetch.t b/t/143-ssl-session-fetch.t +index 686f671..fc796e8 100644 +--- a/t/143-ssl-session-fetch.t ++++ b/t/143-ssl-session-fetch.t +@@ -33,7 +33,7 @@ __DATA__ + ssl_session_fetch_by_lua_block { print("ssl fetch sess by lua is running!") } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + + server_tokens off; + } +@@ -114,7 +114,7 @@ qr/ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!/s + } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + + server_tokens off; + } +@@ -198,7 +198,7 @@ qr/elapsed in ssl fetch session by lua: 0.(?:09|1[01])\d+,/, + return + end + } +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + + server_tokens off; + } +@@ -297,7 +297,7 @@ qr/my timer run!/s + + print("received memc reply: ", res) + } +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + +@@ -377,7 +377,7 @@ qr/received memc reply: OK/s + ngx.exit(0) + ngx.log(ngx.ERR, "should never reached here...") + } +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + +@@ -458,7 +458,7 @@ should never reached here + ngx.exit(ngx.ERROR) + ngx.log(ngx.ERR, "should never reached here...") + } +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + +@@ -540,7 +540,7 @@ should never reached here + ngx.exit(ngx.ERROR) + ngx.log(ngx.ERR, "should never reached here...") + } +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + +@@ -621,7 +621,7 @@ should never reached here + error("bad bad bad") + ngx.log(ngx.ERR, "should never reached here...") + } +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + +@@ -704,7 +704,7 @@ should never reached here + error("bad bad bad") + ngx.log(ngx.ERR, "should never reached here...") + } +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + +@@ -787,7 +787,7 @@ should never reached here + ssl_session_fetch_by_lua_block { print("get_phase: ", ngx.get_phase()) } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + + server_tokens off; + } +@@ -872,7 +872,7 @@ qr/get_phase: ssl_session_fetch/s + } + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + + server_tokens off; + } +@@ -956,7 +956,7 @@ ssl store session by lua is running! + ssl_session_fetch_by_lua_file html/a.lua; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; +- ssl_protocols SSLv3; ++ ssl_protocols TLSv1.2; + + server_tokens off; + } + +From 7b5bd0839cde38a99408092fa53f2c376c80a8a2 Mon Sep 17 00:00:00 2001 +From: Alessandro Ghedini +Date: Thu, 12 May 2016 13:12:23 +0100 +Subject: [PATCH 2/5] bugfix: ssl: do not access SSL_SESSION struct directly + +In OpenSSL 1.1.0 it was made opaque. +--- + src/ngx_http_lua_socket_tcp.c | 15 ++--- + t/129-ssl-socket.t | 152 +++++++++++++++++++++--------------------- + 2 files changed, 82 insertions(+), 85 deletions(-) + +diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c +index fe6001f..1861e6f 100644 +--- a/src/ngx_http_lua_socket_tcp.c ++++ b/src/ngx_http_lua_socket_tcp.c +@@ -1283,9 +1283,8 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) + return 2; + } + +- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, +- "lua ssl set session: %p:%d", +- *psession, (*psession)->references); ++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, ++ "lua ssl set session: %p", *psession); + } + } + +@@ -1549,9 +1548,8 @@ ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, + } else { + *ud = ssl_session; + +- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, +- "lua ssl save session: %p:%d", ssl_session, +- ssl_session->references); ++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, ++ "lua ssl save session: %p", ssl_session); + + /* set up the __gc metamethod */ + lua_pushlightuserdata(L, &ngx_http_lua_ssl_session_metatable_key); +@@ -5272,9 +5270,8 @@ ngx_http_lua_ssl_free_session(lua_State *L) + + psession = lua_touserdata(L, 1); + if (psession && *psession != NULL) { +- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, +- "lua ssl free session: %p:%d", *psession, +- (*psession)->references); ++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, ++ "lua ssl free session: %p", *psession); + + ngx_ssl_free_session(*psession); + } +diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t +index 9da9a5c..98fb5a2 100644 +--- a/t/129-ssl-socket.t ++++ b/t/129-ssl-socket.t +@@ -108,10 +108,10 @@ sent http request: 59 bytes. + received: HTTP/1.1 (?:200 OK|302 Found) + close: 1 nil + \z +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl free session: ([0-9A-F]+):1 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl free session: ([0-9A-F]+) + $/ + --- no_error_log + lua ssl server name: +@@ -185,10 +185,10 @@ received: HTTP/1.1 401 Unauthorized + close: 1 nil + + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl free session: ([0-9A-F]+):1 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl free session: ([0-9A-F]+) + $/ + --- no_error_log + lua ssl server name: +@@ -262,10 +262,10 @@ received: HTTP/1.1 200 OK + close: 1 nil + + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl free session: ([0-9A-F]+):1 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl free session: ([0-9A-F]+) + $/ + --- error_log + lua ssl server name: "iscribblet.org" +@@ -349,13 +349,13 @@ sent http request: 59 bytes. + received: HTTP/1.1 200 OK + close: 1 nil + +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl set session: \1:2 +-lua ssl save session: \1:3 +-lua ssl free session: \1:2 +-lua ssl free session: \1:1 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl set session: \1 ++lua ssl save session: \1 ++lua ssl free session: \1 ++lua ssl free session: \1 + $/ + + --- error_log +@@ -437,7 +437,7 @@ failed to do SSL handshake: certificate host mismatch + failed to send http request: closed + + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out + --- error_log + lua ssl server name: "blah.agentzh.org" +@@ -517,7 +517,7 @@ failed to do SSL handshake: certificate host mismatch + failed to send http request: closed + + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out + --- error_log + lua ssl server name: "blah.agentzh.org" +@@ -592,10 +592,10 @@ received: HTTP/1.1 200 OK + close: 1 nil + + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl free session: ([0-9A-F]+):1 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl free session: ([0-9A-F]+) + $/ + + --- error_log +@@ -677,10 +677,10 @@ received: HTTP/1.1 200 OK + close: 1 nil + + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]++/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl free session: ([0-9A-F]+):1 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl free session: ([0-9A-F]+) + $/ + + --- error_log +@@ -759,7 +759,7 @@ failed to do SSL handshake: 20: unable to get local issuer certificate + failed to send http request: closed + + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out + --- error_log + lua ssl server name: "iscribblet.org" +@@ -838,7 +838,7 @@ failed to do SSL handshake: 20: unable to get local issuer certificate + failed to send http request: closed + + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out + --- error_log + lua ssl server name: "iscribblet.org" +@@ -928,10 +928,10 @@ sent http request: 59 bytes. + received: HTTP/1.1 (?:200 OK|302 Found) + close: 1 nil + \z +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl free session: ([0-9A-F]+):1 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl free session: ([0-9A-F]+) + $/ + --- error_log + lua ssl server name: "www.google.com" +@@ -1018,7 +1018,7 @@ GET /t + connected: 1 + failed to do SSL handshake: 20: unable to get local issuer certificate + +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out + --- error_log + lua ssl server name: "www.google.com" +@@ -1100,10 +1100,10 @@ received: HTTP/1.1 200 OK + close: 1 nil + + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl free session: ([0-9A-F]+):1 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl free session: ([0-9A-F]+) + $/ + + --- error_log +@@ -1179,10 +1179,10 @@ received: HTTP/1.1 200 OK + close: 1 nil + + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl free session: ([0-9A-F]+):1 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl free session: ([0-9A-F]+) + $/ + --- error_log + lua ssl server name: "iscribblet.org" +@@ -1259,10 +1259,10 @@ received: HTTP/1.1 200 OK + close: 1 nil + + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl free session: ([0-9A-F]+):1 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl free session: ([0-9A-F]+) + $/ + --- error_log + lua ssl server name: "iscribblet.org" +@@ -1339,10 +1339,10 @@ received: HTTP/1.1 200 OK + close: 1 nil + + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl free session: ([0-9A-F]+):1 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl free session: ([0-9A-F]+) + $/ + --- error_log + lua ssl server name: "iscribblet.org" +@@ -1417,7 +1417,7 @@ failed to do SSL handshake: handshake failed + failed to send http request: closed + + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out + --- error_log eval + [ +@@ -1493,10 +1493,10 @@ ssl handshake: userdata + set keepalive: 1 nil + + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl free session: \1:2 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl free session: \1 + $/ + + --- error_log +@@ -1569,14 +1569,14 @@ ssl handshake: userdata + set keepalive: 1 nil + + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl save session: \1:3 +-lua ssl save session: \1:4 +-lua ssl free session: \1:4 +-lua ssl free session: \1:3 +-lua ssl free session: \1:2 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl save session: \1 ++lua ssl save session: \1 ++lua ssl free session: \1 ++lua ssl free session: \1 ++lua ssl free session: \1 + $/ + + --- error_log +@@ -1620,7 +1620,7 @@ hello world + --- response_body_like: 500 Internal Server Error + --- error_code: 500 + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out + --- error_log + attempt to call method 'sslhandshake' (a nil value) +@@ -1719,10 +1719,10 @@ $::TestCertificateKey + >>> test.crt + $::TestCertificate" + +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl free session: ([0-9A-F]+):1 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl free session: ([0-9A-F]+) + $/ + --- no_error_log + lua ssl server name: +@@ -1824,10 +1824,10 @@ $::TestCertificateKey + >>> test.crt + $::TestCertificate" + +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl free session: ([0-9A-F]+):1 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl free session: ([0-9A-F]+) + $/ + --- error_log + lua ssl server name: "test.com" +@@ -1917,7 +1917,7 @@ failed to do SSL handshake: handshake failed + ">>> test.crt + $::TestCertificate" + +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out + --- error_log eval + qr/SSL_do_handshake\(\) failed .*?unknown protocol/ +@@ -2016,7 +2016,7 @@ $::TestCertificate + >>> test.crl + $::TestCRL" + +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out + --- error_log + lua ssl server name: "test.com" +@@ -2095,12 +2095,12 @@ received: HTTP/1.1 200 OK + close: 1 nil + + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl save session: ([0-9A-F]+):3 +-lua ssl free session: ([0-9A-F]+):2 +-lua ssl free session: ([0-9A-F]+):1 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl save session: ([0-9A-F]+) ++lua ssl free session: ([0-9A-F]+) ++lua ssl free session: ([0-9A-F]+) + $/ + --- error_log + lua ssl server name: "iscribblet.org" +@@ -2154,7 +2154,7 @@ connected: 1 + failed to do SSL handshake: timeout + + --- log_level: debug +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out + --- error_log + lua ssl server name: "iscribblet.org" +@@ -2226,7 +2226,7 @@ $::TestCertificateKey + >>> test.crt + $::TestCertificate" + +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out + --- no_error_log + lua ssl server name: +@@ -2297,10 +2297,10 @@ $::TestCertificateKey + >>> test.crt + $::TestCertificate" + +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl free session: ([0-9A-F]+):1 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl free session: ([0-9A-F]+) + $/ + --- no_error_log + lua ssl server name: +@@ -2377,7 +2377,7 @@ $::TestCertificateKey + >>> test.crt + $::TestCertificate" + +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out + --- no_error_log + lua ssl server name: +@@ -2479,10 +2479,10 @@ $::TestCertificateKey + >>> test.crt + $::TestCertificate" + +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out eval +-qr/^lua ssl save session: ([0-9A-F]+):2 +-lua ssl free session: ([0-9A-F]+):1 ++qr/^lua ssl save session: ([0-9A-F]+) ++lua ssl free session: ([0-9A-F]+) + $/ + --- error_log + --- no_error_log +@@ -2575,7 +2575,7 @@ $::TestCertificateKey + >>> test.crt + $::TestCertificate" + +---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ++--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ + --- grep_error_log_out + --- error_log + lua ssl certificate verify error: (18: self signed certificate) + +From 4f7dcf142a180c817c038122eeff53148353e0fa Mon Sep 17 00:00:00 2001 +From: Alessandro Ghedini +Date: Thu, 12 May 2016 13:17:52 +0100 +Subject: [PATCH 3/5] bugfix: ssl: do not set tlsext_status_expected flag + +In OpenSSL 1.1.0 the SSL struct was made opaque, and setting this +flag manually is not required anyway since OpenSSL already does that +automatically when ngx_http_lua_ssl_empty_status_callback() returns +"OK" (which is always), and an OCSP response has been set. +--- + src/ngx_http_lua_ssl_ocsp.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/ngx_http_lua_ssl_ocsp.c b/src/ngx_http_lua_ssl_ocsp.c +index 3904aa8..31b4f24 100644 +--- a/src/ngx_http_lua_ssl_ocsp.c ++++ b/src/ngx_http_lua_ssl_ocsp.c +@@ -490,7 +490,6 @@ ngx_http_lua_ffi_ssl_set_ocsp_status_resp(ngx_http_request_t *r, + + dd("set ocsp resp: resp_len=%d", (int) resp_len); + (void) SSL_set_tlsext_status_ocsp_resp(ssl_conn, p, resp_len); +- ssl_conn->tlsext_status_expected = 1; + + return NGX_OK; + + +From 0a1a3dd1ee86732abd2f44c070292eae5064fced Mon Sep 17 00:00:00 2001 +From: Alessandro Ghedini +Date: Fri, 10 Jun 2016 13:23:21 +0100 +Subject: [PATCH 4/5] bugfix: ssl: do not access SSL struct directly for + tlsext_status_type + +In OpenSSL 1.1.0 it was made opaque, and a getter function was added. +--- + src/ngx_http_lua_ssl_ocsp.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/ngx_http_lua_ssl_ocsp.c b/src/ngx_http_lua_ssl_ocsp.c +index 31b4f24..9ec8b50 100644 +--- a/src/ngx_http_lua_ssl_ocsp.c ++++ b/src/ngx_http_lua_ssl_ocsp.c +@@ -468,7 +468,11 @@ ngx_http_lua_ffi_ssl_set_ocsp_status_resp(ngx_http_request_t *r, + return NGX_ERROR; + } + ++#ifdef SSL_CTRL_GET_TLSEXT_STATUS_REQ_TYPE ++ if (SSL_get_tlsext_status_type(ssl_conn) == -1) { ++#else + if (ssl_conn->tlsext_status_type == -1) { ++#endif + dd("no ocsp status req from client"); + return NGX_DECLINED; + } + +From 1769df4649ed54b6cfef97de6cd7a79753be7a43 Mon Sep 17 00:00:00 2001 +From: Alessandro Ghedini +Date: Tue, 13 Sep 2016 22:19:10 +0100 +Subject: [PATCH 5/5] bugfix: ssl: make SSL session callback build with OpenSSL + 1.1.0 + +--- + src/ngx_http_lua_ssl_session_fetchby.c | 9 ++++++--- + src/ngx_http_lua_ssl_session_fetchby.h | 6 +++++- + src/ngx_http_lua_ssl_session_storeby.c | 8 ++++++-- + 3 files changed, 17 insertions(+), 6 deletions(-) + +diff --git a/src/ngx_http_lua_ssl_session_fetchby.c b/src/ngx_http_lua_ssl_session_fetchby.c +index 4c450b5..6212c60 100644 +--- a/src/ngx_http_lua_ssl_session_fetchby.c ++++ b/src/ngx_http_lua_ssl_session_fetchby.c +@@ -171,8 +171,11 @@ ngx_http_lua_ssl_sess_fetch_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + + /* cached session fetching callback to be set with SSL_CTX_sess_set_get_cb */ + ngx_ssl_session_t * +-ngx_http_lua_ssl_sess_fetch_handler(ngx_ssl_conn_t *ssl_conn, u_char *id, +- int len, int *copy) ++ngx_http_lua_ssl_sess_fetch_handler(ngx_ssl_conn_t *ssl_conn, ++#if OPENSSL_VERSION_NUMBER >= 0x10100003L ++ const ++#endif ++ u_char *id, int len, int *copy) + { + lua_State *L; + ngx_int_t rc; +@@ -284,7 +287,7 @@ ngx_http_lua_ssl_sess_fetch_handler(ngx_ssl_conn_t *ssl_conn, u_char *id, + cctx->exit_code = 1; /* successful by default */ + cctx->connection = c; + cctx->request = r; +- cctx->session_id.data = id; ++ cctx->session_id.data = (u_char *) id; + cctx->session_id.len = len; + cctx->entered_sess_fetch_handler = 1; + cctx->done = 0; +diff --git a/src/ngx_http_lua_ssl_session_fetchby.h b/src/ngx_http_lua_ssl_session_fetchby.h +index 5a6f96f..50c6616 100644 +--- a/src/ngx_http_lua_ssl_session_fetchby.h ++++ b/src/ngx_http_lua_ssl_session_fetchby.h +@@ -25,7 +25,11 @@ char *ngx_http_lua_ssl_sess_fetch_by_lua_block(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + + ngx_ssl_session_t *ngx_http_lua_ssl_sess_fetch_handler( +- ngx_ssl_conn_t *ssl_conn, u_char *id, int len, int *copy); ++ ngx_ssl_conn_t *ssl_conn, ++#if OPENSSL_VERSION_NUMBER >= 0x10100003L ++ const ++#endif ++ u_char *id, int len, int *copy); + #endif + + +diff --git a/src/ngx_http_lua_ssl_session_storeby.c b/src/ngx_http_lua_ssl_session_storeby.c +index b5596bc..85dbece 100644 +--- a/src/ngx_http_lua_ssl_session_storeby.c ++++ b/src/ngx_http_lua_ssl_session_storeby.c +@@ -172,6 +172,8 @@ int + ngx_http_lua_ssl_sess_store_handler(ngx_ssl_conn_t *ssl_conn, + ngx_ssl_session_t *sess) + { ++ const u_char *sess_id; ++ unsigned int sess_id_len; + lua_State *L; + ngx_int_t rc; + ngx_connection_t *c, *fc = NULL; +@@ -246,11 +248,13 @@ ngx_http_lua_ssl_sess_store_handler(ngx_ssl_conn_t *ssl_conn, + } + } + ++ sess_id = SSL_SESSION_get_id(sess, &sess_id_len); ++ + cctx->connection = c; + cctx->request = r; + cctx->session = sess; +- cctx->session_id.data = sess->session_id; +- cctx->session_id.len = sess->session_id_length; ++ cctx->session_id.data = (u_char *) sess_id; ++ cctx->session_id.len = sess_id_len; + cctx->done = 0; + + dd("setting cctx"); diff --git a/debian/patches/modules/nginx-lua/series b/debian/patches/modules/nginx-lua/series new file mode 100644 index 0000000..ed0d540 --- /dev/null +++ b/debian/patches/modules/nginx-lua/series @@ -0,0 +1 @@ +openssl-1.1.0.patch From 424f50a53b532f552261df7102adcc8d64881c10 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 3 Nov 2016 16:50:33 +0200 Subject: [PATCH 179/651] Fix FTBFS for OpenSSL 1.1.0 --- debian/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/debian/changelog b/debian/changelog index 5101bbb..470a04a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,8 @@ nginx (1.10.2-2) UNRELEASED; urgency=medium + * Build against OpenSSL 1.1.0. (Closes: #828453) + + Patch for nginx-lua by Alessandro Ghedini. + + Patch for nginx-upstream-fair by Kurt Roeckx. * debian/modules: + Rethink module patching logic. + Convert dav-ext to a dynamic module package: From 6c9b75da5f2af954c9a393f4e30d21f051e6048f Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Sat, 12 Nov 2016 09:18:26 +0200 Subject: [PATCH 180/651] Release 1.10.2-2 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 470a04a..89b8f64 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.10.2-2) UNRELEASED; urgency=medium +nginx (1.10.2-2) unstable; urgency=medium * Build against OpenSSL 1.1.0. (Closes: #828453) + Patch for nginx-lua by Alessandro Ghedini. @@ -8,7 +8,7 @@ nginx (1.10.2-2) UNRELEASED; urgency=medium + Convert dav-ext to a dynamic module package: o libnginx-mod-http-dav-ext - -- Christos Trochalakis Sat, 29 Oct 2016 17:26:04 +0300 + -- Christos Trochalakis Sat, 12 Nov 2016 09:18:12 +0200 nginx (1.10.2-1) unstable; urgency=high From 14707687a2e53588102a3a4d33e7e37eeb52c602 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 16 Nov 2016 10:29:39 +0200 Subject: [PATCH 181/651] New upstream version 1.11.6 --- CHANGES | 39 +++++ CHANGES.ru | 42 ++++- auto/lib/libgd/conf | 5 + src/core/nginx.h | 4 +- src/core/ngx_buf.c | 16 +- src/core/ngx_conf_file.c | 83 ++++++--- src/core/ngx_cycle.c | 3 + src/core/ngx_cycle.h | 4 + src/core/ngx_file.c | 32 +++- src/core/ngx_hash.c | 1 - src/event/ngx_event_openssl.c | 110 +++++++++++- src/event/ngx_event_openssl.h | 4 + src/http/modules/ngx_http_fastcgi_module.c | 34 +++- .../modules/ngx_http_image_filter_module.c | 164 +++++++++++++++++- src/http/modules/ngx_http_mp4_module.c | 74 ++++++-- src/http/modules/ngx_http_proxy_module.c | 75 +++++--- .../modules/ngx_http_range_filter_module.c | 12 +- src/http/modules/ngx_http_scgi_module.c | 34 +++- src/http/modules/ngx_http_ssl_module.c | 6 + src/http/modules/ngx_http_uwsgi_module.c | 34 +++- src/http/modules/perl/ngx_http_perl_module.c | 2 +- src/http/ngx_http_cache.h | 4 +- src/http/ngx_http_core_module.c | 2 - src/http/ngx_http_file_cache.c | 77 ++++---- src/http/ngx_http_special_response.c | 1 - src/http/ngx_http_upstream.c | 156 +++++++++++++---- src/http/ngx_http_upstream.h | 4 +- src/http/ngx_http_upstream_round_robin.c | 2 +- src/http/v2/ngx_http_v2.c | 68 ++++++-- src/http/v2/ngx_http_v2.h | 1 + src/http/v2/ngx_http_v2_filter_module.c | 4 + src/http/v2/ngx_http_v2_module.c | 9 + src/http/v2/ngx_http_v2_module.h | 1 + src/mail/ngx_mail.h | 13 +- src/mail/ngx_mail_auth_http_module.c | 1 + src/mail/ngx_mail_handler.c | 34 ++++ src/mail/ngx_mail_imap_handler.c | 11 ++ src/mail/ngx_mail_imap_module.c | 6 +- src/mail/ngx_mail_parse.c | 22 ++- src/mail/ngx_mail_pop3_handler.c | 11 ++ src/mail/ngx_mail_pop3_module.c | 96 +++++++--- src/mail/ngx_mail_smtp_handler.c | 11 ++ src/mail/ngx_mail_smtp_module.c | 6 +- src/stream/ngx_stream_proxy_module.c | 45 +++-- src/stream/ngx_stream_upstream.h | 1 + src/stream/ngx_stream_upstream_round_robin.c | 2 +- 46 files changed, 1101 insertions(+), 265 deletions(-) diff --git a/CHANGES b/CHANGES index 6a88ce4..1882976 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,43 @@ +Changes with nginx 1.11.6 15 Nov 2016 + + *) Change: format of the $ssl_client_s_dn and $ssl_client_i_dn variables + has been changed to follow RFC 2253 (RFC 4514); values in the old + format are available in the $ssl_client_s_dn_legacy and + $ssl_client_i_dn_legacy variables. + + *) Change: when storing temporary files in a cache directory they will + be stored in the same subdirectories as corresponding cache files + instead of a separate subdirectory for temporary files. + + *) Feature: EXTERNAL authentication mechanism support in mail proxy. + Thanks to Robert Norris. + + *) Feature: WebP support in the ngx_http_image_filter_module. + + *) Feature: variables support in the "proxy_method" directive. + Thanks to Dmitry Lazurkin. + + *) Feature: the "http2_max_requests" directive in the + ngx_http_v2_module. + + *) Feature: the "proxy_cache_max_range_offset", + "fastcgi_cache_max_range_offset", "scgi_cache_max_range_offset", and + "uwsgi_cache_max_range_offset" directives. + + *) Bugfix: graceful shutdown of old worker processes might require + infinite time when using HTTP/2. + + *) Bugfix: in the ngx_http_mp4_module. + + *) Bugfix: "ignore long locked inactive cache entry" alerts might appear + in logs when proxying WebSocket connections with caching enabled. + + *) Bugfix: nginx did not write anything to log and returned a response + with code 502 instead of 504 when a timeout occurred during an SSL + handshake to a backend. + + Changes with nginx 1.11.5 11 Oct 2016 *) Change: the --with-ipv6 configure option was removed, now IPv6 diff --git a/CHANGES.ru b/CHANGES.ru index f0bdaf5..3b66b94 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,44 @@ +Изменения в nginx 1.11.6 15.11.2016 + + *) Изменение: формат переменных $ssl_client_s_dn и $ssl_client_i_dn + изменён на соответствующий RFC 2253 (RFC 4514); значения в старом + формате доступны через переменные $ssl_client_s_dn_legacy и + $ssl_client_i_dn_legacy. + + *) Изменение: при сохранении временных файлов в каталоге кэша они теперь + располагаются не в отдельном подкаталоге для временных файлов, а в + том же подкаталоге, что и соответствующие файлы в кэше. + + *) Добавление: поддержка метода аутентификации EXTERNAL в почтовом + прокси-сервере. + Спасибо Robert Norris. + + *) Добавление: поддержка WebP в модуле ngx_http_image_filter_module. + + *) Добавление: директива proxy_method поддерживает переменные. + Спасибо Дмитрию Лазуркину. + + *) Добавление: директива http2_max_requests в модуле ngx_http_v2_module. + + *) Добавление: директивы proxy_cache_max_range_offset, + fastcgi_cache_max_range_offset, scgi_cache_max_range_offset и + uwsgi_cache_max_range_offset. + + *) Исправление: плавное завершение старых рабочих процессов могло + занимать бесконечное время при использовании HTTP/2. + + *) Исправление: в модуле ngx_http_mp4_module. + + *) Исправление: при проксировании WebSocket-соединений и включённом + кэшировании в логах могли появляться сообщения "ignore long locked + inactive cache entry". + + *) Исправление: если во время SSL handshake с бэкендом происходил + таймаут, nginx ничего не писал в лог и возвращал ответ с кодом 502 + вместо 504. + + Изменения в nginx 1.11.5 11.10.2016 *) Изменение: параметр configure --with-ipv6 упразднён, поддержка IPv6 @@ -5589,7 +5629,7 @@ Изменения в nginx 0.4.11 25.10.2006 - *) Добавление: POP3 прокси поддерживает AUTH LOIGN PLAIN и CRAM-MD5. + *) Добавление: POP3 прокси поддерживает AUTH LOGIN PLAIN и CRAM-MD5. *) Добавление: модуль ngx_http_perl_module поддерживает метод $r->allow_ranges. diff --git a/auto/lib/libgd/conf b/auto/lib/libgd/conf index 6e4e91c..87761f1 100644 --- a/auto/lib/libgd/conf +++ b/auto/lib/libgd/conf @@ -74,6 +74,11 @@ if [ $ngx_found = yes ]; then NGX_LIB_LIBGD=$ngx_feature_libs + ngx_feature="GD WebP support" + ngx_feature_name="NGX_HAVE_GD_WEBP" + ngx_feature_test="gdImagePtr img = gdImageCreateFromWebpPtr(1, NULL);" + . auto/feature + else cat << END diff --git a/src/core/nginx.h b/src/core/nginx.h index 1446251..a75ef04 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1011005 -#define NGINX_VERSION "1.11.5" +#define nginx_version 1011006 +#define NGINX_VERSION "1.11.6" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_buf.c b/src/core/ngx_buf.c index 00b6644..d30a0a4 100644 --- a/src/core/ngx_buf.c +++ b/src/core/ngx_buf.c @@ -186,17 +186,19 @@ ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy, { ngx_chain_t *cl; - if (*busy == NULL) { - *busy = *out; + if (*out) { + if (*busy == NULL) { + *busy = *out; - } else { - for (cl = *busy; cl->next; cl = cl->next) { /* void */ } + } else { + for (cl = *busy; cl->next; cl = cl->next) { /* void */ } - cl->next = *out; + cl->next = *out; + } + + *out = NULL; } - *out = NULL; - while (*busy) { cl = *busy; diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c index ea1dceb..ce8c602 100644 --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -10,6 +10,7 @@ #define NGX_CONF_BUFFER 4096 +static ngx_int_t ngx_conf_add_dump(ngx_conf_t *cf, ngx_str_t *filename); static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last); static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf); static void ngx_conf_flush_files(ngx_cycle_t *cycle); @@ -97,17 +98,70 @@ ngx_conf_param(ngx_conf_t *cf) } +static ngx_int_t +ngx_conf_add_dump(ngx_conf_t *cf, ngx_str_t *filename) +{ + off_t size; + u_char *p; + uint32_t hash; + ngx_buf_t *buf; + ngx_str_node_t *sn; + ngx_conf_dump_t *cd; + + hash = ngx_crc32_long(filename->data, filename->len); + + sn = ngx_str_rbtree_lookup(&cf->cycle->config_dump_rbtree, filename, hash); + + if (sn) { + cf->conf_file->dump = NULL; + return NGX_OK; + } + + p = ngx_pstrdup(cf->cycle->pool, filename); + if (p == NULL) { + return NGX_ERROR; + } + + cd = ngx_array_push(&cf->cycle->config_dump); + if (cd == NULL) { + return NGX_ERROR; + } + + size = ngx_file_size(&cf->conf_file->file.info); + + buf = ngx_create_temp_buf(cf->cycle->pool, (size_t) size); + if (buf == NULL) { + return NGX_ERROR; + } + + cd->name.data = p; + cd->name.len = filename->len; + cd->buffer = buf; + + cf->conf_file->dump = buf; + + sn = ngx_palloc(cf->temp_pool, sizeof(ngx_str_node_t)); + if (sn == NULL) { + return NGX_ERROR; + } + + sn->node.key = hash; + sn->str = cd->name; + + ngx_rbtree_insert(&cf->cycle->config_dump_rbtree, &sn->node); + + return NGX_OK; +} + + char * ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) { char *rv; - u_char *p; - off_t size; ngx_fd_t fd; ngx_int_t rc; - ngx_buf_t buf, *tbuf; + ngx_buf_t buf; ngx_conf_file_t *prev, conf_file; - ngx_conf_dump_t *cd; enum { parse_file = 0, parse_block, @@ -167,29 +221,10 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) #endif ) { - p = ngx_pstrdup(cf->cycle->pool, filename); - if (p == NULL) { + if (ngx_conf_add_dump(cf, filename) != NGX_OK) { goto failed; } - size = ngx_file_size(&cf->conf_file->file.info); - - tbuf = ngx_create_temp_buf(cf->cycle->pool, (size_t) size); - if (tbuf == NULL) { - goto failed; - } - - cd = ngx_array_push(&cf->cycle->config_dump); - if (cd == NULL) { - goto failed; - } - - cd->name.len = filename->len; - cd->name.data = p; - cd->buffer = tbuf; - - cf->conf_file->dump = tbuf; - } else { cf->conf_file->dump = NULL; } diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c index 98599f3..a57991c 100644 --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -132,6 +132,9 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) return NULL; } + ngx_rbtree_init(&cycle->config_dump_rbtree, &cycle->config_dump_sentinel, + ngx_str_rbtree_insert_value); + if (old_cycle->open_files.part.nelts) { n = old_cycle->open_files.part.nelts; for (part = old_cycle->open_files.part.next; part; part = part->next) { diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h index c51b7ff..5cdacf1 100644 --- a/src/core/ngx_cycle.h +++ b/src/core/ngx_cycle.h @@ -56,7 +56,11 @@ struct ngx_cycle_s { ngx_array_t listening; ngx_array_t paths; + ngx_array_t config_dump; + ngx_rbtree_t config_dump_rbtree; + ngx_rbtree_node_t config_dump_sentinel; + ngx_list_t open_files; ngx_list_t shared_memory; diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c index 8359c0f..b7dd4bc 100644 --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -141,12 +141,27 @@ ngx_int_t ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool, ngx_uint_t persistent, ngx_uint_t clean, ngx_uint_t access) { + size_t levels; + u_char *p; uint32_t n; ngx_err_t err; + ngx_str_t name; + ngx_uint_t prefix; ngx_pool_cleanup_t *cln; ngx_pool_cleanup_file_t *clnf; - file->name.len = path->name.len + 1 + path->len + 10; + if (file->name.len) { + name = file->name; + levels = 0; + prefix = 1; + + } else { + name = path->name; + levels = path->len; + prefix = 0; + } + + file->name.len = name.len + 1 + levels + 10; file->name.data = ngx_pnalloc(pool, file->name.len + 1); if (file->name.data == NULL) { @@ -159,7 +174,13 @@ ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool, } #endif - ngx_memcpy(file->name.data, path->name.data, path->name.len); + p = ngx_cpymem(file->name.data, name.data, name.len); + + if (prefix) { + *p = '.'; + } + + p += 1 + levels; n = (uint32_t) ngx_next_temp_number(0); @@ -169,10 +190,11 @@ ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool, } for ( ;; ) { - (void) ngx_sprintf(file->name.data + path->name.len + 1 + path->len, - "%010uD%Z", n); + (void) ngx_sprintf(p, "%010uD%Z", n); - ngx_create_hashed_filename(path, file->name.data, file->name.len); + if (!prefix) { + ngx_create_hashed_filename(path, file->name.data, file->name.len); + } ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0, "hashed path: %s", file->name.data); diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c index 151e643..1944c7a 100644 --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -390,7 +390,6 @@ found: buckets[i] = (ngx_hash_elt_t *) elts; elts += test[i]; - } for (i = 0; i < size; i++) { diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 68d02bf..5c7734d 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -2137,7 +2137,9 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...) break; } - if (p >= last) { + /* ERR_error_string_n() requires at least one byte */ + + if (p >= last - 1) { goto next; } @@ -3435,6 +3437,109 @@ ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) ngx_int_t ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + BIO *bio; + X509 *cert; + X509_NAME *name; + + s->len = 0; + + cert = SSL_get_peer_certificate(c->ssl->connection); + if (cert == NULL) { + return NGX_OK; + } + + name = X509_get_subject_name(cert); + if (name == NULL) { + return NGX_ERROR; + } + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) { + X509_free(cert); + return NGX_ERROR; + } + + if (X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253) < 0) { + goto failed; + } + + s->len = BIO_pending(bio); + s->data = ngx_pnalloc(pool, s->len); + if (s->data == NULL) { + goto failed; + } + + BIO_read(bio, s->data, s->len); + + BIO_free(bio); + X509_free(cert); + + return NGX_OK; + +failed: + + BIO_free(bio); + X509_free(cert); + + return NGX_ERROR; +} + + +ngx_int_t +ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + BIO *bio; + X509 *cert; + X509_NAME *name; + + s->len = 0; + + cert = SSL_get_peer_certificate(c->ssl->connection); + if (cert == NULL) { + return NGX_OK; + } + + name = X509_get_issuer_name(cert); + if (name == NULL) { + return NGX_ERROR; + } + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) { + X509_free(cert); + return NGX_ERROR; + } + + if (X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253) < 0) { + goto failed; + } + + s->len = BIO_pending(bio); + s->data = ngx_pnalloc(pool, s->len); + if (s->data == NULL) { + goto failed; + } + + BIO_read(bio, s->data, s->len); + + BIO_free(bio); + X509_free(cert); + + return NGX_OK; + +failed: + + BIO_free(bio); + X509_free(cert); + + return NGX_ERROR; +} + + +ngx_int_t +ngx_ssl_get_subject_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s) { char *p; size_t len; @@ -3476,7 +3581,8 @@ ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) ngx_int_t -ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +ngx_ssl_get_issuer_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s) { char *p; size_t len; diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 24b812f..d233c02 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -205,6 +205,10 @@ ngx_int_t ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_subject_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); +ngx_int_t ngx_ssl_get_issuer_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_fingerprint(ngx_connection_t *c, ngx_pool_t *pool, diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 62502b0..c7c417b 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -420,6 +420,13 @@ static ngx_command_t ngx_http_fastcgi_commands[] = { offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_min_uses), NULL }, + { ngx_string("fastcgi_cache_max_range_offset"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_off_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_max_range_offset), + NULL }, + { ngx_string("fastcgi_cache_use_stale"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, ngx_conf_set_bitmask_slot, @@ -766,16 +773,14 @@ ngx_http_fastcgi_eval(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf) return NGX_ERROR; } - if (url.addrs && url.addrs[0].sockaddr) { + if (url.addrs) { u->resolved->sockaddr = url.addrs[0].sockaddr; u->resolved->socklen = url.addrs[0].socklen; + u->resolved->name = url.addrs[0].name; u->resolved->naddrs = 1; - u->resolved->host = url.addrs[0].name; - - } else { - u->resolved->host = url.host; } + u->resolved->host = url.host; u->resolved->port = url.port; u->resolved->no_port = url.no_port; @@ -2756,6 +2761,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf) #if (NGX_HTTP_CACHE) conf->upstream.cache = NGX_CONF_UNSET; conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT; + conf->upstream.cache_max_range_offset = NGX_CONF_UNSET; conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR; conf->upstream.no_cache = NGX_CONF_UNSET_PTR; conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; @@ -3001,6 +3007,10 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_uint_value(conf->upstream.cache_min_uses, prev->upstream.cache_min_uses, 1); + ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset, + prev->upstream.cache_max_range_offset, + NGX_MAX_OFF_T_VALUE); + ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale, prev->upstream.cache_use_stale, (NGX_CONF_BITMASK_SET @@ -3127,6 +3137,20 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #endif + /* + * special handling to preserve conf->params in the "http" section + * to inherit it to all servers + */ + + if (prev->params.hash.buckets == NULL + && conf->params_source == prev->params_source) + { + prev->params = conf->params; +#if (NGX_HTTP_CACHE) + prev->params_cache = conf->params_cache; +#endif + } + return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_image_filter_module.c b/src/http/modules/ngx_http_image_filter_module.c index b608de1..dbec5d8 100644 --- a/src/http/modules/ngx_http_image_filter_module.c +++ b/src/http/modules/ngx_http_image_filter_module.c @@ -31,6 +31,7 @@ #define NGX_HTTP_IMAGE_JPEG 1 #define NGX_HTTP_IMAGE_GIF 2 #define NGX_HTTP_IMAGE_PNG 3 +#define NGX_HTTP_IMAGE_WEBP 4 #define NGX_HTTP_IMAGE_BUFFERED 0x08 @@ -42,6 +43,7 @@ typedef struct { ngx_uint_t height; ngx_uint_t angle; ngx_uint_t jpeg_quality; + ngx_uint_t webp_quality; ngx_uint_t sharpen; ngx_flag_t transparency; @@ -51,6 +53,7 @@ typedef struct { ngx_http_complex_value_t *hcv; ngx_http_complex_value_t *acv; ngx_http_complex_value_t *jqcv; + ngx_http_complex_value_t *wqcv; ngx_http_complex_value_t *shcv; size_t buffer_size; @@ -109,6 +112,8 @@ static char *ngx_http_image_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_image_filter_jpeg_quality(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_image_filter_webp_quality(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); static char *ngx_http_image_filter_sharpen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static ngx_int_t ngx_http_image_filter_init(ngx_conf_t *cf); @@ -130,6 +135,13 @@ static ngx_command_t ngx_http_image_filter_commands[] = { 0, NULL }, + { ngx_string("image_filter_webp_quality"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_image_filter_webp_quality, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + { ngx_string("image_filter_sharpen"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_http_image_filter_sharpen, @@ -200,7 +212,8 @@ static ngx_http_output_body_filter_pt ngx_http_next_body_filter; static ngx_str_t ngx_http_image_types[] = { ngx_string("image/jpeg"), ngx_string("image/gif"), - ngx_string("image/png") + ngx_string("image/png"), + ngx_string("image/webp") }; @@ -441,6 +454,13 @@ ngx_http_image_test(ngx_http_request_t *r, ngx_chain_t *in) /* PNG */ return NGX_HTTP_IMAGE_PNG; + + } else if (p[0] == 'R' && p[1] == 'I' && p[2] == 'F' && p[3] == 'F' + && p[8] == 'W' && p[9] == 'E' && p[10] == 'B' && p[11] == 'P') + { + /* WebP */ + + return NGX_HTTP_IMAGE_WEBP; } return NGX_HTTP_IMAGE_NONE; @@ -731,6 +751,56 @@ ngx_http_image_size(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) break; + case NGX_HTTP_IMAGE_WEBP: + + if (ctx->length < 30) { + return NGX_DECLINED; + } + + if (p[12] != 'V' || p[13] != 'P' || p[14] != '8') { + return NGX_DECLINED; + } + + switch (p[15]) { + + case ' ': + if (p[20] & 1) { + /* not a key frame */ + return NGX_DECLINED; + } + + if (p[23] != 0x9d || p[24] != 0x01 || p[25] != 0x2a) { + /* invalid start code */ + return NGX_DECLINED; + } + + width = (p[26] | p[27] << 8) & 0x3fff; + height = (p[28] | p[29] << 8) & 0x3fff; + + break; + + case 'L': + if (p[20] != 0x2f) { + /* invalid signature */ + return NGX_DECLINED; + } + + width = ((p[21] | p[22] << 8) & 0x3fff) + 1; + height = ((p[22] >> 6 | p[23] << 2 | p[24] << 10) & 0x3fff) + 1; + + break; + + case 'X': + width = (p[24] | p[25] << 8 | p[26] << 16) + 1; + height = (p[27] | p[28] << 8 | p[29] << 16) + 1; + break; + + default: + return NGX_DECLINED; + } + + break; + default: return NGX_DECLINED; @@ -1043,6 +1113,15 @@ ngx_http_image_source(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) failed = "gdImageCreateFromPngPtr() failed"; break; + case NGX_HTTP_IMAGE_WEBP: +#if (NGX_HAVE_GD_WEBP) + img = gdImageCreateFromWebpPtr(ctx->length, ctx->image); + failed = "gdImageCreateFromWebpPtr() failed"; +#else + failed = "nginx was built without GD WebP support"; +#endif + break; + default: failed = "unknown image type"; break; @@ -1090,7 +1169,7 @@ ngx_http_image_out(ngx_http_request_t *r, ngx_uint_t type, gdImagePtr img, { char *failed; u_char *out; - ngx_int_t jq; + ngx_int_t q; ngx_http_image_filter_conf_t *conf; out = NULL; @@ -1100,12 +1179,12 @@ ngx_http_image_out(ngx_http_request_t *r, ngx_uint_t type, gdImagePtr img, case NGX_HTTP_IMAGE_JPEG: conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module); - jq = ngx_http_image_filter_get_value(r, conf->jqcv, conf->jpeg_quality); - if (jq <= 0) { + q = ngx_http_image_filter_get_value(r, conf->jqcv, conf->jpeg_quality); + if (q <= 0) { return NULL; } - out = gdImageJpegPtr(img, size, jq); + out = gdImageJpegPtr(img, size, q); failed = "gdImageJpegPtr() failed"; break; @@ -1119,6 +1198,22 @@ ngx_http_image_out(ngx_http_request_t *r, ngx_uint_t type, gdImagePtr img, failed = "gdImagePngPtr() failed"; break; + case NGX_HTTP_IMAGE_WEBP: +#if (NGX_HAVE_GD_WEBP) + conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module); + + q = ngx_http_image_filter_get_value(r, conf->wqcv, conf->webp_quality); + if (q <= 0) { + return NULL; + } + + out = gdImageWebpPtrEx(img, size, q); + failed = "gdImageWebpPtrEx() failed"; +#else + failed = "nginx was built without GD WebP support"; +#endif + break; + default: failed = "unknown image type"; break; @@ -1196,11 +1291,13 @@ ngx_http_image_filter_create_conf(ngx_conf_t *cf) * conf->hcv = NULL; * conf->acv = NULL; * conf->jqcv = NULL; + * conf->wqcv = NULL; * conf->shcv = NULL; */ conf->filter = NGX_CONF_UNSET_UINT; conf->jpeg_quality = NGX_CONF_UNSET_UINT; + conf->webp_quality = NGX_CONF_UNSET_UINT; conf->sharpen = NGX_CONF_UNSET_UINT; conf->transparency = NGX_CONF_UNSET; conf->interlace = NGX_CONF_UNSET; @@ -1242,6 +1339,16 @@ ngx_http_image_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child) } } + if (conf->webp_quality == NGX_CONF_UNSET_UINT) { + + /* 80 is libwebp default quality */ + ngx_conf_merge_uint_value(conf->webp_quality, prev->webp_quality, 80); + + if (conf->wqcv == NULL) { + conf->wqcv = prev->wqcv; + } + } + if (conf->sharpen == NGX_CONF_UNSET_UINT) { ngx_conf_merge_uint_value(conf->sharpen, prev->sharpen, 0); @@ -1461,6 +1568,53 @@ ngx_http_image_filter_jpeg_quality(ngx_conf_t *cf, ngx_command_t *cmd, } +static char * +ngx_http_image_filter_webp_quality(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_http_image_filter_conf_t *imcf = conf; + + ngx_str_t *value; + ngx_int_t n; + ngx_http_complex_value_t cv; + ngx_http_compile_complex_value_t ccv; + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths == NULL) { + n = ngx_http_image_filter_value(&value[1]); + + if (n <= 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid value \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + imcf->webp_quality = (ngx_uint_t) n; + + } else { + imcf->wqcv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); + if (imcf->wqcv == NULL) { + return NGX_CONF_ERROR; + } + + *imcf->wqcv = cv; + } + + return NGX_CONF_OK; +} + + static char * ngx_http_image_filter_sharpen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index 2a68bae..8f2920f 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -216,6 +216,7 @@ typedef struct { static ngx_int_t ngx_http_mp4_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_mp4_atofp(u_char *line, size_t n, size_t point); static ngx_int_t ngx_http_mp4_process(ngx_http_mp4_file_t *mp4); static ngx_int_t ngx_http_mp4_read_atom(ngx_http_mp4_file_t *mp4, @@ -537,26 +538,15 @@ ngx_http_mp4_handler(ngx_http_request_t *r) /* * A Flash player may send start value with a lot of digits - * after dot so strtod() is used instead of atofp(). NaNs and - * infinities become negative numbers after (int) conversion. + * after dot so a custom function is used instead of ngx_atofp(). */ - ngx_set_errno(0); - start = (int) (strtod((char *) value.data, NULL) * 1000); - - if (ngx_errno != 0) { - start = -1; - } + start = ngx_http_mp4_atofp(value.data, value.len, 3); } if (ngx_http_arg(r, (u_char *) "end", 3, &value) == NGX_OK) { - ngx_set_errno(0); - end = (int) (strtod((char *) value.data, NULL) * 1000); - - if (ngx_errno != 0) { - end = -1; - } + end = ngx_http_mp4_atofp(value.data, value.len, 3); if (end > 0) { if (start < 0) { @@ -686,6 +676,62 @@ ngx_http_mp4_handler(ngx_http_request_t *r) } +static ngx_int_t +ngx_http_mp4_atofp(u_char *line, size_t n, size_t point) +{ + ngx_int_t value, cutoff, cutlim; + ngx_uint_t dot; + + /* same as ngx_atofp(), but allows additional digits */ + + if (n == 0) { + return NGX_ERROR; + } + + cutoff = NGX_MAX_INT_T_VALUE / 10; + cutlim = NGX_MAX_INT_T_VALUE % 10; + + dot = 0; + + for (value = 0; n--; line++) { + + if (*line == '.') { + if (dot) { + return NGX_ERROR; + } + + dot = 1; + continue; + } + + if (*line < '0' || *line > '9') { + return NGX_ERROR; + } + + if (point == 0) { + continue; + } + + if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) { + return NGX_ERROR; + } + + value = value * 10 + (*line - '0'); + point -= dot; + } + + while (point--) { + if (value > cutoff) { + return NGX_ERROR; + } + + value = value * 10; + } + + return value; +} + + static ngx_int_t ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) { diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 4f49a52..42b6afc 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -73,7 +73,7 @@ typedef struct { ngx_array_t *cookie_domains; ngx_array_t *cookie_paths; - ngx_str_t method; + ngx_http_complex_value_t *method; ngx_str_t location; ngx_str_t url; @@ -380,7 +380,7 @@ static ngx_command_t ngx_http_proxy_commands[] = { { ngx_string("proxy_method"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_proxy_loc_conf_t, method), NULL }, @@ -492,6 +492,13 @@ static ngx_command_t ngx_http_proxy_commands[] = { offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_min_uses), NULL }, + { ngx_string("proxy_cache_max_range_offset"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_off_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_max_range_offset), + NULL }, + { ngx_string("proxy_cache_use_stale"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, ngx_conf_set_bitmask_slot, @@ -1008,16 +1015,14 @@ ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx, return NGX_ERROR; } - if (url.addrs && url.addrs[0].sockaddr) { + if (url.addrs) { u->resolved->sockaddr = url.addrs[0].sockaddr; u->resolved->socklen = url.addrs[0].socklen; + u->resolved->name = url.addrs[0].name; u->resolved->naddrs = 1; - u->resolved->host = url.addrs[0].name; - - } else { - u->resolved->host = url.host; } + u->resolved->host = url.host; u->resolved->port = (in_port_t) (url.no_port ? port : url.port); u->resolved->no_port = url.no_port; @@ -1159,8 +1164,10 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) /* HEAD was changed to GET to cache response */ method = u->method; - } else if (plcf->method.len) { - method = plcf->method; + } else if (plcf->method) { + if (ngx_http_complex_value(r, plcf->method, &method) != NGX_OK) { + return NGX_ERROR; + } } else { method = r->method_name; @@ -2797,7 +2804,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) * conf->upstream.store_values = NULL; * conf->upstream.ssl_name = NULL; * - * conf->method = { 0, NULL }; + * conf->method = NULL; * conf->headers_source = NULL; * conf->headers.lengths = NULL; * conf->headers.values = NULL; @@ -2847,6 +2854,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) #if (NGX_HTTP_CACHE) conf->upstream.cache = NGX_CONF_UNSET; conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT; + conf->upstream.cache_max_range_offset = NGX_CONF_UNSET; conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR; conf->upstream.no_cache = NGX_CONF_UNSET_PTR; conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; @@ -3108,6 +3116,10 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_uint_value(conf->upstream.cache_min_uses, prev->upstream.cache_min_uses, 1); + ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset, + prev->upstream.cache_max_range_offset, + NGX_MAX_OFF_T_VALUE); + ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale, prev->upstream.cache_use_stale, (NGX_CONF_BITMASK_SET @@ -3158,7 +3170,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #endif - ngx_conf_merge_str_value(conf->method, prev->method, ""); + if (conf->method == NULL) { + conf->method = prev->method; + } ngx_conf_merge_value(conf->upstream.pass_request_headers, prev->upstream.pass_request_headers, 1); @@ -3357,6 +3371,20 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #endif + /* + * special handling to preserve conf->headers in the "http" section + * to inherit it to all servers + */ + + if (prev->headers.hash.buckets == NULL + && conf->headers_source == prev->headers_source) + { + prev->headers = conf->headers; +#if (NGX_HTTP_CACHE) + prev->headers_cache = conf->headers_cache; +#endif + } + return NGX_CONF_OK; } @@ -3392,14 +3420,6 @@ ngx_http_proxy_init_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, return NGX_ERROR; } - if (conf->headers_source == NULL) { - conf->headers_source = ngx_array_create(cf->pool, 4, - sizeof(ngx_keyval_t)); - if (conf->headers_source == NULL) { - return NGX_ERROR; - } - } - headers->lengths = ngx_array_create(cf->pool, 64, 1); if (headers->lengths == NULL) { return NGX_ERROR; @@ -3410,15 +3430,18 @@ ngx_http_proxy_init_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, return NGX_ERROR; } - src = conf->headers_source->elts; - for (i = 0; i < conf->headers_source->nelts; i++) { + if (conf->headers_source) { - s = ngx_array_push(&headers_merged); - if (s == NULL) { - return NGX_ERROR; + src = conf->headers_source->elts; + for (i = 0; i < conf->headers_source->nelts; i++) { + + s = ngx_array_push(&headers_merged); + if (s == NULL) { + return NGX_ERROR; + } + + *s = src[i]; } - - *s = src[i]; } h = default_headers; diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index 095ef06..951a00d 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -224,12 +224,6 @@ parse: ctx->offset = r->headers_out.content_offset; - if (ngx_array_init(&ctx->ranges, r->pool, 1, sizeof(ngx_http_range_t)) - != NGX_OK) - { - return NGX_ERROR; - } - ranges = r->single_range ? 1 : clcf->max_ranges; switch (ngx_http_range_parse(r, ctx, ranges)) { @@ -291,6 +285,12 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, } } + if (ngx_array_init(&ctx->ranges, r->pool, 1, sizeof(ngx_http_range_t)) + != NGX_OK) + { + return NGX_ERROR; + } + p = r->headers_in.range->value.data + 6; size = 0; content_length = r->headers_out.content_length_n; diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index 36656ec..aa84a3d 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -270,6 +270,13 @@ static ngx_command_t ngx_http_scgi_commands[] = { offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_min_uses), NULL }, + { ngx_string("scgi_cache_max_range_offset"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_off_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_max_range_offset), + NULL }, + { ngx_string("scgi_cache_use_stale"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, ngx_conf_set_bitmask_slot, @@ -562,16 +569,14 @@ ngx_http_scgi_eval(ngx_http_request_t *r, ngx_http_scgi_loc_conf_t * scf) return NGX_ERROR; } - if (url.addrs && url.addrs[0].sockaddr) { + if (url.addrs) { u->resolved->sockaddr = url.addrs[0].sockaddr; u->resolved->socklen = url.addrs[0].socklen; + u->resolved->name = url.addrs[0].name; u->resolved->naddrs = 1; - u->resolved->host = url.addrs[0].name; - - } else { - u->resolved->host = url.host; } + u->resolved->host = url.host; u->resolved->port = url.port; u->resolved->no_port = url.no_port; @@ -1206,6 +1211,7 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t *cf) #if (NGX_HTTP_CACHE) conf->upstream.cache = NGX_CONF_UNSET; conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT; + conf->upstream.cache_max_range_offset = NGX_CONF_UNSET; conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR; conf->upstream.no_cache = NGX_CONF_UNSET_PTR; conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; @@ -1446,6 +1452,10 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_uint_value(conf->upstream.cache_min_uses, prev->upstream.cache_min_uses, 1); + ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset, + prev->upstream.cache_max_range_offset, + NGX_MAX_OFF_T_VALUE); + ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale, prev->upstream.cache_use_stale, (NGX_CONF_BITMASK_SET @@ -1558,6 +1568,20 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #endif + /* + * special handling to preserve conf->params in the "http" section + * to inherit it to all servers + */ + + if (prev->params.hash.buckets == NULL + && conf->params_source == prev->params_source) + { + prev->params = conf->params; +#if (NGX_HTTP_CACHE) + prev->params_cache = conf->params_cache; +#endif + } + return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index d685ae9..e75f5d8 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -298,6 +298,12 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_client_i_dn"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_issuer_dn, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_s_dn_legacy"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_subject_dn_legacy, NGX_HTTP_VAR_CHANGEABLE, 0 }, + + { ngx_string("ssl_client_i_dn_legacy"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_issuer_dn_legacy, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_serial"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_serial_number, NGX_HTTP_VAR_CHANGEABLE, 0 }, diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index 7f916e8..b9c8dba 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -330,6 +330,13 @@ static ngx_command_t ngx_http_uwsgi_commands[] = { offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_min_uses), NULL }, + { ngx_string("uwsgi_cache_max_range_offset"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_off_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_max_range_offset), + NULL }, + { ngx_string("uwsgi_cache_use_stale"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, ngx_conf_set_bitmask_slot, @@ -764,16 +771,14 @@ ngx_http_uwsgi_eval(ngx_http_request_t *r, ngx_http_uwsgi_loc_conf_t * uwcf) return NGX_ERROR; } - if (url.addrs && url.addrs[0].sockaddr) { + if (url.addrs) { u->resolved->sockaddr = url.addrs[0].sockaddr; u->resolved->socklen = url.addrs[0].socklen; + u->resolved->name = url.addrs[0].name; u->resolved->naddrs = 1; - u->resolved->host = url.addrs[0].name; - - } else { - u->resolved->host = url.host; } + u->resolved->host = url.host; u->resolved->port = url.port; u->resolved->no_port = url.no_port; @@ -1412,6 +1417,7 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf) #if (NGX_HTTP_CACHE) conf->upstream.cache = NGX_CONF_UNSET; conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT; + conf->upstream.cache_max_range_offset = NGX_CONF_UNSET; conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR; conf->upstream.no_cache = NGX_CONF_UNSET_PTR; conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; @@ -1660,6 +1666,10 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_uint_value(conf->upstream.cache_min_uses, prev->upstream.cache_min_uses, 1); + ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset, + prev->upstream.cache_max_range_offset, + NGX_MAX_OFF_T_VALUE); + ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale, prev->upstream.cache_use_stale, (NGX_CONF_BITMASK_SET @@ -1820,6 +1830,20 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #endif + /* + * special handling to preserve conf->params in the "http" section + * to inherit it to all servers + */ + + if (prev->params.hash.buckets == NULL + && conf->params_source == prev->params_source) + { + prev->params = conf->params; +#if (NGX_HTTP_CACHE) + prev->params_cache = conf->params_cache; +#endif + } + return NGX_CONF_OK; } diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c index 6a8894c..f9a9a84 100644 --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -410,7 +410,7 @@ ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx, args = ¶ms[NGX_HTTP_PERL_SSI_ARG]; - if (args) { + if (args[0]) { for (i = 0; args[i]; i++) { /* void */ } diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h index 70342d0..4075f3d 100644 --- a/src/http/ngx_http_cache.h +++ b/src/http/ngx_http_cache.h @@ -151,7 +151,6 @@ struct ngx_http_file_cache_s { ngx_slab_pool_t *shpool; ngx_path_t *path; - ngx_path_t *temp_path; off_t max_size; size_t bsize; @@ -171,6 +170,9 @@ struct ngx_http_file_cache_s { ngx_msec_t manager_threshold; ngx_shm_zone_t *shm_zone; + + ngx_uint_t use_temp_path; + /* unsigned use_temp_path:1 */ }; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 9da5d10..4e37cec 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -4827,8 +4827,6 @@ ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) case NGX_HTTPS_CERT_ERROR: case NGX_HTTPS_NO_CERT: err->overwrite = NGX_HTTP_BAD_REQUEST; - default: - break; } } diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index 199a901..3c8ad7d 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -1920,17 +1920,18 @@ ngx_http_file_cache_manager(void *data) ngx_http_file_cache_t *cache = data; off_t size; - time_t next, wait; - ngx_msec_t elapsed; + time_t wait; + ngx_msec_t elapsed, next; ngx_uint_t count, watermark; cache->last = ngx_current_msec; cache->files = 0; - next = ngx_http_file_cache_expire(cache); + next = (ngx_msec_t) ngx_http_file_cache_expire(cache) * 1000; if (next == 0) { - return cache->manager_sleep; + next = cache->manager_sleep; + goto done; } for ( ;; ) { @@ -1947,21 +1948,23 @@ ngx_http_file_cache_manager(void *data) size, count, (ngx_int_t) watermark); if (size < cache->max_size && count < watermark) { - return (ngx_msec_t) next * 1000; + break; } wait = ngx_http_file_cache_forced_expire(cache); if (wait > 0) { - return (ngx_msec_t) wait * 1000; + next = (ngx_msec_t) wait * 1000; + break; } if (ngx_quit || ngx_terminate) { - return (ngx_msec_t) next * 1000; + break; } if (++cache->files >= cache->manager_files) { - return cache->manager_sleep; + next = cache->manager_sleep; + break; } ngx_time_update(); @@ -1969,9 +1972,20 @@ ngx_http_file_cache_manager(void *data) elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last)); if (elapsed >= cache->manager_threshold) { - return cache->manager_sleep; + next = cache->manager_sleep; + break; } } + +done: + + elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last)); + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache manager: %ui e:%M n:%M", + cache->files, elapsed, next); + + return next; } @@ -2098,6 +2112,17 @@ ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx, ngx_str_t *name) return NGX_ERROR; } + /* + * Temporary files in cache have a suffix consisting of a dot + * followed by 10 digits. + */ + + if (name->len >= 2 * NGX_HTTP_CACHE_KEY_LEN + 1 + 10 + && name->data[name->len - 10 - 1] == '.') + { + return NGX_OK; + } + if (ctx->size < (off_t) sizeof(ngx_http_file_cache_header_t)) { ngx_log_error(NGX_LOG_CRIT, ctx->log, 0, "cache file \"%s\" is too small", name->data); @@ -2242,7 +2267,6 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) off_t max_size; u_char *last, *p; time_t inactive; - size_t len; ssize_t size; ngx_str_t s, name, *value; ngx_int_t loader_files, manager_files; @@ -2515,37 +2539,6 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - if (!use_temp_path) { - cache->temp_path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t)); - if (cache->temp_path == NULL) { - return NGX_CONF_ERROR; - } - - len = cache->path->name.len + sizeof("/temp") - 1; - - p = ngx_pnalloc(cf->pool, len + 1); - if (p == NULL) { - return NGX_CONF_ERROR; - } - - cache->temp_path->name.len = len; - cache->temp_path->name.data = p; - - p = ngx_cpymem(p, cache->path->name.data, cache->path->name.len); - ngx_memcpy(p, "/temp", sizeof("/temp")); - - ngx_memcpy(&cache->temp_path->level, &cache->path->level, - NGX_MAX_PATH_LEVEL * sizeof(size_t)); - - cache->temp_path->len = cache->path->len; - cache->temp_path->conf_file = cf->conf_file->file.name.data; - cache->temp_path->line = cf->conf_file->line; - - if (ngx_add_path(cf, &cache->temp_path) != NGX_OK) { - return NGX_CONF_ERROR; - } - } - cache->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post); if (cache->shm_zone == NULL) { return NGX_CONF_ERROR; @@ -2561,6 +2554,8 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) cache->shm_zone->init = ngx_http_file_cache_init; cache->shm_zone->data = cache; + cache->use_temp_path = use_temp_path; + cache->inactive = inactive; cache->max_size = max_size; diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c index 7692f80..d4c39ff 100644 --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -473,7 +473,6 @@ ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error) case NGX_HTTPS_NO_CERT: case NGX_HTTP_REQUEST_HEADER_TOO_LARGE: r->err_status = NGX_HTTP_BAD_REQUEST; - break; } } else { diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index ceb798f..ed25f43 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -17,6 +17,8 @@ static ngx_int_t ngx_http_upstream_cache_get(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_http_file_cache_t **cache); static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u); +static ngx_int_t ngx_http_upstream_cache_check_range(ngx_http_request_t *r, + ngx_http_upstream_t *u); static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_upstream_cache_last_modified(ngx_http_request_t *r, @@ -654,6 +656,23 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) host = &u->resolved->host; + umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); + + uscfp = umcf->upstreams.elts; + + for (i = 0; i < umcf->upstreams.nelts; i++) { + + uscf = uscfp[i]; + + if (uscf->host.len == host->len + && ((uscf->port == 0 && u->resolved->no_port) + || uscf->port == u->resolved->port) + && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0) + { + goto found; + } + } + if (u->resolved->sockaddr) { if (u->resolved->port == 0 @@ -679,23 +698,6 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) return; } - umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); - - uscfp = umcf->upstreams.elts; - - for (i = 0; i < umcf->upstreams.nelts; i++) { - - uscf = uscfp[i]; - - if (uscf->host.len == host->len - && ((uscf->port == 0 && u->resolved->no_port) - || uscf->port == u->resolved->port) - && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0) - { - goto found; - } - } - if (u->resolved->port == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no port in upstream \"%V\"", host); @@ -922,6 +924,10 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u) return rc; } + if (ngx_http_upstream_cache_check_range(r, u) == NGX_DECLINED) { + u->cacheable = 0; + } + r->cached = 0; return NGX_DECLINED; @@ -1023,6 +1029,55 @@ ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u) return rc; } + +static ngx_int_t +ngx_http_upstream_cache_check_range(ngx_http_request_t *r, + ngx_http_upstream_t *u) +{ + off_t offset; + u_char *p, *start; + ngx_table_elt_t *h; + + h = r->headers_in.range; + + if (h == NULL + || !u->cacheable + || u->conf->cache_max_range_offset == NGX_MAX_OFF_T_VALUE) + { + return NGX_OK; + } + + if (u->conf->cache_max_range_offset == 0) { + return NGX_DECLINED; + } + + if (h->value.len < 7 + || ngx_strncasecmp(h->value.data, (u_char *) "bytes=", 6) != 0) + { + return NGX_OK; + } + + p = h->value.data + 6; + + while (*p == ' ') { p++; } + + if (*p == '-') { + return NGX_DECLINED; + } + + start = p; + + while (*p >= '0' && *p <= '9') { p++; } + + offset = ngx_atoof(start, p - start); + + if (offset >= u->conf->cache_max_range_offset) { + return NGX_DECLINED; + } + + return NGX_OK; +} + #endif @@ -1611,6 +1666,13 @@ ngx_http_upstream_ssl_handshake(ngx_connection_t *c) return; } + if (c->write->timedout) { + c = r->connection; + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT); + ngx_http_run_posted_requests(c); + return; + } + failed: c = r->connection; @@ -1696,7 +1758,10 @@ ngx_http_upstream_ssl_name(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "upstream SSL server name: \"%s\"", name.data); - if (SSL_set_tlsext_host_name(c->ssl->connection, name.data) == 0) { + if (SSL_set_tlsext_host_name(c->ssl->connection, + (char *) name.data) + == 0) + { ngx_ssl_error(NGX_LOG_ERR, r->connection->log, 0, "SSL_set_tlsext_host_name(\"%s\") failed", name.data); return NGX_ERROR; @@ -2702,6 +2767,15 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) u->header_sent = 1; if (u->upgrade) { + +#if (NGX_HTTP_CACHE) + + if (r->cache) { + ngx_http_file_cache_free(r->cache, u->pipe->temp_file); + } + +#endif + ngx_http_upstream_upgrade(r, u); return; } @@ -2732,6 +2806,14 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) if (!u->buffering) { +#if (NGX_HTTP_CACHE) + + if (r->cache) { + ngx_http_file_cache_free(r->cache, u->pipe->temp_file); + } + +#endif + if (u->input_filter == NULL) { u->input_filter_init = ngx_http_upstream_non_buffered_filter_init; u->input_filter = ngx_http_upstream_non_buffered_filter; @@ -2922,8 +3004,9 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) p->temp_file->persistent = 1; #if (NGX_HTTP_CACHE) - if (r->cache && r->cache->file_cache->temp_path) { - p->temp_file->path = r->cache->file_cache->temp_path; + if (r->cache && !r->cache->file_cache->use_temp_path) { + p->temp_file->path = r->cache->file_cache->path; + p->temp_file->file.name = r->cache->file.name; } #endif @@ -5757,14 +5840,9 @@ ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags) continue; } - if (uscfp[i]->default_port && u->default_port - && uscfp[i]->default_port != u->default_port) - { - continue; - } - if (flags & NGX_HTTP_UPSTREAM_CREATE) { uscfp[i]->flags = flags; + uscfp[i]->port = 0; } return uscfp[i]; @@ -5780,7 +5858,6 @@ ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags) uscf->file_name = cf->conf_file->file.name.data; uscf->line = cf->conf_file->line; uscf->port = u->port; - uscf->default_port = u->default_port; uscf->no_port = u->no_port; if (u->naddrs == 1 && (u->port || u->family == AF_UNIX)) { @@ -6021,12 +6098,7 @@ ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf, conf->hide_headers_hash = prev->hide_headers_hash; - if (conf->hide_headers_hash.buckets -#if (NGX_HTTP_CACHE) - && ((conf->cache == 0) == (prev->cache == 0)) -#endif - ) - { + if (conf->hide_headers_hash.buckets) { return NGX_OK; } @@ -6111,7 +6183,23 @@ ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf, hash->pool = cf->pool; hash->temp_pool = NULL; - return ngx_hash_init(hash, hide_headers.elts, hide_headers.nelts); + if (ngx_hash_init(hash, hide_headers.elts, hide_headers.nelts) != NGX_OK) { + return NGX_ERROR; + } + + /* + * special handling to preserve conf->hide_headers_hash + * in the "http" section to inherit it to all servers + */ + + if (prev->hide_headers_hash.buckets == NULL + && conf->hide_headers == prev->hide_headers + && conf->pass_headers == prev->pass_headers) + { + prev->hide_headers_hash = conf->hide_headers_hash; + } + + return NGX_OK; } diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index 3d521f2..7390f2e 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -128,7 +128,6 @@ struct ngx_http_upstream_srv_conf_s { u_char *file_name; ngx_uint_t line; in_port_t port; - in_port_t default_port; ngx_uint_t no_port; /* unsigned no_port:1 */ #if (NGX_HTTP_UPSTREAM_ZONE) @@ -199,6 +198,8 @@ typedef struct { ngx_uint_t cache_use_stale; ngx_uint_t cache_methods; + off_t cache_max_range_offset; + ngx_flag_t cache_lock; ngx_msec_t cache_lock_timeout; ngx_msec_t cache_lock_age; @@ -300,6 +301,7 @@ typedef struct { struct sockaddr *sockaddr; socklen_t socklen; + ngx_str_t name; ngx_resolver_ctx_t *ctx; } ngx_http_upstream_resolved_t; diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c index 0137bf6..f6051ae 100644 --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -337,7 +337,7 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, if (ur->sockaddr) { peer[0].sockaddr = ur->sockaddr; peer[0].socklen = ur->socklen; - peer[0].name = ur->host; + peer[0].name = ur->name.data ? ur->name : ur->host; peer[0].weight = 1; peer[0].effective_weight = 1; peer[0].current_weight = 0; diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 235092b..8301630 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -136,6 +136,8 @@ static ngx_int_t ngx_http_v2_send_window_update(ngx_http_v2_connection_t *h2c, ngx_uint_t sid, size_t window); static ngx_int_t ngx_http_v2_send_rst_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t sid, ngx_uint_t status); +static ngx_int_t ngx_http_v2_send_goaway(ngx_http_v2_connection_t *h2c, + ngx_uint_t status); static ngx_http_v2_out_frame_t *ngx_http_v2_get_frame( ngx_http_v2_connection_t *h2c, size_t length, ngx_uint_t type, @@ -293,6 +295,8 @@ ngx_http_v2_init(ngx_event_t *rev) rev->handler = ngx_http_v2_read_handler; c->write->handler = ngx_http_v2_write_handler; + c->idle = 1; + ngx_http_v2_read_handler(rev); } @@ -320,6 +324,30 @@ ngx_http_v2_read_handler(ngx_event_t *rev) h2c->blocked = 1; + if (c->close) { + c->close = 0; + + if (!h2c->goaway) { + h2c->goaway = 1; + + if (ngx_http_v2_send_goaway(h2c, NGX_HTTP_V2_NO_ERROR) + == NGX_ERROR) + { + ngx_http_v2_finalize_connection(h2c, 0); + return; + } + + if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) { + ngx_http_v2_finalize_connection(h2c, 0); + return; + } + } + + h2c->blocked = 0; + + return; + } + h2mcf = ngx_http_get_module_main_conf(h2c->http_connection->conf_ctx, ngx_http_v2_module); @@ -633,6 +661,11 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) /* rc == NGX_OK */ } + if (h2c->goaway) { + ngx_http_close_connection(c); + return; + } + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, ngx_http_v2_module); if (h2c->state.incomplete) { @@ -640,11 +673,6 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) return; } - if (ngx_terminate || ngx_exiting) { - ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR); - return; - } - ngx_destroy_pool(h2c->pool); h2c->pool = NULL; @@ -658,7 +686,6 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) #endif c->destroyed = 1; - c->idle = 1; ngx_reusable_connection(c, 1); c->write->handler = ngx_http_empty_handler; @@ -1027,6 +1054,12 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); } + if (h2c->goaway) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "skipping http2 HEADERS frame"); + return ngx_http_v2_state_skip(h2c, pos, end); + } + if ((size_t) (end - pos) < size) { return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_headers); @@ -1149,6 +1182,15 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, ngx_http_v2_set_dependency(h2c, node, depend, excl); } + if (h2c->connection->requests >= h2scf->max_requests) { + h2c->goaway = 1; + + if (ngx_http_v2_send_goaway(h2c, NGX_HTTP_V2_NO_ERROR) == NGX_ERROR) { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + } + return ngx_http_v2_state_header_block(h2c, pos, end); rst_stream: @@ -2550,7 +2592,7 @@ ngx_http_v2_send_rst_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t sid, ngx_http_v2_out_frame_t *frame; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2 send RST_STREAM frame sid:%ui, status:%uz", + "http2 send RST_STREAM frame sid:%ui, status:%ui", sid, status); frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_RST_STREAM_SIZE, @@ -2576,8 +2618,9 @@ ngx_http_v2_send_goaway(ngx_http_v2_connection_t *h2c, ngx_uint_t status) ngx_buf_t *buf; ngx_http_v2_out_frame_t *frame; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2 send GOAWAY frame, status:%uz", status); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 send GOAWAY frame: last sid %ui, error %ui", + h2c->last_sid, status); frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_GOAWAY_SIZE, NGX_HTTP_V2_GOAWAY_FRAME, @@ -4162,7 +4205,6 @@ ngx_http_v2_idle_handler(ngx_event_t *rev) #endif c->destroyed = 0; - c->idle = 0; ngx_reusable_connection(c, 0); h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, @@ -4197,8 +4239,10 @@ ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c, h2c->blocked = 1; - if (!c->error && ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) { - (void) ngx_http_v2_send_output_queue(h2c); + if (!c->error && !h2c->goaway) { + if (ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) { + (void) ngx_http_v2_send_output_queue(h2c); + } } c->error = 1; diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index d712d38..63bbdad 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -146,6 +146,7 @@ struct ngx_http_v2_connection_s { unsigned closed_nodes:8; unsigned settings_ack:1; unsigned blocked:1; + unsigned goaway:1; }; diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index 4ab7791..878020e 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -1079,6 +1079,10 @@ static ngx_inline ngx_int_t ngx_http_v2_flow_control(ngx_http_v2_connection_t *h2c, ngx_http_v2_stream_t *stream) { + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2:%ui available windows: conn:%uz stream:%z", + stream->node->id, h2c->send_window, stream->send_window); + if (stream->send_window <= 0) { stream->exhausted = 1; return NGX_DECLINED; diff --git a/src/http/v2/ngx_http_v2_module.c b/src/http/v2/ngx_http_v2_module.c index b7d99e0..032abcb 100644 --- a/src/http/v2/ngx_http_v2_module.c +++ b/src/http/v2/ngx_http_v2_module.c @@ -73,6 +73,13 @@ static ngx_command_t ngx_http_v2_commands[] = { offsetof(ngx_http_v2_srv_conf_t, concurrent_streams), NULL }, + { ngx_string("http2_max_requests"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v2_srv_conf_t, max_requests), + NULL }, + { ngx_string("http2_max_field_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, @@ -322,6 +329,7 @@ ngx_http_v2_create_srv_conf(ngx_conf_t *cf) h2scf->pool_size = NGX_CONF_UNSET_SIZE; h2scf->concurrent_streams = NGX_CONF_UNSET_UINT; + h2scf->max_requests = NGX_CONF_UNSET_UINT; h2scf->max_field_size = NGX_CONF_UNSET_SIZE; h2scf->max_header_size = NGX_CONF_UNSET_SIZE; @@ -347,6 +355,7 @@ ngx_http_v2_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_uint_value(conf->concurrent_streams, prev->concurrent_streams, 128); + ngx_conf_merge_uint_value(conf->max_requests, prev->max_requests, 1000); ngx_conf_merge_size_value(conf->max_field_size, prev->max_field_size, 4096); diff --git a/src/http/v2/ngx_http_v2_module.h b/src/http/v2/ngx_http_v2_module.h index 91f97c2..540f826 100644 --- a/src/http/v2/ngx_http_v2_module.h +++ b/src/http/v2/ngx_http_v2_module.h @@ -23,6 +23,7 @@ typedef struct { typedef struct { size_t pool_size; ngx_uint_t concurrent_streams; + ngx_uint_t max_requests; size_t max_field_size; size_t max_header_size; size_t preread_size; diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index c30af35..6002508 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -132,7 +132,8 @@ typedef enum { ngx_pop3_auth_login_username, ngx_pop3_auth_login_password, ngx_pop3_auth_plain, - ngx_pop3_auth_cram_md5 + ngx_pop3_auth_cram_md5, + ngx_pop3_auth_external } ngx_pop3_state_e; @@ -142,6 +143,7 @@ typedef enum { ngx_imap_auth_login_password, ngx_imap_auth_plain, ngx_imap_auth_cram_md5, + ngx_imap_auth_external, ngx_imap_login, ngx_imap_user, ngx_imap_passwd @@ -154,6 +156,7 @@ typedef enum { ngx_smtp_auth_login_password, ngx_smtp_auth_plain, ngx_smtp_auth_cram_md5, + ngx_smtp_auth_external, ngx_smtp_helo, ngx_smtp_helo_xclient, ngx_smtp_helo_from, @@ -285,14 +288,16 @@ typedef struct { #define NGX_MAIL_AUTH_LOGIN_USERNAME 2 #define NGX_MAIL_AUTH_APOP 3 #define NGX_MAIL_AUTH_CRAM_MD5 4 -#define NGX_MAIL_AUTH_NONE 5 +#define NGX_MAIL_AUTH_EXTERNAL 5 +#define NGX_MAIL_AUTH_NONE 6 #define NGX_MAIL_AUTH_PLAIN_ENABLED 0x0002 #define NGX_MAIL_AUTH_LOGIN_ENABLED 0x0004 #define NGX_MAIL_AUTH_APOP_ENABLED 0x0008 #define NGX_MAIL_AUTH_CRAM_MD5_ENABLED 0x0010 -#define NGX_MAIL_AUTH_NONE_ENABLED 0x0020 +#define NGX_MAIL_AUTH_EXTERNAL_ENABLED 0x0020 +#define NGX_MAIL_AUTH_NONE_ENABLED 0x0040 #define NGX_MAIL_PARSE_INVALID_COMMAND 20 @@ -377,6 +382,8 @@ ngx_int_t ngx_mail_auth_login_password(ngx_mail_session_t *s, ngx_int_t ngx_mail_auth_cram_md5_salt(ngx_mail_session_t *s, ngx_connection_t *c, char *prefix, size_t len); ngx_int_t ngx_mail_auth_cram_md5(ngx_mail_session_t *s, ngx_connection_t *c); +ngx_int_t ngx_mail_auth_external(ngx_mail_session_t *s, ngx_connection_t *c, + ngx_uint_t n); ngx_int_t ngx_mail_auth_parse(ngx_mail_session_t *s, ngx_connection_t *c); void ngx_mail_send(ngx_event_t *wev); diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c index a94434a..6b57358 100644 --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -151,6 +151,7 @@ static ngx_str_t ngx_mail_auth_http_method[] = { ngx_string("plain"), ngx_string("apop"), ngx_string("cram-md5"), + ngx_string("external"), ngx_string("none") }; diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index 901bb8f..9d4ef56 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -612,6 +612,40 @@ ngx_mail_auth_cram_md5(ngx_mail_session_t *s, ngx_connection_t *c) } +ngx_int_t +ngx_mail_auth_external(ngx_mail_session_t *s, ngx_connection_t *c, + ngx_uint_t n) +{ + ngx_str_t *arg, external; + + arg = s->args.elts; + + ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, + "mail auth external: \"%V\"", &arg[n]); + + external.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len)); + if (external.data == NULL) { + return NGX_ERROR; + } + + if (ngx_decode_base64(&external, &arg[n]) != NGX_OK) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent invalid base64 encoding in AUTH EXTERNAL command"); + return NGX_MAIL_PARSE_INVALID_COMMAND; + } + + s->login.len = external.len; + s->login.data = external.data; + + ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, + "mail auth external: \"%V\"", &s->login); + + s->auth_method = NGX_MAIL_AUTH_EXTERNAL; + + return NGX_DONE; +} + + void ngx_mail_send(ngx_event_t *wev) { diff --git a/src/mail/ngx_mail_imap_handler.c b/src/mail/ngx_mail_imap_handler.c index 57e2fb7..1c54457 100644 --- a/src/mail/ngx_mail_imap_handler.c +++ b/src/mail/ngx_mail_imap_handler.c @@ -222,6 +222,10 @@ ngx_mail_imap_auth_state(ngx_event_t *rev) case ngx_imap_auth_cram_md5: rc = ngx_mail_auth_cram_md5(s, c); break; + + case ngx_imap_auth_external: + rc = ngx_mail_auth_external(s, c, 0); + break; } } else if (rc == NGX_IMAP_NEXT) { @@ -399,6 +403,13 @@ ngx_mail_imap_authenticate(ngx_mail_session_t *s, ngx_connection_t *c) } return NGX_ERROR; + + case NGX_MAIL_AUTH_EXTERNAL: + + ngx_str_set(&s->out, imap_username); + s->mail_state = ngx_imap_auth_external; + + return NGX_OK; } return rc; diff --git a/src/mail/ngx_mail_imap_module.c b/src/mail/ngx_mail_imap_module.c index d281070..1f187fd 100644 --- a/src/mail/ngx_mail_imap_module.c +++ b/src/mail/ngx_mail_imap_module.c @@ -29,6 +29,7 @@ static ngx_conf_bitmask_t ngx_mail_imap_auth_methods[] = { { ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED }, { ngx_string("login"), NGX_MAIL_AUTH_LOGIN_ENABLED }, { ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED }, + { ngx_string("external"), NGX_MAIL_AUTH_EXTERNAL_ENABLED }, { ngx_null_string, 0 } }; @@ -38,6 +39,7 @@ static ngx_str_t ngx_mail_imap_auth_methods_names[] = { ngx_string("AUTH=LOGIN"), ngx_null_string, /* APOP */ ngx_string("AUTH=CRAM-MD5"), + ngx_string("AUTH=EXTERNAL"), ngx_null_string /* NONE */ }; @@ -179,7 +181,7 @@ ngx_mail_imap_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) } for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0; - m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED; + m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED; m <<= 1, i++) { if (m & conf->auth_methods) { @@ -205,7 +207,7 @@ ngx_mail_imap_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) auth = p; for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0; - m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED; + m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED; m <<= 1, i++) { if (m & conf->auth_methods) { diff --git a/src/mail/ngx_mail_parse.c b/src/mail/ngx_mail_parse.c index b158f5a..2c2cdff 100644 --- a/src/mail/ngx_mail_parse.c +++ b/src/mail/ngx_mail_parse.c @@ -905,13 +905,27 @@ ngx_mail_auth_parse(ngx_mail_session_t *s, ngx_connection_t *c) if (arg[0].len == 8) { - if (s->args.nelts != 1) { - return NGX_MAIL_PARSE_INVALID_COMMAND; - } - if (ngx_strncasecmp(arg[0].data, (u_char *) "CRAM-MD5", 8) == 0) { + + if (s->args.nelts != 1) { + return NGX_MAIL_PARSE_INVALID_COMMAND; + } + return NGX_MAIL_AUTH_CRAM_MD5; } + + if (ngx_strncasecmp(arg[0].data, (u_char *) "EXTERNAL", 8) == 0) { + + if (s->args.nelts == 1) { + return NGX_MAIL_AUTH_EXTERNAL; + } + + if (s->args.nelts == 2) { + return ngx_mail_auth_external(s, c, 1); + } + } + + return NGX_MAIL_PARSE_INVALID_COMMAND; } return NGX_MAIL_PARSE_INVALID_COMMAND; diff --git a/src/mail/ngx_mail_pop3_handler.c b/src/mail/ngx_mail_pop3_handler.c index 51bc257..a2d5658 100644 --- a/src/mail/ngx_mail_pop3_handler.c +++ b/src/mail/ngx_mail_pop3_handler.c @@ -240,6 +240,10 @@ ngx_mail_pop3_auth_state(ngx_event_t *rev) case ngx_pop3_auth_cram_md5: rc = ngx_mail_auth_cram_md5(s, c); break; + + case ngx_pop3_auth_external: + rc = ngx_mail_auth_external(s, c, 0); + break; } } @@ -494,6 +498,13 @@ ngx_mail_pop3_auth(ngx_mail_session_t *s, ngx_connection_t *c) } return NGX_ERROR; + + case NGX_MAIL_AUTH_EXTERNAL: + + ngx_str_set(&s->out, pop3_username); + s->mail_state = ngx_pop3_auth_external; + + return NGX_OK; } return rc; diff --git a/src/mail/ngx_mail_pop3_module.c b/src/mail/ngx_mail_pop3_module.c index 73f8531..bd60e0a 100644 --- a/src/mail/ngx_mail_pop3_module.c +++ b/src/mail/ngx_mail_pop3_module.c @@ -29,23 +29,19 @@ static ngx_conf_bitmask_t ngx_mail_pop3_auth_methods[] = { { ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED }, { ngx_string("apop"), NGX_MAIL_AUTH_APOP_ENABLED }, { ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED }, + { ngx_string("external"), NGX_MAIL_AUTH_EXTERNAL_ENABLED }, { ngx_null_string, 0 } }; -static ngx_str_t ngx_mail_pop3_auth_plain_capability = - ngx_string("+OK methods supported:" CRLF - "LOGIN" CRLF - "PLAIN" CRLF - "." CRLF); - - -static ngx_str_t ngx_mail_pop3_auth_cram_md5_capability = - ngx_string("+OK methods supported:" CRLF - "LOGIN" CRLF - "PLAIN" CRLF - "CRAM-MD5" CRLF - "." CRLF); +static ngx_str_t ngx_mail_pop3_auth_methods_names[] = { + ngx_string("PLAIN"), + ngx_string("LOGIN"), + ngx_null_string, /* APOP */ + ngx_string("CRAM-MD5"), + ngx_string("EXTERNAL"), + ngx_null_string /* NONE */ +}; static ngx_mail_protocol_t ngx_mail_pop3_protocol = { @@ -140,13 +136,17 @@ ngx_mail_pop3_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) u_char *p; size_t size, stls_only_size; ngx_str_t *c, *d; - ngx_uint_t i; + ngx_uint_t i, m; ngx_conf_merge_bitmask_value(conf->auth_methods, prev->auth_methods, (NGX_CONF_BITMASK_SET |NGX_MAIL_AUTH_PLAIN_ENABLED)); + if (conf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED) { + conf->auth_methods |= NGX_MAIL_AUTH_LOGIN_ENABLED; + } + if (conf->capabilities.nelts == 0) { conf->capabilities = prev->capabilities; } @@ -179,11 +179,15 @@ ngx_mail_pop3_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) stls_only_size += c[i].len + sizeof(CRLF) - 1; } - if (conf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) { - size += sizeof("SASL LOGIN PLAIN CRAM-MD5" CRLF) - 1; + size += sizeof("SASL") - 1 + sizeof(CRLF) - 1; - } else { - size += sizeof("SASL LOGIN PLAIN" CRLF) - 1; + for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0; + m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED; + m <<= 1, i++) + { + if (m & conf->auth_methods) { + size += 1 + ngx_mail_pop3_auth_methods_names[i].len; + } } p = ngx_pnalloc(cf->pool, size); @@ -202,15 +206,21 @@ ngx_mail_pop3_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) *p++ = CR; *p++ = LF; } - if (conf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) { - p = ngx_cpymem(p, "SASL LOGIN PLAIN CRAM-MD5" CRLF, - sizeof("SASL LOGIN PLAIN CRAM-MD5" CRLF) - 1); + p = ngx_cpymem(p, "SASL", sizeof("SASL") - 1); - } else { - p = ngx_cpymem(p, "SASL LOGIN PLAIN" CRLF, - sizeof("SASL LOGIN PLAIN" CRLF) - 1); + for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0; + m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED; + m <<= 1, i++) + { + if (m & conf->auth_methods) { + *p++ = ' '; + p = ngx_cpymem(p, ngx_mail_pop3_auth_methods_names[i].data, + ngx_mail_pop3_auth_methods_names[i].len); + } } + *p++ = CR; *p++ = LF; + *p++ = '.'; *p++ = CR; *p = LF; @@ -231,13 +241,43 @@ ngx_mail_pop3_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) *p++ = '.'; *p++ = CR; *p = LF; - if (conf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) { - conf->auth_capability = ngx_mail_pop3_auth_cram_md5_capability; + size = sizeof("+OK methods supported:" CRLF) - 1 + + sizeof("." CRLF) - 1; - } else { - conf->auth_capability = ngx_mail_pop3_auth_plain_capability; + for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0; + m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED; + m <<= 1, i++) + { + if (m & conf->auth_methods) { + size += ngx_mail_pop3_auth_methods_names[i].len + + sizeof(CRLF) - 1; + } } + p = ngx_pnalloc(cf->pool, size); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + conf->auth_capability.data = p; + conf->auth_capability.len = size; + + p = ngx_cpymem(p, "+OK methods supported:" CRLF, + sizeof("+OK methods supported:" CRLF) - 1); + + for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0; + m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED; + m <<= 1, i++) + { + if (m & conf->auth_methods) { + p = ngx_cpymem(p, ngx_mail_pop3_auth_methods_names[i].data, + ngx_mail_pop3_auth_methods_names[i].len); + *p++ = CR; *p++ = LF; + } + } + + *p++ = '.'; *p++ = CR; *p = LF; + p = ngx_pnalloc(cf->pool, stls_only_size); if (p == NULL) { diff --git a/src/mail/ngx_mail_smtp_handler.c b/src/mail/ngx_mail_smtp_handler.c index 81cc75f..47756c3 100644 --- a/src/mail/ngx_mail_smtp_handler.c +++ b/src/mail/ngx_mail_smtp_handler.c @@ -485,6 +485,10 @@ ngx_mail_smtp_auth_state(ngx_event_t *rev) case ngx_smtp_auth_cram_md5: rc = ngx_mail_auth_cram_md5(s, c); break; + + case ngx_smtp_auth_external: + rc = ngx_mail_auth_external(s, c, 0); + break; } } @@ -652,6 +656,13 @@ ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c) } return NGX_ERROR; + + case NGX_MAIL_AUTH_EXTERNAL: + + ngx_str_set(&s->out, smtp_username); + s->mail_state = ngx_smtp_auth_external; + + return NGX_OK; } return rc; diff --git a/src/mail/ngx_mail_smtp_module.c b/src/mail/ngx_mail_smtp_module.c index d5bb51c..f03bd90 100644 --- a/src/mail/ngx_mail_smtp_module.c +++ b/src/mail/ngx_mail_smtp_module.c @@ -21,6 +21,7 @@ static ngx_conf_bitmask_t ngx_mail_smtp_auth_methods[] = { { ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED }, { ngx_string("login"), NGX_MAIL_AUTH_LOGIN_ENABLED }, { ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED }, + { ngx_string("external"), NGX_MAIL_AUTH_EXTERNAL_ENABLED }, { ngx_string("none"), NGX_MAIL_AUTH_NONE_ENABLED }, { ngx_null_string, 0 } }; @@ -31,6 +32,7 @@ static ngx_str_t ngx_mail_smtp_auth_methods_names[] = { ngx_string("LOGIN"), ngx_null_string, /* APOP */ ngx_string("CRAM-MD5"), + ngx_string("EXTERNAL"), ngx_null_string /* NONE */ }; @@ -207,7 +209,7 @@ ngx_mail_smtp_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) auth_enabled = 0; for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0; - m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED; + m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED; m <<= 1, i++) { if (m & conf->auth_methods) { @@ -250,7 +252,7 @@ ngx_mail_smtp_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) *p++ = 'A'; *p++ = 'U'; *p++ = 'T'; *p++ = 'H'; for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0; - m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED; + m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED; m <<= 1, i++) { if (m & conf->auth_methods) { diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 4231f97..c03b515 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -433,6 +433,23 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) host = &u->resolved->host; + umcf = ngx_stream_get_module_main_conf(s, ngx_stream_upstream_module); + + uscfp = umcf->upstreams.elts; + + for (i = 0; i < umcf->upstreams.nelts; i++) { + + uscf = uscfp[i]; + + if (uscf->host.len == host->len + && ((uscf->port == 0 && u->resolved->no_port) + || uscf->port == u->resolved->port) + && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0) + { + goto found; + } + } + if (u->resolved->sockaddr) { if (u->resolved->port == 0 @@ -456,23 +473,6 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) return; } - umcf = ngx_stream_get_module_main_conf(s, ngx_stream_upstream_module); - - uscfp = umcf->upstreams.elts; - - for (i = 0; i < umcf->upstreams.nelts; i++) { - - uscf = uscfp[i]; - - if (uscf->host.len == host->len - && ((uscf->port == 0 && u->resolved->no_port) - || uscf->port == u->resolved->port) - && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0) - { - goto found; - } - } - if (u->resolved->port == 0) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "no port in upstream \"%V\"", host); @@ -578,16 +578,14 @@ ngx_stream_proxy_eval(ngx_stream_session_t *s, return NGX_ERROR; } - if (url.addrs && url.addrs[0].sockaddr) { + if (url.addrs) { u->resolved->sockaddr = url.addrs[0].sockaddr; u->resolved->socklen = url.addrs[0].socklen; + u->resolved->name = url.addrs[0].name; u->resolved->naddrs = 1; - u->resolved->host = url.addrs[0].name; - - } else { - u->resolved->host = url.host; } + u->resolved->host = url.host; u->resolved->port = url.port; u->resolved->no_port = url.no_port; @@ -1183,7 +1181,8 @@ ngx_stream_proxy_ssl_name(ngx_stream_session_t *s) ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "upstream SSL server name: \"%s\"", name.data); - if (SSL_set_tlsext_host_name(u->peer.connection->ssl->connection, name.data) + if (SSL_set_tlsext_host_name(u->peer.connection->ssl->connection, + (char *) name.data) == 0) { ngx_ssl_error(NGX_LOG_ERR, s->connection->log, 0, diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h index 764a340..ec75768 100644 --- a/src/stream/ngx_stream_upstream.h +++ b/src/stream/ngx_stream_upstream.h @@ -105,6 +105,7 @@ typedef struct { struct sockaddr *sockaddr; socklen_t socklen; + ngx_str_t name; ngx_resolver_ctx_t *ctx; } ngx_stream_upstream_resolved_t; diff --git a/src/stream/ngx_stream_upstream_round_robin.c b/src/stream/ngx_stream_upstream_round_robin.c index 3a62501..db620ef 100644 --- a/src/stream/ngx_stream_upstream_round_robin.c +++ b/src/stream/ngx_stream_upstream_round_robin.c @@ -344,7 +344,7 @@ ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, if (ur->sockaddr) { peer[0].sockaddr = ur->sockaddr; peer[0].socklen = ur->socklen; - peer[0].name = ur->host; + peer[0].name = ur->name; peer[0].weight = 1; peer[0].effective_weight = 1; peer[0].current_weight = 0; From 7c03e6673ba20bd34ae0795219eb2baf90825702 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 18 Nov 2016 17:17:57 +0200 Subject: [PATCH 182/651] Adjust experimental flow We now dummy merge (-s ours) upstream into upstream-1.11 instead of force pushing a clean branch on every release. That way we can easier track the branch's history. --- debian/README.Packaging | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/debian/README.Packaging b/debian/README.Packaging index bbb7875..47a582f 100644 --- a/debian/README.Packaging +++ b/debian/README.Packaging @@ -58,11 +58,11 @@ them. are commited (changelog entry etc) and the build is made. * upstream-1.11 - Force-pushed on every 1.11.x release. + Pushed on every 1.11.x release. - Before a new 1.11.x release the branch is reset to origin/upstream. - This is a technicallity so we can avoid resolving conflicts when a new 1.10.x - release happens between two experimental releases. + Before a new 1.11.x release origin/upstream is dummy merged (-s ours) into + ustream-1.11. This is a technicallity so we can avoid resolving conflicts + when a new 1.10.x release happens between two experimental releases. Older 1.11.x releases are not referenced by any branch, but they can be found by the relevant debian/* tag. From e7164cf7acc2ef081cbedc8f5c9801f53e64c1ba Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 21 Nov 2016 16:20:29 +0200 Subject: [PATCH 183/651] Change my email --- debian/control | 2 +- debian/copyright | 2 +- debian/dh_nginx | 2 +- ...2-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch | 2 +- debian/patches/perl-use-dpkg-buildflags.patch | 2 +- debian/po/templates.pot | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/debian/control b/debian/control index e553a8a..ff6aace 100644 --- a/debian/control +++ b/debian/control @@ -4,7 +4,7 @@ Priority: optional Maintainer: Debian Nginx Maintainers Uploaders: Kartik Mistry , Michael Lustfield , - Christos Trochalakis + Christos Trochalakis Build-Depends: autotools-dev, debhelper (>= 9), po-debconf, diff --git a/debian/copyright b/debian/copyright index 019dc9d..40218cb 100644 --- a/debian/copyright +++ b/debian/copyright @@ -34,7 +34,7 @@ Copyright: 2007-2009, Fabio Tranchitella 2010-2014, Michael Lustfield 2011 Dmitry E. Oboukhov 2011-2013, Cyril Lavier - 2013-2014, Christos Trochalakis + 2013-2016, Christos Trochalakis License: BSD-2-clause Files: debian/modules/headers-more-nginx-module/* diff --git a/debian/dh_nginx b/debian/dh_nginx index 3be792d..8e6ce3b 100755 --- a/debian/dh_nginx +++ b/debian/dh_nginx @@ -1,7 +1,7 @@ #! /usr/bin/perl # dh_nginx - Nginx configuration helper -# Copyright (C) 2016 Christos Trochalakis +# Copyright (C) 2016 Christos Trochalakis # # This program is licensed under the terms of the GNU General # Public License veserion 2+ diff --git a/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch b/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch index 1bea8b2..9cc3962 100644 --- a/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch +++ b/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch @@ -1,4 +1,4 @@ -From: Christos Trochalakis +From: Christos Trochalakis Date: Wed, 30 Mar 2016 09:47:11 +0300 Subject: Make sure signature stays the same in all nginx builds diff --git a/debian/patches/perl-use-dpkg-buildflags.patch b/debian/patches/perl-use-dpkg-buildflags.patch index d6b6f96..5379313 100644 --- a/debian/patches/perl-use-dpkg-buildflags.patch +++ b/debian/patches/perl-use-dpkg-buildflags.patch @@ -1,6 +1,6 @@ Description: Use linker flags from environment for perl (dpkg-buildflags). Necessary for hardening flags. -Author: Christos Trochalakis +Author: Christos Trochalakis --- a/src/http/modules/perl/Makefile.PL +++ b/src/http/modules/perl/Makefile.PL @@ -3,6 +3,7 @@ diff --git a/debian/po/templates.pot b/debian/po/templates.pot index bb72383..9260ff1 100644 --- a/debian/po/templates.pot +++ b/debian/po/templates.pot @@ -1,7 +1,7 @@ # Nginx debconf translations # Copyright (C) 2016 Christos Trochalakis # This file is distributed under the same license as the nginx package. -# Chrirtos Trochalakis , 2016. +# Christos Trochalakis , 2016. # #, fuzzy msgid "" From bf78540e31b57a79b79b54d019a2faa2f988c89c Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 18 Nov 2016 16:14:24 +0200 Subject: [PATCH 184/651] debian/rules: Correctly clean patched modules Closes: #844506 Thanks: Sven-Haegar Koch for the initial patch. --- debian/rules | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/debian/rules b/debian/rules index f1806b1..4a8d986 100755 --- a/debian/rules +++ b/debian/rules @@ -145,7 +145,7 @@ extras_configure_flags := \ override_dh_auto_configure: config_patch_modules $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) override_dh_auto_build: $(foreach flavour,$(FLAVOURS),build.arch.$(flavour)) override_dh_strip: $(foreach flavour,$(FLAVOURS),strip.arch.$(flavour)) $(foreach mod,$(DYN_MODS),strip.mods.$(mod)) -override_dh_clean: $(foreach flavour,$(FLAVOURS),clean.$(flavour)) +override_dh_clean: clean_patch_modules $(foreach flavour,$(FLAVOURS),clean.$(flavour)) dh_clean override_dh_install: @@ -174,6 +174,13 @@ config_patch_modules: $(foreach mod,$(modules_with_patches),config.patch.$(mod)) config.patch.%: cd $(MODULESDIR)/$* && QUILT_PATCHES=$(MODULESPATCHDIR)/$* quilt push -a +clean_patch_modules: $(foreach mod,$(modules_with_patches),clean.patch.$(mod)) +clean.patch.%: + if [ -s $(MODULESDIR)/$*/.pc/applied-patches ]; then \ + cd $(MODULESDIR)/$* && QUILT_PATCHES=$(MODULESPATCHDIR)/$* quilt pop -q -a; \ + rm -rf $(MODULESDIR)/$*/.pc; \ + fi + config.arch.%: dh_testdir mkdir -p $(BUILDDIR_$*) @@ -188,4 +195,4 @@ config.arch.%: clean.%: rm -rf $(BUILDDIR_$*) -.PHONY: config_patch_modules +.PHONY: config_patch_modules clean_patch_modules From 4deb3d7f527d86f4d2072bb96b8090214d0bdc8a Mon Sep 17 00:00:00 2001 From: Michael Lustfield Date: Sat, 3 Dec 2016 07:58:19 +0000 Subject: [PATCH 185/651] Correcting location of default php-fpm socket. --- debian/changelog | 7 +++++++ debian/conf/sites-available/default | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 89b8f64..af0ea9f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.10.2-3) UNRELEASED; urgency=medium + + * debian/conf/sites-enabled/default: + + Correcting location of default php-fpm socket. (Closes #846145) + + -- Michael Lustfield Sat, 03 Dec 2016 07:57:39 +0000 + nginx (1.10.2-2) unstable; urgency=medium * Build against OpenSSL 1.1.0. (Closes: #828453) diff --git a/debian/conf/sites-available/default b/debian/conf/sites-available/default index 890f572..c841ceb 100644 --- a/debian/conf/sites-available/default +++ b/debian/conf/sites-available/default @@ -57,7 +57,7 @@ server { # include snippets/fastcgi-php.conf; # # # With php-fpm (or other unix sockets): - # fastcgi_pass unix:/var/run/php7.0-fpm.sock; + # fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; # # With php-cgi (or other tcp sockets): # fastcgi_pass 127.0.0.1:9000; #} From 0b60e49e0895dcdbac7a8773359eec09d4a5f746 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 13 Dec 2016 18:47:26 +0200 Subject: [PATCH 186/651] New upstream version 1.11.7 --- CHANGES | 27 ++ CHANGES.ru | 27 ++ auto/lib/perl/conf | 6 +- auto/make | 17 +- auto/module | 4 + auto/modules | 4 +- src/core/nginx.c | 48 ++- src/core/nginx.h | 4 +- src/core/ngx_cycle.c | 13 +- src/core/ngx_output_chain.c | 2 +- src/core/ngx_slab.c | 338 +++++++++-------- src/core/ngx_slab.h | 12 + src/event/modules/ngx_devpoll_module.c | 10 +- src/event/modules/ngx_epoll_module.c | 19 +- src/event/modules/ngx_eventport_module.c | 10 +- src/event/modules/ngx_poll_module.c | 10 +- src/event/ngx_event_openssl.c | 380 ++++++++++++++++++- src/event/ngx_event_openssl.h | 11 + src/event/ngx_event_openssl_stapling.c | 79 ++-- src/http/modules/ngx_http_map_module.c | 18 +- src/http/modules/ngx_http_mp4_module.c | 4 +- src/http/modules/ngx_http_ssl_module.c | 15 + src/http/modules/perl/ngx_http_perl_module.c | 8 + src/http/v2/ngx_http_v2.c | 32 +- src/http/v2/ngx_http_v2.h | 3 +- src/http/v2/ngx_http_v2_filter_module.c | 50 ++- src/stream/ngx_stream_map_module.c | 18 +- src/stream/ngx_stream_ssl_module.c | 6 + 28 files changed, 866 insertions(+), 309 deletions(-) diff --git a/CHANGES b/CHANGES index 1882976..99e360e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,31 @@ +Changes with nginx 1.11.7 13 Dec 2016 + + *) Change: now in case of a client certificate verification error the + $ssl_client_verify variable contains a string with the failure + reason, for example, "FAILED:certificate has expired". + + *) Feature: the $ssl_ciphers, $ssl_curves, $ssl_client_v_start, + $ssl_client_v_end, and $ssl_client_v_remain variables. + + *) Feature: the "volatile" parameter of the "map" directive. + + *) Bugfix: dependencies specified for a module were ignored while + building dynamic modules. + + *) Bugfix: when using HTTP/2 and the "limit_req" or "auth_request" + directives client request body might be corrupted; the bug had + appeared in 1.11.0. + + *) Bugfix: a segmentation fault might occur in a worker process when + using HTTP/2; the bug had appeared in 1.11.3. + + *) Bugfix: in the ngx_http_mp4_module. + Thanks to Congcong Hu. + + *) Bugfix: in the ngx_http_perl_module. + + Changes with nginx 1.11.6 15 Nov 2016 *) Change: format of the $ssl_client_s_dn and $ssl_client_i_dn variables diff --git a/CHANGES.ru b/CHANGES.ru index 3b66b94..695547b 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,31 @@ +Изменения в nginx 1.11.7 13.12.2016 + + *) Изменение: переменная $ssl_client_verify теперь в случае ошибки + проверки клиентского сертификата содержит строку с описанием ошибки, + например, "FAILED:certificate has expired". + + *) Добавление: переменные $ssl_ciphers, $ssl_curves, + $ssl_client_v_start, $ssl_client_v_end и $ssl_client_v_remain. + + *) Добавление: параметр volatile директивы map. + + *) Исправление: при сборке динамических модулей не учитывались заданные + для модуля зависимости. + + *) Исправление: при использовании HTTP/2 и директив limit_req или + auth_request тело запроса могло быть повреждено; ошибка появилась в + 1.11.0. + + *) Исправление: при использовании HTTP/2 в рабочем процессе мог + произойти segmentation fault; ошибка появилась в 1.11.3. + + *) Исправление: в модуле ngx_http_mp4_module. + Спасибо Congcong Hu. + + *) Исправление: в модуле ngx_http_perl_module. + + Изменения в nginx 1.11.6 15.11.2016 *) Изменение: формат переменных $ssl_client_s_dn и $ssl_client_i_dn diff --git a/auto/lib/perl/conf b/auto/lib/perl/conf index d891d82..e16a1bc 100644 --- a/auto/lib/perl/conf +++ b/auto/lib/perl/conf @@ -12,9 +12,9 @@ NGX_PERL_VER=`$NGX_PERL -v 2>&1 | grep '^This is perl' 2>&1 \ if test -n "$NGX_PERL_VER"; then echo " + perl version: $NGX_PERL_VER" - if [ "`$NGX_PERL -e 'use 5.006001; print "OK"'`" != "OK" ]; then + if [ "`$NGX_PERL -e 'use 5.008006; print "OK"'`" != "OK" ]; then echo - echo "$0: error: perl 5.6.1 or higher is required" + echo "$0: error: perl 5.8.6 or higher is required" echo exit 1; @@ -76,7 +76,7 @@ if test -n "$NGX_PERL_VER"; then else echo - echo "$0: error: perl 5.6.1 or higher is required" + echo "$0: error: perl 5.8.6 or higher is required" echo exit 1; diff --git a/auto/make b/auto/make index 84d2668..7ddd100 100644 --- a/auto/make +++ b/auto/make @@ -156,7 +156,7 @@ fi ngx_all_srcs="$ngx_all_srcs $MISC_SRCS" -if test -n "$NGX_ADDON_SRCS"; then +if test -n "$NGX_ADDON_SRCS$DYNAMIC_MODULES"; then cat << END >> $NGX_MAKEFILE @@ -499,17 +499,6 @@ else ngx_perl_cc="$ngx_perl_cc \$(ALL_INCS)" fi -ngx_obj_deps="\$(CORE_DEPS)" -if [ $HTTP != NO ]; then - ngx_obj_deps="$ngx_obj_deps \$(HTTP_DEPS)" -fi -if [ $MAIL != NO ]; then - ngx_obj_deps="$ngx_obj_deps \$(MAIL_DEPS)" -fi -if [ $STREAM != NO ]; then - ngx_obj_deps="$ngx_obj_deps \$(STREAM_DEPS)" -fi - for ngx_module in $DYNAMIC_MODULES do eval ngx_module_srcs="\$${ngx_module}_SRCS" @@ -665,7 +654,7 @@ END cat << END >> $NGX_MAKEFILE -$ngx_obj: $ngx_obj_deps$ngx_cont$ngx_src +$ngx_obj: \$(ADDON_DEPS)$ngx_cont$ngx_src $ngx_perl_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX END @@ -673,7 +662,7 @@ END cat << END >> $NGX_MAKEFILE -$ngx_obj: $ngx_obj_deps$ngx_cont$ngx_src +$ngx_obj: \$(ADDON_DEPS)$ngx_cont$ngx_src $ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX END diff --git a/auto/module b/auto/module index 3b00a07..a2b578d 100644 --- a/auto/module +++ b/auto/module @@ -35,6 +35,10 @@ if [ "$ngx_module_link" = DYNAMIC ]; then CORE_INCS="$CORE_INCS $ngx_module_incs" fi + if test -n "$ngx_module_deps"; then + NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_module_deps" + fi + libs= for lib in $ngx_module_libs do diff --git a/auto/modules b/auto/modules index 89377bf..c664fe3 100644 --- a/auto/modules +++ b/auto/modules @@ -1252,7 +1252,7 @@ if [ $MAIL != NO ]; then elif [ $MAIL = DYNAMIC ]; then ngx_module_name=$MAIL_MODULES ngx_module_incs= - ngx_module_deps=$MAIL_DEPS + ngx_module_deps= ngx_module_srcs=$MAIL_SRCS ngx_module_libs= ngx_module_link=DYNAMIC @@ -1272,7 +1272,7 @@ if [ $STREAM != NO ]; then elif [ $STREAM = DYNAMIC ]; then ngx_module_name=$STREAM_MODULES ngx_module_incs= - ngx_module_deps=$STREAM_DEPS + ngx_module_deps= ngx_module_srcs=$STREAM_SRCS ngx_module_libs= ngx_module_link=DYNAMIC diff --git a/src/core/nginx.c b/src/core/nginx.c index 60f8fe7..c5f09a5 100644 --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -12,6 +12,7 @@ static void ngx_show_version_info(void); static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle); +static void ngx_cleanup_environment(void *data); static ngx_int_t ngx_get_options(int argc, char *const *argv); static ngx_int_t ngx_process_options(ngx_cycle_t *cycle); static ngx_int_t ngx_save_argv(ngx_cycle_t *cycle, int argc, char *const *argv); @@ -495,10 +496,11 @@ ngx_add_inherited_sockets(ngx_cycle_t *cycle) char ** ngx_set_environment(ngx_cycle_t *cycle, ngx_uint_t *last) { - char **p, **env; - ngx_str_t *var; - ngx_uint_t i, n; - ngx_core_conf_t *ccf; + char **p, **env; + ngx_str_t *var; + ngx_uint_t i, n; + ngx_core_conf_t *ccf; + ngx_pool_cleanup_t *cln; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); @@ -550,14 +552,25 @@ tz_found: if (last) { env = ngx_alloc((*last + n + 1) * sizeof(char *), cycle->log); + if (env == NULL) { + return NULL; + } + *last = n; } else { - env = ngx_palloc(cycle->pool, (n + 1) * sizeof(char *)); - } + cln = ngx_pool_cleanup_add(cycle->pool, 0); + if (cln == NULL) { + return NULL; + } - if (env == NULL) { - return NULL; + env = ngx_alloc((n + 1) * sizeof(char *), cycle->log); + if (env == NULL) { + return NULL; + } + + cln->handler = ngx_cleanup_environment; + cln->data = env; } n = 0; @@ -591,6 +604,25 @@ tz_found: } +static void +ngx_cleanup_environment(void *data) +{ + char **env = data; + + if (environ == env) { + + /* + * if the environment is still used, as it happens on exit, + * the only option is to leak it + */ + + return; + } + + ngx_free(env); +} + + ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv) { diff --git a/src/core/nginx.h b/src/core/nginx.h index a75ef04..7733313 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1011006 -#define NGINX_VERSION "1.11.6" +#define nginx_version 1011007 +#define NGINX_VERSION "1.11.7" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c index a57991c..5e95628 100644 --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -37,7 +37,7 @@ ngx_cycle_t * ngx_init_cycle(ngx_cycle_t *old_cycle) { void *rv; - char **senv, **env; + char **senv; ngx_uint_t i, n; ngx_log_t *log; ngx_time_t *tp; @@ -750,20 +750,9 @@ old_shm_zone_done: if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) { - /* - * perl_destruct() frees environ, if it is not the same as it was at - * perl_construct() time, therefore we save the previous cycle - * environment before ngx_conf_parse() where it will be changed. - */ - - env = environ; - environ = senv; - ngx_destroy_pool(old_cycle->pool); cycle->old_cycle = NULL; - environ = env; - return cycle; } diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c index f784578..7f5dc78 100644 --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -512,7 +512,7 @@ ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx) size = ngx_buf_size(src); size = ngx_min(size, dst->end - dst->pos); - sendfile = ctx->sendfile & !ctx->directio; + sendfile = ctx->sendfile && !ctx->directio; #if (NGX_SENDFILE_LIMIT) diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c index 56e7765..66faecc 100644 --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -41,6 +41,19 @@ #endif +#define ngx_slab_slots(pool) \ + (ngx_slab_page_t *) ((u_char *) (pool) + sizeof(ngx_slab_pool_t)) + +#define ngx_slab_page_type(page) ((page)->prev & NGX_SLAB_PAGE_MASK) + +#define ngx_slab_page_prev(page) \ + (ngx_slab_page_t *) ((page)->prev & ~NGX_SLAB_PAGE_MASK) + +#define ngx_slab_page_addr(pool, page) \ + ((((page) - (pool)->pages) << ngx_pagesize_shift) \ + + (uintptr_t) (pool)->start) + + #if (NGX_DEBUG_MALLOC) #define ngx_slab_junk(p, size) ngx_memset(p, 0xA5, size) @@ -76,7 +89,7 @@ ngx_slab_init(ngx_slab_pool_t *pool) size_t size; ngx_int_t m; ngx_uint_t i, n, pages; - ngx_slab_page_t *slots; + ngx_slab_page_t *slots, *page; /* STUB */ if (ngx_slab_max_size == 0) { @@ -90,15 +103,17 @@ ngx_slab_init(ngx_slab_pool_t *pool) pool->min_size = 1 << pool->min_shift; - p = (u_char *) pool + sizeof(ngx_slab_pool_t); + slots = ngx_slab_slots(pool); + + p = (u_char *) slots; size = pool->end - p; ngx_slab_junk(p, size); - slots = (ngx_slab_page_t *) p; n = ngx_pagesize_shift - pool->min_shift; for (i = 0; i < n; i++) { + /* only "next" is used in list head */ slots[i].slab = 0; slots[i].next = &slots[i]; slots[i].prev = 0; @@ -106,30 +121,40 @@ ngx_slab_init(ngx_slab_pool_t *pool) p += n * sizeof(ngx_slab_page_t); + pool->stats = (ngx_slab_stat_t *) p; + ngx_memzero(pool->stats, n * sizeof(ngx_slab_stat_t)); + + p += n * sizeof(ngx_slab_stat_t); + + size -= n * (sizeof(ngx_slab_page_t) + sizeof(ngx_slab_stat_t)); + pages = (ngx_uint_t) (size / (ngx_pagesize + sizeof(ngx_slab_page_t))); - ngx_memzero(p, pages * sizeof(ngx_slab_page_t)); - pool->pages = (ngx_slab_page_t *) p; + ngx_memzero(pool->pages, pages * sizeof(ngx_slab_page_t)); + page = pool->pages; + + /* only "next" is used in list head */ + pool->free.slab = 0; + pool->free.next = page; pool->free.prev = 0; - pool->free.next = (ngx_slab_page_t *) p; - pool->pages->slab = pages; - pool->pages->next = &pool->free; - pool->pages->prev = (uintptr_t) &pool->free; + page->slab = pages; + page->next = &pool->free; + page->prev = (uintptr_t) &pool->free; - pool->start = (u_char *) - ngx_align_ptr((uintptr_t) p + pages * sizeof(ngx_slab_page_t), - ngx_pagesize); + pool->start = ngx_align_ptr(p + pages * sizeof(ngx_slab_page_t), + ngx_pagesize); m = pages - (pool->end - pool->start) / ngx_pagesize; if (m > 0) { pages -= m; - pool->pages->slab = pages; + page->slab = pages; } pool->last = pool->pages + pages; + pool->pfree = pages; pool->log_nomem = 1; pool->log_ctx = &pool->zero; @@ -168,8 +193,7 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) page = ngx_slab_alloc_pages(pool, (size >> ngx_pagesize_shift) + ((size % ngx_pagesize) ? 1 : 0)); if (page) { - p = (page - pool->pages) << ngx_pagesize_shift; - p += (uintptr_t) pool->start; + p = ngx_slab_page_addr(pool, page); } else { p = 0; @@ -184,166 +208,140 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) slot = shift - pool->min_shift; } else { - size = pool->min_size; shift = pool->min_shift; slot = 0; } + pool->stats[slot].reqs++; + ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab alloc: %uz slot: %ui", size, slot); - slots = (ngx_slab_page_t *) ((u_char *) pool + sizeof(ngx_slab_pool_t)); + slots = ngx_slab_slots(pool); page = slots[slot].next; if (page->next != page) { if (shift < ngx_slab_exact_shift) { - do { - p = (page - pool->pages) << ngx_pagesize_shift; - bitmap = (uintptr_t *) (pool->start + p); + bitmap = (uintptr_t *) ngx_slab_page_addr(pool, page); - map = (1 << (ngx_pagesize_shift - shift)) - / (sizeof(uintptr_t) * 8); + map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8); - for (n = 0; n < map; n++) { + for (n = 0; n < map; n++) { - if (bitmap[n] != NGX_SLAB_BUSY) { + if (bitmap[n] != NGX_SLAB_BUSY) { - for (m = 1, i = 0; m; m <<= 1, i++) { - if ((bitmap[n] & m)) { - continue; - } - - bitmap[n] |= m; - - i = ((n * sizeof(uintptr_t) * 8) << shift) - + (i << shift); - - if (bitmap[n] == NGX_SLAB_BUSY) { - for (n = n + 1; n < map; n++) { - if (bitmap[n] != NGX_SLAB_BUSY) { - p = (uintptr_t) bitmap + i; - - goto done; - } - } - - prev = (ngx_slab_page_t *) - (page->prev & ~NGX_SLAB_PAGE_MASK); - prev->next = page->next; - page->next->prev = page->prev; - - page->next = NULL; - page->prev = NGX_SLAB_SMALL; - } - - p = (uintptr_t) bitmap + i; - - goto done; + for (m = 1, i = 0; m; m <<= 1, i++) { + if (bitmap[n] & m) { + continue; } + + bitmap[n] |= m; + + i = (n * sizeof(uintptr_t) * 8 + i) << shift; + + p = (uintptr_t) bitmap + i; + + pool->stats[slot].used++; + + if (bitmap[n] == NGX_SLAB_BUSY) { + for (n = n + 1; n < map; n++) { + if (bitmap[n] != NGX_SLAB_BUSY) { + goto done; + } + } + + prev = ngx_slab_page_prev(page); + prev->next = page->next; + page->next->prev = page->prev; + + page->next = NULL; + page->prev = NGX_SLAB_SMALL; + } + + goto done; } } - - page = page->next; - - } while (page); + } } else if (shift == ngx_slab_exact_shift) { - do { - if (page->slab != NGX_SLAB_BUSY) { - - for (m = 1, i = 0; m; m <<= 1, i++) { - if ((page->slab & m)) { - continue; - } - - page->slab |= m; - - if (page->slab == NGX_SLAB_BUSY) { - prev = (ngx_slab_page_t *) - (page->prev & ~NGX_SLAB_PAGE_MASK); - prev->next = page->next; - page->next->prev = page->prev; - - page->next = NULL; - page->prev = NGX_SLAB_EXACT; - } - - p = (page - pool->pages) << ngx_pagesize_shift; - p += i << shift; - p += (uintptr_t) pool->start; - - goto done; - } + for (m = 1, i = 0; m; m <<= 1, i++) { + if (page->slab & m) { + continue; } - page = page->next; + page->slab |= m; - } while (page); + if (page->slab == NGX_SLAB_BUSY) { + prev = ngx_slab_page_prev(page); + prev->next = page->next; + page->next->prev = page->prev; + + page->next = NULL; + page->prev = NGX_SLAB_EXACT; + } + + p = ngx_slab_page_addr(pool, page) + (i << shift); + + pool->stats[slot].used++; + + goto done; + } } else { /* shift > ngx_slab_exact_shift */ - n = ngx_pagesize_shift - (page->slab & NGX_SLAB_SHIFT_MASK); - n = 1 << n; - n = ((uintptr_t) 1 << n) - 1; - mask = n << NGX_SLAB_MAP_SHIFT; + mask = ((uintptr_t) 1 << (ngx_pagesize >> shift)) - 1; + mask <<= NGX_SLAB_MAP_SHIFT; - do { - if ((page->slab & NGX_SLAB_MAP_MASK) != mask) { - - for (m = (uintptr_t) 1 << NGX_SLAB_MAP_SHIFT, i = 0; - m & mask; - m <<= 1, i++) - { - if ((page->slab & m)) { - continue; - } - - page->slab |= m; - - if ((page->slab & NGX_SLAB_MAP_MASK) == mask) { - prev = (ngx_slab_page_t *) - (page->prev & ~NGX_SLAB_PAGE_MASK); - prev->next = page->next; - page->next->prev = page->prev; - - page->next = NULL; - page->prev = NGX_SLAB_BIG; - } - - p = (page - pool->pages) << ngx_pagesize_shift; - p += i << shift; - p += (uintptr_t) pool->start; - - goto done; - } + for (m = (uintptr_t) 1 << NGX_SLAB_MAP_SHIFT, i = 0; + m & mask; + m <<= 1, i++) + { + if (page->slab & m) { + continue; } - page = page->next; + page->slab |= m; - } while (page); + if ((page->slab & NGX_SLAB_MAP_MASK) == mask) { + prev = ngx_slab_page_prev(page); + prev->next = page->next; + page->next->prev = page->prev; + + page->next = NULL; + page->prev = NGX_SLAB_BIG; + } + + p = ngx_slab_page_addr(pool, page) + (i << shift); + + pool->stats[slot].used++; + + goto done; + } } + + ngx_slab_error(pool, NGX_LOG_ALERT, "ngx_slab_alloc(): page is busy"); + ngx_debug_point(); } page = ngx_slab_alloc_pages(pool, 1); if (page) { if (shift < ngx_slab_exact_shift) { - p = (page - pool->pages) << ngx_pagesize_shift; - bitmap = (uintptr_t *) (pool->start + p); + bitmap = (uintptr_t *) ngx_slab_page_addr(pool, page); - s = 1 << shift; - n = (1 << (ngx_pagesize_shift - shift)) / 8 / s; + n = (ngx_pagesize >> shift) / ((1 << shift) * 8); if (n == 0) { n = 1; } - bitmap[0] = (2 << n) - 1; + /* "n" elements for bitmap, plus one requested */ + bitmap[0] = ((uintptr_t) 2 << n) - 1; - map = (1 << (ngx_pagesize_shift - shift)) / (sizeof(uintptr_t) * 8); + map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8); for (i = 1; i < map; i++) { bitmap[i] = 0; @@ -355,8 +353,11 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) slots[slot].next = page; - p = ((page - pool->pages) << ngx_pagesize_shift) + s * n; - p += (uintptr_t) pool->start; + pool->stats[slot].total += (ngx_pagesize >> shift) - n; + + p = ngx_slab_page_addr(pool, page) + (n << shift); + + pool->stats[slot].used++; goto done; @@ -368,8 +369,11 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) slots[slot].next = page; - p = (page - pool->pages) << ngx_pagesize_shift; - p += (uintptr_t) pool->start; + pool->stats[slot].total += sizeof(uintptr_t) * 8; + + p = ngx_slab_page_addr(pool, page); + + pool->stats[slot].used++; goto done; @@ -381,8 +385,11 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) slots[slot].next = page; - p = (page - pool->pages) << ngx_pagesize_shift; - p += (uintptr_t) pool->start; + pool->stats[slot].total += ngx_pagesize >> shift; + + p = ngx_slab_page_addr(pool, page); + + pool->stats[slot].used++; goto done; } @@ -390,6 +397,8 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) p = 0; + pool->stats[slot].fails++; + done: ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, @@ -444,7 +453,7 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) { size_t size; uintptr_t slab, m, *bitmap; - ngx_uint_t n, type, slot, shift, map; + ngx_uint_t i, n, type, slot, shift, map; ngx_slab_page_t *slots, *page; ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab free: %p", p); @@ -457,7 +466,7 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) n = ((u_char *) p - pool->start) >> ngx_pagesize_shift; page = &pool->pages[n]; slab = page->slab; - type = page->prev & NGX_SLAB_PAGE_MASK; + type = ngx_slab_page_type(page); switch (type) { @@ -471,17 +480,16 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) } n = ((uintptr_t) p & (ngx_pagesize - 1)) >> shift; - m = (uintptr_t) 1 << (n & (sizeof(uintptr_t) * 8 - 1)); - n /= (sizeof(uintptr_t) * 8); + m = (uintptr_t) 1 << (n % (sizeof(uintptr_t) * 8)); + n /= sizeof(uintptr_t) * 8; bitmap = (uintptr_t *) ((uintptr_t) p & ~((uintptr_t) ngx_pagesize - 1)); if (bitmap[n] & m) { + slot = shift - pool->min_shift; if (page->next == NULL) { - slots = (ngx_slab_page_t *) - ((u_char *) pool + sizeof(ngx_slab_pool_t)); - slot = shift - pool->min_shift; + slots = ngx_slab_slots(pool); page->next = slots[slot].next; slots[slot].next = page; @@ -492,7 +500,7 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) bitmap[n] &= ~m; - n = (1 << (ngx_pagesize_shift - shift)) / 8 / (1 << shift); + n = (ngx_pagesize >> shift) / ((1 << shift) * 8); if (n == 0) { n = 1; @@ -502,16 +510,18 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) goto done; } - map = (1 << (ngx_pagesize_shift - shift)) / (sizeof(uintptr_t) * 8); + map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8); - for (n = 1; n < map; n++) { - if (bitmap[n]) { + for (i = 1; i < map; i++) { + if (bitmap[i]) { goto done; } } ngx_slab_free_pages(pool, page, 1); + pool->stats[slot].total -= (ngx_pagesize >> shift) - n; + goto done; } @@ -528,10 +538,10 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) } if (slab & m) { + slot = ngx_slab_exact_shift - pool->min_shift; + if (slab == NGX_SLAB_BUSY) { - slots = (ngx_slab_page_t *) - ((u_char *) pool + sizeof(ngx_slab_pool_t)); - slot = ngx_slab_exact_shift - pool->min_shift; + slots = ngx_slab_slots(pool); page->next = slots[slot].next; slots[slot].next = page; @@ -548,6 +558,8 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) ngx_slab_free_pages(pool, page, 1); + pool->stats[slot].total -= sizeof(uintptr_t) * 8; + goto done; } @@ -566,11 +578,10 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) + NGX_SLAB_MAP_SHIFT); if (slab & m) { + slot = shift - pool->min_shift; if (page->next == NULL) { - slots = (ngx_slab_page_t *) - ((u_char *) pool + sizeof(ngx_slab_pool_t)); - slot = shift - pool->min_shift; + slots = ngx_slab_slots(pool); page->next = slots[slot].next; slots[slot].next = page; @@ -587,6 +598,8 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) ngx_slab_free_pages(pool, page, 1); + pool->stats[slot].total -= ngx_pagesize >> shift; + goto done; } @@ -598,7 +611,7 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) goto wrong_chunk; } - if (slab == NGX_SLAB_PAGE_FREE) { + if (!(slab & NGX_SLAB_PAGE_START)) { ngx_slab_error(pool, NGX_LOG_ALERT, "ngx_slab_free(): page is already free"); goto fail; @@ -626,6 +639,8 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) done: + pool->stats[slot].used--; + ngx_slab_junk(p, size); return; @@ -678,6 +693,8 @@ ngx_slab_alloc_pages(ngx_slab_pool_t *pool, ngx_uint_t pages) page->next = NULL; page->prev = NGX_SLAB_PAGE; + pool->pfree -= pages; + if (--pages == 0) { return page; } @@ -706,9 +723,10 @@ static void ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page, ngx_uint_t pages) { - ngx_uint_t type; ngx_slab_page_t *prev, *join; + pool->pfree += pages; + page->slab = pages--; if (pages) { @@ -716,7 +734,7 @@ ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page, } if (page->next) { - prev = (ngx_slab_page_t *) (page->prev & ~NGX_SLAB_PAGE_MASK); + prev = ngx_slab_page_prev(page); prev->next = page->next; page->next->prev = page->prev; } @@ -724,15 +742,14 @@ ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page, join = page + page->slab; if (join < pool->last) { - type = join->prev & NGX_SLAB_PAGE_MASK; - if (type == NGX_SLAB_PAGE) { + if (ngx_slab_page_type(join) == NGX_SLAB_PAGE) { if (join->next != NULL) { pages += join->slab; page->slab += join->slab; - prev = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK); + prev = ngx_slab_page_prev(join); prev->next = join->next; join->next->prev = join->prev; @@ -745,19 +762,18 @@ ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page, if (page > pool->pages) { join = page - 1; - type = join->prev & NGX_SLAB_PAGE_MASK; - if (type == NGX_SLAB_PAGE) { + if (ngx_slab_page_type(join) == NGX_SLAB_PAGE) { if (join->slab == NGX_SLAB_PAGE_FREE) { - join = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK); + join = ngx_slab_page_prev(join); } if (join->next != NULL) { pages += join->slab; join->slab += page->slab; - prev = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK); + prev = ngx_slab_page_prev(join); prev->next = join->next; join->next->prev = join->prev; diff --git a/src/core/ngx_slab.h b/src/core/ngx_slab.h index 2922a80..eff893c 100644 --- a/src/core/ngx_slab.h +++ b/src/core/ngx_slab.h @@ -22,6 +22,15 @@ struct ngx_slab_page_s { }; +typedef struct { + ngx_uint_t total; + ngx_uint_t used; + + ngx_uint_t reqs; + ngx_uint_t fails; +} ngx_slab_stat_t; + + typedef struct { ngx_shmtx_sh_t lock; @@ -32,6 +41,9 @@ typedef struct { ngx_slab_page_t *last; ngx_slab_page_t free; + ngx_slab_stat_t *stats; + ngx_uint_t pfree; + u_char *start; u_char *end; diff --git a/src/event/modules/ngx_devpoll_module.c b/src/event/modules/ngx_devpoll_module.c index f985fbd..39e480e 100644 --- a/src/event/modules/ngx_devpoll_module.c +++ b/src/event/modules/ngx_devpoll_module.c @@ -481,13 +481,11 @@ ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, fd, event_list[i].events, revents); } - if ((revents & (POLLERR|POLLHUP|POLLNVAL)) - && (revents & (POLLIN|POLLOUT)) == 0) - { + if (revents & (POLLERR|POLLHUP|POLLNVAL)) { + /* - * if the error events were returned without POLLIN or POLLOUT, - * then add these flags to handle the events at least in one - * active handler + * if the error events were returned, add POLLIN and POLLOUT + * to handle the events at least in one active handler */ revents |= POLLIN|POLLOUT; diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c index c267fd6..760c69b 100644 --- a/src/event/modules/ngx_epoll_module.c +++ b/src/event/modules/ngx_epoll_module.c @@ -863,6 +863,13 @@ ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "epoll_wait() error on fd:%d ev:%04XD", c->fd, revents); + + /* + * if the error events were returned, add EPOLLIN and EPOLLOUT + * to handle the events at least in one active handler + */ + + revents |= EPOLLIN|EPOLLOUT; } #if 0 @@ -873,18 +880,6 @@ ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) } #endif - if ((revents & (EPOLLERR|EPOLLHUP)) - && (revents & (EPOLLIN|EPOLLOUT)) == 0) - { - /* - * if the error events were returned without EPOLLIN or EPOLLOUT, - * then add these flags to handle the events at least in one - * active handler - */ - - revents |= EPOLLIN|EPOLLOUT; - } - if ((revents & EPOLLIN) && rev->active) { #if (NGX_HAVE_EPOLLRDHUP) diff --git a/src/event/modules/ngx_eventport_module.c b/src/event/modules/ngx_eventport_module.c index dafa27f..0413599 100644 --- a/src/event/modules/ngx_eventport_module.c +++ b/src/event/modules/ngx_eventport_module.c @@ -540,13 +540,11 @@ ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, (int) event_list[i].portev_object, revents); } - if ((revents & (POLLERR|POLLHUP|POLLNVAL)) - && (revents & (POLLIN|POLLOUT)) == 0) - { + if (revents & (POLLERR|POLLHUP|POLLNVAL)) { + /* - * if the error events were returned without POLLIN or POLLOUT, - * then add these flags to handle the events at least in one - * active handler + * if the error events were returned, add POLLIN and POLLOUT + * to handle the events at least in one active handler */ revents |= POLLIN|POLLOUT; diff --git a/src/event/modules/ngx_poll_module.c b/src/event/modules/ngx_poll_module.c index 4370950..a2a7079 100644 --- a/src/event/modules/ngx_poll_module.c +++ b/src/event/modules/ngx_poll_module.c @@ -353,13 +353,11 @@ ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) continue; } - if ((revents & (POLLERR|POLLHUP|POLLNVAL)) - && (revents & (POLLIN|POLLOUT)) == 0) - { + if (revents & (POLLERR|POLLHUP|POLLNVAL)) { + /* - * if the error events were returned without POLLIN or POLLOUT, - * then add these flags to handle the events at least in one - * active handler + * if the error events were returned, add POLLIN and POLLOUT + * to handle the events at least in one active handler */ revents |= POLLIN|POLLOUT; diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 5c7734d..1b39f33 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -59,6 +59,12 @@ static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, static ngx_int_t ngx_ssl_check_name(ngx_str_t *name, ASN1_STRING *str); #endif +static time_t ngx_ssl_parse_time( +#if OPENSSL_VERSION_NUMBER > 0x10100000L + const +#endif + ASN1_TIME *asn1time); + static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void ngx_openssl_exit(ngx_cycle_t *cycle); @@ -106,6 +112,7 @@ int ngx_ssl_session_cache_index; int ngx_ssl_session_ticket_keys_index; int ngx_ssl_certificate_index; int ngx_ssl_next_certificate_index; +int ngx_ssl_certificate_name_index; int ngx_ssl_stapling_index; @@ -193,6 +200,14 @@ ngx_ssl_init(ngx_log_t *log) return NGX_ERROR; } + ngx_ssl_certificate_name_index = X509_get_ex_new_index(0, NULL, NULL, NULL, + NULL); + + if (ngx_ssl_certificate_name_index == -1) { + ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed"); + return NGX_ERROR; + } + ngx_ssl_stapling_index = X509_get_ex_new_index(0, NULL, NULL, NULL, NULL); if (ngx_ssl_stapling_index == -1) { @@ -385,6 +400,15 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, return NGX_ERROR; } + if (X509_set_ex_data(x509, ngx_ssl_certificate_name_index, cert->data) + == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed"); + X509_free(x509); + BIO_free(bio); + return NGX_ERROR; + } + if (X509_set_ex_data(x509, ngx_ssl_next_certificate_index, SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index)) == 0) @@ -3269,6 +3293,158 @@ ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } +ngx_int_t +ngx_ssl_get_ciphers(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ +#ifdef SSL_CTRL_GET_RAW_CIPHERLIST + + int n, i, bytes; + size_t len; + u_char *ciphers, *p; + const SSL_CIPHER *cipher; + + bytes = SSL_get0_raw_cipherlist(c->ssl->connection, NULL); + n = SSL_get0_raw_cipherlist(c->ssl->connection, &ciphers); + + if (n <= 0) { + s->len = 0; + return NGX_OK; + } + + len = 0; + n /= bytes; + + for (i = 0; i < n; i++) { + cipher = SSL_CIPHER_find(c->ssl->connection, ciphers + i * bytes); + + if (cipher) { + len += ngx_strlen(SSL_CIPHER_get_name(cipher)); + + } else { + len += sizeof("0x") - 1 + bytes * (sizeof("00") - 1); + } + + len += sizeof(":") - 1; + } + + s->data = ngx_pnalloc(pool, len); + if (s->data == NULL) { + return NGX_ERROR; + } + + p = s->data; + + for (i = 0; i < n; i++) { + cipher = SSL_CIPHER_find(c->ssl->connection, ciphers + i * bytes); + + if (cipher) { + p = ngx_sprintf(p, "%s", SSL_CIPHER_get_name(cipher)); + + } else { + p = ngx_sprintf(p, "0x"); + p = ngx_hex_dump(p, ciphers + i * bytes, bytes); + } + + *p++ = ':'; + } + + p--; + + s->len = p - s->data; + +#else + + u_char buf[4096]; + + if (SSL_get_shared_ciphers(c->ssl->connection, (char *) buf, 4096) + == NULL) + { + s->len = 0; + return NGX_OK; + } + + s->len = ngx_strlen(buf); + s->data = ngx_pnalloc(pool, s->len); + if (s->data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(s->data, buf, s->len); + +#endif + + return NGX_OK; +} + + +ngx_int_t +ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ +#ifdef SSL_CTRL_GET_CURVES + + int *curves, n, i, nid; + u_char *p; + size_t len; + + n = SSL_get1_curves(c->ssl->connection, NULL); + + if (n <= 0) { + s->len = 0; + return NGX_OK; + } + + curves = ngx_palloc(pool, n * sizeof(int)); + + n = SSL_get1_curves(c->ssl->connection, curves); + len = 0; + + for (i = 0; i < n; i++) { + nid = curves[i]; + + if (nid & TLSEXT_nid_unknown) { + len += sizeof("0x0000") - 1; + + } else { + len += ngx_strlen(OBJ_nid2sn(nid)); + } + + len += sizeof(":") - 1; + } + + s->data = ngx_pnalloc(pool, len); + if (s->data == NULL) { + return NGX_ERROR; + } + + p = s->data; + + for (i = 0; i < n; i++) { + nid = curves[i]; + + if (nid & TLSEXT_nid_unknown) { + p = ngx_sprintf(p, "0x%04xd", nid & 0xffff); + + } else { + p = ngx_sprintf(p, "%s", OBJ_nid2sn(nid)); + } + + *p++ = ':'; + } + + p--; + + s->len = p - s->data; + +#else + + s->len = 0; + +#endif + + return NGX_OK; +} + + ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { @@ -3699,28 +3875,210 @@ ngx_ssl_get_fingerprint(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) ngx_int_t ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { - X509 *cert; - - if (SSL_get_verify_result(c->ssl->connection) != X509_V_OK) { - ngx_str_set(s, "FAILED"); - return NGX_OK; - } + X509 *cert; + long rc; + const char *str; cert = SSL_get_peer_certificate(c->ssl->connection); - - if (cert) { - ngx_str_set(s, "SUCCESS"); - - } else { + if (cert == NULL) { ngx_str_set(s, "NONE"); + return NGX_OK; } X509_free(cert); + rc = SSL_get_verify_result(c->ssl->connection); + + if (rc == X509_V_OK) { + ngx_str_set(s, "SUCCESS"); + return NGX_OK; + } + + str = X509_verify_cert_error_string(rc); + + s->data = ngx_pnalloc(pool, sizeof("FAILED:") - 1 + ngx_strlen(str)); + if (s->data == NULL) { + return NGX_ERROR; + } + + s->len = ngx_sprintf(s->data, "FAILED:%s", str) - s->data; + return NGX_OK; } +ngx_int_t +ngx_ssl_get_client_v_start(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + BIO *bio; + X509 *cert; + size_t len; + + s->len = 0; + + cert = SSL_get_peer_certificate(c->ssl->connection); + if (cert == NULL) { + return NGX_OK; + } + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) { + X509_free(cert); + return NGX_ERROR; + } + +#if OPENSSL_VERSION_NUMBER > 0x10100000L + ASN1_TIME_print(bio, X509_get0_notBefore(cert)); +#else + ASN1_TIME_print(bio, X509_get_notBefore(cert)); +#endif + + len = BIO_pending(bio); + + s->len = len; + s->data = ngx_pnalloc(pool, len); + if (s->data == NULL) { + BIO_free(bio); + X509_free(cert); + return NGX_ERROR; + } + + BIO_read(bio, s->data, len); + BIO_free(bio); + X509_free(cert); + + return NGX_OK; +} + + +ngx_int_t +ngx_ssl_get_client_v_end(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + BIO *bio; + X509 *cert; + size_t len; + + s->len = 0; + + cert = SSL_get_peer_certificate(c->ssl->connection); + if (cert == NULL) { + return NGX_OK; + } + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) { + X509_free(cert); + return NGX_ERROR; + } + +#if OPENSSL_VERSION_NUMBER > 0x10100000L + ASN1_TIME_print(bio, X509_get0_notAfter(cert)); +#else + ASN1_TIME_print(bio, X509_get_notAfter(cert)); +#endif + + len = BIO_pending(bio); + + s->len = len; + s->data = ngx_pnalloc(pool, len); + if (s->data == NULL) { + BIO_free(bio); + X509_free(cert); + return NGX_ERROR; + } + + BIO_read(bio, s->data, len); + BIO_free(bio); + X509_free(cert); + + return NGX_OK; +} + + +ngx_int_t +ngx_ssl_get_client_v_remain(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + X509 *cert; + time_t now, end; + + s->len = 0; + + cert = SSL_get_peer_certificate(c->ssl->connection); + if (cert == NULL) { + return NGX_OK; + } + +#if OPENSSL_VERSION_NUMBER > 0x10100000L + end = ngx_ssl_parse_time(X509_get0_notAfter(cert)); +#else + end = ngx_ssl_parse_time(X509_get_notAfter(cert)); +#endif + + if (end == (time_t) NGX_ERROR) { + X509_free(cert); + return NGX_OK; + } + + now = ngx_time(); + + if (end < now + 86400) { + ngx_str_set(s, "0"); + X509_free(cert); + return NGX_OK; + } + + s->data = ngx_pnalloc(pool, NGX_TIME_T_LEN); + if (s->data == NULL) { + X509_free(cert); + return NGX_ERROR; + } + + s->len = ngx_sprintf(s->data, "%T", (end - now) / 86400) - s->data; + + X509_free(cert); + + return NGX_OK; +} + + +static time_t +ngx_ssl_parse_time( +#if OPENSSL_VERSION_NUMBER > 0x10100000L + const +#endif + ASN1_TIME *asn1time) +{ + BIO *bio; + u_char *value; + size_t len; + time_t time; + + /* + * OpenSSL doesn't provide a way to convert ASN1_TIME + * into time_t. To do this, we use ASN1_TIME_print(), + * which uses the "MMM DD HH:MM:SS YYYY [GMT]" format (e.g., + * "Feb 3 00:55:52 2015 GMT"), and parse the result. + */ + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) { + return NGX_ERROR; + } + + /* fake weekday prepended to match C asctime() format */ + + BIO_write(bio, "Tue ", sizeof("Tue ") - 1); + ASN1_TIME_print(bio, asn1time); + len = BIO_get_mem_data(bio, &value); + + time = ngx_parse_http_time(value, len); + + BIO_free(bio); + + return time; +} + + static void * ngx_openssl_create_conf(ngx_cycle_t *cycle) { diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index d233c02..c022307 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -191,6 +191,10 @@ ngx_int_t ngx_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_ciphers(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); +ngx_int_t ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_session_reused(ngx_connection_t *c, ngx_pool_t *pool, @@ -215,6 +219,12 @@ ngx_int_t ngx_ssl_get_fingerprint(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_client_v_start(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); +ngx_int_t ngx_ssl_get_client_v_end(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); +ngx_int_t ngx_ssl_get_client_v_remain(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_handshake(ngx_connection_t *c); @@ -236,6 +246,7 @@ extern int ngx_ssl_session_cache_index; extern int ngx_ssl_session_ticket_keys_index; extern int ngx_ssl_certificate_index; extern int ngx_ssl_next_certificate_index; +extern int ngx_ssl_certificate_name_index; extern int ngx_ssl_stapling_index; diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c index 09fab76..2100516 100644 --- a/src/event/ngx_event_openssl_stapling.c +++ b/src/event/ngx_event_openssl_stapling.c @@ -31,6 +31,8 @@ typedef struct { X509 *cert; X509 *issuer; + u_char *name; + time_t valid; time_t refresh; @@ -45,6 +47,8 @@ struct ngx_ssl_ocsp_ctx_s { X509 *cert; X509 *issuer; + u_char *name; + ngx_uint_t naddrs; ngx_addr_t *addrs; @@ -57,14 +61,14 @@ struct ngx_ssl_ocsp_ctx_s { ngx_msec_t timeout; - void (*handler)(ngx_ssl_ocsp_ctx_t *r); + void (*handler)(ngx_ssl_ocsp_ctx_t *ctx); void *data; ngx_buf_t *request; ngx_buf_t *response; ngx_peer_connection_t peer; - ngx_int_t (*process)(ngx_ssl_ocsp_ctx_t *r); + ngx_int_t (*process)(ngx_ssl_ocsp_ctx_t *ctx); ngx_uint_t state; @@ -173,6 +177,8 @@ ngx_ssl_stapling_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, X509 *cert, staple->timeout = 60000; staple->verify = verify; staple->cert = cert; + staple->name = X509_get_ex_data(staple->cert, + ngx_ssl_certificate_name_index); if (file->len) { /* use OCSP response from the file */ @@ -354,7 +360,9 @@ ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl, if (rc == 0) { ngx_log_error(NGX_LOG_WARN, ssl->log, 0, - "\"ssl_stapling\" ignored, issuer certificate not found"); + "\"ssl_stapling\" ignored, " + "issuer certificate not found for certificate \"%s\"", + staple->name); X509_STORE_CTX_free(store_ctx); return NGX_DECLINED; } @@ -374,9 +382,9 @@ static ngx_int_t ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_ssl_stapling_t *staple, ngx_str_t *responder) { - ngx_url_t u; char *s; ngx_str_t rsp; + ngx_url_t u; STACK_OF(OPENSSL_STRING) *aia; if (responder->len == 0) { @@ -387,7 +395,8 @@ ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl, if (aia == NULL) { ngx_log_error(NGX_LOG_WARN, ssl->log, 0, "\"ssl_stapling\" ignored, " - "no OCSP responder URL in the certificate"); + "no OCSP responder URL in the certificate \"%s\"", + staple->name); return NGX_DECLINED; } @@ -399,7 +408,8 @@ ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl, if (s == NULL) { ngx_log_error(NGX_LOG_WARN, ssl->log, 0, "\"ssl_stapling\" ignored, " - "no OCSP responder URL in the certificate"); + "no OCSP responder URL in the certificate \"%s\"", + staple->name); X509_email_free(aia); return NGX_DECLINED; } @@ -432,7 +442,9 @@ ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl, } else { ngx_log_error(NGX_LOG_WARN, ssl->log, 0, "\"ssl_stapling\" ignored, " - "invalid URL prefix in OCSP responder \"%V\"", &u.url); + "invalid URL prefix in OCSP responder \"%V\" " + "in the certificate \"%s\"", + &u.url, staple->name); return NGX_DECLINED; } @@ -440,7 +452,9 @@ ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl, if (u.err) { ngx_log_error(NGX_LOG_WARN, ssl->log, 0, "\"ssl_stapling\" ignored, " - "%s in OCSP responder \"%V\"", u.err, &u.url); + "%s in OCSP responder \"%V\" " + "in the certificate \"%s\"", + u.err, &u.url, staple->name); return NGX_DECLINED; } @@ -547,6 +561,7 @@ ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple) ctx->cert = staple->cert; ctx->issuer = staple->issuer; + ctx->name = staple->name; ctx->addrs = staple->addrs; ctx->host = staple->host; @@ -757,10 +772,10 @@ error: static time_t ngx_ssl_stapling_time(ASN1_GENERALIZEDTIME *asn1time) { + BIO *bio; u_char *value; size_t len; time_t time; - BIO *bio; /* * OpenSSL doesn't provide a way to convert ASN1_GENERALIZEDTIME @@ -1005,7 +1020,7 @@ failed: static void ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx) { - ngx_int_t rc; + ngx_int_t rc; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0, "ssl ocsp connect"); @@ -1103,10 +1118,10 @@ ngx_ssl_ocsp_write_handler(ngx_event_t *wev) static void ngx_ssl_ocsp_read_handler(ngx_event_t *rev) { - ssize_t n, size; - ngx_int_t rc; - ngx_ssl_ocsp_ctx_t *ctx; - ngx_connection_t *c; + ssize_t n, size; + ngx_int_t rc; + ngx_connection_t *c; + ngx_ssl_ocsp_ctx_t *ctx; c = rev->data; ctx = c->data; @@ -1310,12 +1325,11 @@ ngx_ssl_ocsp_process_status_line(ngx_ssl_ocsp_ctx_t *ctx) rc = ngx_ssl_ocsp_parse_status_line(ctx); if (rc == NGX_OK) { -#if 0 - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0, - "ssl ocsp status line \"%*s\"", - ctx->response->pos - ctx->response->start, - ctx->response->start); -#endif + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ctx->log, 0, + "ssl ocsp status %ui \"%*s\"", + ctx->code, + ctx->header_end - ctx->header_start, + ctx->header_start); ctx->process = ngx_ssl_ocsp_process_headers; return ctx->process(ctx); @@ -1476,6 +1490,7 @@ ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx) if (++ctx->count == 3) { state = sw_space_after_status; + ctx->header_start = p - 2; } break; @@ -1493,6 +1508,7 @@ ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx) state = sw_almost_done; break; case LF: + ctx->header_end = p; goto done; default: return NGX_ERROR; @@ -1506,6 +1522,7 @@ ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx) state = sw_almost_done; break; case LF: + ctx->header_end = p; goto done; } break; @@ -1514,6 +1531,7 @@ ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx) case sw_almost_done: switch (ch) { case LF: + ctx->header_end = p - 1; goto done; default: return NGX_ERROR; @@ -1608,10 +1626,11 @@ ngx_ssl_ocsp_process_headers(ngx_ssl_ocsp_ctx_t *ctx) return ctx->process(ctx); } + static ngx_int_t ngx_ssl_ocsp_parse_header_line(ngx_ssl_ocsp_ctx_t *ctx) { - u_char c, ch, *p; + u_char c, ch, *p; enum { sw_start = 0, sw_name, @@ -1821,12 +1840,27 @@ ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len) if (log->action) { p = ngx_snprintf(buf, len, " while %s", log->action); len -= p - buf; + buf = p; } ctx = log->data; if (ctx) { - p = ngx_snprintf(p, len, ", responder: %V", &ctx->host); + p = ngx_snprintf(buf, len, ", responder: %V", &ctx->host); + len -= p - buf; + buf = p; + } + + if (ctx && ctx->peer.name) { + p = ngx_snprintf(buf, len, ", peer: %V", ctx->peer.name); + len -= p - buf; + buf = p; + } + + if (ctx && ctx->name) { + p = ngx_snprintf(buf, len, ", certificate: \"%s\"", ctx->name); + len -= p - buf; + buf = p; } return p; @@ -1846,6 +1880,7 @@ ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file, return NGX_OK; } + ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_resolver_t *resolver, ngx_msec_t resolver_timeout) diff --git a/src/http/modules/ngx_http_map_module.c b/src/http/modules/ngx_http_map_module.c index 732aa5d..2fc9be9 100644 --- a/src/http/modules/ngx_http_map_module.c +++ b/src/http/modules/ngx_http_map_module.c @@ -26,7 +26,8 @@ typedef struct { ngx_http_variable_value_t *default_value; ngx_conf_t *cf; - ngx_uint_t hostnames; /* unsigned hostnames:1 */ + unsigned hostnames:1; + unsigned no_cacheable:1; } ngx_http_map_conf_ctx_t; @@ -265,6 +266,7 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ctx.default_value = NULL; ctx.cf = &save; ctx.hostnames = 0; + ctx.no_cacheable = 0; save = *cf; cf->pool = pool; @@ -281,6 +283,10 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return rv; } + if (ctx.no_cacheable) { + var->flags |= NGX_HTTP_VAR_NOCACHEABLE; + } + map->default_value = ctx.default_value ? ctx.default_value: &ngx_http_variable_null_value; @@ -393,8 +399,16 @@ ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) { ctx->hostnames = 1; return NGX_CONF_OK; + } - } else if (cf->args->nelts != 2) { + if (cf->args->nelts == 1 + && ngx_strcmp(value[0].data, "volatile") == 0) + { + ctx->no_cacheable = 1; + return NGX_CONF_OK; + } + + if (cf->args->nelts != 2) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid number of the map parameters"); return NGX_CONF_ERROR; diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index 8f2920f..f3c0fdd 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -1229,7 +1229,9 @@ ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, off_t start_offset, atom_header = mp4->mdat_atom_header; - if ((uint64_t) atom_data_size > (uint64_t) 0xffffffff) { + if ((uint64_t) atom_data_size + > (uint64_t) 0xffffffff - sizeof(ngx_mp4_atom_header_t)) + { atom_size = 1; atom_header_size = sizeof(ngx_mp4_atom_header64_t); ngx_mp4_set_64value(atom_header + sizeof(ngx_mp4_atom_header_t), diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index e75f5d8..2771ac1 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -276,6 +276,12 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_cipher"), NULL, ngx_http_ssl_static_variable, (uintptr_t) ngx_ssl_get_cipher_name, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_ciphers"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_ciphers, NGX_HTTP_VAR_CHANGEABLE, 0 }, + + { ngx_string("ssl_curves"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_curves, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_session_id"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_session_id, NGX_HTTP_VAR_CHANGEABLE, 0 }, @@ -313,6 +319,15 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_client_verify"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_client_verify, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_v_start"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_client_v_start, NGX_HTTP_VAR_CHANGEABLE, 0 }, + + { ngx_string("ssl_client_v_end"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_client_v_end, NGX_HTTP_VAR_CHANGEABLE, 0 }, + + { ngx_string("ssl_client_v_remain"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_client_v_remain, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_null_string, NULL, NULL, 0, 0, 0 } }; diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c index f9a9a84..2796319 100644 --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -207,6 +207,7 @@ ngx_http_perl_handle_request(ngx_http_request_t *r) dTHXa(pmcf->perl); PERL_SET_CONTEXT(pmcf->perl); + PERL_SET_INTERP(pmcf->perl); if (ctx->next == NULL) { plcf = ngx_http_get_module_loc_conf(r, ngx_http_perl_module); @@ -322,6 +323,7 @@ ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, dTHXa(pmcf->perl); PERL_SET_CONTEXT(pmcf->perl); + PERL_SET_INTERP(pmcf->perl); rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, pv->sub, NULL, &pv->handler, &value); @@ -387,6 +389,7 @@ ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx, dTHXa(pmcf->perl); PERL_SET_CONTEXT(pmcf->perl); + PERL_SET_INTERP(pmcf->perl); #if 0 @@ -568,6 +571,7 @@ ngx_http_perl_create_interpreter(ngx_conf_t *cf, dTHXa(perl); PERL_SET_CONTEXT(perl); + PERL_SET_INTERP(perl); perl_construct(perl); @@ -828,6 +832,7 @@ ngx_http_perl_cleanup_perl(void *data) PerlInterpreter *perl = data; PERL_SET_CONTEXT(perl); + PERL_SET_INTERP(perl); (void) perl_destruct(perl); @@ -936,6 +941,7 @@ ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) dTHXa(pmcf->perl); PERL_SET_CONTEXT(pmcf->perl); + PERL_SET_INTERP(pmcf->perl); ngx_http_perl_eval_anon_sub(aTHX_ &value[1], &plcf->sub); @@ -1007,6 +1013,7 @@ ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) dTHXa(pmcf->perl); PERL_SET_CONTEXT(pmcf->perl); + PERL_SET_INTERP(pmcf->perl); ngx_http_perl_eval_anon_sub(aTHX_ &value[2], &pv->sub); @@ -1039,6 +1046,7 @@ ngx_http_perl_init_worker(ngx_cycle_t *cycle) if (pmcf) { dTHXa(pmcf->perl); PERL_SET_CONTEXT(pmcf->perl); + PERL_SET_INTERP(pmcf->perl); /* set worker's $$ */ diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 8301630..f3050f1 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -286,7 +286,6 @@ ngx_http_v2_init(ngx_event_t *rev) : ngx_http_v2_state_preface; ngx_queue_init(&h2c->waiting); - ngx_queue_init(&h2c->posted); ngx_queue_init(&h2c->dependencies); ngx_queue_init(&h2c->closed); @@ -420,9 +419,7 @@ static void ngx_http_v2_write_handler(ngx_event_t *wev) { ngx_int_t rc; - ngx_queue_t *q; ngx_connection_t *c; - ngx_http_v2_stream_t *stream; ngx_http_v2_connection_t *h2c; c = wev->data; @@ -457,26 +454,6 @@ ngx_http_v2_write_handler(ngx_event_t *wev) return; } - while (!ngx_queue_empty(&h2c->posted)) { - q = ngx_queue_head(&h2c->posted); - - ngx_queue_remove(q); - - stream = ngx_queue_data(q, ngx_http_v2_stream_t, queue); - - stream->handled = 0; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "run http2 stream %ui", stream->node->id); - - wev = stream->request->connection->write; - - wev->active = 0; - wev->ready = 1; - - wev->handler(wev); - } - h2c->blocked = 0; if (rc == NGX_AGAIN) { @@ -2254,7 +2231,7 @@ ngx_http_v2_state_window_update(ngx_http_v2_connection_t *h2c, u_char *pos, stream = ngx_queue_data(q, ngx_http_v2_stream_t, queue); - stream->handled = 0; + stream->waiting = 0; wev = stream->request->connection->write; @@ -3575,6 +3552,11 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r, rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); } else { + if (stream->preread) { + /* enforce writing preread buffer to file */ + r->request_body_in_file_only = 1; + } + rb->buf = ngx_calloc_buf(r->pool); if (rb->buf != NULL) { @@ -4271,7 +4253,7 @@ ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c, continue; } - stream->handled = 0; + stream->waiting = 0; r = stream->request; fc = r->connection; diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 63bbdad..cddfccd 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -137,7 +137,6 @@ struct ngx_http_v2_connection_s { ngx_http_v2_out_frame_t *last_out; - ngx_queue_t posted; ngx_queue_t dependencies; ngx_queue_t closed; @@ -192,7 +191,7 @@ struct ngx_http_v2_stream_s { ngx_pool_t *pool; - unsigned handled:1; + unsigned waiting:1; unsigned blocked:1; unsigned exhausted:1; unsigned in_closed:1; diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index 878020e..8abca4d 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -1104,11 +1104,11 @@ ngx_http_v2_waiting_queue(ngx_http_v2_connection_t *h2c, ngx_queue_t *q; ngx_http_v2_stream_t *s; - if (stream->handled) { + if (stream->waiting) { return; } - stream->handled = 1; + stream->waiting = 1; for (q = ngx_queue_last(&h2c->waiting); q != ngx_queue_sentinel(&h2c->waiting); @@ -1298,20 +1298,29 @@ static ngx_inline void ngx_http_v2_handle_stream(ngx_http_v2_connection_t *h2c, ngx_http_v2_stream_t *stream) { + ngx_event_t *wev; ngx_connection_t *fc; - if (stream->handled || stream->blocked) { + if (stream->waiting || stream->blocked) { return; } fc = stream->request->connection; - if (!fc->error && (stream->exhausted || fc->write->delayed)) { + if (!fc->error && stream->exhausted) { return; } - stream->handled = 1; - ngx_queue_insert_tail(&h2c->posted, &stream->queue); + wev = fc->write; + + wev->active = 0; + wev->ready = 1; + + if (!fc->error && wev->delayed) { + return; + } + + ngx_post_event(wev, &ngx_posted_events); } @@ -1321,11 +1330,13 @@ ngx_http_v2_filter_cleanup(void *data) ngx_http_v2_stream_t *stream = data; size_t window; + ngx_event_t *wev; + ngx_queue_t *q; ngx_http_v2_out_frame_t *frame, **fn; ngx_http_v2_connection_t *h2c; - if (stream->handled) { - stream->handled = 0; + if (stream->waiting) { + stream->waiting = 0; ngx_queue_remove(&stream->queue); } @@ -1359,9 +1370,26 @@ ngx_http_v2_filter_cleanup(void *data) fn = &frame->next; } - if (h2c->send_window == 0 && window && !ngx_queue_empty(&h2c->waiting)) { - ngx_queue_add(&h2c->posted, &h2c->waiting); - ngx_queue_init(&h2c->waiting); + if (h2c->send_window == 0 && window) { + + while (!ngx_queue_empty(&h2c->waiting)) { + q = ngx_queue_head(&h2c->waiting); + + ngx_queue_remove(q); + + stream = ngx_queue_data(q, ngx_http_v2_stream_t, queue); + + stream->waiting = 0; + + wev = stream->request->connection->write; + + wev->active = 0; + wev->ready = 1; + + if (!wev->delayed) { + ngx_post_event(wev, &ngx_posted_events); + } + } } h2c->send_window += window; diff --git a/src/stream/ngx_stream_map_module.c b/src/stream/ngx_stream_map_module.c index 47a15be..ef06b2d 100644 --- a/src/stream/ngx_stream_map_module.c +++ b/src/stream/ngx_stream_map_module.c @@ -26,7 +26,8 @@ typedef struct { ngx_stream_variable_value_t *default_value; ngx_conf_t *cf; - ngx_uint_t hostnames; /* unsigned hostnames:1 */ + unsigned hostnames:1; + unsigned no_cacheable:1; } ngx_stream_map_conf_ctx_t; @@ -264,6 +265,7 @@ ngx_stream_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ctx.default_value = NULL; ctx.cf = &save; ctx.hostnames = 0; + ctx.no_cacheable = 0; save = *cf; cf->pool = pool; @@ -280,6 +282,10 @@ ngx_stream_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return rv; } + if (ctx.no_cacheable) { + var->flags |= NGX_STREAM_VAR_NOCACHEABLE; + } + map->default_value = ctx.default_value ? ctx.default_value: &ngx_stream_variable_null_value; @@ -392,8 +398,16 @@ ngx_stream_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) { ctx->hostnames = 1; return NGX_CONF_OK; + } - } else if (cf->args->nelts != 2) { + if (cf->args->nelts == 1 + && ngx_strcmp(value[0].data, "volatile") == 0) + { + ctx->no_cacheable = 1; + return NGX_CONF_OK; + } + + if (cf->args->nelts != 2) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid number of the map parameters"); return NGX_CONF_ERROR; diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index d00718b..9191641 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -182,6 +182,12 @@ static ngx_stream_variable_t ngx_stream_ssl_vars[] = { { ngx_string("ssl_cipher"), NULL, ngx_stream_ssl_static_variable, (uintptr_t) ngx_ssl_get_cipher_name, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_ciphers"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_ciphers, NGX_STREAM_VAR_CHANGEABLE, 0 }, + + { ngx_string("ssl_curves"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_curves, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_session_id"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_session_id, NGX_STREAM_VAR_CHANGEABLE, 0 }, From a27ccda8362f40679d80e10bd1d8f0ab138bf677 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 19 Dec 2016 17:02:11 +0200 Subject: [PATCH 187/651] Fix lintian error 'possible-missing-colon-in-closes' Gbp-Dch: Ignore --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index af0ea9f..8e4f587 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,7 +1,7 @@ nginx (1.10.2-3) UNRELEASED; urgency=medium * debian/conf/sites-enabled/default: - + Correcting location of default php-fpm socket. (Closes #846145) + + Correcting location of default php-fpm socket. (Closes: #846145) -- Michael Lustfield Sat, 03 Dec 2016 07:57:39 +0000 From 5140bc7eae4c595e8f2eb20ac3f1f8ec5d986df1 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 20 Dec 2016 16:29:48 +0200 Subject: [PATCH 188/651] mod: Upgrade nchan to 1.0.8 Closes: #844473 --- debian/modules/README.Modules-versions | 2 +- debian/modules/nchan/README.md | 147 +- debian/modules/nchan/changelog.txt | 35 + debian/modules/nchan/config | 1 + debian/modules/nchan/dev/.gitignore | 6 - debian/modules/nchan/dev/Gemfile | 28 - debian/modules/nchan/dev/authserver.rb | 62 - debian/modules/nchan/dev/bench-parallel.sh | 27 - debian/modules/nchan/dev/bench.rb | 178 - debian/modules/nchan/dev/cert-key.pem | 28 - debian/modules/nchan/dev/cert.pem | 22 - debian/modules/nchan/dev/chattertest.rb | 43 - debian/modules/nchan/dev/debug.sh | 11 - debian/modules/nchan/dev/dev.conf | 63 - debian/modules/nchan/dev/examine_coredump.sh | 17 - .../modules/nchan/dev/gen_config_commands.rb | 129 - debian/modules/nchan/dev/longtest.rb | 184 - debian/modules/nchan/dev/memparse.lua | 269 - debian/modules/nchan/dev/nginx | 1 - .../modules/nchan/dev/nginx-cachemanager.conf | 67 - .../modules/nchan/dev/nginx-nchan/.gitignore | 6 - debian/modules/nchan/dev/nginx-nchan/PKGBUILD | 225 - debian/modules/nchan/dev/nginx-nchan/bl.txt | 6 - debian/modules/nchan/dev/nginx-nchan/install | 11 - debian/modules/nchan/dev/nginx-nchan/nchan | 1 - .../modules/nchan/dev/nginx-nchan/nginx.conf | 1 - .../nchan/dev/nginx-nchan/nginx.logrotate | 8 - .../nchan/dev/nginx-nchan/nginx.service | 14 - .../nchan/dev/nginx-nchan/ngx_slab.patch | 98 - debian/modules/nchan/dev/nginx-proxy.conf | 26 - debian/modules/nchan/dev/nginx.conf | 444 - debian/modules/nchan/dev/nginx.sh | 277 - debian/modules/nchan/dev/package/.gitignore | 1 - .../dev/package/nginx-nchan-static/.gitignore | 5 - .../dev/package/nginx-nchan-static/PKGBUILD | 165 - .../dev/package/nginx-nchan-static/nginx.conf | 1 - .../nginx-nchan-static/nginx.logrotate | 11 - .../package/nginx-nchan-static/nginx.service | 18 - debian/modules/nchan/dev/package/repackage.sh | 28 - debian/modules/nchan/dev/pub-multi.rb | 39 - debian/modules/nchan/dev/pub.rb | 90 - debian/modules/nchan/dev/pubsub.rb | 1483 - debian/modules/nchan/dev/rebuild.sh | 170 - debian/modules/nchan/dev/redis-trib.rb | 1696 - debian/modules/nchan/dev/redis.conf | 1018 - .../nchan/dev/redis_clusterconf/.gitignore | 1 - .../nchan/dev/redis_clusterconf/cluster.sh | 10 - .../nchan/dev/redis_clusterconf/failover.sh | 62 - .../dev/redis_clusterconf/redis-7000.conf | 1018 - .../dev/redis_clusterconf/redis-7001.conf | 1018 - .../dev/redis_clusterconf/redis-7002.conf | 1018 - .../dev/redis_clusterconf/redis-7003.conf | 1018 - .../dev/redis_clusterconf/redis-7004.conf | 1018 - .../dev/redis_clusterconf/redis-7005.conf | 1018 - .../dev/redis_clusterconf/redis-7006.conf | 1018 - .../redis-cluster-node-7000.conf | 7 - .../redis-cluster-node-7001.conf | 7 - .../redis-cluster-node-7002.conf | 7 - .../redis-cluster-node-7003.conf | 7 - .../redis-cluster-node-7004.conf | 7 - .../redis-cluster-node-7005.conf | 7 - .../redis-cluster-node-7006.conf | 2 - debian/modules/nchan/dev/redocument.rb | 295 - debian/modules/nchan/dev/rsck.sh | 67 - debian/modules/nchan/dev/sub.rb | 125 - debian/modules/nchan/dev/test-parallel.sh | 27 - debian/modules/nchan/dev/test.rb | 875 - debian/modules/nchan/dev/vg.supp | 26977 ---------------- debian/modules/nchan/src/nchan_commands.rb | 119 +- .../modules/nchan/src/nchan_config_commands.c | 30 +- debian/modules/nchan/src/nchan_defs.h | 2 +- debian/modules/nchan/src/nchan_module.c | 256 +- debian/modules/nchan/src/nchan_module.h | 5 +- debian/modules/nchan/src/nchan_setup.c | 74 +- debian/modules/nchan/src/nchan_types.h | 19 +- .../modules/nchan/src/store/memory/memstore.c | 239 +- .../nchan/src/store/memory/store-private.h | 4 +- debian/modules/nchan/src/store/memory/store.h | 2 + .../modules/nchan/src/store/redis/rdsstore.c | 21 +- .../src/store/redis/redis_lua_commands.h | 49 +- .../src/store/redis/scripts/find_channel.lua | 47 +- debian/modules/nchan/src/store/spool.c | 41 +- debian/modules/nchan/src/store/spool.h | 6 + debian/modules/nchan/src/subscribers/common.c | 418 +- debian/modules/nchan/src/subscribers/common.h | 9 +- .../nchan/src/subscribers/eventsource.c | 8 +- .../src/subscribers/http-multipart-mixed.c | 8 +- .../modules/nchan/src/subscribers/internal.c | 10 +- .../modules/nchan/src/subscribers/longpoll.c | 38 +- .../nchan/src/subscribers/memstore_ipc.c | 8 +- .../nchan/src/subscribers/memstore_multi.c | 2 +- .../nchan/src/subscribers/memstore_redis.c | 6 +- .../modules/nchan/src/subscribers/websocket.c | 615 +- .../nchan/src/util/nchan_channel_info.c | 13 +- .../nchan/src/util/nchan_fake_request.c | 277 + .../nchan/src/util/nchan_fake_request.h | 6 + debian/modules/nchan/src/util/nchan_output.c | 120 +- debian/modules/nchan/src/util/nchan_output.h | 2 + debian/modules/nchan/src/util/nchan_reaper.c | 2 +- debian/modules/nchan/src/util/nchan_reaper.h | 2 +- .../modules/nchan/src/util/nchan_subrequest.c | 17 + .../modules/nchan/src/util/nchan_subrequest.h | 1 + debian/modules/nchan/src/util/nchan_util.c | 14 + debian/modules/nchan/src/util/nchan_util.h | 1 + .../nchan/src/util/ngx_nchan_hacked_slab.c | 11 +- 105 files changed, 1990 insertions(+), 43283 deletions(-) delete mode 100644 debian/modules/nchan/dev/.gitignore delete mode 100644 debian/modules/nchan/dev/Gemfile delete mode 100755 debian/modules/nchan/dev/authserver.rb delete mode 100755 debian/modules/nchan/dev/bench-parallel.sh delete mode 100755 debian/modules/nchan/dev/bench.rb delete mode 100644 debian/modules/nchan/dev/cert-key.pem delete mode 100644 debian/modules/nchan/dev/cert.pem delete mode 100755 debian/modules/nchan/dev/chattertest.rb delete mode 100755 debian/modules/nchan/dev/debug.sh delete mode 100644 debian/modules/nchan/dev/dev.conf delete mode 100755 debian/modules/nchan/dev/examine_coredump.sh delete mode 100755 debian/modules/nchan/dev/gen_config_commands.rb delete mode 100755 debian/modules/nchan/dev/longtest.rb delete mode 100755 debian/modules/nchan/dev/memparse.lua delete mode 120000 debian/modules/nchan/dev/nginx delete mode 100644 debian/modules/nchan/dev/nginx-cachemanager.conf delete mode 100644 debian/modules/nchan/dev/nginx-nchan/.gitignore delete mode 100644 debian/modules/nchan/dev/nginx-nchan/PKGBUILD delete mode 100644 debian/modules/nchan/dev/nginx-nchan/bl.txt delete mode 100644 debian/modules/nchan/dev/nginx-nchan/install delete mode 120000 debian/modules/nchan/dev/nginx-nchan/nchan delete mode 100644 debian/modules/nchan/dev/nginx-nchan/nginx.conf delete mode 100644 debian/modules/nchan/dev/nginx-nchan/nginx.logrotate delete mode 100644 debian/modules/nchan/dev/nginx-nchan/nginx.service delete mode 100644 debian/modules/nchan/dev/nginx-nchan/ngx_slab.patch delete mode 100644 debian/modules/nchan/dev/nginx-proxy.conf delete mode 100644 debian/modules/nchan/dev/nginx.conf delete mode 100755 debian/modules/nchan/dev/nginx.sh delete mode 100644 debian/modules/nchan/dev/package/.gitignore delete mode 100644 debian/modules/nchan/dev/package/nginx-nchan-static/.gitignore delete mode 100644 debian/modules/nchan/dev/package/nginx-nchan-static/PKGBUILD delete mode 100644 debian/modules/nchan/dev/package/nginx-nchan-static/nginx.conf delete mode 100644 debian/modules/nchan/dev/package/nginx-nchan-static/nginx.logrotate delete mode 100644 debian/modules/nchan/dev/package/nginx-nchan-static/nginx.service delete mode 100755 debian/modules/nchan/dev/package/repackage.sh delete mode 100755 debian/modules/nchan/dev/pub-multi.rb delete mode 100755 debian/modules/nchan/dev/pub.rb delete mode 100644 debian/modules/nchan/dev/pubsub.rb delete mode 100755 debian/modules/nchan/dev/rebuild.sh delete mode 100755 debian/modules/nchan/dev/redis-trib.rb delete mode 100644 debian/modules/nchan/dev/redis.conf delete mode 100644 debian/modules/nchan/dev/redis_clusterconf/.gitignore delete mode 100755 debian/modules/nchan/dev/redis_clusterconf/cluster.sh delete mode 100755 debian/modules/nchan/dev/redis_clusterconf/failover.sh delete mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-7000.conf delete mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-7001.conf delete mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-7002.conf delete mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-7003.conf delete mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-7004.conf delete mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-7005.conf delete mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-7006.conf delete mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-cluster-node-7000.conf delete mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-cluster-node-7001.conf delete mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-cluster-node-7002.conf delete mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-cluster-node-7003.conf delete mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-cluster-node-7004.conf delete mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-cluster-node-7005.conf delete mode 100644 debian/modules/nchan/dev/redis_clusterconf/redis-cluster-node-7006.conf delete mode 100755 debian/modules/nchan/dev/redocument.rb delete mode 100755 debian/modules/nchan/dev/rsck.sh delete mode 100755 debian/modules/nchan/dev/sub.rb delete mode 100755 debian/modules/nchan/dev/test-parallel.sh delete mode 100755 debian/modules/nchan/dev/test.rb delete mode 100644 debian/modules/nchan/dev/vg.supp create mode 100644 debian/modules/nchan/src/util/nchan_fake_request.c create mode 100644 debian/modules/nchan/src/util/nchan_fake_request.h diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index a8b93ff..957ac00 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -33,7 +33,7 @@ README for Modules versions nchan Homepage: https://github.com/slact/nchan - Version: 1.0.2 + Version: 1.0.8 nginx-upload-progress Homepage: https://github.com/masterzen/nginx-upload-progress-module diff --git a/debian/modules/nchan/README.md b/debian/modules/nchan/README.md index fecd417..ee43ac9 100644 --- a/debian/modules/nchan/README.md +++ b/debian/modules/nchan/README.md @@ -2,20 +2,31 @@ https://nchan.slact.net -Nchan is a scalable, flexible pub/sub server for the modern web, built as a module for the [Nginx](http://nginx.org) web server. It can be configured as a standalone server, or as a shim between your application and tens, thousands, or millions of live subscribers. It can buffer messages in memory, on-disk, or via [Redis](http://redis.io). All connections are handled asynchronously and distributed among any number of worker processes. It can also scale to many nginx server instances with [Redis](http://redis.io). +Nchan is a scalable, flexible pub/sub server for the modern web, built as a module for the [Nginx](http://nginx.org) web server. It can be configured as a standalone server, or as a shim between your application and hundreds, thousands, or millions of live subscribers. It can buffer messages in memory, on-disk, or via [Redis](http://redis.io). All connections are handled asynchronously and distributed among any number of worker processes. It can also scale to many Nginx servers with [Redis](http://redis.io). -Messages are [published](#publisher-endpoints) to channels with HTTP `POST` requests or websockets, and [subscribed](#subscriber-endpoint) also through websockets, [long-polling](#long-polling), [EventSource](#eventsource) (SSE), old-fashioned [interval polling](#interval-polling), [and](#http-chunked-transfer) [more](#http-multipart-mixed). Each subscriber can listen to [up to 255 channels](#channel-multiplexing) per connection, and can be optionally [authenticated](https://nchan.slact.net/details#authenticate-with-nchan_authorize_request) via a custom application url. An [events](#nchan_channel_event_string) [meta channel](#nchan_channel_events_channel_id) is also available for debugging. +Messages are [published](#publisher-endpoints) to channels with HTTP `POST` requests or Websocket, and [subscribed](#subscriber-endpoint) also through [Websocket](#websocket), [long-polling](#long-polling), [EventSource](#eventsource) (SSE), old-fashioned [interval polling](#interval-polling), [and](#http-chunked-transfer) [more](#http-multipart-mixed). -For use in a web browser, you can try the [NchanSubscriber.js](https://github.com/slact/nchan/blob/master/NchanSubscriber.js) wrapper library. It supports Long-Polling, EventSource, and resumable Websockets -- or you can build your own. +In a web browser, you can use Websocket or EventSource directly, or the [NchanSubscriber.js](https://github.com/slact/nchan/blob/master/NchanSubscriber.js) wrapper library. It supports Long-Polling, EventSource, and resumable Websockets, and has a few other added convenience options. + +## Features + - RESTful, HTTP-native API. + - Supports [Websocket](https://nchan.slact.net/#websocket), [EventSource (Server-Sent Events)](https://nchan.slact.net/#eventsource), [Long-Polling](https://nchan.slact.net/#long-polling) and other HTTP-based subscribers. + - No-repeat, no-loss message delivery guarantees with per-channel configurable message buffers. + - Subscribe to [hundreds of channels](#channel-multiplexing) over a single subscriber connection. + - HTTP request [callbacks and hooks](https://nchan.slact.net/details#application-callbacks) for easy integration. + - Introspection with [channel events](https://nchan.slact.net/details#channel-events) and [url for monitoring performance statistics](https://nchan.slact.net/details#nchan_stub_status). + - Fast ephemeral local message storage and optional, slower, persistent storage with [Redis](https://nchan.slact.net/details#connecting-to-a-redis-server). + - Horizontally scalable (using [Redis](https://nchan.slact.net/details#connecting-to-a-redis-server)). + - Highly Available with no single point of failure (using [Redis Cluster](https://nchan.slact.net/details#redis-cluster)). + + ## Status and History -The latest Nchan release is v1.0.2 (August 29, 2016) ([changelog](https://nchan.slact.net/changelog)). +The latest Nchan release is v1.0.8 (November 28, 2016) ([changelog](https://nchan.slact.net/changelog)). The first iteration of Nchan was written in 2009-2010 as the [Nginx HTTP Push Module](https://pushmodule.slact.net), and was vastly refactored into its present state in 2014-2016. The present release is in the **testing** phase. The core features and old functionality are thoroughly tested and stable. Some of the new functionality, especially Redis Cluster may be a bit buggy. -Please help make the entire codebase ready for production use! Report any quirks, bugs, leaks, crashes, or larvae you find. - #### Upgrade from Nginx HTTP Push Module Although Nchan is backwards-compatible with all Push Module configuration directives, some of the more unusual and rarely used settings have been disabled and will be ignored (with a warning). See the [upgrade page](https://nchan.slact.net/upgrade) for a detailed list of changes and improvements, as well as a full list of incompatibilities. @@ -27,18 +38,19 @@ Although Nchan is backwards-compatible with all Push Module configuration direct Yes it does. Like Nginx, Nchan can easily handle as much traffic as you can throw at it. I've tried to benchmark it, but my benchmarking tools are much slower than Nchan. The data I've gathered is on how long Nchan itself takes to respond to every subscriber after publishing a message -- this excludes TCP handshake times and internal HTTP request parsing. Basically, it measures how Nchan scales assuming all other components are already tuned for scalability. The graphed data are averages of 5 runs with 50-byte messages. -With a well-tuned OS and network stack on commodity server hardware, expect to handle upwards of 300K concurrent subscribers per second at minimal CPU load. Nchan can also be scaled out to multiple Nginx instances using the [Redis storage engine](#nchan_use_redis), and that too can be scaled up beyond a single-point-of-failure by using Redis Cluster. +With a well-tuned OS and network stack on commodity server hardware, expect to handle upwards of 300K concurrent subscribers per second at minimal CPU load. Nchan can also be scaled out to multiple Nginx instances using the [Redis storage engine](#nchan_use_redis), and that too can be scaled up beyond a single-point-of-failure by using [Redis Cluster](https://nchan.slact.net/details#using-redis). -Currently, Nchan's performance is limited by available memory bandwidth. This can be improved significantly in future versions with fewer allocations and the use of contiguous memory pools. Please consider supporting Nchan to speed up the work of memory cache optimization. +Currently, Nchan's main bottleneck is not CPU load but memory bandwidth. This can be improved significantly in future versions with fewer allocations and better use of contiguous memory pools. Please consider supporting Nchan to speed up the work of memory cache optimization. ## Install #### Download Packages - [Arch Linux](https://archlinux.org): [nginx-nchan](https://aur.archlinux.org/packages/nginx-nchan/) and [nginx-nchan-git](https://aur.archlinux.org/packages/nginx-nchan-git/) are available in the Arch User Repository. - Mac OS X: a [homebrew](http://brew.sh) package is available. `brew tap homebrew/nginx; brew install nginx-full --with-nchan-module` - - [Debian](https://www.debian.org/): [nginx-common.deb](https://nchan.slact.net/download/nginx-common.deb) and [nginx-extras.deb](https://nchan.slact.net/download/nginx-extras.deb). Download both and install them with `dpkg -i`, followed by `sudo apt-get -f install`. These packages should soon be available directly from the Debian repository. + - [Debian](https://www.debian.org/): A dynamic module build for is available in the Debian package repository: [libnginx-mod-nchan](https://packages.debian.org/sid/libnginx-mod-nchan). + Additionally, you can use the pre-built static module packages [nginx-common.deb](https://nchan.slact.net/download/nginx-common.deb) and [nginx-extras.deb](https://nchan.slact.net/download/nginx-extras.deb). Download both and install them with `dpkg -i`, followed by `sudo apt-get -f install`. - [Ubuntu](http://www.ubuntu.com/): [nginx-common.ubuntu.deb](https://nchan.slact.net/download/nginx-common.ubuntu.deb) and [nginx-extras.ubuntu.deb](https://nchan.slact.net/download/nginx-extras.ubuntu.deb). Download both and install them with `dpkg -i`, followed by `sudo apt-get -f install`. Who knows when Ubuntu will add them to their repository?... - - [Fedora](https://fedoraproject.org): A 64-bit binary rpm and a source rpm are available: [nginx-nchan.x86_64.rpm](https://nchan.slact.net/download/nginx-nchan.x86-64.rpm), [ngx-nchan.src.rpm](https://nchan.slact.net/download/nginx-nchan.src.rpm). + - [Fedora](https://fedoraproject.org): Dynamic module builds for Nginx > 1.10.0 are available: [nginx-mod-nchan.x86_64.rpm](https://nchan.slact.net/download/nginx-mod-nchan.x86-64.rpm), [nginx-mod-nchan.src.rpm](https://nchan.slact.net/download/nginx-mod-nchan.src.rpm). - A statically compiled binary and associated linux nginx installation files are also [available as a tarball](https://nchan.slact.net/download/nginx-nchan-latest.tar.gz). @@ -52,6 +64,33 @@ If you're using Nginx > 1.9.11, you can build Nchan as a [dynamic module](https Run `make`, `make install`, and enjoy. (Caution, contents may be hot.) +## Getting Started + +Once you've built and installed Nchan, it's very easy to start using. Add two locations to your nginx config: + +```nginx +#... +http { + server { + #... + + location = /sub { + nchan_subscriber; + nchan_channel_id $arg_id; + } + + location = /pub { + nchan_publisher; + nchan_channel_id $arg_id; + } + } +} +``` + +You can now publish messages to channels by `POST`ing data to `/sub?id=channel_id` , and subscribe by pointing Websocket, EventSource, or [NchanSubscriber.js](https://github.com/slact/nchan/blob/master/NchanSubscriber.js) to `sub/?id=channel_id`. It's that simple. + +But Nchan is very flexible and highly configurable. So, of course, it can get a lot more complicated... + ## Conceptual Overview The basic unit of most pub/sub solutions is the messaging *channel*. Nchan is no different. Publishers send messages to channels with a certain *channel id*, and subscribers subscribed to those channels receive them. Some number of messages may be buffered for a time in a channel's message buffer before they are deleted. Pretty simple, right? @@ -88,6 +127,8 @@ Publisher endpoints are Nginx config *locations* with the [*`nchan_publisher`*]( Messages can be published to a channel by sending HTTP **POST** requests with the message contents to the *publisher endpoint* locations. You can also publish messages through a **Websocket** connection to the same location. + + ##### Publishing Messages Requests and websocket messages are responded to with information about the channel at time of message publication. Here's an example from publishing with `curl`: @@ -130,7 +171,9 @@ Metadata can be added to a message when using an HTTP POST request for publishin **HTTP `DELETE`** requests delete a channel and end all subscriber connections. Like the `GET` requests, this returns a `200` status response with channel info if the channel existed, and a `404` otherwise. -#### Subscriber Endpoint +For an in-depth explanation of how settings are applied to channels from publisher locations, see the [details page](https://nchan.slact.net/details#publisher-endpoint-configs). + +#### Subscriber Endpoints Subscriber endpoints are Nginx config *locations* with the [*`nchan_subscriber`*](#nchan_subscriber) directive. @@ -142,6 +185,7 @@ Nchan supports several different kinds of subscribers for receiving messages: [* The long-polling subscriber walks through a channel's message queue via the built-in cache mechanism of HTTP clients, namely with the "`Last-Modified`" and "`Etag`" headers. Explicitly, to receive the next message for given a long-poll subscriber response, send a request with the "`If-Modified-Since`" header set to the previous response's "`Last-Modified`" header, and "`If-None-Match`" likewise set to the previous response's "`Etag`" header. Sending a request without a "`If-Modified-Since`" or "`If-None-Match`" headers returns the oldest message in a channel's message queue, or waits until the next published message, depending on the value of the `nchan_subscriber_first_message` config directive. A message's associated content type, if present, will be sent to this subscriber with the `Content-Type` header. + - ##### Interval-Polling Works just like long-polling, except if the requested message is not yet available, immediately responds with a `304 Not Modified`. @@ -151,7 +195,7 @@ Nchan supports several different kinds of subscribers for receiving messages: [* Bidirectional communication for web browsers. Part of the [HTML5 spec](http://www.w3.org/TR/2014/REC-html5-20141028/single-page.html). Nchan supports the latest protocol version 13 ([RFC 6455](https://tools.ietf.org/html/rfc6455)). Initiated by sending a websocket handshake to the desired subscriber endpoint location. If the websocket connection is closed by the server, the `close` frame will contain the HTTP response code and status line describing the reason for closing the connection. Server-initiated keep-alive pings can be configured with the [`nchan_websocket_ping_interval`](#nchan_websocket_ping_interval) config directive. Websocket extensions are not yet supported. - Messages published through a websocket connection can be forwarded to an upstream application with the [`nchan_publisher_upstream_request`](nchan_publisher_upstream_request) config directive. + Messages published through a websocket connection can be forwarded to an upstream application with the [`nchan_publisher_upstream_request`](#nchan_publisher_upstream_request) config directive. Websocket subscribers can use the custom `ws+meta.nchan` subprotocol to receive message metadata with messages, making websocket connections resumable. Messages received with this subprotocol are of the form
   id: message_id
@@ -160,6 +204,8 @@ Nchan supports several different kinds of subscribers for receiving messages: [*
   message_data
   
The `content-type:` line may be omitted. + + - ##### EventSource Also known as [Server-Sent Events](https://en.wikipedia.org/wiki/Server-sent_events) or SSE, it predates Websockets in the [HTML5 spec](http://www.w3.org/TR/2014/REC-html5-20141028/single-page.html), and is a [very simple protocol](http://www.w3.org/TR/eventsource/#event-stream-interpretation). Initiated by sending an HTTP `GET` request to a channel subscriber endpoint with the "`Accept: text/event-stream`" header. @@ -167,7 +213,9 @@ Nchan supports several different kinds of subscribers for receiving messages: [* To resume a closed EventSource connection from the last-received message, one *should* start the connection with the "`Last-Event-ID`" header set to the last message's `id`. Unfortunately, browsers [don't support setting](http://www.w3.org/TR/2011/WD-eventsource-20111020/#concept-event-stream-last-event-id) this header for an `EventSource` object, so by default the last message id is set either from the "`Last-Event-Id`" header or the `last_event_id` url query string argument. This behavior can be configured via the [`nchan_subscriber_last_message_id`](#nchan_subscriber_last_message_id) config. - A message's associated `event` type, if present, will be sent to this subscriber with the `event:` line. + A message's `content-type` will not be received by an EventSource subscriber, as the protocol makes no provisions for this metadata. + A message's associated `event` type, if present, will be sent to this subscriber with the `event:` line. + - ##### HTTP [multipart/mixed](http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html#z0) The `multipart/mixed` MIMEtype was conceived for emails, but hey, why not use it for HTTP? It's easy to parse and includes metadata with each message. @@ -175,9 +223,11 @@ Nchan supports several different kinds of subscribers for receiving messages: [* The response headers and the unused "preamble" portion of the response body are sent right away, with the boundary string generated randomly for each subscriber. Each subsequent message will be sent as one part of the multipart message, and will include the message time and tag (`Last-Modified` and `Etag`) as well as the optional `Content-Type` headers. Each message is terminated with the next multipart message's boundary **without a trailing newline**. While this conforms to the multipart spec, it is unusual as multipart messages are defined as *starting*, rather than ending with a boundary. A message's associated content type, if present, will be sent to this subscriber with the `Content-Type` header. + - ##### HTTP Raw Stream A simple subscription method similar to the [streaming subscriber](https://github.com/wandenberg/nginx-push-stream-module/blob/master/docs/directives/subscribers.textile#push_stream_subscriber) of the [Nginx HTTP Push Stream Module](https://github.com/wandenberg/nginx-push-stream-module). Messages are appended to the response body, separated by a newline or configurable by `nchan_subscriber_http_raw_stream_separator`. + - ##### HTTP [Chunked Transfer](http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1) This subscription method uses the `chunked` `Transfer-Encoding` to receive messages. @@ -185,7 +235,10 @@ Nchan supports several different kinds of subscribers for receiving messages: [* `TE: chunked` (or `TE: chunked;q=??` where the qval > 0) The response headers are sent right away, and each message will be sent as an individual chunk. Note that because a zero-length chunk terminates the transfer, **zero-length messages will not be sent** to the subscriber. Unlike the other subscriber types, the `chunked` subscriber cannot be used with http/2 because it dissallows chunked encoding. - + + + + #### PubSub Endpoint PubSub endpoints are Nginx config *locations* with the [*`nchan_pubsub`*](#nchan_pubsub) directive. @@ -212,6 +265,8 @@ A more applicable setup may set different publisher and subscriber channel ids: Here, subscribers will listen for messages on channel `foo`, and publishers will publish messages to channel `bar`. This can be useful when setting up websocket proxying between web clients and your application. + + ### The Channel ID So far the examples have used static channel ids, which is not very useful in practice. It can be set to any nginx *variable*, such as a querystring argument, a header value, or a part of the location url: @@ -239,9 +294,11 @@ So far the examples have used static channel ids, which is not very useful in pr } ``` + + #### Channel Multiplexing -Any subscriber location can be an endpoint for up to 255 channels. Messages published to all the specified channels will be delivered in-order to the subscriber. There are two ways to enable multiplexing: +With channel multiplexing, subscribers can subscribe to up to 255 channels per connection. Messages published to all the specified channels will be delivered in-order to the subscriber. There are two ways to enable multiplexing: Up to 7 channel ids can be specified for the `nchan_channel_id` or `nchan_channel_subscriber_id` config directive: @@ -268,8 +325,6 @@ For more than 7 channels, `nchan_channel_id_split_delimiter` can be used to spli } ``` -`DELETE` requests on any channel are forwarded to relevant multi-channel subscribers, and their connections are terminated. - Publishing to multiple channels with a single request is also possible, with similar configuration: ```nginx @@ -278,14 +333,25 @@ Publishing to multiple channels with a single request is also possible, with sim nchan_channel_id "$1" "$2" "another_channel"; } ``` + +`DELETE` requests to a multiplexed channel broadcast the deletion to each of the channels it multiplexes, deletes all their messages and kicks out all clients subscribed to any of the channel ids. + +See the [details page](https://nchan.slact.net/details#securing-channels) for more information about using good IDs and keeping channels secure. + + + ## Storage Nchan can stores messages in memory, on disk, or via Redis. Memory storage is much faster, whereas Redis has additional overhead as is considerably slower for publishing messages, but offers near unlimited scalability for broadcast use cases with far more subscribers than publishers. + + ### Memory Storage This storage method uses a segment of shared memory to store messages and channel data. Large messages as determined by Nginx's caching layer are stored on-disk. The size of the memory segment is configured with `nchan_max_reserved_memory`. Data stored here is not persistent, and is lost if Nginx is restarted or reloaded. + + ### Redis Nchan can also store messages and channels on a Redis server, or in a Redis cluster. To use a Redis server, set `nchan_use_redis on;` and set the server url with `nchan_redis_url`. These two settings are inheritable by nested locations, so it is enough to set them within an `http { }` block to enable Redis for all Nchan locations in that block. Different locations can also use different Redis servers. @@ -317,6 +383,10 @@ Note that `nchan_redis_pass` implies `nchan_use_redis on;`, and that this settin When connecting several Nchan servers to the same Redis server (or cluster), the servers **must have their times synced up**. Failure to do so may result in missing and duplicated messages. +See the [details page](https://nchan.slact.net/details#using-redis) for more information on using Redis. + + + ## Variables Nchan makes several variables usabled in the config file: @@ -361,12 +431,14 @@ Additionally, `nchan_stub_status` data is also exposed as variables. These are a default: `(none)` context: server, location, if > Channel id for a publisher or subscriber location. Can have up to 4 values to subscribe to up to 4 channels. + [more details](#the-channel-id) - **nchan_channel_id_split_delimiter** arguments: 1 default: `(none)` context: server, location, if > Split the channel id into several ids for multiplexing using the delimiter string provided. + [more details](#channel-multiplexing) - **nchan_eventsource_event** arguments: 1 @@ -386,6 +458,7 @@ Additionally, `nchan_stub_status` data is also exposed as variables. These are a context: server, location, if legacy name: push_publisher > Defines a server or location as a publisher endpoint. Requests to a publisher location are treated as messages to be sent to subscribers. See the protocol documentation for a detailed description. + [more details](#publisher-endpoints) - **nchan_publisher_channel_id** arguments: 1 - 7 @@ -397,13 +470,15 @@ Additionally, `nchan_stub_status` data is also exposed as variables. These are a arguments: 1 context: server, location, if > Send POST request to internal location (which may proxy to an upstream server) with published message in the request body. Useful for bridging websocket publishers with HTTP applications, or for transforming message via upstream application before publishing to a channel. - > The upstream response code determine how publishing will proceed. A `200 OK` will publish the message from the upstream response's body. A `304 Not Modified` will publish the message as it was received from the publisher. A `204 No Content` will result in the message not being published. + > The upstream response code determines how publishing will proceed. A `200 OK` will publish the message from the upstream response's body. A `304 Not Modified` will publish the message as it was received from the publisher. A `204 No Content` will result in the message not being published. + [more details](https://nchan.slact.net/details#message-publishing-callbacks) - **nchan_pubsub** `[ http | websocket | eventsource | longpoll | intervalpoll | chunked | multipart-mixed | http-raw-stream ]` arguments: 0 - 6 default: `http websocket eventsource longpoll chunked multipart-mixed` context: server, location, if > Defines a server or location as a pubsub endpoint. For long-polling, GETs subscribe. and POSTs publish. For Websockets, publishing data on a connection does not yield a channel metadata response. Without additional configuration, this turns a location into an echo server. + [more details](#pubsub-endpoint) - **nchan_subscriber** `[ websocket | eventsource | longpoll | intervalpoll | chunked | multipart-mixed | http-raw-stream ]` arguments: 0 - 5 @@ -412,6 +487,7 @@ Additionally, `nchan_stub_status` data is also exposed as variables. These are a legacy name: push_subscriber > Defines a server or location as a channel subscriber endpoint. This location represents a subscriber's interface to a channel's message queue. The queue is traversed automatically, starting at the position defined by the `nchan_subscriber_first_message` setting. > The value is a list of permitted subscriber types. + [more details](#subscriber-endpoints) - **nchan_subscriber_channel_id** arguments: 1 - 7 @@ -426,12 +502,13 @@ Additionally, `nchan_stub_status` data is also exposed as variables. These are a > Override the default behavior of using both `Last-Modified` and `Etag` headers for the message id. > Enabling this option packs the entire message id into the `Etag` header, and discards > `Last-Modified` and `If-Modified-Since` headers. + [more details]() - **nchan_subscriber_first_message** `[ oldest | newest | ]` arguments: 1 default: `oldest` context: server, location, if - > Controls the first message received by a new subscriber. 'oldest' starts at the oldest available message in a channel's message queue, 'newest' waits until a message arrives. If a number `n` is specified, starts at `n`th message from the oldest. (`-n` start at `n`th from now). 0 is equivalent to 'newest'. + > Controls the first message received by a new subscriber. 'oldest' starts at the oldest available message in a channel's message queue, 'newest' waits until a message arrives. If a number `n` is specified, starts at `n`th message from the oldest. (`-n` starts at `n`th from now). 0 is equivalent to 'newest'. - **nchan_subscriber_http_raw_stream_separator** `` arguments: 1 @@ -468,6 +545,19 @@ Additionally, `nchan_stub_status` data is also exposed as variables. These are a arguments: 1 context: server, location, if > Send GET request to internal location (which may proxy to an upstream server) for authorization of a publisher or subscriber request. A 200 response authorizes the request, a 403 response forbids it. + [more details](https://nchan.slact.net/details#request-authorization) + +- **nchan_subscribe_request** `` + arguments: 1 + context: server, location, if + > Send GET request to internal location (which may proxy to an upstream server) after subscribing. Disabled for longpoll and interval-polling subscribers. + [more details](https://nchan.slact.net/details#subsribe-and-unsubscribe-callbacks) + +- **nchan_unsubscribe_request** `` + arguments: 1 + context: server, location, if + > Send GET request to internal location (which may proxy to an upstream server) after unsubscribing. Disabled for longpoll and interval-polling subscribers. + [more details](https://nchan.slact.net/details#subsribe-and-unsubscribe-callbacks) - **nchan_max_reserved_memory** `` arguments: 1 @@ -475,20 +565,21 @@ Additionally, `nchan_stub_status` data is also exposed as variables. These are a context: http legacy name: push_max_reserved_memory > The size of the shared memory chunk this module will use for message queuing and buffering. + [more details](#memory-storage) -- **nchan_message_buffer_length** `` +- **nchan_message_buffer_length** `[ | ]` arguments: 1 default: `10` context: http, server, location legacy names: push_max_message_buffer_length, push_message_buffer_length - > Publisher configuration setting the maximum number of messages to store per channel. A channel's message buffer will retain a maximum of this many most recent messages. + > Publisher configuration setting the maximum number of messages to store per channel. A channel's message buffer will retain a maximum of this many most recent messages. An Nginx variable can also be used to set the buffer length dynamically. -- **nchan_message_timeout** `
last = ngx_cpymem(b->last, - sort_url_args, - ngx_sizeof_ssz("?C=N&O=A")); + /* "Parent dir" entry, always first if displayed */ + if (r->uri.len > 1) { + b->last = ngx_cpymem_ssz(b->last, + "
last = ngx_cpymem(b->last, + sort_url_args, + ngx_sizeof_ssz("?C=N&O=A")); + } + b->last = ngx_cpymem_ssz(b->last, + "\">Parent directory/--
--
%02d-%s-%d %02d:%02d
"); + b->last = ngx_fancyindex_timefmt(b->last, &alcf->time_format, &tm); + b->last = ngx_cpymem_ssz(b->last, "
File Name  ↓ File Size  ↓ Date  ↓ File Name  ↓ File Size  ↓ Date  ↓ 
File Name  ↓ File Size  ↓ Date  ↓ File Name  ↓ File Size  ↓ Date  ↓ 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RTMP#clientsVideoAudioIn bytesOut bytesIn bits/sOut bits/sStateTime
Accepted: codecbits/ssizefpscodecbits/sfreqchan + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + live streams + + + + + + + + + + + + vod streams + + + + + + + + + + + + + #cccccc + #dddddd + + + + + + var d=document.getElementById('-'); + d.style.display=d.style.display=='none'?'':'none'; + return false + + + + [EMPTY] + + + + + +    + + + + + + + + + + + + + + + +   + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + +
IdStateAddressFlash versionPage URLSWF URLDroppedTimestampA-VTime
+ + +
+ + + + + + + + + + + d + + + + h + + + + m + + + s + + + + + + + + + + + + + T + + + G + + + M + + K + + + + b + B + + /s + + + + + + active + idle + + + + + + + publishing + playing + + + + + + + + + #cccccc + #eeeeee + + + + + + + + http://apps.db.ripe.net/search/query.html?searchtext= + + whois + + + + + + + + + + + + + + + + + + + + + + + + + + publishing + + + + active + + + + x + + + diff --git a/debian/rules b/debian/rules index 9ca4443..3951529 100755 --- a/debian/rules +++ b/debian/rules @@ -24,6 +24,7 @@ DYN_MODS := \ http-xslt-filter \ mail \ nchan \ + rtmp \ stream MODULESDIR = $(CURDIR)/debian/modules @@ -131,6 +132,7 @@ extras_configure_flags := \ --add-dynamic-module=$(MODULESDIR)/ngx-fancyindex \ --add-dynamic-module=$(MODULESDIR)/nchan \ --add-dynamic-module=$(MODULESDIR)/nginx-lua \ + --add-dynamic-module=$(MODULESDIR)/nginx-rtmp \ --add-dynamic-module=$(MODULESDIR)/nginx-upload-progress \ --add-dynamic-module=$(MODULESDIR)/nginx-upstream-fair \ --add-dynamic-module=$(MODULESDIR)/ngx_http_substitutions_filter_module diff --git a/debian/tests/control b/debian/tests/control index 03cd901..d276e4f 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -34,6 +34,7 @@ Depends: nginx-full, libnginx-mod-http-xslt-filter, libnginx-mod-mail, libnginx-mod-nchan, + libnginx-mod-rtmp, libnginx-mod-stream Tests: light-module-deps @@ -56,6 +57,7 @@ Depends: nginx-light, libnginx-mod-http-xslt-filter, libnginx-mod-mail, libnginx-mod-nchan, + libnginx-mod-rtmp, libnginx-mod-stream Tests: extras-module-deps @@ -78,4 +80,5 @@ Depends: nginx-extras, libnginx-mod-http-xslt-filter, libnginx-mod-mail, libnginx-mod-nchan, + libnginx-mod-rtmp, libnginx-mod-stream From d546f527ee6fb613a571829ee50816462ceefaa6 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 30 Jun 2017 22:02:19 +0300 Subject: [PATCH 248/651] Fix nginx-cache-purge segfaults The module copies verbatim the ngx_http_proxy_loc_conf_t struct, but the `method` member has changed since Nginx 1.11.6. Closes: #866750 --- debian/modules/README.Modules-versions | 1 + .../nginx-cache-purge/segfault-1.11.6.patch | 25 +++++++++++++++++++ .../modules/patches/nginx-cache-purge/series | 1 + 3 files changed, 27 insertions(+) create mode 100644 debian/modules/patches/nginx-cache-purge/segfault-1.11.6.patch diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index 8ed4610..c336064 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -47,6 +47,7 @@ README for Modules versions Homepage: https://github.com/FRiCKLE/ngx_cache_purge/ Version: 2.3 Patch: dynamic-module.patch + Patch: segfault-1.11.6.patch nginx-dav-ext-module Homepage: https://github.com/arut/nginx-dav-ext-module diff --git a/debian/modules/patches/nginx-cache-purge/segfault-1.11.6.patch b/debian/modules/patches/nginx-cache-purge/segfault-1.11.6.patch new file mode 100644 index 0000000..11972c8 --- /dev/null +++ b/debian/modules/patches/nginx-cache-purge/segfault-1.11.6.patch @@ -0,0 +1,25 @@ +From: Pawel Sulowicz +Date: Thu, 2 Feb 2017 09:39:37 +0100 +Subject: [PATCH] Fix compatibility with nginx-1.11.6+ +Origin: other, https://github.com/FRiCKLE/ngx_cache_purge/pull/51 + +--- + ngx_cache_purge_module.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/ngx_cache_purge_module.c b/ngx_cache_purge_module.c +index 62d3818..fd1ebde 100644 +--- a/ngx_cache_purge_module.c ++++ b/ngx_cache_purge_module.c +@@ -492,7 +492,11 @@ typedef struct { + ngx_str_t body_source; + # endif /* nginx_version < 1007008 */ + ++# if (nginx_version >= 1011006) ++ ngx_http_complex_value_t *method; ++# else + ngx_str_t method; ++# endif /* nginx_version >= 1011006 */ + ngx_str_t location; + ngx_str_t url; + diff --git a/debian/modules/patches/nginx-cache-purge/series b/debian/modules/patches/nginx-cache-purge/series index f9b9360..2876b35 100644 --- a/debian/modules/patches/nginx-cache-purge/series +++ b/debian/modules/patches/nginx-cache-purge/series @@ -1 +1,2 @@ dynamic-module.patch +segfault-1.11.6.patch From f4979c7c960b73049282ed87a07a7b7d7f72f91a Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 3 Jul 2017 14:15:40 +0300 Subject: [PATCH 249/651] Switch the copyright-format URL to https Complements the debian-policy bump to 4.0.0 (22fe275) Gbp-Dch: Ignore --- debian/copyright | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/copyright b/debian/copyright index 78ea210..3d1b4c5 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,4 +1,4 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: nginx Source: http://nginx.org/en/download.html From 5ccd94c7e9f19d6815e2b27e1325b8c3a8e626fc Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 3 Jul 2017 13:45:10 +0300 Subject: [PATCH 250/651] Release 1.13.2-1 --- debian/changelog | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/debian/changelog b/debian/changelog index fac5d1c..0b7711b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,22 @@ +nginx (1.13.2-1) unstable; urgency=medium + + [ Christos Trochalakis ] + * New upstream version 1.13.2. + * Fix nginx-cache-purge segfaults (Closes: #866750) + * Merge ca translations. + Thanks to Alytidae (Closes: #865996) + * Merge es translations. + Thanks to Jonathan Bustillos (Closes: #855610) + * Merge pt translations. + Thanks to Rui Branco (Closes: #858741) + * Bump Standards to 4.0.0. + - Switch the copyright-format URL to https. + + [ Nicolas Dandrimont ] + * Introduce libnginx-mod-rtmp (Closes: #843777) + + -- Christos Trochalakis Mon, 03 Jul 2017 13:44:59 +0300 + nginx (1.13.1-2) unstable; urgency=medium * Upload to unstable. From ab3dccab6aae29fd6a91d77aa8fc554c34e07a8c Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 7 Jul 2017 13:01:25 +0300 Subject: [PATCH 251/651] Drop gzip_disable "msie6" directive. IE6 is really deprecated nowdays. Also, this only affected earlier IE6 versions that was later patched to fix this issue. Closes: #867024 --- debian/conf/nginx.conf | 1 - debian/help/examples/http | 1 - 2 files changed, 2 deletions(-) diff --git a/debian/conf/nginx.conf b/debian/conf/nginx.conf index 6e57ea9..132f680 100644 --- a/debian/conf/nginx.conf +++ b/debian/conf/nginx.conf @@ -46,7 +46,6 @@ http { ## gzip on; - gzip_disable "msie6"; # gzip_vary on; # gzip_proxied any; diff --git a/debian/help/examples/http b/debian/help/examples/http index 89b2dde..bac9f90 100644 --- a/debian/help/examples/http +++ b/debian/help/examples/http @@ -38,7 +38,6 @@ http { ## gzip on; - gzip_disable "msie6"; # gzip_vary on; # gzip_proxied any; From 3d12f812d7285ac862794e62e92098c166b741e2 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 12 Jul 2017 08:12:27 +0300 Subject: [PATCH 252/651] New upstream version 1.13.3 --- CHANGES | 7 + CHANGES.ru | 8 + src/core/nginx.h | 4 +- src/core/ngx_resolver.c | 123 ++++++------- src/core/ngx_resolver.h | 1 + src/core/ngx_slab.c | 37 ++-- src/http/modules/ngx_http_proxy_module.c | 165 +++++++----------- .../modules/ngx_http_range_filter_module.c | 6 +- src/http/ngx_http_variables.c | 16 +- 9 files changed, 164 insertions(+), 203 deletions(-) diff --git a/CHANGES b/CHANGES index e7126ff..30b01ef 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,11 @@ +Changes with nginx 1.13.3 11 Jul 2017 + + *) Security: a specially crafted request might result in an integer + overflow and incorrect processing of ranges in the range filter, + potentially resulting in sensitive information leak (CVE-2017-7529). + + Changes with nginx 1.13.2 27 Jun 2017 *) Change: nginx now returns 200 instead of 416 when a range starting diff --git a/CHANGES.ru b/CHANGES.ru index 69e2be1..dab50c9 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,12 @@ +Изменения в nginx 1.13.3 11.07.2017 + + *) Безопасность: специально созданный запрос мог вызвать целочисленное + переполнение в range-фильтре и последующую некорректную обработку + запрошенных диапазонов, что потенциально могло привести к утечке + конфиденциальной информации (CVE-2017-7529). + + Изменения в nginx 1.13.2 27.06.2017 *) Изменение: теперь при запросе диапазона, начинающегося с 0, из diff --git a/src/core/nginx.h b/src/core/nginx.h index 37e257f..1f3a369 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1013002 -#define NGINX_VERSION "1.13.2" +#define nginx_version 1013003 +#define NGINX_VERSION "1.13.3" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index 91f8a5e..cd55520 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -105,6 +105,8 @@ static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name, u_char *buf, u_char *src, u_char *last); +static ngx_int_t ngx_resolver_set_timeout(ngx_resolver_t *r, + ngx_resolver_ctx_t *ctx); static void ngx_resolver_timeout_handler(ngx_event_t *ev); static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn); static void *ngx_resolver_alloc(ngx_resolver_t *r, size_t size); @@ -189,6 +191,7 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) r->event->handler = ngx_resolver_resend_handler; r->event->data = r; r->event->log = &cf->cycle->new_log; + r->event->cancelable = 1; r->ident = -1; r->resend_timeout = 5; @@ -728,19 +731,8 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, } if (rn->waiting) { - - if (ctx->event == NULL && ctx->timeout) { - ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); - if (ctx->event == NULL) { - return NGX_ERROR; - } - - ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; - ctx->event->log = r->log; - ctx->ident = -1; - - ngx_add_timer(ctx->event, ctx->timeout); + if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) { + return NGX_ERROR; } last->next = rn->waiting; @@ -864,18 +856,8 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, goto failed; } - if (ctx->event == NULL && ctx->timeout) { - ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); - if (ctx->event == NULL) { - goto failed; - } - - ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; - ctx->event->log = r->log; - ctx->ident = -1; - - ngx_add_timer(ctx->event, ctx->timeout); + if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) { + goto failed; } if (ngx_resolver_resend_empty(r)) { @@ -1007,19 +989,8 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) } if (rn->waiting) { - - if (ctx->event == NULL && ctx->timeout) { - ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); - if (ctx->event == NULL) { - return NGX_ERROR; - } - - ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; - ctx->event->log = r->log; - ctx->ident = -1; - - ngx_add_timer(ctx->event, ctx->timeout); + if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) { + return NGX_ERROR; } ctx->next = rn->waiting; @@ -1089,18 +1060,8 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) goto failed; } - if (ctx->event == NULL && ctx->timeout) { - ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); - if (ctx->event == NULL) { - goto failed; - } - - ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; - ctx->event->log = r->log; - ctx->ident = -1; - - ngx_add_timer(ctx->event, ctx->timeout); + if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) { + goto failed; } if (ngx_resolver_resend_empty(r)) { @@ -3034,25 +2995,15 @@ ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx) addrs = ngx_resolver_calloc(r, cctx->naddrs * sizeof(ngx_addr_t)); if (addrs == NULL) { - ngx_resolve_name_done(cctx); - - ctx->state = NGX_ERROR; - ctx->valid = ngx_time() + (r->valid ? r->valid : 10); - - ctx->handler(ctx); - return; + srv->state = NGX_ERROR; + goto done; } sockaddr = ngx_resolver_alloc(r, cctx->naddrs * sizeof(ngx_sockaddr_t)); if (sockaddr == NULL) { ngx_resolver_free(r, addrs); - ngx_resolve_name_done(cctx); - - ctx->state = NGX_ERROR; - ctx->valid = ngx_time() + (r->valid ? r->valid : 10); - - ctx->handler(ctx); - return; + srv->state = NGX_ERROR; + goto done; } for (i = 0; i < cctx->naddrs; i++) { @@ -3069,6 +3020,8 @@ ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx) srv->naddrs = cctx->naddrs; } +done: + ngx_resolve_name_done(cctx); if (ctx->count == 0) { @@ -4041,6 +3994,30 @@ done: } +static ngx_int_t +ngx_resolver_set_timeout(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) +{ + if (ctx->event || ctx->timeout == 0) { + return NGX_OK; + } + + ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); + if (ctx->event == NULL) { + return NGX_ERROR; + } + + ctx->event->handler = ngx_resolver_timeout_handler; + ctx->event->data = ctx; + ctx->event->log = r->log; + ctx->event->cancelable = ctx->cancelable; + ctx->ident = -1; + + ngx_add_timer(ctx->event, ctx->timeout); + + return NGX_OK; +} + + static void ngx_resolver_timeout_handler(ngx_event_t *ev) { @@ -4254,10 +4231,21 @@ ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) ngx_resolver_addr_t *addrs; ngx_resolver_srv_name_t *srvs; + srvs = ctx->srvs; + nsrvs = ctx->nsrvs; + naddrs = 0; - for (i = 0; i < ctx->nsrvs; i++) { - naddrs += ctx->srvs[i].naddrs; + for (i = 0; i < nsrvs; i++) { + if (srvs[i].state == NGX_ERROR) { + ctx->state = NGX_ERROR; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); + + ctx->handler(ctx); + return; + } + + naddrs += srvs[i].naddrs; } if (naddrs == 0) { @@ -4277,9 +4265,6 @@ ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) return; } - srvs = ctx->srvs; - nsrvs = ctx->nsrvs; - i = 0; n = 0; diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h index 6f099b7..0bd3921 100644 --- a/src/core/ngx_resolver.h +++ b/src/core/ngx_resolver.h @@ -220,6 +220,7 @@ struct ngx_resolver_ctx_s { unsigned quick:1; unsigned async:1; + unsigned cancelable:1; ngx_uint_t recursion; ngx_event_t *event; }; diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c index 1d4ce2b..9e7796d 100644 --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -181,8 +181,8 @@ void * ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) { size_t s; - uintptr_t p, n, m, mask, *bitmap; - ngx_uint_t i, slot, shift, map; + uintptr_t p, m, mask, *bitmap; + ngx_uint_t i, n, slot, shift, map; ngx_slab_page_t *page, *prev, *slots; if (size > ngx_slab_max_size) { @@ -226,7 +226,7 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) bitmap = (uintptr_t *) ngx_slab_page_addr(pool, page); - map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8); + map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t)); for (n = 0; n < map; n++) { @@ -239,7 +239,7 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) bitmap[n] |= m; - i = (n * sizeof(uintptr_t) * 8 + i) << shift; + i = (n * 8 * sizeof(uintptr_t) + i) << shift; p = (uintptr_t) bitmap + i; @@ -339,11 +339,17 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) } /* "n" elements for bitmap, plus one requested */ - bitmap[0] = ((uintptr_t) 2 << n) - 1; - map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8); + for (i = 0; i < (n + 1) / (8 * sizeof(uintptr_t)); i++) { + bitmap[i] = NGX_SLAB_BUSY; + } - for (i = 1; i < map; i++) { + m = ((uintptr_t) 1 << ((n + 1) % (8 * sizeof(uintptr_t)))) - 1; + bitmap[i] = m; + + map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t)); + + for (i = i + 1; i < map; i++) { bitmap[i] = 0; } @@ -369,7 +375,7 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) slots[slot].next = page; - pool->stats[slot].total += sizeof(uintptr_t) * 8; + pool->stats[slot].total += 8 * sizeof(uintptr_t); p = ngx_slab_page_addr(pool, page); @@ -480,8 +486,8 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) } n = ((uintptr_t) p & (ngx_pagesize - 1)) >> shift; - m = (uintptr_t) 1 << (n % (sizeof(uintptr_t) * 8)); - n /= sizeof(uintptr_t) * 8; + m = (uintptr_t) 1 << (n % (8 * sizeof(uintptr_t))); + n /= 8 * sizeof(uintptr_t); bitmap = (uintptr_t *) ((uintptr_t) p & ~((uintptr_t) ngx_pagesize - 1)); @@ -506,13 +512,16 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) n = 1; } - if (bitmap[0] & ~(((uintptr_t) 1 << n) - 1)) { + i = n / (8 * sizeof(uintptr_t)); + m = ((uintptr_t) 1 << (n % (8 * sizeof(uintptr_t)))) - 1; + + if (bitmap[i] & ~m) { goto done; } - map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8); + map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t)); - for (i = 1; i < map; i++) { + for (i = i + 1; i < map; i++) { if (bitmap[i]) { goto done; } @@ -558,7 +567,7 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) ngx_slab_free_pages(pool, page, 1); - pool->stats[slot].total -= sizeof(uintptr_t) * 8; + pool->stats[slot].total -= 8 * sizeof(uintptr_t); goto done; } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 839d479..61bf55c 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -1143,7 +1143,8 @@ ngx_http_proxy_create_key(ngx_http_request_t *r) static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r) { - size_t len, uri_len, loc_len, body_len; + size_t len, uri_len, loc_len, body_len, + key_len, val_len; uintptr_t escape; ngx_buf_t *b; ngx_str_t method; @@ -1258,11 +1259,20 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) le.flushed = 1; while (*(uintptr_t *) le.ip) { - while (*(uintptr_t *) le.ip) { + + lcode = *(ngx_http_script_len_code_pt *) le.ip; + key_len = 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); } le.ip += sizeof(uintptr_t); + + if (val_len == 0) { + continue; + } + + len += key_len + sizeof(": ") - 1 + val_len + sizeof(CRLF) - 1; } @@ -1362,30 +1372,41 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) le.ip = headers->lengths->elts; while (*(uintptr_t *) le.ip) { - lcode = *(ngx_http_script_len_code_pt *) le.ip; - /* skip the header line name length */ + lcode = *(ngx_http_script_len_code_pt *) le.ip; (void) lcode(&le); - if (*(ngx_http_script_len_code_pt *) le.ip) { + 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); - for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) { - lcode = *(ngx_http_script_len_code_pt *) le.ip; + if (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 = (len == sizeof(CRLF) - 1) ? 1 : 0; - - } else { e.skip = 0; + + continue; } - le.ip += sizeof(uintptr_t); + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + + *e.pos++ = ':'; *e.pos++ = ' '; 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.pos++ = CR; *e.pos++ = LF; } b->last = e.pos; @@ -3498,108 +3519,40 @@ ngx_http_proxy_init_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, continue; } - if (ngx_http_script_variables_count(&src[i].value) == 0) { - copy = ngx_array_push_n(headers->lengths, - sizeof(ngx_http_script_copy_code_t)); - if (copy == NULL) { - return NGX_ERROR; - } + copy = ngx_array_push_n(headers->lengths, + 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].key.len + sizeof(": ") - 1 - + src[i].value.len + sizeof(CRLF) - 1; + copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code; + copy->len = src[i].key.len; + size = (sizeof(ngx_http_script_copy_code_t) + + src[i].key.len + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); - size = (sizeof(ngx_http_script_copy_code_t) - + src[i].key.len + sizeof(": ") - 1 - + src[i].value.len + sizeof(CRLF) - 1 - + sizeof(uintptr_t) - 1) - & ~(sizeof(uintptr_t) - 1); + copy = ngx_array_push_n(headers->values, size); + if (copy == NULL) { + return NGX_ERROR; + } - copy = ngx_array_push_n(headers->values, size); - if (copy == NULL) { - return NGX_ERROR; - } + copy->code = ngx_http_script_copy_code; + copy->len = src[i].key.len; - copy->code = ngx_http_script_copy_code; - copy->len = src[i].key.len + sizeof(": ") - 1 - + src[i].value.len + sizeof(CRLF) - 1; + p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); + ngx_memcpy(p, src[i].key.data, src[i].key.len); - p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); - p = ngx_cpymem(p, src[i].key.data, src[i].key.len); - *p++ = ':'; *p++ = ' '; - p = ngx_cpymem(p, src[i].value.data, src[i].value.len); - *p++ = CR; *p = LF; + sc.cf = cf; + sc.source = &src[i].value; + sc.flushes = &headers->flushes; + sc.lengths = &headers->lengths; + sc.values = &headers->values; - } else { - copy = ngx_array_push_n(headers->lengths, - 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].key.len + sizeof(": ") - 1; - - - size = (sizeof(ngx_http_script_copy_code_t) - + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1) - & ~(sizeof(uintptr_t) - 1); - - copy = ngx_array_push_n(headers->values, size); - if (copy == NULL) { - return NGX_ERROR; - } - - copy->code = ngx_http_script_copy_code; - copy->len = src[i].key.len + sizeof(": ") - 1; - - p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); - p = ngx_cpymem(p, src[i].key.data, src[i].key.len); - *p++ = ':'; *p = ' '; - - - ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); - - sc.cf = cf; - sc.source = &src[i].value; - sc.flushes = &headers->flushes; - sc.lengths = &headers->lengths; - sc.values = &headers->values; - - if (ngx_http_script_compile(&sc) != NGX_OK) { - return NGX_ERROR; - } - - - copy = ngx_array_push_n(headers->lengths, - 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 = sizeof(CRLF) - 1; - - - size = (sizeof(ngx_http_script_copy_code_t) - + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1) - & ~(sizeof(uintptr_t) - 1); - - copy = ngx_array_push_n(headers->values, size); - if (copy == NULL) { - return NGX_ERROR; - } - - copy->code = ngx_http_script_copy_code; - copy->len = sizeof(CRLF) - 1; - - p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); - *p++ = CR; *p = LF; + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_ERROR; } code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t)); diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index 7ad9db9..292a2b8 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -355,7 +355,7 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, } if (suffix) { - start = content_length - end; + start = (end < content_length) ? content_length - end : 0; end = content_length - 1; } @@ -377,6 +377,10 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, range->start = start; range->end = end; + if (size > NGX_MAX_OFF_T_VALUE - (end - start)) { + return NGX_HTTP_RANGE_NOT_SATISFIABLE; + } + size += end - start; if (ranges-- == 0) { diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index cfb538a..fbc9ffa 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -1463,17 +1463,15 @@ static ngx_int_t ngx_http_variable_is_args(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - if (r->args.len == 0) { - v->len = 0; - v->data = NULL; + *v = ngx_http_variable_null_value; return NGX_OK; } v->len = 1; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; v->data = (u_char *) "?"; return NGX_OK; @@ -1990,11 +1988,7 @@ ngx_http_variable_request_completion(ngx_http_request_t *r, return NGX_OK; } - v->len = 0; - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - v->data = (u_char *) ""; + *v = ngx_http_variable_null_value; return NGX_OK; } From 95f7f656da1f216cba0e292813cf0889dff2dd04 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 12 Jul 2017 11:20:46 +0300 Subject: [PATCH 253/651] Release 1.13.3-1 --- debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index 0b7711b..7d350cf 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +nginx (1.13.3-1) unstable; urgency=high + + * New upstream version 1.13.3. + Fixes CVE-2017-7529 (Closes: #868109) + * Drop gzip_disable "msie6" directive. (Closes: #867024) + + -- Christos Trochalakis Wed, 12 Jul 2017 11:20:27 +0300 + nginx (1.13.2-1) unstable; urgency=medium [ Christos Trochalakis ] From ec292afcb9b056d4434dd393c41b52d00fccceca Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 9 Aug 2017 09:05:28 +0300 Subject: [PATCH 254/651] New upstream version 1.13.4 --- CHANGES | 20 + CHANGES.ru | 20 + auto/lib/conf | 2 +- auto/modules | 22 + auto/options | 3 + src/core/nginx.c | 6 + src/core/nginx.h | 4 +- src/core/ngx_connection.c | 4 +- src/core/ngx_parse_time.c | 16 +- src/core/ngx_slab.c | 23 +- src/core/ngx_slab.h | 1 + src/core/ngx_string.c | 8 +- src/event/ngx_event_openssl.c | 2 +- src/event/ngx_event_openssl_stapling.c | 2 +- .../modules/ngx_http_addition_filter_module.c | 2 + src/http/modules/ngx_http_browser_module.c | 45 +- src/http/modules/ngx_http_fastcgi_module.c | 2 +- src/http/modules/ngx_http_geoip_module.c | 2 +- src/http/modules/ngx_http_mirror_module.c | 264 ++++++++++++ src/http/modules/ngx_http_proxy_module.c | 2 +- .../modules/ngx_http_range_filter_module.c | 4 +- src/http/modules/ngx_http_realip_module.c | 2 +- src/http/modules/ngx_http_referer_module.c | 39 +- .../modules/ngx_http_slice_filter_module.c | 10 +- src/http/modules/ngx_http_ssi_filter_module.c | 4 +- src/http/modules/ngx_http_ssl_module.c | 2 +- .../modules/ngx_http_stub_status_module.c | 2 +- src/http/modules/ngx_http_try_files_module.c | 404 ++++++++++++++++++ .../modules/ngx_http_upstream_zone_module.c | 95 +++- src/http/ngx_http.c | 21 +- src/http/ngx_http_core_module.c | 310 -------------- src/http/ngx_http_core_module.h | 18 +- src/http/ngx_http_file_cache.c | 1 + src/http/ngx_http_parse.c | 14 +- src/http/ngx_http_request.h | 1 + src/http/ngx_http_upstream.c | 16 +- src/http/ngx_http_variables.c | 2 +- src/http/ngx_http_variables.h | 2 + src/http/v2/ngx_http_v2_module.c | 2 +- src/misc/ngx_google_perftools_module.c | 2 +- src/stream/ngx_stream_geoip_module.c | 2 +- src/stream/ngx_stream_realip_module.c | 2 +- src/stream/ngx_stream_ssl_module.c | 2 +- src/stream/ngx_stream_ssl_preread_module.c | 2 +- src/stream/ngx_stream_upstream.c | 2 +- src/stream/ngx_stream_upstream_zone_module.c | 95 +++- src/stream/ngx_stream_variables.c | 2 +- src/stream/ngx_stream_variables.h | 2 + 48 files changed, 1055 insertions(+), 455 deletions(-) create mode 100644 src/http/modules/ngx_http_mirror_module.c create mode 100644 src/http/modules/ngx_http_try_files_module.c diff --git a/CHANGES b/CHANGES index 30b01ef..cc22571 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,24 @@ +Changes with nginx 1.13.4 08 Aug 2017 + + *) Feature: the ngx_http_mirror_module. + + *) Bugfix: client connections might be dropped during configuration + testing when using the "reuseport" parameter of the "listen" + directive on Linux. + + *) Bugfix: request body might not be available in subrequests if it was + saved to a file and proxying was used. + + *) Bugfix: cleaning cache based on the "max_size" parameter did not work + on Windows. + + *) Bugfix: any shared memory allocation required 4096 bytes on Windows. + + *) Bugfix: nginx worker might be terminated abnormally when using the + "zone" directive inside the "upstream" block on Windows. + + Changes with nginx 1.13.3 11 Jul 2017 *) Security: a specially crafted request might result in an integer diff --git a/CHANGES.ru b/CHANGES.ru index dab50c9..f466c4d 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,24 @@ +Изменения в nginx 1.13.4 08.08.2017 + + *) Добавление: модуль ngx_http_mirror_module. + + *) Исправление: клиентские соединения могли сбрасываться при + тестировании конфигурации, если использовался параметр reuseport + директивы listen на Linux. + + *) Исправление: тело запроса могло быть недоступно в подзапросах, если + оно было сохранено в файл и использовалось проксирование. + + *) Исправление: очистка кэша по max_size не работала на Windows. + + *) Исправление: любое выделение разделяемой памяти на Windows требовало + 4096 байт памяти. + + *) Исправление: при использовании директивы zone в блоке upstream на + Windows рабочий процесс мог завершаться аварийно. + + Изменения в nginx 1.13.3 11.07.2017 *) Безопасность: специально созданный запрос мог вызвать целочисленное diff --git a/auto/lib/conf b/auto/lib/conf index 0b8545a..2c7af10 100644 --- a/auto/lib/conf +++ b/auto/lib/conf @@ -7,7 +7,7 @@ if [ $USE_PCRE = YES -o $PCRE != NONE ]; then . auto/lib/pcre/conf else - if [ $USE_PCRE = DISABLED -a $HTTP_REWRITE = YES ]; then + if [ $USE_PCRE = DISABLED -a $HTTP = YES -a $HTTP_REWRITE = YES ]; then cat << END diff --git a/auto/modules b/auto/modules index be3561e..26b05bd 100644 --- a/auto/modules +++ b/auto/modules @@ -506,6 +506,28 @@ if [ $HTTP = YES ]; then . auto/module fi + if [ $HTTP_MIRROR = YES ]; then + ngx_module_name=ngx_http_mirror_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_mirror_module.c + ngx_module_libs= + ngx_module_link=$HTTP_MIRROR + + . auto/module + fi + + if :; then + ngx_module_name=ngx_http_try_files_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_try_files_module.c + ngx_module_libs= + ngx_module_link=YES + + . auto/module + fi + if [ $HTTP_AUTH_REQUEST = YES ]; then ngx_module_name=ngx_http_auth_request_module ngx_module_incs= diff --git a/auto/options b/auto/options index 66b822a..24c2618 100644 --- a/auto/options +++ b/auto/options @@ -70,6 +70,7 @@ HTTP_DAV=NO HTTP_ACCESS=YES HTTP_AUTH_BASIC=YES HTTP_AUTH_REQUEST=NO +HTTP_MIRROR=YES HTTP_USERID=YES HTTP_SLICE=NO HTTP_AUTOINDEX=YES @@ -249,6 +250,7 @@ $0: warning: the \"--with-ipv6\" option is deprecated" --without-http_userid_module) HTTP_USERID=NO ;; --without-http_access_module) HTTP_ACCESS=NO ;; --without-http_auth_basic_module) HTTP_AUTH_BASIC=NO ;; + --without-http_mirror_module) HTTP_MIRROR=NO ;; --without-http_autoindex_module) HTTP_AUTOINDEX=NO ;; --without-http_status_module) HTTP_STATUS=NO ;; --without-http_geo_module) HTTP_GEO=NO ;; @@ -458,6 +460,7 @@ cat << END --without-http_userid_module disable ngx_http_userid_module --without-http_access_module disable ngx_http_access_module --without-http_auth_basic_module disable ngx_http_auth_basic_module + --without-http_mirror_module disable ngx_http_mirror_module --without-http_autoindex_module disable ngx_http_autoindex_module --without-http_geo_module disable ngx_http_geo_module --without-http_map_module disable ngx_http_map_module diff --git a/src/core/nginx.c b/src/core/nginx.c index abaa50d..c3a29cc 100644 --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -273,6 +273,12 @@ main(int argc, char *const *argv) return 1; } + /* + * ngx_slab_sizes_init() requires ngx_pagesize set in ngx_os_init() + */ + + ngx_slab_sizes_init(); + if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) { return 1; } diff --git a/src/core/nginx.h b/src/core/nginx.h index 1f3a369..3649945 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1013003 -#define NGINX_VERSION "1.13.3" +#define nginx_version 1013004 +#define NGINX_VERSION "1.13.4" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index ec4692b..392fc35 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -473,7 +473,7 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) #if (NGX_HAVE_REUSEPORT) - if (ls[i].reuseport) { + if (ls[i].reuseport && !ngx_test_config) { int reuseport; reuseport = 1; @@ -483,7 +483,7 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - "setsockopt(SO_REUSEPORT) %V failed, ignored", + "setsockopt(SO_REUSEPORT) %V failed", &ls[i].addr_text); if (ngx_close_socket(s) == -1) { diff --git a/src/core/ngx_parse_time.c b/src/core/ngx_parse_time.c index 13afde3..a5c5034 100644 --- a/src/core/ngx_parse_time.c +++ b/src/core/ngx_parse_time.c @@ -58,7 +58,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - day = (*p - '0') * 10 + *(p + 1) - '0'; + day = (*p - '0') * 10 + (*(p + 1) - '0'); p += 2; if (*p == ' ') { @@ -132,7 +132,7 @@ ngx_parse_http_time(u_char *value, size_t len) } year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100 - + (*(p + 2) - '0') * 10 + *(p + 3) - '0'; + + (*(p + 2) - '0') * 10 + (*(p + 3) - '0'); p += 4; } else if (fmt == rfc850) { @@ -140,7 +140,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - year = (*p - '0') * 10 + *(p + 1) - '0'; + year = (*p - '0') * 10 + (*(p + 1) - '0'); year += (year < 70) ? 2000 : 1900; p += 2; } @@ -161,7 +161,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - day = day * 10 + *p++ - '0'; + day = day * 10 + (*p++ - '0'); } if (end - p < 14) { @@ -177,7 +177,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - hour = (*p - '0') * 10 + *(p + 1) - '0'; + hour = (*p - '0') * 10 + (*(p + 1) - '0'); p += 2; if (*p++ != ':') { @@ -188,7 +188,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - min = (*p - '0') * 10 + *(p + 1) - '0'; + min = (*p - '0') * 10 + (*(p + 1) - '0'); p += 2; if (*p++ != ':') { @@ -199,7 +199,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - sec = (*p - '0') * 10 + *(p + 1) - '0'; + sec = (*p - '0') * 10 + (*(p + 1) - '0'); if (fmt == isoc) { p += 2; @@ -216,7 +216,7 @@ ngx_parse_http_time(u_char *value, size_t len) } year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100 - + (*(p + 2) - '0') * 10 + *(p + 3) - '0'; + + (*(p + 2) - '0') * 10 + (*(p + 3) - '0'); } if (hour > 23 || min > 59 || sec > 59) { diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c index 9e7796d..4023870 100644 --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -82,6 +82,19 @@ static ngx_uint_t ngx_slab_exact_size; static ngx_uint_t ngx_slab_exact_shift; +void +ngx_slab_sizes_init(void) +{ + ngx_uint_t n; + + ngx_slab_max_size = ngx_pagesize / 2; + ngx_slab_exact_size = ngx_pagesize / (8 * sizeof(uintptr_t)); + for (n = ngx_slab_exact_size; n >>= 1; ngx_slab_exact_shift++) { + /* void */ + } +} + + void ngx_slab_init(ngx_slab_pool_t *pool) { @@ -91,16 +104,6 @@ ngx_slab_init(ngx_slab_pool_t *pool) ngx_uint_t i, n, pages; ngx_slab_page_t *slots, *page; - /* STUB */ - if (ngx_slab_max_size == 0) { - ngx_slab_max_size = ngx_pagesize / 2; - ngx_slab_exact_size = ngx_pagesize / (8 * sizeof(uintptr_t)); - for (n = ngx_slab_exact_size; n >>= 1; ngx_slab_exact_shift++) { - /* void */ - } - } - /**/ - pool->min_size = (size_t) 1 << pool->min_shift; slots = ngx_slab_slots(pool); diff --git a/src/core/ngx_slab.h b/src/core/ngx_slab.h index eff893c..d1876bb 100644 --- a/src/core/ngx_slab.h +++ b/src/core/ngx_slab.h @@ -59,6 +59,7 @@ typedef struct { } ngx_slab_pool_t; +void ngx_slab_sizes_init(void); void ngx_slab_init(ngx_slab_pool_t *pool); void *ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size); void *ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size); diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index 7526f60..de10a06 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -178,7 +178,7 @@ ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args) slen = (size_t) -1; while (*fmt >= '0' && *fmt <= '9') { - width = width * 10 + *fmt++ - '0'; + width = width * 10 + (*fmt++ - '0'); } @@ -211,7 +211,7 @@ ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args) fmt++; while (*fmt >= '0' && *fmt <= '9') { - frac_width = frac_width * 10 + *fmt++ - '0'; + frac_width = frac_width * 10 + (*fmt++ - '0'); } break; @@ -1655,7 +1655,7 @@ ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type) state = sw_usual; if (ch >= '0' && ch <= '9') { - ch = (u_char) ((decoded << 4) + ch - '0'); + ch = (u_char) ((decoded << 4) + (ch - '0')); if (type & NGX_UNESCAPE_REDIRECT) { if (ch > '%' && ch < 0x7f) { @@ -1675,7 +1675,7 @@ ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type) c = (u_char) (ch | 0x20); if (c >= 'a' && c <= 'f') { - ch = (u_char) ((decoded << 4) + c - 'a' + 10); + ch = (u_char) ((decoded << 4) + (c - 'a') + 10); if (type & NGX_UNESCAPE_URI) { if (ch == '?') { diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 2c4e114..07646b6 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -3128,7 +3128,7 @@ ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) { if (paths) { ngx_log_error(NGX_LOG_WARN, ssl->log, 0, - "\"ssl_session_ticket_keys\" ignored, not supported"); + "\"ssl_session_ticket_key\" ignored, not supported"); } return NGX_OK; diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c index d332c11..0bea5e7 100644 --- a/src/event/ngx_event_openssl_stapling.c +++ b/src/event/ngx_event_openssl_stapling.c @@ -1486,7 +1486,7 @@ ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx) return NGX_ERROR; } - ctx->code = ctx->code * 10 + ch - '0'; + ctx->code = ctx->code * 10 + (ch - '0'); if (++ctx->count == 3) { state = sw_space_after_status; diff --git a/src/http/modules/ngx_http_addition_filter_module.c b/src/http/modules/ngx_http_addition_filter_module.c index 2fad0e5..e546f0d 100644 --- a/src/http/modules/ngx_http_addition_filter_module.c +++ b/src/http/modules/ngx_http_addition_filter_module.c @@ -123,6 +123,8 @@ ngx_http_addition_header_filter(ngx_http_request_t *r) ngx_http_clear_accept_ranges(r); ngx_http_weak_etag(r); + r->preserve_body = 1; + return ngx_http_next_header_filter(r); } diff --git a/src/http/modules/ngx_http_browser_module.c b/src/http/modules/ngx_http_browser_module.c index 80da0d8..f774254 100644 --- a/src/http/modules/ngx_http_browser_module.c +++ b/src/http/modules/ngx_http_browser_module.c @@ -37,13 +37,6 @@ typedef struct { } ngx_http_modern_browser_t; -typedef struct { - ngx_str_t name; - ngx_http_get_variable_pt handler; - uintptr_t data; -} ngx_http_browser_variable_t; - - typedef struct { ngx_array_t *modern_browsers; ngx_array_t *ancient_browsers; @@ -63,7 +56,7 @@ static ngx_int_t ngx_http_browser_variable(ngx_http_request_t *r, static ngx_uint_t ngx_http_browser(ngx_http_request_t *r, ngx_http_browser_conf_t *cf); -static ngx_int_t ngx_http_browser_add_variable(ngx_conf_t *cf); +static ngx_int_t ngx_http_browser_add_variables(ngx_conf_t *cf); static void *ngx_http_browser_create_conf(ngx_conf_t *cf); static char *ngx_http_browser_merge_conf(ngx_conf_t *cf, void *parent, void *child); @@ -114,7 +107,7 @@ static ngx_command_t ngx_http_browser_commands[] = { static ngx_http_module_t ngx_http_browser_module_ctx = { - ngx_http_browser_add_variable, /* preconfiguration */ + ngx_http_browser_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ @@ -218,13 +211,18 @@ static ngx_http_modern_browser_mask_t ngx_http_modern_browser_masks[] = { }; -static ngx_http_browser_variable_t ngx_http_browsers[] = { - { ngx_string("msie"), ngx_http_msie_variable, 0 }, - { ngx_string("modern_browser"), ngx_http_browser_variable, - NGX_HTTP_MODERN_BROWSER }, - { ngx_string("ancient_browser"), ngx_http_browser_variable, - NGX_HTTP_ANCIENT_BROWSER }, - { ngx_null_string, NULL, 0 } +static ngx_http_variable_t ngx_http_browser_vars[] = { + + { ngx_string("msie"), NULL, ngx_http_msie_variable, + 0, NGX_HTTP_VAR_CHANGEABLE, 0 }, + + { ngx_string("modern_browser"), NULL, ngx_http_browser_variable, + NGX_HTTP_MODERN_BROWSER, NGX_HTTP_VAR_CHANGEABLE, 0 }, + + { ngx_string("ancient_browser"), NULL, ngx_http_browser_variable, + NGX_HTTP_ANCIENT_BROWSER, NGX_HTTP_VAR_CHANGEABLE, 0 }, + + ngx_http_null_variable }; @@ -397,20 +395,19 @@ ngx_http_msie_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, static ngx_int_t -ngx_http_browser_add_variable(ngx_conf_t *cf) +ngx_http_browser_add_variables(ngx_conf_t *cf) { - ngx_http_browser_variable_t *var; - ngx_http_variable_t *v; + ngx_http_variable_t *var, *v; - for (var = ngx_http_browsers; var->name.len; var++) { + for (v = ngx_http_browser_vars; v->name.len; v++) { - v = ngx_http_add_variable(cf, &var->name, NGX_HTTP_VAR_CHANGEABLE); - if (v == NULL) { + var = ngx_http_add_variable(cf, &v->name, v->flags); + if (var == NULL) { return NGX_ERROR; } - v->get_handler = var->handler; - v->data = var->data; + var->get_handler = v->get_handler; + var->data = v->data; } return NGX_OK; diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 741e577..ea16eca 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -631,7 +631,7 @@ static ngx_http_variable_t ngx_http_fastcgi_vars[] = { ngx_http_fastcgi_path_info_variable, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/modules/ngx_http_geoip_module.c b/src/http/modules/ngx_http_geoip_module.c index 8e151aa..5ea4f5f 100644 --- a/src/http/modules/ngx_http_geoip_module.c +++ b/src/http/modules/ngx_http_geoip_module.c @@ -232,7 +232,7 @@ static ngx_http_variable_t ngx_http_geoip_vars[] = { ngx_http_geoip_city_int_variable, offsetof(GeoIPRecord, area_code), 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/modules/ngx_http_mirror_module.c b/src/http/modules/ngx_http_mirror_module.c new file mode 100644 index 0000000..787adb3 --- /dev/null +++ b/src/http/modules/ngx_http_mirror_module.c @@ -0,0 +1,264 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_array_t *mirror; + ngx_flag_t request_body; +} ngx_http_mirror_loc_conf_t; + + +typedef struct { + ngx_int_t status; +} ngx_http_mirror_ctx_t; + + +static ngx_int_t ngx_http_mirror_handler(ngx_http_request_t *r); +static void ngx_http_mirror_body_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_mirror_handler_internal(ngx_http_request_t *r); +static void *ngx_http_mirror_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_mirror_merge_loc_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_http_mirror(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static ngx_int_t ngx_http_mirror_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_http_mirror_commands[] = { + + { ngx_string("mirror"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_mirror, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("mirror_request_body"), + 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_mirror_loc_conf_t, request_body), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_mirror_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_mirror_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_mirror_create_loc_conf, /* create location configuration */ + ngx_http_mirror_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_mirror_module = { + NGX_MODULE_V1, + &ngx_http_mirror_module_ctx, /* module context */ + ngx_http_mirror_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_mirror_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_mirror_ctx_t *ctx; + ngx_http_mirror_loc_conf_t *mlcf; + + if (r != r->main) { + return NGX_DECLINED; + } + + mlcf = ngx_http_get_module_loc_conf(r, ngx_http_mirror_module); + + if (mlcf->mirror == NULL) { + return NGX_DECLINED; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "mirror handler"); + + if (mlcf->request_body) { + ctx = ngx_http_get_module_ctx(r, ngx_http_mirror_module); + + if (ctx) { + return ctx->status; + } + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_mirror_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ctx->status = NGX_DONE; + + ngx_http_set_ctx(r, ctx, ngx_http_mirror_module); + + rc = ngx_http_read_client_request_body(r, ngx_http_mirror_body_handler); + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + return rc; + } + + ngx_http_finalize_request(r, NGX_DONE); + return NGX_DONE; + } + + return ngx_http_mirror_handler_internal(r); +} + + +static void +ngx_http_mirror_body_handler(ngx_http_request_t *r) +{ + ngx_http_mirror_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_mirror_module); + + ctx->status = ngx_http_mirror_handler_internal(r); + + r->preserve_body = 1; + + r->write_event_handler = ngx_http_core_run_phases; + ngx_http_core_run_phases(r); +} + + +static ngx_int_t +ngx_http_mirror_handler_internal(ngx_http_request_t *r) +{ + ngx_str_t *name; + ngx_uint_t i; + ngx_http_request_t *sr; + ngx_http_mirror_loc_conf_t *mlcf; + + mlcf = ngx_http_get_module_loc_conf(r, ngx_http_mirror_module); + + name = mlcf->mirror->elts; + + for (i = 0; i < mlcf->mirror->nelts; i++) { + if (ngx_http_subrequest(r, &name[i], &r->args, &sr, NULL, + NGX_HTTP_SUBREQUEST_BACKGROUND) + != NGX_OK) + { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + sr->header_only = 1; + sr->method = r->method; + sr->method_name = r->method_name; + } + + return NGX_DECLINED; +} + + +static void * +ngx_http_mirror_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_mirror_loc_conf_t *mlcf; + + mlcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_mirror_loc_conf_t)); + if (mlcf == NULL) { + return NULL; + } + + mlcf->mirror = NGX_CONF_UNSET_PTR; + mlcf->request_body = NGX_CONF_UNSET; + + return mlcf; +} + + +static char * +ngx_http_mirror_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_mirror_loc_conf_t *prev = parent; + ngx_http_mirror_loc_conf_t *conf = child; + + ngx_conf_merge_ptr_value(conf->mirror, prev->mirror, NULL); + ngx_conf_merge_value(conf->request_body, prev->request_body, 1); + + return NGX_CONF_OK; +} + + +static char * +ngx_http_mirror(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_mirror_loc_conf_t *mlcf = conf; + + ngx_str_t *value, *s; + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "off") == 0) { + if (mlcf->mirror != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + mlcf->mirror = NULL; + return NGX_CONF_OK; + } + + if (mlcf->mirror == NULL) { + return "is duplicate"; + } + + if (mlcf->mirror == NGX_CONF_UNSET_PTR) { + mlcf->mirror = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t)); + if (mlcf->mirror == NULL) { + return NGX_CONF_ERROR; + } + } + + s = ngx_array_push(mlcf->mirror); + if (s == NULL) { + return NGX_CONF_ERROR; + } + + *s = value[1]; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_mirror_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_PRECONTENT_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_mirror_handler; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 61bf55c..b42839c 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -829,7 +829,7 @@ static ngx_http_variable_t ngx_http_proxy_vars[] = { ngx_http_proxy_internal_chunked_variable, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index 292a2b8..6256b13 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -315,7 +315,7 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, return NGX_HTTP_RANGE_NOT_SATISFIABLE; } - start = start * 10 + *p++ - '0'; + start = start * 10 + (*p++ - '0'); } while (*p == ' ') { p++; } @@ -345,7 +345,7 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, return NGX_HTTP_RANGE_NOT_SATISFIABLE; } - end = end * 10 + *p++ - '0'; + end = end * 10 + (*p++ - '0'); } while (*p == ' ') { p++; } diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c index e1839e6..7d3f2a9 100644 --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -122,7 +122,7 @@ static ngx_http_variable_t ngx_http_realip_vars[] = { { ngx_string("realip_remote_port"), NULL, ngx_http_realip_remote_port_variable, 0, 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/modules/ngx_http_referer_module.c b/src/http/modules/ngx_http_referer_module.c index 3f0f78e..599dd3a 100644 --- a/src/http/modules/ngx_http_referer_module.c +++ b/src/http/modules/ngx_http_referer_module.c @@ -32,6 +32,7 @@ typedef struct { } ngx_http_referer_conf_t; +static ngx_int_t ngx_http_referer_add_variables(ngx_conf_t *cf); static void * ngx_http_referer_create_conf(ngx_conf_t *cf); static char * ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child); @@ -77,7 +78,7 @@ static ngx_command_t ngx_http_referer_commands[] = { static ngx_http_module_t ngx_http_referer_module_ctx = { - NULL, /* preconfiguration */ + ngx_http_referer_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ @@ -107,6 +108,9 @@ ngx_module_t ngx_http_referer_module = { }; +static ngx_str_t ngx_http_invalid_referer_name = ngx_string("invalid_referer"); + + static ngx_int_t ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) @@ -263,6 +267,23 @@ valid: } +static ngx_int_t +ngx_http_referer_add_variables(ngx_conf_t *cf) +{ + ngx_http_variable_t *var; + + var = ngx_http_add_variable(cf, &ngx_http_invalid_referer_name, + NGX_HTTP_VAR_CHANGEABLE); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = ngx_http_referer_variable; + + return NGX_OK; +} + + static void * ngx_http_referer_create_conf(ngx_conf_t *cf) { @@ -452,19 +473,9 @@ ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_referer_conf_t *rlcf = conf; - u_char *p; - ngx_str_t *value, uri, name; - ngx_uint_t i; - ngx_http_variable_t *var; - - ngx_str_set(&name, "invalid_referer"); - - var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); - if (var == NULL) { - return NGX_CONF_ERROR; - } - - var->get_handler = ngx_http_referer_variable; + u_char *p; + ngx_str_t *value, uri; + ngx_uint_t i; if (rlcf->keys == NULL) { rlcf->keys = ngx_pcalloc(cf->temp_pool, sizeof(ngx_hash_keys_arrays_t)); diff --git a/src/http/modules/ngx_http_slice_filter_module.c b/src/http/modules/ngx_http_slice_filter_module.c index 7758342..c1edbca 100644 --- a/src/http/modules/ngx_http_slice_filter_module.c +++ b/src/http/modules/ngx_http_slice_filter_module.c @@ -190,6 +190,8 @@ ngx_http_slice_header_filter(ngx_http_request_t *r) return rc; } + r->preserve_body = 1; + if (r->headers_out.status == NGX_HTTP_PARTIAL_CONTENT) { if (ctx->start + (off_t) slcf->size <= r->headers_out.content_offset) { ctx->start = slcf->size @@ -317,7 +319,7 @@ ngx_http_slice_parse_content_range(ngx_http_request_t *r, return NGX_ERROR; } - start = start * 10 + *p++ - '0'; + start = start * 10 + (*p++ - '0'); } while (*p == ' ') { p++; } @@ -337,7 +339,7 @@ ngx_http_slice_parse_content_range(ngx_http_request_t *r, return NGX_ERROR; } - end = end * 10 + *p++ - '0'; + end = end * 10 + (*p++ - '0'); } end++; @@ -362,7 +364,7 @@ ngx_http_slice_parse_content_range(ngx_http_request_t *r, return NGX_ERROR; } - complete_length = complete_length * 10 + *p++ - '0'; + complete_length = complete_length * 10 + (*p++ - '0'); } } else { @@ -479,7 +481,7 @@ ngx_http_slice_get_start(ngx_http_request_t *r) return 0; } - start = start * 10 + *p++ - '0'; + start = start * 10 + (*p++ - '0'); } return start; diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index b92ad4c..e29e173 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -321,7 +321,7 @@ static ngx_http_variable_t ngx_http_ssi_vars[] = { { ngx_string("date_gmt"), NULL, ngx_http_ssi_date_gmt_local_variable, 1, NGX_HTTP_VAR_NOCACHEABLE, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; @@ -370,6 +370,8 @@ ngx_http_ssi_header_filter(ngx_http_request_t *r) ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); + r->preserve_body = 1; + if (!slcf->last_modified) { ngx_http_clear_last_modified(r); ngx_http_clear_etag(r); diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index b466e5d..4370275 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -329,7 +329,7 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_client_v_remain"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_client_v_remain, NGX_HTTP_VAR_CHANGEABLE, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/modules/ngx_http_stub_status_module.c b/src/http/modules/ngx_http_stub_status_module.c index 61199f2..9bdf881 100644 --- a/src/http/modules/ngx_http_stub_status_module.c +++ b/src/http/modules/ngx_http_stub_status_module.c @@ -76,7 +76,7 @@ static ngx_http_variable_t ngx_http_stub_status_vars[] = { { ngx_string("connections_waiting"), NULL, ngx_http_stub_status_variable, 3, NGX_HTTP_VAR_NOCACHEABLE, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/modules/ngx_http_try_files_module.c b/src/http/modules/ngx_http_try_files_module.c new file mode 100644 index 0000000..ce783a2 --- /dev/null +++ b/src/http/modules/ngx_http_try_files_module.c @@ -0,0 +1,404 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_array_t *lengths; + ngx_array_t *values; + ngx_str_t name; + + unsigned code:10; + unsigned test_dir:1; +} ngx_http_try_file_t; + + +typedef struct { + ngx_http_try_file_t *try_files; +} ngx_http_try_files_loc_conf_t; + + +static ngx_int_t ngx_http_try_files_handler(ngx_http_request_t *r); +static char *ngx_http_try_files(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static void *ngx_http_try_files_create_loc_conf(ngx_conf_t *cf); +static ngx_int_t ngx_http_try_files_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_http_try_files_commands[] = { + + { ngx_string("try_files"), + NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE, + ngx_http_try_files, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_try_files_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_try_files_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_try_files_create_loc_conf, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_try_files_module = { + NGX_MODULE_V1, + &ngx_http_try_files_module_ctx, /* module context */ + ngx_http_try_files_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_try_files_handler(ngx_http_request_t *r) +{ + size_t len, root, alias, reserve, allocated; + u_char *p, *name; + ngx_str_t path, args; + ngx_uint_t test_dir; + ngx_http_try_file_t *tf; + ngx_open_file_info_t of; + ngx_http_script_code_pt code; + ngx_http_script_engine_t e; + ngx_http_core_loc_conf_t *clcf; + ngx_http_script_len_code_pt lcode; + ngx_http_try_files_loc_conf_t *tlcf; + + tlcf = ngx_http_get_module_loc_conf(r, ngx_http_try_files_module); + + if (tlcf->try_files == NULL) { + return NGX_DECLINED; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "try files handler"); + + allocated = 0; + root = 0; + name = NULL; + /* suppress MSVC warning */ + path.data = NULL; + + tf = tlcf->try_files; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + alias = clcf->alias; + + for ( ;; ) { + + if (tf->lengths) { + ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); + + e.ip = tf->lengths->elts; + e.request = r; + + /* 1 is for terminating '\0' as in static names */ + len = 1; + + while (*(uintptr_t *) e.ip) { + lcode = *(ngx_http_script_len_code_pt *) e.ip; + len += lcode(&e); + } + + } else { + len = tf->name.len; + } + + if (!alias) { + reserve = len > r->uri.len ? len - r->uri.len : 0; + + } else if (alias == NGX_MAX_SIZE_T_VALUE) { + reserve = len; + + } else { + reserve = len > r->uri.len - alias ? len - (r->uri.len - alias) : 0; + } + + if (reserve > allocated || !allocated) { + + /* 16 bytes are preallocation */ + allocated = reserve + 16; + + if (ngx_http_map_uri_to_path(r, &path, &root, allocated) == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + name = path.data + root; + } + + if (tf->values == NULL) { + + /* tf->name.len includes the terminating '\0' */ + + ngx_memcpy(name, tf->name.data, tf->name.len); + + path.len = (name + tf->name.len - 1) - path.data; + + } else { + e.ip = tf->values->elts; + e.pos = name; + e.flushed = 1; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + } + + path.len = e.pos - path.data; + + *e.pos = '\0'; + + if (alias && alias != NGX_MAX_SIZE_T_VALUE + && ngx_strncmp(name, r->uri.data, alias) == 0) + { + ngx_memmove(name, name + alias, len - alias); + path.len -= alias; + } + } + + test_dir = tf->test_dir; + + tf++; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "trying to use %s: \"%s\" \"%s\"", + test_dir ? "dir" : "file", name, path.data); + + if (tf->lengths == NULL && tf->name.len == 0) { + + if (tf->code) { + return tf->code; + } + + path.len -= root; + path.data += root; + + if (path.data[0] == '@') { + (void) ngx_http_named_location(r, &path); + + } else { + ngx_http_split_args(r, &path, &args); + + (void) ngx_http_internal_redirect(r, &path, &args); + } + + ngx_http_finalize_request(r, NGX_DONE); + return NGX_DONE; + } + + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + + of.read_ahead = clcf->read_ahead; + of.directio = clcf->directio; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; + of.test_only = 1; + 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) + { + if (of.err == 0) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (of.err != NGX_ENOENT + && of.err != NGX_ENOTDIR + && of.err != NGX_ENAMETOOLONG) + { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, + "%s \"%s\" failed", of.failed, path.data); + } + + continue; + } + + if (of.is_dir != test_dir) { + continue; + } + + path.len -= root; + path.data += root; + + if (!alias) { + r->uri = path; + + } else if (alias == NGX_MAX_SIZE_T_VALUE) { + if (!test_dir) { + r->uri = path; + r->add_uri_to_alias = 1; + } + + } else { + name = r->uri.data; + + r->uri.len = alias + path.len; + r->uri.data = ngx_pnalloc(r->pool, r->uri.len); + if (r->uri.data == NULL) { + r->uri.len = 0; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + p = ngx_copy(r->uri.data, name, alias); + ngx_memcpy(p, path.data, path.len); + } + + ngx_http_set_exten(r); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "try file uri: \"%V\"", &r->uri); + + return NGX_DECLINED; + } + + /* not reached */ +} + + +static char * +ngx_http_try_files(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_try_files_loc_conf_t *tlcf = conf; + + ngx_str_t *value; + ngx_int_t code; + ngx_uint_t i, n; + ngx_http_try_file_t *tf; + ngx_http_script_compile_t sc; + + if (tlcf->try_files) { + return "is duplicate"; + } + + tf = ngx_pcalloc(cf->pool, cf->args->nelts * sizeof(ngx_http_try_file_t)); + if (tf == NULL) { + return NGX_CONF_ERROR; + } + + tlcf->try_files = tf; + + value = cf->args->elts; + + for (i = 0; i < cf->args->nelts - 1; i++) { + + tf[i].name = value[i + 1]; + + if (tf[i].name.len > 0 + && tf[i].name.data[tf[i].name.len - 1] == '/' + && i + 2 < cf->args->nelts) + { + tf[i].test_dir = 1; + tf[i].name.len--; + tf[i].name.data[tf[i].name.len] = '\0'; + } + + n = ngx_http_script_variables_count(&tf[i].name); + + if (n) { + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = &tf[i].name; + sc.lengths = &tf[i].lengths; + sc.values = &tf[i].values; + sc.variables = n; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + + } else { + /* add trailing '\0' to length */ + tf[i].name.len++; + } + } + + if (tf[i - 1].name.data[0] == '=') { + + code = ngx_atoi(tf[i - 1].name.data + 1, tf[i - 1].name.len - 2); + + if (code == NGX_ERROR || code > 999) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid code \"%*s\"", + tf[i - 1].name.len - 1, tf[i - 1].name.data); + return NGX_CONF_ERROR; + } + + tf[i].code = code; + } + + return NGX_CONF_OK; +} + + +static void * +ngx_http_try_files_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_try_files_loc_conf_t *tlcf; + + tlcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_try_files_loc_conf_t)); + if (tlcf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * tlcf->try_files = NULL; + */ + + return tlcf; +} + + +static ngx_int_t +ngx_http_try_files_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_PRECONTENT_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_try_files_handler; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_upstream_zone_module.c b/src/http/modules/ngx_http_upstream_zone_module.c index 7e5bd74..d340b48 100644 --- a/src/http/modules/ngx_http_upstream_zone_module.c +++ b/src/http/modules/ngx_http_upstream_zone_module.c @@ -16,6 +16,8 @@ static ngx_int_t ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data); static ngx_http_upstream_rr_peers_t *ngx_http_upstream_zone_copy_peers( ngx_slab_pool_t *shpool, ngx_http_upstream_srv_conf_t *uscf); +static ngx_http_upstream_rr_peer_t *ngx_http_upstream_zone_copy_peer( + ngx_http_upstream_rr_peers_t *peers, ngx_http_upstream_rr_peer_t *src); static ngx_command_t ngx_http_upstream_zone_commands[] = { @@ -185,6 +187,7 @@ static ngx_http_upstream_rr_peers_t * ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_http_upstream_srv_conf_t *uscf) { + ngx_str_t *name; ngx_http_upstream_rr_peer_t *peer, **peerp; ngx_http_upstream_rr_peers_t *peers, *backup; @@ -195,18 +198,30 @@ ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_memcpy(peers, uscf->peer.data, sizeof(ngx_http_upstream_rr_peers_t)); + name = ngx_slab_alloc(shpool, sizeof(ngx_str_t)); + if (name == NULL) { + return NULL; + } + + name->data = ngx_slab_alloc(shpool, peers->name->len); + if (name->data == NULL) { + return NULL; + } + + ngx_memcpy(name->data, peers->name->data, peers->name->len); + name->len = peers->name->len; + + peers->name = name; + peers->shpool = shpool; for (peerp = &peers->peer; *peerp; peerp = &peer->next) { /* pool is unlocked */ - peer = ngx_slab_calloc_locked(shpool, - sizeof(ngx_http_upstream_rr_peer_t)); + peer = ngx_http_upstream_zone_copy_peer(peers, *peerp); if (peer == NULL) { return NULL; } - ngx_memcpy(peer, *peerp, sizeof(ngx_http_upstream_rr_peer_t)); - *peerp = peer; } @@ -221,18 +236,17 @@ ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_memcpy(backup, peers->next, sizeof(ngx_http_upstream_rr_peers_t)); + backup->name = name; + backup->shpool = shpool; for (peerp = &backup->peer; *peerp; peerp = &peer->next) { /* pool is unlocked */ - peer = ngx_slab_calloc_locked(shpool, - sizeof(ngx_http_upstream_rr_peer_t)); + peer = ngx_http_upstream_zone_copy_peer(backup, *peerp); if (peer == NULL) { return NULL; } - ngx_memcpy(peer, *peerp, sizeof(ngx_http_upstream_rr_peer_t)); - *peerp = peer; } @@ -244,3 +258,68 @@ done: return peers; } + + +static ngx_http_upstream_rr_peer_t * +ngx_http_upstream_zone_copy_peer(ngx_http_upstream_rr_peers_t *peers, + ngx_http_upstream_rr_peer_t *src) +{ + ngx_slab_pool_t *pool; + ngx_http_upstream_rr_peer_t *dst; + + pool = peers->shpool; + + dst = ngx_slab_calloc_locked(pool, sizeof(ngx_http_upstream_rr_peer_t)); + if (dst == NULL) { + return NULL; + } + + if (src) { + ngx_memcpy(dst, src, sizeof(ngx_http_upstream_rr_peer_t)); + dst->sockaddr = NULL; + dst->name.data = NULL; + dst->server.data = NULL; + } + + dst->sockaddr = ngx_slab_calloc_locked(pool, NGX_SOCKADDRLEN); + if (dst->sockaddr == NULL) { + goto failed; + } + + dst->name.data = ngx_slab_calloc_locked(pool, NGX_SOCKADDR_STRLEN); + if (dst->name.data == NULL) { + goto failed; + } + + if (src) { + ngx_memcpy(dst->sockaddr, src->sockaddr, src->socklen); + ngx_memcpy(dst->name.data, src->name.data, src->name.len); + + dst->server.data = ngx_slab_alloc_locked(pool, src->server.len); + if (dst->server.data == NULL) { + goto failed; + } + + ngx_memcpy(dst->server.data, src->server.data, src->server.len); + } + + return dst; + +failed: + + if (dst->server.data) { + ngx_slab_free_locked(pool, dst->server.data); + } + + if (dst->name.data) { + ngx_slab_free_locked(pool, dst->name.data); + } + + if (dst->sockaddr) { + ngx_slab_free_locked(pool, dst->sockaddr); + } + + ngx_slab_free_locked(pool, dst); + + return NULL; +} diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index c036389..9d8b6d7 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -382,6 +382,13 @@ ngx_http_init_phases(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) return NGX_ERROR; } + if (ngx_array_init(&cmcf->phases[NGX_HTTP_PRECONTENT_PHASE].handlers, + cf->pool, 2, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers, cf->pool, 4, sizeof(ngx_http_handler_pt)) != NGX_OK) @@ -459,8 +466,7 @@ ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) n = 1 /* find config phase */ + use_rewrite /* post rewrite phase */ - + use_access /* post access phase */ - + cmcf->try_files; + + use_access; /* post access phase */ for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) { n += cmcf->phases[i].handlers.nelts; @@ -529,15 +535,6 @@ ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) continue; - case NGX_HTTP_TRY_FILES_PHASE: - if (cmcf->try_files) { - ph->checker = ngx_http_core_try_files_phase; - n++; - ph++; - } - - continue; - case NGX_HTTP_CONTENT_PHASE: checker = ngx_http_core_content_phase; break; @@ -548,7 +545,7 @@ ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) n += cmcf->phases[i].handlers.nelts; - for (j = cmcf->phases[i].handlers.nelts - 1; j >=0; j--) { + for (j = cmcf->phases[i].handlers.nelts - 1; j >= 0; j--) { ph->checker = checker; ph->handler = h[j]; ph->next = n; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 02059ef..57a4742 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -61,8 +61,6 @@ static char *ngx_http_core_directio(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static char *ngx_http_core_try_files(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); static char *ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, @@ -649,13 +647,6 @@ static ngx_command_t ngx_http_core_commands[] = { 0, NULL }, - { ngx_string("try_files"), - NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE, - ngx_http_core_try_files, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - { ngx_string("post_action"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_TAKE1, @@ -1158,223 +1149,6 @@ ngx_http_core_post_access_phase(ngx_http_request_t *r, } -ngx_int_t -ngx_http_core_try_files_phase(ngx_http_request_t *r, - ngx_http_phase_handler_t *ph) -{ - size_t len, root, alias, reserve, allocated; - u_char *p, *name; - ngx_str_t path, args; - ngx_uint_t test_dir; - ngx_http_try_file_t *tf; - ngx_open_file_info_t of; - ngx_http_script_code_pt code; - ngx_http_script_engine_t e; - ngx_http_core_loc_conf_t *clcf; - ngx_http_script_len_code_pt lcode; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "try files phase: %ui", r->phase_handler); - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - if (clcf->try_files == NULL) { - r->phase_handler++; - return NGX_AGAIN; - } - - allocated = 0; - root = 0; - name = NULL; - /* suppress MSVC warning */ - path.data = NULL; - - tf = clcf->try_files; - - alias = clcf->alias; - - for ( ;; ) { - - if (tf->lengths) { - ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); - - e.ip = tf->lengths->elts; - e.request = r; - - /* 1 is for terminating '\0' as in static names */ - len = 1; - - while (*(uintptr_t *) e.ip) { - lcode = *(ngx_http_script_len_code_pt *) e.ip; - len += lcode(&e); - } - - } else { - len = tf->name.len; - } - - if (!alias) { - reserve = len > r->uri.len ? len - r->uri.len : 0; - - } else if (alias == NGX_MAX_SIZE_T_VALUE) { - reserve = len; - - } else { - reserve = len > r->uri.len - alias ? len - (r->uri.len - alias) : 0; - } - - 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; - } - - if (tf->values == NULL) { - - /* tf->name.len includes the terminating '\0' */ - - ngx_memcpy(name, tf->name.data, tf->name.len); - - path.len = (name + tf->name.len - 1) - path.data; - - } else { - e.ip = tf->values->elts; - e.pos = name; - e.flushed = 1; - - while (*(uintptr_t *) e.ip) { - code = *(ngx_http_script_code_pt *) e.ip; - code((ngx_http_script_engine_t *) &e); - } - - path.len = e.pos - path.data; - - *e.pos = '\0'; - - if (alias && alias != NGX_MAX_SIZE_T_VALUE - && ngx_strncmp(name, r->uri.data, alias) == 0) - { - ngx_memmove(name, name + alias, len - alias); - path.len -= alias; - } - } - - test_dir = tf->test_dir; - - tf++; - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "trying to use %s: \"%s\" \"%s\"", - test_dir ? "dir" : "file", name, path.data); - - if (tf->lengths == NULL && tf->name.len == 0) { - - if (tf->code) { - ngx_http_finalize_request(r, tf->code); - return NGX_OK; - } - - path.len -= root; - path.data += root; - - if (path.data[0] == '@') { - (void) ngx_http_named_location(r, &path); - - } else { - ngx_http_split_args(r, &path, &args); - - (void) ngx_http_internal_redirect(r, &path, &args); - } - - ngx_http_finalize_request(r, NGX_DONE); - return NGX_OK; - } - - ngx_memzero(&of, sizeof(ngx_open_file_info_t)); - - of.read_ahead = clcf->read_ahead; - of.directio = clcf->directio; - of.valid = clcf->open_file_cache_valid; - of.min_uses = clcf->open_file_cache_min_uses; - of.test_only = 1; - 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) - { - if (of.err == 0) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_OK; - } - - if (of.err != NGX_ENOENT - && of.err != NGX_ENOTDIR - && of.err != NGX_ENAMETOOLONG) - { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, - "%s \"%s\" failed", of.failed, path.data); - } - - continue; - } - - if (of.is_dir != test_dir) { - continue; - } - - path.len -= root; - path.data += root; - - if (!alias) { - r->uri = path; - - } else if (alias == NGX_MAX_SIZE_T_VALUE) { - if (!test_dir) { - r->uri = path; - r->add_uri_to_alias = 1; - } - - } else { - name = r->uri.data; - - r->uri.len = alias + path.len; - r->uri.data = ngx_pnalloc(r->pool, r->uri.len); - if (r->uri.data == NULL) { - r->uri.len = 0; - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_OK; - } - - p = ngx_copy(r->uri.data, name, alias); - ngx_memcpy(p, path.data, path.len); - } - - ngx_http_set_exten(r); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "try file uri: \"%V\"", &r->uri); - - r->phase_handler++; - return NGX_AGAIN; - } - - /* not reached */ -} - - ngx_int_t ngx_http_core_content_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) @@ -3561,7 +3335,6 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf) * clcf->default_type = { 0, NULL }; * clcf->error_log = NULL; * clcf->error_pages = NULL; - * clcf->try_files = NULL; * clcf->client_body_path = NULL; * clcf->regex = NULL; * clcf->exact_match = 0; @@ -4884,89 +4657,6 @@ ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } -static char * -ngx_http_core_try_files(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_core_loc_conf_t *clcf = conf; - - ngx_str_t *value; - ngx_int_t code; - ngx_uint_t i, n; - ngx_http_try_file_t *tf; - ngx_http_script_compile_t sc; - ngx_http_core_main_conf_t *cmcf; - - if (clcf->try_files) { - return "is duplicate"; - } - - cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - - cmcf->try_files = 1; - - tf = ngx_pcalloc(cf->pool, cf->args->nelts * sizeof(ngx_http_try_file_t)); - if (tf == NULL) { - return NGX_CONF_ERROR; - } - - clcf->try_files = tf; - - value = cf->args->elts; - - for (i = 0; i < cf->args->nelts - 1; i++) { - - tf[i].name = value[i + 1]; - - if (tf[i].name.len > 0 - && tf[i].name.data[tf[i].name.len - 1] == '/' - && i + 2 < cf->args->nelts) - { - tf[i].test_dir = 1; - tf[i].name.len--; - tf[i].name.data[tf[i].name.len] = '\0'; - } - - n = ngx_http_script_variables_count(&tf[i].name); - - if (n) { - ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); - - sc.cf = cf; - sc.source = &tf[i].name; - sc.lengths = &tf[i].lengths; - sc.values = &tf[i].values; - sc.variables = n; - sc.complete_lengths = 1; - sc.complete_values = 1; - - if (ngx_http_script_compile(&sc) != NGX_OK) { - return NGX_CONF_ERROR; - } - - } else { - /* add trailing '\0' to length */ - tf[i].name.len++; - } - } - - if (tf[i - 1].name.data[0] == '=') { - - code = ngx_atoi(tf[i - 1].name.data + 1, tf[i - 1].name.len - 2); - - if (code == NGX_ERROR || code > 999) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid code \"%*s\"", - tf[i - 1].name.len - 1, tf[i - 1].name.data); - return NGX_CONF_ERROR; - } - - tf[i].code = code; - } - - return NGX_CONF_OK; -} - - static char * ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 5018da0..a6128b5 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -119,7 +119,8 @@ typedef enum { NGX_HTTP_ACCESS_PHASE, NGX_HTTP_POST_ACCESS_PHASE, - NGX_HTTP_TRY_FILES_PHASE, + NGX_HTTP_PRECONTENT_PHASE, + NGX_HTTP_CONTENT_PHASE, NGX_HTTP_LOG_PHASE @@ -172,8 +173,6 @@ typedef struct { ngx_array_t *ports; - ngx_uint_t try_files; /* unsigned try_files:1 */ - ngx_http_phase_t phases[NGX_HTTP_LOG_PHASE + 1]; } ngx_http_core_main_conf_t; @@ -296,16 +295,6 @@ typedef struct { } ngx_http_err_page_t; -typedef struct { - ngx_array_t *lengths; - ngx_array_t *values; - ngx_str_t name; - - unsigned code:10; - unsigned test_dir:1; -} ngx_http_try_file_t; - - struct ngx_http_core_loc_conf_s { ngx_str_t name; /* location name */ @@ -425,7 +414,6 @@ struct ngx_http_core_loc_conf_s { #endif ngx_array_t *error_pages; /* error_page */ - ngx_http_try_file_t *try_files; /* try_files */ ngx_path_t *client_body_temp_path; /* client_body_temp_path */ @@ -486,8 +474,6 @@ ngx_int_t ngx_http_core_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph); ngx_int_t ngx_http_core_post_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph); -ngx_int_t ngx_http_core_try_files_phase(ngx_http_request_t *r, - ngx_http_phase_handler_t *ph); ngx_int_t ngx_http_core_content_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph); diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index a823c51..3b2b68a 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -129,6 +129,7 @@ ngx_http_file_cache_init(ngx_shm_zone_t *shm_zone, void *data) if (shm_zone->shm.exists) { cache->sh = cache->shpool->data; cache->bsize = ngx_fs_bsize(cache->path->name.data); + cache->max_size /= cache->bsize; return NGX_OK; } diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index e8e5156..844054c 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -742,7 +742,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) return NGX_HTTP_PARSE_INVALID_REQUEST; } - r->http_major = r->http_major * 10 + ch - '0'; + r->http_major = r->http_major * 10 + (ch - '0'); if (r->http_major > 1) { return NGX_HTTP_PARSE_INVALID_VERSION; @@ -784,7 +784,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) return NGX_HTTP_PARSE_INVALID_REQUEST; } - r->http_minor = r->http_minor * 10 + ch - '0'; + r->http_minor = r->http_minor * 10 + (ch - '0'); break; case sw_spaces_after_digit: @@ -1518,7 +1518,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) case sw_quoted_second: if (ch >= '0' && ch <= '9') { - ch = (u_char) ((decoded << 4) + ch - '0'); + ch = (u_char) ((decoded << 4) + (ch - '0')); if (ch == '%' || ch == '#') { state = sw_usual; @@ -1536,7 +1536,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) c = (u_char) (ch | 0x20); if (c >= 'a' && c <= 'f') { - ch = (u_char) ((decoded << 4) + c - 'a' + 10); + ch = (u_char) ((decoded << 4) + (c - 'a') + 10); if (ch == '?') { state = sw_usual; @@ -1701,7 +1701,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'; + r->http_major = r->http_major * 10 + (ch - '0'); break; /* the first digit of minor HTTP version */ @@ -1729,7 +1729,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'; + r->http_minor = r->http_minor * 10 + (ch - '0'); break; /* HTTP status code */ @@ -1742,7 +1742,7 @@ ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b, return NGX_ERROR; } - status->code = status->code * 10 + ch - '0'; + status->code = status->code * 10 + (ch - '0'); if (++status->count == 3) { state = sw_space_after_status; diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index f7f3e97..421004a 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -537,6 +537,7 @@ struct ngx_http_request_s { unsigned main_filter_need_in_memory:1; unsigned filter_need_in_memory:1; unsigned filter_need_temporary:1; + unsigned preserve_body:1; unsigned allow_ranges:1; unsigned subrequest_ranges:1; unsigned single_range:1; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index c394b29..6a2b322 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -427,7 +427,7 @@ static ngx_http_variable_t ngx_http_upstream_vars[] = { { ngx_string("upstream_cookie_"), NULL, ngx_http_upstream_cookie_variable, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; @@ -1077,6 +1077,10 @@ ngx_http_upstream_cache_background_update(ngx_http_request_t *r, return NGX_OK; } + if (r == r->main) { + r->preserve_body = 1; + } + if (ngx_http_subrequest(r, &r->uri, &r->args, &sr, NULL, NGX_HTTP_SUBREQUEST_CLONE |NGX_HTTP_SUBREQUEST_BACKGROUND) @@ -2857,7 +2861,9 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) u->pipe->downstream_error = 1; } - if (r->request_body && r->request_body->temp_file) { + if (r->request_body && r->request_body->temp_file + && r == r->main && !r->preserve_body) + { ngx_pool_run_cleanup_file(r->pool, r->request_body->temp_file->file.fd); r->request_body->temp_file->file.fd = NGX_INVALID_FILE; } @@ -4503,7 +4509,7 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r, } if (*p >= '0' && *p <= '9') { - n = n * 10 + *p - '0'; + n = n * 10 + (*p - '0'); continue; } @@ -4531,7 +4537,7 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r, } if (*p >= '0' && *p <= '9') { - n = n * 10 + *p - '0'; + n = n * 10 + (*p - '0'); continue; } @@ -4554,7 +4560,7 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r, } if (*p >= '0' && *p <= '9') { - n = n * 10 + *p - '0'; + n = n * 10 + (*p - '0'); continue; } diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index fbc9ffa..afeb4ce 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -376,7 +376,7 @@ static ngx_http_variable_t ngx_http_core_variables[] = { { ngx_string("arg_"), NULL, ngx_http_variable_argument, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/ngx_http_variables.h b/src/http/ngx_http_variables.h index df337de..f3f7f3c 100644 --- a/src/http/ngx_http_variables.h +++ b/src/http/ngx_http_variables.h @@ -43,6 +43,8 @@ struct ngx_http_variable_s { ngx_uint_t index; }; +#define ngx_http_null_variable { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_variable_t *ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags); diff --git a/src/http/v2/ngx_http_v2_module.c b/src/http/v2/ngx_http_v2_module.c index 032abcb..7f7dab2 100644 --- a/src/http/v2/ngx_http_v2_module.c +++ b/src/http/v2/ngx_http_v2_module.c @@ -225,7 +225,7 @@ static ngx_http_variable_t ngx_http_v2_vars[] = { { ngx_string("http2"), NULL, ngx_http_v2_variable, 0, 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/misc/ngx_google_perftools_module.c b/src/misc/ngx_google_perftools_module.c index f2f8221..381f3d1 100644 --- a/src/misc/ngx_google_perftools_module.c +++ b/src/misc/ngx_google_perftools_module.c @@ -36,7 +36,7 @@ static ngx_command_t ngx_google_perftools_commands[] = { offsetof(ngx_google_perftools_conf_t, profiles), NULL }, - ngx_null_command + ngx_null_command }; diff --git a/src/stream/ngx_stream_geoip_module.c b/src/stream/ngx_stream_geoip_module.c index f694033..6507b71 100644 --- a/src/stream/ngx_stream_geoip_module.c +++ b/src/stream/ngx_stream_geoip_module.c @@ -210,7 +210,7 @@ static ngx_stream_variable_t ngx_stream_geoip_vars[] = { ngx_stream_geoip_city_int_variable, offsetof(GeoIPRecord, area_code), 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_realip_module.c b/src/stream/ngx_stream_realip_module.c index 1266605..57b1ac2 100644 --- a/src/stream/ngx_stream_realip_module.c +++ b/src/stream/ngx_stream_realip_module.c @@ -89,7 +89,7 @@ static ngx_stream_variable_t ngx_stream_realip_vars[] = { { ngx_string("realip_remote_port"), NULL, ngx_stream_realip_remote_port_variable, 0, 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index da26a41..010b98b 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -273,7 +273,7 @@ static ngx_stream_variable_t ngx_stream_ssl_vars[] = { { ngx_string("ssl_client_v_remain"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_client_v_remain, NGX_STREAM_VAR_CHANGEABLE, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_ssl_preread_module.c b/src/stream/ngx_stream_ssl_preread_module.c index 2040b4f..e3d11fd 100644 --- a/src/stream/ngx_stream_ssl_preread_module.c +++ b/src/stream/ngx_stream_ssl_preread_module.c @@ -85,7 +85,7 @@ static ngx_stream_variable_t ngx_stream_ssl_preread_vars[] = { { ngx_string("ssl_preread_server_name"), NULL, ngx_stream_ssl_preread_server_name_variable, 0, 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_upstream.c b/src/stream/ngx_stream_upstream.c index c9e1784..7feac43 100644 --- a/src/stream/ngx_stream_upstream.c +++ b/src/stream/ngx_stream_upstream.c @@ -100,7 +100,7 @@ static ngx_stream_variable_t ngx_stream_upstream_vars[] = { ngx_stream_upstream_bytes_variable, 1, NGX_STREAM_VAR_NOCACHEABLE, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_upstream_zone_module.c b/src/stream/ngx_stream_upstream_zone_module.c index 07ab88d..4f72188 100644 --- a/src/stream/ngx_stream_upstream_zone_module.c +++ b/src/stream/ngx_stream_upstream_zone_module.c @@ -16,6 +16,8 @@ static ngx_int_t ngx_stream_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data); static ngx_stream_upstream_rr_peers_t *ngx_stream_upstream_zone_copy_peers( ngx_slab_pool_t *shpool, ngx_stream_upstream_srv_conf_t *uscf); +static ngx_stream_upstream_rr_peer_t *ngx_stream_upstream_zone_copy_peer( + ngx_stream_upstream_rr_peers_t *peers, ngx_stream_upstream_rr_peer_t *src); static ngx_command_t ngx_stream_upstream_zone_commands[] = { @@ -182,6 +184,7 @@ static ngx_stream_upstream_rr_peers_t * ngx_stream_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_stream_upstream_srv_conf_t *uscf) { + ngx_str_t *name; ngx_stream_upstream_rr_peer_t *peer, **peerp; ngx_stream_upstream_rr_peers_t *peers, *backup; @@ -192,18 +195,30 @@ ngx_stream_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_memcpy(peers, uscf->peer.data, sizeof(ngx_stream_upstream_rr_peers_t)); + name = ngx_slab_alloc(shpool, sizeof(ngx_str_t)); + if (name == NULL) { + return NULL; + } + + name->data = ngx_slab_alloc(shpool, peers->name->len); + if (name->data == NULL) { + return NULL; + } + + ngx_memcpy(name->data, peers->name->data, peers->name->len); + name->len = peers->name->len; + + peers->name = name; + peers->shpool = shpool; for (peerp = &peers->peer; *peerp; peerp = &peer->next) { /* pool is unlocked */ - peer = ngx_slab_calloc_locked(shpool, - sizeof(ngx_stream_upstream_rr_peer_t)); + peer = ngx_stream_upstream_zone_copy_peer(peers, *peerp); if (peer == NULL) { return NULL; } - ngx_memcpy(peer, *peerp, sizeof(ngx_stream_upstream_rr_peer_t)); - *peerp = peer; } @@ -218,18 +233,17 @@ ngx_stream_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_memcpy(backup, peers->next, sizeof(ngx_stream_upstream_rr_peers_t)); + backup->name = name; + backup->shpool = shpool; for (peerp = &backup->peer; *peerp; peerp = &peer->next) { /* pool is unlocked */ - peer = ngx_slab_calloc_locked(shpool, - sizeof(ngx_stream_upstream_rr_peer_t)); + peer = ngx_stream_upstream_zone_copy_peer(backup, *peerp); if (peer == NULL) { return NULL; } - ngx_memcpy(peer, *peerp, sizeof(ngx_stream_upstream_rr_peer_t)); - *peerp = peer; } @@ -241,3 +255,68 @@ done: return peers; } + + +static ngx_stream_upstream_rr_peer_t * +ngx_stream_upstream_zone_copy_peer(ngx_stream_upstream_rr_peers_t *peers, + ngx_stream_upstream_rr_peer_t *src) +{ + ngx_slab_pool_t *pool; + ngx_stream_upstream_rr_peer_t *dst; + + pool = peers->shpool; + + dst = ngx_slab_calloc_locked(pool, sizeof(ngx_stream_upstream_rr_peer_t)); + if (dst == NULL) { + return NULL; + } + + if (src) { + ngx_memcpy(dst, src, sizeof(ngx_stream_upstream_rr_peer_t)); + dst->sockaddr = NULL; + dst->name.data = NULL; + dst->server.data = NULL; + } + + dst->sockaddr = ngx_slab_calloc_locked(pool, NGX_SOCKADDRLEN); + if (dst->sockaddr == NULL) { + goto failed; + } + + dst->name.data = ngx_slab_calloc_locked(pool, NGX_SOCKADDR_STRLEN); + if (dst->name.data == NULL) { + goto failed; + } + + if (src) { + ngx_memcpy(dst->sockaddr, src->sockaddr, src->socklen); + ngx_memcpy(dst->name.data, src->name.data, src->name.len); + + dst->server.data = ngx_slab_alloc_locked(pool, src->server.len); + if (dst->server.data == NULL) { + goto failed; + } + + ngx_memcpy(dst->server.data, src->server.data, src->server.len); + } + + return dst; + +failed: + + if (dst->server.data) { + ngx_slab_free_locked(pool, dst->server.data); + } + + if (dst->name.data) { + ngx_slab_free_locked(pool, dst->name.data); + } + + if (dst->sockaddr) { + ngx_slab_free_locked(pool, dst->sockaddr); + } + + ngx_slab_free_locked(pool, dst); + + return NULL; +} diff --git a/src/stream/ngx_stream_variables.c b/src/stream/ngx_stream_variables.c index 5d15f3a..45d6e60 100644 --- a/src/stream/ngx_stream_variables.c +++ b/src/stream/ngx_stream_variables.c @@ -111,7 +111,7 @@ static ngx_stream_variable_t ngx_stream_core_variables[] = { { ngx_string("protocol"), NULL, ngx_stream_variable_protocol, 0, 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_variables.h b/src/stream/ngx_stream_variables.h index 8155111..4ead2a6 100644 --- a/src/stream/ngx_stream_variables.h +++ b/src/stream/ngx_stream_variables.h @@ -43,6 +43,8 @@ struct ngx_stream_variable_s { ngx_uint_t index; }; +#define ngx_stream_null_variable { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_variable_t *ngx_stream_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags); From ef8a520c389d205a8e72414aedb4fe133161f41e Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 14:43:20 +0300 Subject: [PATCH 255/651] Add a simple lua autopkgtest --- debian/tests/control | 4 ++++ debian/tests/lua | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 debian/tests/lua diff --git a/debian/tests/control b/debian/tests/control index d276e4f..b491482 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -6,6 +6,10 @@ Tests: ec-x25519 Restrictions: allow-stderr isolation-container needs-root Depends: nginx-light, ssl-cert, curl +Tests: lua +Restrictions: allow-stderr isolation-container needs-root +Depends: nginx-extras, curl + Tests: full-simple Restrictions: allow-stderr isolation-container Depends: nginx-full, curl diff --git a/debian/tests/lua b/debian/tests/lua new file mode 100644 index 0000000..396d8a9 --- /dev/null +++ b/debian/tests/lua @@ -0,0 +1,18 @@ +#!/bin/bash + +set -e + +rm /etc/nginx/sites-enabled/default +cat < "/etc/nginx/sites-enabled/lua" +server { + listen 80 default_server; + + location /ping { + content_by_lua 'ngx.say("PONG")'; + } +} +EOF + +nginx -t +nginx -s reload +curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ping From 2a34dcb90fc48ecf0d078d6b34132dacbe387ce2 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 13:50:13 +0300 Subject: [PATCH 256/651] Discover LuaJIT 2.1 (FTBFS) Closes: #873319 --- debian/modules/README.Modules-versions | 1 + .../nginx-lua/discover-luajit-2.1.patch | 47 +++++++++++++++++++ debian/modules/patches/nginx-lua/series | 1 + 3 files changed, 49 insertions(+) create mode 100644 debian/modules/patches/nginx-lua/discover-luajit-2.1.patch diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index c336064..ef2bb91 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -26,6 +26,7 @@ README for Modules versions Version: v0.10.7 Patch: openssl-1.1.0.patch Patch: build-nginx-1.11.11.patch + Patch: discover-luajit-2.1.patch nginx-upstream-fair Homepage: https://github.com/gnosek/nginx-upstream-fair diff --git a/debian/modules/patches/nginx-lua/discover-luajit-2.1.patch b/debian/modules/patches/nginx-lua/discover-luajit-2.1.patch new file mode 100644 index 0000000..4fcbbac --- /dev/null +++ b/debian/modules/patches/nginx-lua/discover-luajit-2.1.patch @@ -0,0 +1,47 @@ +From 0bb37a210d165870f7c4c9ad85e1751bdc1aec8f Mon Sep 17 00:00:00 2001 +From: Christos Trochalakis +Date: Mon, 28 Aug 2017 13:48:08 +0300 +Subject: [PATCH] Inventorize LuaJIT 2.1 + +--- + config | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/config b/config +index 01a6b3c3..5819c00f 100644 +--- a/config ++++ b/config +@@ -281,6 +281,30 @@ END + fi + . auto/feature + fi ++ ++ if [ $ngx_found = no ]; then ++ # LuaJIT-2.1, try with -ldl ++ ngx_feature="LuaJIT 2.1 library in /usr/" ++ ngx_feature_path="/usr/include/luajit-2.1" ++ if [ $NGX_RPATH = YES ]; then ++ ngx_feature_libs="-R/usr/lib -L/usr/lib -lm -lluajit-5.1 -ldl" ++ else ++ ngx_feature_libs="-L/usr/lib -lm -lluajit-5.1 -ldl" ++ fi ++ . auto/feature ++ fi ++ ++ if [ $ngx_found = no ]; then ++ # Gentoo with LuaJIT 2.1 ++ ngx_feature="LuaJIT library in /usr/" ++ ngx_feature_path="/usr/include/luajit-2.1" ++ if [ $NGX_RPATH = YES ]; then ++ ngx_feature_libs="-R/usr/lib -L/usr/lib -lm -lluajit-5.1" ++ else ++ ngx_feature_libs="-L/usr/lib -lm -lluajit-5.1" ++ fi ++ . auto/feature ++ fi + fi + fi + +-- +2.14.1 + diff --git a/debian/modules/patches/nginx-lua/series b/debian/modules/patches/nginx-lua/series index bf7b34f..8edeaf5 100644 --- a/debian/modules/patches/nginx-lua/series +++ b/debian/modules/patches/nginx-lua/series @@ -1,2 +1,3 @@ openssl-1.1.0.patch build-nginx-1.1.11.patch +discover-luajit-2.1.patch From 75a3ff5eaa1d1708d6c89940a36506860d5fbbbd Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 15:08:10 +0300 Subject: [PATCH 257/651] Update nginx-lua to v0.10.10 Fixes an issue with LuaJIT v2.1, luaL_getn() is no longer available. --- debian/modules/README.Modules-versions | 2 +- debian/modules/nginx-lua/README.markdown | 275 ++++++--- debian/modules/nginx-lua/config | 29 +- .../modules/nginx-lua/doc/HttpLuaModule.wiki | 415 ++++++++----- .../nginx-lua/src/api/ngx_http_lua_api.h | 2 +- .../modules/nginx-lua/src/ngx_http_lua_api.c | 7 +- .../modules/nginx-lua/src/ngx_http_lua_args.c | 2 +- .../nginx-lua/src/ngx_http_lua_balancer.c | 15 +- .../nginx-lua/src/ngx_http_lua_common.h | 27 +- .../nginx-lua/src/ngx_http_lua_control.c | 4 +- .../nginx-lua/src/ngx_http_lua_directive.c | 67 ++ .../nginx-lua/src/ngx_http_lua_directive.h | 3 +- .../nginx-lua/src/ngx_http_lua_headers.c | 124 +++- .../nginx-lua/src/ngx_http_lua_headers.h | 3 + .../modules/nginx-lua/src/ngx_http_lua_log.c | 117 ++++ .../modules/nginx-lua/src/ngx_http_lua_log.h | 4 + .../nginx-lua/src/ngx_http_lua_log_ringbuf.c | 225 +++++++ .../nginx-lua/src/ngx_http_lua_log_ringbuf.h | 31 + .../nginx-lua/src/ngx_http_lua_module.c | 70 +-- .../nginx-lua/src/ngx_http_lua_regex.c | 82 ++- .../nginx-lua/src/ngx_http_lua_regex.h | 2 + .../nginx-lua/src/ngx_http_lua_semaphore.c | 11 +- .../nginx-lua/src/ngx_http_lua_sleep.c | 30 +- .../nginx-lua/src/ngx_http_lua_socket_tcp.c | 25 +- .../modules/nginx-lua/src/ngx_http_lua_ssl.h | 6 +- .../nginx-lua/src/ngx_http_lua_ssl_certby.c | 27 +- .../nginx-lua/src/ngx_http_lua_ssl_ocsp.c | 1 - .../src/ngx_http_lua_ssl_session_fetchby.c | 14 +- .../src/ngx_http_lua_ssl_session_storeby.c | 8 +- .../nginx-lua/src/ngx_http_lua_string.c | 9 +- .../nginx-lua/src/ngx_http_lua_timer.c | 209 ++++++- .../modules/nginx-lua/src/ngx_http_lua_util.c | 52 +- .../nginx-lua/src/ngx_http_lua_worker.c | 45 ++ debian/modules/nginx-lua/t/000--init.t | 1 - debian/modules/nginx-lua/t/000-sanity.t | 1 - debian/modules/nginx-lua/t/001-set.t | 1 - debian/modules/nginx-lua/t/002-content.t | 1 - debian/modules/nginx-lua/t/003-errors.t | 1 - debian/modules/nginx-lua/t/004-require.t | 1 - debian/modules/nginx-lua/t/005-exit.t | 1 - debian/modules/nginx-lua/t/006-escape.t | 20 +- debian/modules/nginx-lua/t/007-md5.t | 1 - debian/modules/nginx-lua/t/008-today.t | 1 - debian/modules/nginx-lua/t/009-log.t | 1 - debian/modules/nginx-lua/t/010-request_body.t | 1 - debian/modules/nginx-lua/t/012-now.t | 1 - debian/modules/nginx-lua/t/014-bugs.t | 3 +- debian/modules/nginx-lua/t/016-resp-header.t | 70 ++- debian/modules/nginx-lua/t/017-exec.t | 1 - debian/modules/nginx-lua/t/018-ndk.t | 1 - debian/modules/nginx-lua/t/019-const.t | 1 - debian/modules/nginx-lua/t/021-cookie-time.t | 1 - debian/modules/nginx-lua/t/022-redirect.t | 53 +- .../nginx-lua/t/023-rewrite/client-abort.t | 1 - debian/modules/nginx-lua/t/023-rewrite/exec.t | 1 - debian/modules/nginx-lua/t/023-rewrite/exit.t | 1 - .../modules/nginx-lua/t/023-rewrite/mixed.t | 1 - .../nginx-lua/t/023-rewrite/multi-capture.t | 1 - .../nginx-lua/t/023-rewrite/on-abort.t | 1 - .../nginx-lua/t/023-rewrite/redirect.t | 1 - .../nginx-lua/t/023-rewrite/req-body.t | 1 - .../nginx-lua/t/023-rewrite/req-socket.t | 1 - .../nginx-lua/t/023-rewrite/request_body.t | 1 - .../modules/nginx-lua/t/023-rewrite/sanity.t | 1 - .../modules/nginx-lua/t/023-rewrite/sleep.t | 1 - .../t/023-rewrite/socket-keepalive.t | 1 - .../nginx-lua/t/023-rewrite/subrequest.t | 1 - .../t/023-rewrite/tcp-socket-timeout.t | 29 +- .../nginx-lua/t/023-rewrite/tcp-socket.t | 9 +- .../nginx-lua/t/023-rewrite/unix-socket.t | 1 - .../t/023-rewrite/uthread-redirect.t | 1 - .../nginx-lua/t/023-rewrite/uthread-spawn.t | 1 - debian/modules/nginx-lua/t/024-access/auth.t | 1 - .../nginx-lua/t/024-access/client-abort.t | 1 - debian/modules/nginx-lua/t/024-access/exit.t | 1 - .../nginx-lua/t/024-access/multi-capture.t | 1 - .../modules/nginx-lua/t/024-access/on-abort.t | 1 - .../modules/nginx-lua/t/024-access/redirect.t | 1 - .../modules/nginx-lua/t/024-access/req-body.t | 1 - .../nginx-lua/t/024-access/request_body.t | 1 - .../modules/nginx-lua/t/024-access/sanity.t | 1 - .../modules/nginx-lua/t/024-access/satisfy.t | 1 - debian/modules/nginx-lua/t/024-access/sleep.t | 1 - .../nginx-lua/t/024-access/subrequest.t | 1 - .../nginx-lua/t/024-access/uthread-exec.t | 1 - .../nginx-lua/t/024-access/uthread-exit.t | 1 - .../nginx-lua/t/024-access/uthread-redirect.t | 1 - .../nginx-lua/t/024-access/uthread-spawn.t | 1 - debian/modules/nginx-lua/t/025-codecache.t | 1 - debian/modules/nginx-lua/t/026-mysql.t | 5 +- .../modules/nginx-lua/t/027-multi-capture.t | 1 - debian/modules/nginx-lua/t/029-http-time.t | 1 - debian/modules/nginx-lua/t/030-uri-args.t | 18 +- debian/modules/nginx-lua/t/031-post-args.t | 2 +- debian/modules/nginx-lua/t/032-iolist.t | 1 - debian/modules/nginx-lua/t/033-ctx.t | 1 - debian/modules/nginx-lua/t/034-match.t | 4 +- debian/modules/nginx-lua/t/035-gmatch.t | 5 +- debian/modules/nginx-lua/t/036-sub.t | 4 +- debian/modules/nginx-lua/t/037-gsub.t | 4 +- debian/modules/nginx-lua/t/038-match-o.t | 1 - debian/modules/nginx-lua/t/039-sub-o.t | 1 - debian/modules/nginx-lua/t/040-gsub-o.t | 1 - .../modules/nginx-lua/t/041-header-filter.t | 1 - debian/modules/nginx-lua/t/042-crc32.t | 1 - debian/modules/nginx-lua/t/045-ngx-var.t | 9 +- debian/modules/nginx-lua/t/046-hmac.t | 1 - debian/modules/nginx-lua/t/047-match-jit.t | 1 - debian/modules/nginx-lua/t/048-match-dfa.t | 1 - debian/modules/nginx-lua/t/049-gmatch-jit.t | 1 - debian/modules/nginx-lua/t/051-sub-jit.t | 1 - debian/modules/nginx-lua/t/053-gsub-jit.t | 1 - debian/modules/nginx-lua/t/055-subreq-vars.t | 1 - debian/modules/nginx-lua/t/056-flush.t | 1 - .../modules/nginx-lua/t/057-flush-timeout.t | 1 - debian/modules/nginx-lua/t/058-tcp-socket.t | 80 ++- .../modules/nginx-lua/t/060-lua-memcached.t | 1 - debian/modules/nginx-lua/t/061-lua-redis.t | 1 - debian/modules/nginx-lua/t/062-count.t | 2 +- debian/modules/nginx-lua/t/063-abort.t | 1 - debian/modules/nginx-lua/t/064-pcall.t | 1 - .../nginx-lua/t/065-tcp-socket-timeout.t | 41 +- .../nginx-lua/t/066-socket-receiveuntil.t | 1 - debian/modules/nginx-lua/t/067-req-socket.t | 1 - debian/modules/nginx-lua/t/069-null.t | 1 - debian/modules/nginx-lua/t/071-idle-socket.t | 1 - .../modules/nginx-lua/t/072-conditional-get.t | 1 - debian/modules/nginx-lua/t/073-backtrace.t | 1 - debian/modules/nginx-lua/t/074-prefix-var.t | 1 - debian/modules/nginx-lua/t/075-logby.t | 1 - debian/modules/nginx-lua/t/077-sleep.t | 99 ++- debian/modules/nginx-lua/t/078-hup-vars.t | 1 - .../nginx-lua/t/079-unused-directives.t | 1 - debian/modules/nginx-lua/t/080-hup-shdict.t | 1 - .../modules/nginx-lua/t/083-bad-sock-self.t | 1 - .../nginx-lua/t/084-inclusive-receiveuntil.t | 1 - debian/modules/nginx-lua/t/085-if.t | 1 - debian/modules/nginx-lua/t/086-init-by.t | 19 +- debian/modules/nginx-lua/t/087-udp-socket.t | 9 +- debian/modules/nginx-lua/t/088-req-method.t | 1 - debian/modules/nginx-lua/t/089-phase.t | 1 - .../nginx-lua/t/090-log-socket-errors.t | 19 +- debian/modules/nginx-lua/t/091-coroutine.t | 9 +- debian/modules/nginx-lua/t/092-eof.t | 1 - .../modules/nginx-lua/t/093-uthread-spawn.t | 1 - debian/modules/nginx-lua/t/094-uthread-exit.t | 1 - debian/modules/nginx-lua/t/095-uthread-exec.t | 1 - .../nginx-lua/t/096-uthread-redirect.t | 1 - .../modules/nginx-lua/t/097-uthread-rewrite.t | 1 - debian/modules/nginx-lua/t/098-uthread-wait.t | 1 - debian/modules/nginx-lua/t/100-client-abort.t | 1 - debian/modules/nginx-lua/t/101-on-abort.t | 1 - .../modules/nginx-lua/t/102-req-start-time.t | 1 - debian/modules/nginx-lua/t/103-req-http-ver.t | 1 - .../modules/nginx-lua/t/104-req-raw-header.t | 1 - debian/modules/nginx-lua/t/105-pressure.t | 1 - debian/modules/nginx-lua/t/106-timer.t | 1 - debian/modules/nginx-lua/t/107-timer-errors.t | 1 - debian/modules/nginx-lua/t/108-timer-safe.t | 1 - debian/modules/nginx-lua/t/109-timer-hup.t | 1 - debian/modules/nginx-lua/t/110-etag.t | 1 - .../modules/nginx-lua/t/111-req-header-ua.t | 1 - .../modules/nginx-lua/t/112-req-header-conn.t | 1 - .../nginx-lua/t/113-req-header-cookie.t | 1 - .../modules/nginx-lua/t/115-quote-sql-str.t | 1 - .../modules/nginx-lua/t/116-raw-req-socket.t | 1 - .../nginx-lua/t/117-raw-req-socket-timeout.t | 1 - .../modules/nginx-lua/t/119-config-prefix.t | 1 - debian/modules/nginx-lua/t/120-re-find.t | 30 +- debian/modules/nginx-lua/t/121-version.t | 1 - debian/modules/nginx-lua/t/122-worker.t | 1 - debian/modules/nginx-lua/t/123-lua-path.t | 1 - debian/modules/nginx-lua/t/124-init-worker.t | 2 +- .../modules/nginx-lua/t/125-configure-args.t | 1 - debian/modules/nginx-lua/t/126-shdict-frag.t | 1 - debian/modules/nginx-lua/t/127-uthread-kill.t | 3 +- .../nginx-lua/t/128-duplex-tcp-socket.t | 23 +- debian/modules/nginx-lua/t/129-ssl-socket.t | 573 +++++++++--------- debian/modules/nginx-lua/t/130-internal-api.t | 1 - debian/modules/nginx-lua/t/135-worker-id.t | 2 +- debian/modules/nginx-lua/t/137-req-misc.t | 1 - debian/modules/nginx-lua/t/138-balancer.t | 99 ++- debian/modules/nginx-lua/t/139-ssl-cert-by.t | 296 ++++++++- debian/modules/nginx-lua/t/140-ssl-c-api.t | 8 +- debian/modules/nginx-lua/t/141-luajit.t | 3 +- .../nginx-lua/t/142-ssl-session-store.t | 24 +- .../nginx-lua/t/143-ssl-session-fetch.t | 24 +- debian/modules/nginx-lua/t/146-malloc-trim.t | 41 +- .../nginx-lua/t/147-tcp-socket-timeouts.t | 2 +- .../nginx-lua/t/150-fake-delayed-load.t | 56 ++ debian/modules/nginx-lua/t/151-initby-hup.t | 168 +++++ debian/modules/nginx-lua/t/152-timer-every.t | 385 ++++++++++++ .../modules/nginx-lua/t/153-semaphore-hup.t | 154 +++++ debian/modules/nginx-lua/t/154-semaphore.t | 118 ++++ debian/modules/nginx-lua/t/cert/comodo-ca.crt | 29 + debian/modules/nginx-lua/t/cert/startcom.crt | 87 --- .../t/data/fake-delayed-load-module/config | 3 + .../ngx_http_lua_fake_delayed_load_module.c | 77 +++ .../t/data/fake-module/ngx_http_fake_module.c | 3 +- debian/modules/nginx-lua/util/build.sh | 1 + debian/modules/nginx-lua/util/gdbinit | 415 ------------- debian/modules/nginx-lua/util/reindex | 64 -- debian/modules/nginx-lua/valgrind.suppress | 15 + 203 files changed, 3745 insertions(+), 1536 deletions(-) create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.c create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.h create mode 100644 debian/modules/nginx-lua/t/150-fake-delayed-load.t create mode 100644 debian/modules/nginx-lua/t/151-initby-hup.t create mode 100644 debian/modules/nginx-lua/t/152-timer-every.t create mode 100644 debian/modules/nginx-lua/t/153-semaphore-hup.t create mode 100644 debian/modules/nginx-lua/t/154-semaphore.t create mode 100644 debian/modules/nginx-lua/t/cert/comodo-ca.crt delete mode 100644 debian/modules/nginx-lua/t/cert/startcom.crt create mode 100644 debian/modules/nginx-lua/t/data/fake-delayed-load-module/config create mode 100644 debian/modules/nginx-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c delete mode 100644 debian/modules/nginx-lua/util/gdbinit delete mode 100755 debian/modules/nginx-lua/util/reindex diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index ef2bb91..6b581cd 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -23,7 +23,7 @@ README for Modules versions nginx-lua Homepage: https://github.com/openresty/lua-nginx-module - Version: v0.10.7 + Version: v0.10.10 Patch: openssl-1.1.0.patch Patch: build-nginx-1.11.11.patch Patch: discover-luajit-2.1.patch diff --git a/debian/modules/nginx-lua/README.markdown b/debian/modules/nginx-lua/README.markdown index 3699a72..fac3a0d 100644 --- a/debian/modules/nginx-lua/README.markdown +++ b/debian/modules/nginx-lua/README.markdown @@ -62,7 +62,7 @@ Production ready. Version ======= -This document describes ngx_lua [v0.10.7](https://github.com/openresty/lua-nginx-module/tags) released on 4 November 2016. +This document describes ngx_lua [v0.10.10](https://github.com/openresty/lua-nginx-module/tags) released on 8 August 2017. Synopsis ======== @@ -150,7 +150,7 @@ Synopsis } # use nginx var in code path - # WARNING: contents in nginx var must be carefully filtered, + # CAUTION: contents in nginx var must be carefully filtered, # otherwise there'll be great security risk! location ~ ^/app/([-_a-zA-Z0-9/]+) { set $path $1; @@ -263,7 +263,7 @@ Nginx cores older than 1.6.0 (exclusive) are *not* supported. Installation ============ -It is highly recommended to use the [OpenResty bundle](http://openresty.org) that bundles Nginx, ngx_lua, LuaJIT 2.0/2.1 (or the optional standard Lua 5.1 interpreter), as well as a package of powerful companion Nginx modules. The basic installation step is a simple command: `./configure --with-luajit && make && make install`. +It is *highly* recommended to use [OpenResty releases](http://openresty.org) which integrate Nginx, ngx_lua, LuaJIT 2.1, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. Alternatively, ngx_lua can be manually compiled into Nginx: @@ -298,6 +298,12 @@ Build the source with this module: --add-module=/path/to/ngx_devel_kit \ --add-module=/path/to/lua-nginx-module + # Note that you may also want to add `./configure` options which are used in your + # current nginx build. + # You can get usually those options using command nginx -V + + # you can change the parallism number 2 below to fit the number of spare CPU cores in your + # machine. make -j2 make install ``` @@ -312,8 +318,9 @@ Starting from NGINX 1.9.11, you can also compile this module as a dynamic module directive, for example, ```nginx -load_module /path/to/modules/ndk_http_module.so; # assuming NDK is built as a dynamic module too -load_module /path/to/modules/ngx_http_lua_module.so; + + load_module /path/to/modules/ndk_http_module.so; # assuming NDK is built as a dynamic module too + load_module /path/to/modules/ngx_http_lua_module.so; ``` [Back to TOC](#table-of-contents) @@ -406,14 +413,14 @@ Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible wi ```bash - /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.luac + /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.ljbc ``` The `-bg` option can be used to include debug information in the LuaJIT bytecode file: ```bash - /path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.luac + /path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.ljbc ``` Please refer to the official LuaJIT documentation on the `-b` option for more details: @@ -623,9 +630,9 @@ Known Issues TCP socket connect operation issues ----------------------------------- -The [tcpsock:connect](#tcpsockconnect) method may indicate `success` despite connection failures such as with `Connection Refused` errors. +The [tcpsock:connect](#tcpsockconnect) method may indicate `success` despite connection failures such as with `Connection Refused` errors. -However, later attempts to manipulate the cosocket object will fail and return the actual error status message generated by the failed connect operation. +However, later attempts to manipulate the cosocket object will fail and return the actual error status message generated by the failed connect operation. This issue is due to limitations in the Nginx event model and only appears to affect Mac OS X. @@ -656,15 +663,29 @@ instead of the old deprecated form: Here is the reason: by design, the global environment has exactly the same lifetime as the Nginx request handler associated with it. Each request handler has its own set of Lua global variables and that is the idea of request isolation. The Lua module is actually loaded by the first Nginx request handler and is cached by the `require()` built-in in the `package.loaded` table for later reference, and the `module()` builtin used by some Lua modules has the side effect of setting a global variable to the loaded module table. But this global variable will be cleared at the end of the request handler, and every subsequent request handler all has its own (clean) global environment. So one will get Lua exception for accessing the `nil` value. -Generally, use of Lua global variables is a really really bad idea in the context of ngx_lua because +The use of Lua global variables is a generally inadvisable in the ngx_lua context as: -1. misuse of Lua globals has very bad side effects for concurrent requests when these variables are actually supposed to be local only, -1. Lua global variables require Lua table look-up in the global environment (which is just a Lua table), which is kinda expensive, and -1. some Lua global variable references are just typos, which are hard to debug. +1. the misuse of Lua globals has detrimental side effects on concurrent requests when such variables should instead be local in scope, +1. Lua global variables require Lua table look-ups in the global environment which is computationally expensive, and +1. some Lua global variable references may include typing errors which make such difficult to debug. -It's *highly* recommended to always declare them via "local" in the scope that is reasonable. +It is therefore *highly* recommended to always declare such within an appropriate local scope instead. -To find out all the uses of Lua global variables in your Lua code, you can run the [lua-releng tool](https://github.com/openresty/nginx-devel-utils/blob/master/lua-releng) across all your .lua source files: +```lua + + -- Avoid + foo = 123 + -- Recommended + local foo = 123 + + -- Avoid + function foo() return 123 end + -- Recommended + local function foo() return 123 end +``` + + +To find all instances of Lua global variables in your Lua code, run the [lua-releng tool](https://github.com/openresty/nginx-devel-utils/blob/master/lua-releng) across all `.lua` source files: $ lua-releng Checking use of Lua global variables in file lib/foo/bar.lua ... @@ -709,28 +730,27 @@ will not work as expected. Cosockets Not Available Everywhere ---------------------------------- -Due the internal limitations in the nginx core, the cosocket API are disabled in the following contexts: [set_by_lua*](#set_by_lua), [log_by_lua*](#log_by_lua), [header_filter_by_lua*](#header_filter_by_lua), and [body_filter_by_lua](#body_filter_by_lua). +Due to internal limitations in the nginx core, the cosocket API is disabled in the following contexts: [set_by_lua*](#set_by_lua), [log_by_lua*](#log_by_lua), [header_filter_by_lua*](#header_filter_by_lua), and [body_filter_by_lua](#body_filter_by_lua). The cosockets are currently also disabled in the [init_by_lua*](#init_by_lua) and [init_worker_by_lua*](#init_worker_by_lua) directive contexts but we may add support for these contexts in the future because there is no limitation in the nginx core (or the limitation might be worked around). -There exists a work-around, however, when the original context does *not* need to wait for the cosocket results. That is, creating a 0-delay timer via the [ngx.timer.at](#ngxtimerat) API and do the cosocket results in the timer handler, which runs asynchronously as to the original context creating the timer. +There exists a work-around, however, when the original context does *not* need to wait for the cosocket results. That is, creating a zero-delay timer via the [ngx.timer.at](#ngxtimerat) API and do the cosocket results in the timer handler, which runs asynchronously as to the original context creating the timer. [Back to TOC](#table-of-contents) Special Escaping Sequences -------------------------- -**WARNING** We no longer suffer from this pitfall since the introduction of the -`*_by_lua_block {}` configuration directives. +**NOTE** Following the `v0.9.17` release, this pitfall can be avoided by using the `*_by_lua_block {}` configuration directives. -PCRE sequences such as `\d`, `\s`, or `\w`, require special attention because in string literals, the backslash character, `\`, is stripped out by both the Lua language parser and by the Nginx config file parser before processing. So the following snippet will not work as expected: +PCRE sequences such as `\d`, `\s`, or `\w`, require special attention because in string literals, the backslash character, `\`, is stripped out by both the Lua language parser and by the nginx config file parser before processing if not within a `*_by_lua_block {}` directive. So the following snippet will not work as expected: ```nginx # nginx.conf ? location /test { ? content_by_lua ' - ? local regex = "\d+" -- THIS IS WRONG!! + ? local regex = "\d+" -- THIS IS WRONG OUTSIDE OF A *_by_lua_block DIRECTIVE ? local m = ngx.re.match("hello, 1234", regex) ? if m then ngx.say(m[0]) else ngx.say("not matched!") end ? '; @@ -755,7 +775,7 @@ To avoid this, *double* escape the backslash: Here, `\\\\d+` is stripped down to `\\d+` by the Nginx config file parser and this is further stripped down to `\d+` by the Lua language parser before running. -Alternatively, the regex pattern can be presented as a long-bracketed Lua string literal by encasing it in "long brackets", `[[...]]`, in which case backslashes have to only be escaped once for the Nginx config file parser. +Alternatively, the regex pattern can be presented as a long-bracketed Lua string literal by encasing it in "long brackets", `[[...]]`, in which case backslashes have to only be escaped once for the Nginx config file parser. ```nginx @@ -772,7 +792,7 @@ Alternatively, the regex pattern can be presented as a long-bracketed Lua string Here, `[[\\d+]]` is stripped down to `[[\d+]]` by the Nginx config file parser and this is processed correctly. -Note that a longer from of the long bracket, `[=[...]=]`, may be required if the regex pattern contains `[...]` sequences. +Note that a longer from of the long bracket, `[=[...]=]`, may be required if the regex pattern contains `[...]` sequences. The `[=[...]=]` form may be used as the default form if desired. ```nginx @@ -788,7 +808,7 @@ The `[=[...]=]` form may be used as the default form if desired. # evaluates to "1234" ``` -An alternative approach to escaping PCRE sequences is to ensure that Lua code is placed in external script files and executed using the various `*_by_lua_file` directives. +An alternative approach to escaping PCRE sequences is to ensure that Lua code is placed in external script files and executed using the various `*_by_lua_file` directives. With this approach, the backslashes are only stripped by the Lua language parser and therefore only need to be escaped once each. ```lua @@ -800,8 +820,8 @@ With this approach, the backslashes are only stripped by the Lua language parser -- evaluates to "1234" ``` -Within external script files, PCRE sequences presented as long-bracketed Lua string literals do not require modification. - +Within external script files, PCRE sequences presented as long-bracketed Lua string literals do not require modification. + ```lua -- test.lua @@ -811,6 +831,22 @@ Within external script files, PCRE sequences presented as long-bracketed Lua str -- evaluates to "1234" ``` +As noted earlier, PCRE sequences presented within `*_by_lua_block {}` directives (available following the `v0.9.17` release) do not require modification. + +```nginx + + # nginx.conf + location /test { + content_by_lua_block { + local regex = "\d+" + local m = ngx.re.match("hello, 1234", regex) + if m then ngx.say(m[0]) else ngx.say("not matched!") end + } + } + # evaluates to "1234" +``` + + [Back to TOC](#table-of-contents) Mixing with SSI Not Supported @@ -871,7 +907,6 @@ servers in Lua. For example, * cosocket: pool-based backend concurrency level control: implement automatic `connect` queueing when the backend concurrency exceeds its connection pool limit. * cosocket: review and merge aviramc's [patch](https://github.com/openresty/lua-nginx-module/pull/290) for adding the `bsdrecv` method. * add new API function `ngx.resp.add_header` to emulate the standard `add_header` config directive. -* review and apply Jader H. Silva's patch for `ngx.re.split()`. * review and apply vadim-pavlov's patch for [ngx.location.capture](#ngxlocationcapture)'s `extra_headers` option * use `ngx_hash_t` to optimize the built-in header look-up process for [ngx.req.set_header](#ngxreqset_header), [ngx.header.HEADER](#ngxheaderheader), and etc. * add configure options for different strategies of handling the cosocket connection exceeding in the pools. @@ -879,14 +914,14 @@ servers in Lua. For example, * add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) methods, to allow micro performance tuning on the user side. * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add `stat` mode similar to [mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html). -* cosocket: add client SSL certificiate support. +* cosocket: add client SSL certificate support. [Back to TOC](#table-of-contents) Changes ======= -The changes of every release of this module can be obtained from the OpenResty bundle's change logs: +The changes made in every release of this module are listed in the change logs of the OpenResty bundle: @@ -955,9 +990,9 @@ Copyright and License This module is licensed under the BSD license. -Copyright (C) 2009-2016, by Xiaozhe Wang (chaoslawful) . +Copyright (C) 2009-2017, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2016, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +Copyright (C) 2009-2017, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. All rights reserved. @@ -1001,6 +1036,7 @@ See Also Directives ========== +* [lua_capture_error_log](#lua_capture_error_log) * [lua_use_default_type](#lua_use_default_type) * [lua_malloc_trim](#lua_malloc_trim) * [lua_code_cache](#lua_code_cache) @@ -1074,6 +1110,56 @@ how the result will be used. Below is a diagram showing the order in which direc [Back to TOC](#table-of-contents) +lua_capture_error_log +--------------------- +**syntax:** *lua_capture_error_log size* + +**default:** *none* + +**context:** *http* + +Enables a buffer of the specified `size` for capturing all the nginx error log message data (not just those produced +by this module or the nginx http subsystem, but everything) without touching files or disks. + +You can use units like `k` and `m` in the `size` value, as in + +```nginx + + lua_capture_error_log 100k; +``` + +As a rule of thumb, a 4KB buffer can usually hold about 20 typical error log messages. So do the maths! + +This buffer never grows. If it is full, new error log messages will replace the oldest ones in the buffer. + +The size of the buffer must be bigger than the maximum length of a single error log message (which is 4K in OpenResty and 2K in stock NGINX). + +You can read the messages in the buffer on the Lua land via the +[get_logs()](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#get_logs) +function of the +[ngx.errlog](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#readme) +module of the [lua-resty-core](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#readme) +library. This Lua API function will return the captured error log messages and +also remove these already read from the global capturing buffer, making room +for any new error log data. For this reason, the user should not configure this +buffer to be too big if the user read the buffered error log data fast enough. + +Note that the log level specified in the standard [error_log](http://nginx.org/r/error_log) directive +*does* have effect on this capturing facility. It only captures log +messages of a level no lower than the specified log level in the [error_log](http://nginx.org/r/error_log) directive. +The user can still choose to set an even higher filtering log level on the fly via the Lua API function +[errlog.set_filter_level](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#set_filter_level). +So it is more flexible than the static [error_log](http://nginx.org/r/error_log) directive. + +It is worth noting that there is no way to capture the debugging logs +without building OpenResty or NGINX with the `./configure` +option `--with-debug`. And enabling debugging logs is +strongly discouraged in production builds due to high overhead. + +This directive was first introduced in the `v0.10.9` release. + +[Back to TOC](#directives) + lua_use_default_type -------------------- **syntax:** *lua_use_default_type on | off* @@ -1082,7 +1168,7 @@ lua_use_default_type **context:** *http, server, location, location if* -Specifies whether to use the MIME type specified by the [default_type](http://nginx.org/en/docs/http/ngx_http_core_module.html#default_type) directive for the default value of the `Content-Type` response header. If you do not want a default `Content-Type` response header for your Lua request handlers, then turn this directive off. +Specifies whether to use the MIME type specified by the [default_type](http://nginx.org/en/docs/http/ngx_http_core_module.html#default_type) directive for the default value of the `Content-Type` response header. Deactivate this directive if a default `Content-Type` response header for Lua request handlers is not desired. This directive is turned on by default. @@ -1153,8 +1239,8 @@ The ngx_lua module does not support the `stat` mode available with the Apache `mod_lua` module (yet). Disabling the Lua code cache is strongly -discouraged for production use and should only be used during -development as it has a significant negative impact on overall performance. For example, the performance a "hello world" Lua example can drop by an order of magnitude after disabling the Lua code cache. +discouraged for production use and should only be used during +development as it has a significant negative impact on overall performance. For example, the performance of a "hello world" Lua example can drop by an order of magnitude after disabling the Lua code cache. [Back to TOC](#directives) @@ -1176,6 +1262,8 @@ The default number of entries allowed is 1024 and when this limit is reached, ne 2011/08/27 23:18:26 [warn] 31997#0: *1 lua exceeding regex cache max entries (1024), ... +If you are using the `ngx.re.*` implementation of [lua-resty-core](https://github.com/openresty/lua-resty-core) by loading the `resty.core.regex` module (or just the `resty.core` module), then an LRU cache is used for the regex cache being used here. + Do not activate the `o` option for regular expressions (and/or `replace` string arguments for [ngx.re.sub](#ngxresub) and [ngx.re.gsub](#ngxregsub)) that are generated *on the fly* and give rise to infinite variations to avoid hitting the specified limit. [Back to TOC](#directives) @@ -1241,8 +1329,7 @@ init_by_lua **phase:** *loading-config* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; -use the new [init_by_lua_block](#init_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [init_by_lua_block](#init_by_lua_block) directive instead. Runs the Lua code specified by the argument `` on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file. @@ -1358,7 +1445,7 @@ init_worker_by_lua **phase:** *starting-worker* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; use the new [init_worker_by_lua_block](#init_worker_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [init_worker_by_lua_block](#init_worker_by_lua_block) directive instead. Runs the specified Lua code upon every Nginx worker process's startup when the master process is enabled. When the master process is disabled, this hook will just run after [init_by_lua*](#init_by_lua). @@ -1384,8 +1471,8 @@ This hook is often used to create per-worker reoccurring timers (via the [ngx.ti end end - local ok, err = new_timer(delay, check) - if not ok then + local hdl, err = new_timer(delay, check) + if not hdl then log(ERR, "failed to create timer: ", err) return end @@ -1447,7 +1534,7 @@ set_by_lua **phase:** *rewrite* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; use the new [set_by_lua_block](#set_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [set_by_lua_block](#set_by_lua_block) directive instead. Executes code specified in `` with optional input arguments `$arg1 $arg2 ...`, and returns string output to `$res`. The code in `` can make [API calls](#nginx-api-for-lua) and can retrieve input arguments from the `ngx.arg` table (index starts from `1` and increases sequentially). @@ -1537,15 +1624,15 @@ set_by_lua_file **phase:** *rewrite* -Equivalent to [set_by_lua](#set_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. +Equivalent to [set_by_lua](#set_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. Nginx variable interpolation is supported in the `` argument string of this directive. But special care must be taken for injection attacks. When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached +When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by +The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. This directive requires the [ngx_devel_kit](https://github.com/simpl/ngx_devel_kit) module. @@ -1561,10 +1648,9 @@ content_by_lua **phase:** *content* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; -use the new [content_by_lua_block](#content_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [content_by_lua_block](#content_by_lua_block) directive instead. -Acts as a "content handler" and executes Lua code string specified in `` for every request. +Acts as a "content handler" and executes Lua code string specified in `` for every request. The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). Do not use this directive and other content handler directives in the same location. For example, this directive and the [proxy_pass](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass) directive should not be used in the same location. @@ -1613,16 +1699,16 @@ Nginx variables can be used in the `` string to provide When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached +When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by +The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. Nginx variables are supported in the file path for dynamic dispatch, for example: ```nginx - # WARNING: contents in nginx var must be carefully filtered, + # CAUTION: contents in nginx var must be carefully filtered, # otherwise there'll be great security risk! location ~ ^/app/([-_a-zA-Z0-9/]+) { set $path $1; @@ -1643,8 +1729,7 @@ rewrite_by_lua **phase:** *rewrite tail* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; -use the new [rewrite_by_lua_block](#rewrite_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [rewrite_by_lua_block](#rewrite_by_lua_block) directive instead. Acts as a rewrite phase handler and executes Lua code string specified in `` for every request. The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). @@ -1820,8 +1905,7 @@ access_by_lua **phase:** *access tail* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; -use the new [access_by_lua_block](#access_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [access_by_lua_block](#access_by_lua_block) directive instead. Acts as an access phase handler and executes Lua code string specified in `` for every request. The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). @@ -1933,7 +2017,7 @@ Nginx variables can be used in the `` string to provide When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached +When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid repeatedly reloading Nginx. @@ -1950,8 +2034,7 @@ header_filter_by_lua **phase:** *output-header-filter* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; -use the new [header_filter_by_lua_block](#header_filter_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [header_filter_by_lua_block](#header_filter_by_lua_block) directive instead. Uses Lua code specified in `` to define an output header filter. @@ -2029,8 +2112,7 @@ body_filter_by_lua **phase:** *output-body-filter* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; -use the new [body_filter_by_lua_block](#body_filter_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [body_filter_by_lua_block](#body_filter_by_lua_block) directive instead. Uses Lua code specified in `` to define an output body filter. @@ -2166,15 +2248,14 @@ log_by_lua **phase:** *log* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; -use the new [log_by_lua_block](#log_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [log_by_lua_block](#log_by_lua_block) directive instead. Runs the Lua source code inlined as the `` at the `log` request processing phase. This does not replace the current access logs, but runs before. Note that the following API functions are currently disabled within this context: * Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.exit](#ngxexit)) +* Control API functions (e.g., [ngx.exit](#ngxexit)) * Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) * Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). @@ -2883,7 +2964,7 @@ lua_http10_buffering **context:** *http, server, location, location-if* -Enables or disables automatic response buffering for HTTP 1.0 (or older) requests. This buffering mechanism is mainly used for HTTP 1.0 keep-alive which replies on a proper `Content-Length` response header. +Enables or disables automatic response buffering for HTTP 1.0 (or older) requests. This buffering mechanism is mainly used for HTTP 1.0 keep-alive which relies on a proper `Content-Length` response header. If the Lua code explicitly sets a `Content-Length` response header before sending the headers (either explicitly via [ngx.send_headers](#ngxsend_headers) or implicitly via the first [ngx.say](#ngxsay) or [ngx.print](#ngxprint) call), then the HTTP 1.0 response buffering will be disabled even when this directive is turned on. @@ -2951,7 +3032,7 @@ lua_check_client_abort This directive controls whether to check for premature client connection abortion. -When this directive is turned on, the ngx_lua module will monitor the premature connection close event on the downstream connections. And when there is such an event, it will call the user Lua function callback (registered by [ngx.on_abort](#ngxon_abort)) or just stop and clean up all the Lua "light threads" running in the current request's request handler when there is no user callback function registered. +When this directive is on, the ngx_lua module will monitor the premature connection close event on the downstream connections and when there is such an event, it will call the user Lua function callback (registered by [ngx.on_abort](#ngxon_abort)) or just stop and clean up all the Lua "light threads" running in the current request's request handler when there is no user callback function registered. According to the current implementation, however, if the client closes the connection before the Lua code finishes reading the request body data via [ngx.req.socket](#ngxreqsocket), then ngx_lua will neither stop all the running "light threads" nor call the user callback (if [ngx.on_abort](#ngxon_abort) has been called). Instead, the reading operation on [ngx.req.socket](#ngxreqsocket) will just return the error message "client aborted" as the second return value (the first return value is surely `nil`). @@ -3136,6 +3217,7 @@ Nginx API for Lua * [ngx.thread.kill](#ngxthreadkill) * [ngx.on_abort](#ngxon_abort) * [ngx.timer.at](#ngxtimerat) +* [ngx.timer.every](#ngxtimerevery) * [ngx.timer.running_count](#ngxtimerrunning_count) * [ngx.timer.pending_count](#ngxtimerpending_count) * [ngx.config.subsystem](#ngxconfigsubsystem) @@ -3280,7 +3362,7 @@ Setting `ngx.var.Foo` to a `nil` value will unset the `$Foo` Nginx variable. ngx.var.args = nil ``` -**WARNING** When reading from an Nginx variable, Nginx will allocate memory in the per-request memory pool which is freed only at request termination. So when you need to read from an Nginx variable repeatedly in your Lua code, cache the Nginx variable value to your own Lua variable, for example, +**CAUTION** When reading from an Nginx variable, Nginx will allocate memory in the per-request memory pool which is freed only at request termination. So when you need to read from an Nginx variable repeatedly in your Lua code, cache the Nginx variable value to your own Lua variable, for example, ```lua @@ -3438,7 +3520,7 @@ ngx.ctx ------- **context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua** -This table can be used to store per-request Lua context data and has a life time identical to the current request (as with the Nginx variables). +This table can be used to store per-request Lua context data and has a life time identical to the current request (as with the Nginx variables). Consider the following example, @@ -3541,7 +3623,7 @@ When being used in the context of [init_worker_by_lua*](#init_worker_by_lua), th The `ngx.ctx` lookup requires relatively expensive metamethod calls and it is much slower than explicitly passing per-request data along by your own function arguments. So do not abuse this API for saving your own function arguments because it usually has quite some performance impact. -Because of the metamethod magic, never "local" the `ngx.ctx` table outside your Lua function scope on the Lua module level level due to [worker-level data sharing](#data-sharing-within-an-nginx-worker). For example, the following is bad: +Because of the metamethod magic, never "local" the `ngx.ctx` table outside your Lua function scope on the Lua module level due to [worker-level data sharing](#data-sharing-within-an-nginx-worker). For example, the following is bad: ```lua @@ -3549,7 +3631,7 @@ Because of the metamethod magic, never "local" the `ngx.ctx` table outside your local _M = {} -- the following line is bad since ngx.ctx is a per-request - -- data while this `ctx` variable is on the Lua module level + -- data while this ctx variable is on the Lua module level -- and thus is per-nginx-worker. local ctx = ngx.ctx @@ -3701,7 +3783,7 @@ The `args` option can also take plain query strings: This is functionally identical to the previous examples. -The `share_all_vars` option controls whether to share nginx variables among the current request and its subrequests. +The `share_all_vars` option controls whether to share nginx variables among the current request and its subrequests. If this option is set to `true`, then the current request and associated subrequests will share the same Nginx variable scope. Hence, changes to Nginx variables made by a subrequest will affect the current request. Care should be taken in using this option as variable scope sharing can have unexpected side effects. The `args`, `vars`, or `copy_all_vars` options are generally preferable instead. @@ -3768,7 +3850,7 @@ In addition to the two settings above, it is possible to specify values for variables in the subrequest using the `vars` option. These variables are set after the sharing or copying of variables has been evaluated, and provides a more efficient method of passing specific -values to a subrequest over encoding them as URL arguments and +values to a subrequest over encoding them as URL arguments and unescaping them in the Nginx config file. ```nginx @@ -3853,7 +3935,7 @@ Note that subrequests issued by [ngx.location.capture](#ngxlocationcapture) inhe request headers of the current request by default and that this may have unexpected side effects on the subrequest responses. For example, when using the standard `ngx_proxy` module to serve subrequests, an "Accept-Encoding: gzip" header in the main request may result -in gzipped responses that cannot be handled properly in Lua code. Original request headers should be ignored by setting +in gzipped responses that cannot be handled properly in Lua code. Original request headers should be ignored by setting [proxy_pass_request_headers](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass_request_headers) to `off` in subrequest locations. When the `body` option is not specified and the `always_forward_body` option is false (the default value), the `POST` and `PUT` subrequests will inherit the request bodies of the parent request (if any). @@ -3993,7 +4075,7 @@ will yield Set-Cookie: b=4; path=/ ``` -in the response headers. +in the response headers. Only Lua tables are accepted (Only the last element in the table will take effect for standard headers such as `Content-Type` that only accept a single value). @@ -4025,7 +4107,7 @@ The same applies to assigning an empty table: Setting `ngx.header.HEADER` after sending out response headers (either explicitly with [ngx.send_headers](#ngxsend_headers) or implicitly with [ngx.print](#ngxprint) and similar) will throw out a Lua exception. -Reading `ngx.header.HEADER` will return the value of the response header named `HEADER`. +Reading `ngx.header.HEADER` will return the value of the response header named `HEADER`. Underscores (`_`) in the header names will also be replaced by dashes (`-`) and the header names will be matched case-insensitively. If the response header is not present at all, `nil` will be returned. @@ -4536,7 +4618,7 @@ That is, they will take Lua boolean values `true`. However, they are different f Empty key arguments are discarded. `POST /test` with body `=hello&=world` will yield empty outputs for instance. -Note that a maximum of 100 request arguments are parsed by default (including those with the same name) and that additional request arguments are silently discarded to guard against potential denial of service attacks. +Note that a maximum of 100 request arguments are parsed by default (including those with the same name) and that additional request arguments are silently discarded to guard against potential denial of service attacks. However, the optional `max_args` function argument can be used to override this limit: @@ -4597,7 +4679,7 @@ the value of `ngx.req.get_headers()["Foo"]` will be a Lua (array) table such as: {"foo", "bar", "baz"} ``` -Note that a maximum of 100 request headers are parsed by default (including those with the same name) and that additional request headers are silently discarded to guard against potential denial of service attacks. +Note that a maximum of 100 request headers are parsed by default (including those with the same name) and that additional request headers are silently discarded to guard against potential denial of service attacks. However, the optional `max_headers` function argument can be used to override this limit: @@ -4999,6 +5081,7 @@ The optional `status` parameter specifies the HTTP status code to be used. The f * `301` * `302` (default) +* `303` * `307` It is `302` (`ngx.HTTP_MOVED_TEMPORARILY`) by default. @@ -5237,7 +5320,7 @@ Note that while this method accepts all [HTTP status constants](#http-status-con Also note that this method call terminates the processing of the current request and that it is recommended that a coding style that combines this method call with the `return` statement, i.e., `return ngx.exit(...)` be used to reinforce the fact that the request processing is being terminated. -When being used in the contexts of [header_filter_by_lua](#header_filter_by_lua) and +When being used in the contexts of [header_filter_by_lua*](#header_filter_by_lua), [balancer_by_lua*](#balancer_by_lua_block), and [ssl_session_store_by_lua*](#ssl_session_store_by_lua_block), `ngx.exit()` is an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use `return` in combination as suggested above. @@ -5251,7 +5334,7 @@ ngx.eof Explicitly specify the end of the response output stream. In the case of HTTP 1.1 chunked encoded output, it will just trigger the Nginx core to send out the "last chunk". -When you disable the HTTP 1.1 keep-alive feature for your downstream connections, you can rely on descent HTTP clients to close the connection actively for you when you call this method. This trick can be used do back-ground jobs without letting the HTTP clients to wait on the connection, as in the following example: +When you disable the HTTP 1.1 keep-alive feature for your downstream connections, you can rely on well written HTTP clients to close the connection actively for you when you call this method. This trick can be used do back-ground jobs without letting the HTTP clients to wait on the connection, as in the following example: ```nginx @@ -5259,7 +5342,7 @@ When you disable the HTTP 1.1 keep-alive feature for your downstream connections keepalive_timeout 0; content_by_lua_block { ngx.say("got the task!") - ngx.eof() -- a descent HTTP client will close the connection at this point + ngx.eof() -- well written HTTP clients will close the connection at this point -- access MySQL, PostgreSQL, Redis, Memcached, and etc here... } } @@ -5576,7 +5659,7 @@ ngx.time Returns the elapsed seconds from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). -Updates of the Nginx time cache an be forced by calling [ngx.update_time](#ngxupdate_time) first. +Updates of the Nginx time cache can be forced by calling [ngx.update_time](#ngxupdate_time) first. [Back to TOC](#nginx-api-for-lua) @@ -5826,7 +5909,7 @@ The optional fourth argument, `ctx`, can be a Lua table holding an optional `pos local ctx = { pos = 2 } local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) - -- m[0] = "34" + -- m[0] = "234" -- ctx.pos == 5 ``` @@ -6006,7 +6089,7 @@ When the `replace` is a string, then it is treated as a special template for str where `$0` referring to the whole substring matched by the pattern and `$1` referring to the first parenthesized capturing substring. -Curly braces can also be used to disambiguate variable names from the background string literals: +Curly braces can also be used to disambiguate variable names from the background string literals: ```lua @@ -6116,6 +6199,8 @@ The resulting object `dict` has the following methods: * [flush_expired](#ngxshareddictflush_expired) * [get_keys](#ngxshareddictget_keys) +All these methods are *atomic* operations, that is, safe from concurrent accesses from multiple nginx worker processes for the same `lua_shared_dict` zone. + Here is an example: ```nginx @@ -6495,7 +6580,7 @@ Fetch a list of the keys from the dictionary, up to ``. By default, only the first 1024 keys (if any) are returned. When the `` argument is given the value `0`, then all the keys will be returned even there is more than 1024 keys in the dictionary. -**WARNING** Be careful when calling this method on dictionaries with a really huge number of keys. This method may lock the dictionary for quite a while and block all the nginx worker processes that are trying to access the dictionary. +**CAUTION** Avoid calling this method on dictionaries with a very large number of keys as it may lock the dictionary for significant amount of time and block Nginx worker processes trying to access the dictionary. This feature was first introduced in the `v0.7.3` release. @@ -7280,7 +7365,7 @@ Then it will generate the output 4 -"Light threads" are mostly useful for doing concurrent upstream requests in a single Nginx request handler, kinda like a generalized version of [ngx.location.capture_multi](#ngxlocationcapture_multi) that can work with all the [Nginx API for Lua](#nginx-api-for-lua). The following example demonstrates parallel requests to MySQL, Memcached, and upstream HTTP services in a single Lua handler, and outputting the results in the order that they actually return (very much like the Facebook BigPipe model): +"Light threads" are mostly useful for making concurrent upstream requests in a single Nginx request handler, much like a generalized version of [ngx.location.capture_multi](#ngxlocationcapture_multi) that can work with all the [Nginx API for Lua](#nginx-api-for-lua). The following example demonstrates parallel requests to MySQL, Memcached, and upstream HTTP services in a single Lua handler, and outputting the results in the order that they actually return (similar to Facebook's BigPipe model): ```lua @@ -7486,7 +7571,7 @@ See also [lua_check_client_abort](#lua_check_client_abort). ngx.timer.at ------------ -**syntax:** *ok, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)* +**syntax:** *hdl, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)* **context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** @@ -7512,7 +7597,7 @@ Premature timer expiration happens when the Nginx worker process is trying to shut down, as in an Nginx configuration reload triggered by the `HUP` signal or in an Nginx server shutdown. When the Nginx worker is trying to shut down, one can no longer call `ngx.timer.at` to -create new timers with nonzero delays and in that case `ngx.timer.at` will return `nil` and +create new timers with nonzero delays and in that case `ngx.timer.at` will return a "conditional false" value and a string describing the error, that is, "process exiting". Starting from the `v0.9.3` release, it is allowed to create zero-delay timers even when the Nginx worker process starts shutting down. @@ -7571,6 +7656,9 @@ One can also create infinite re-occurring timers, for instance, a timer getting end ``` +It is recommended, however, to use the [ngx.timer.every](#ngxtimerevery) API function +instead for creating recurring timers since it is more robust. + Because timer callbacks run in the background and their running time will not add to any client request's response time, they can easily accumulate in the server and exhaust system resources due to either @@ -7610,6 +7698,25 @@ This API was first introduced in the `v0.8.0` release. [Back to TOC](#nginx-api-for-lua) +ngx.timer.every +--------------- +**syntax:** *hdl, err = ngx.timer.every(delay, callback, user_arg1, user_arg2, ...)* + +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** + +Similar to the [ngx.timer.at](#ngxtimerat) API function, but + +1. `delay` *cannot* be zero, +1. timer will be created every `delay` seconds until the current Nginx worker process starts exiting. + +When success, returns a "conditional true" value (but not a `true`). Otherwise, returns a "conditional false" value and a string describing the error. + +This API also respect the [lua_max_pending_timers](#lua_max_pending_timers) and [lua_max_running_timers](#lua_max_running_timers). + +This API was first introduced in the `v0.10.9` release. + +[Back to TOC](#nginx-api-for-lua) + ngx.timer.running_count ----------------------- **syntax:** *count = ngx.timer.running_count()* diff --git a/debian/modules/nginx-lua/config b/debian/modules/nginx-lua/config index 01a6b3c..044deb9 100644 --- a/debian/modules/nginx-lua/config +++ b/debian/modules/nginx-lua/config @@ -360,6 +360,7 @@ HTTP_LUA_SRCS=" \ $ngx_addon_dir/src/ngx_http_lua_ssl_session_storeby.c \ $ngx_addon_dir/src/ngx_http_lua_ssl_session_fetchby.c \ $ngx_addon_dir/src/ngx_http_lua_ssl.c \ + $ngx_addon_dir/src/ngx_http_lua_log_ringbuf.c \ " HTTP_LUA_DEPS=" \ @@ -420,6 +421,7 @@ HTTP_LUA_DEPS=" \ $ngx_addon_dir/src/ngx_http_lua_ssl_session_storeby.h \ $ngx_addon_dir/src/ngx_http_lua_ssl_session_fetchby.h \ $ngx_addon_dir/src/ngx_http_lua_ssl.h \ + $ngx_addon_dir/src/ngx_http_lua_log_ringbuf.h \ " CFLAGS="$CFLAGS -DNDK_SET_VAR" @@ -472,33 +474,6 @@ ngx_feature_test='setsockopt(1, SOL_SOCKET, SO_PASSCRED, NULL, 0);' . auto/feature -ngx_feature="mmap(sbrk(0))" -ngx_feature_libs= -ngx_feature_name="NGX_HTTP_LUA_HAVE_MMAP_SBRK" -ngx_feature_run=yes -ngx_feature_incs="#include -#include -#include -#include -#define align_ptr(p, a) \ - (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1)) -" -ngx_feature_test=" -#if defined(__x86_64__) -exit(mmap(align_ptr(sbrk(0), getpagesize()), 1, PROT_READ, - MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0) < (void *) 0x40000000LL - ? 0 : 1); -#else -exit(1); -#endif -" -SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" -CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS" - -. auto/feature - -CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" - ngx_feature="__attribute__(constructor)" ngx_feature_libs= ngx_feature_name="NGX_HTTP_LUA_HAVE_CONSTRUCTOR" diff --git a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki index be454af..8393056 100644 --- a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki @@ -10,40 +10,40 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.7] released on 4 November 2016. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.10] released on 8 August 2017. = Synopsis = # set search paths for pure Lua external libraries (';;' is the default path): lua_package_path '/foo/bar/?.lua;/blah/?.lua;;'; - + # set search paths for Lua external libraries written in C (can also use ';;'): lua_package_cpath '/bar/baz/?.so;/blah/blah/?.so;;'; - + server { location /lua_content { # MIME type determined by default_type: default_type 'text/plain'; - + content_by_lua_block { ngx.say('Hello,world!') } } - + location /nginx_var { # MIME type determined by default_type: default_type 'text/plain'; - + # try access /nginx_var?a=hello,world content_by_lua_block { ngx.say(ngx.var.arg_a) } } - + location = /request_body { client_max_body_size 50k; client_body_buffer_size 50k; - + content_by_lua_block { ngx.req.read_body() -- explicitly read the req body local data = ngx.req.get_body_data() @@ -62,13 +62,13 @@ This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/t end } } - + # transparent non-blocking I/O in Lua via subrequests # (well, a better way is to use cosockets) location = /lua { # MIME type determined by default_type: default_type 'text/plain'; - + content_by_lua_block { local res = ngx.location.capture("/some_other_location") if res then @@ -78,51 +78,51 @@ This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/t end } } - + location = /foo { rewrite_by_lua_block { res = ngx.location.capture("/memc", { args = { cmd = "incr", key = ngx.var.uri } } ) } - + proxy_pass http://blah.blah.com; } - + location = /mixed { rewrite_by_lua_file /path/to/rewrite.lua; access_by_lua_file /path/to/access.lua; content_by_lua_file /path/to/content.lua; } - + # use nginx var in code path - # WARNING: contents in nginx var must be carefully filtered, + # CAUTION: contents in nginx var must be carefully filtered, # otherwise there'll be great security risk! location ~ ^/app/([-_a-zA-Z0-9/]+) { set $path $1; content_by_lua_file /path/to/lua/app/root/$path.lua; } - + location / { client_max_body_size 100k; client_body_buffer_size 100k; - + access_by_lua_block { -- check the client IP address is in our black list if ngx.var.remote_addr == "132.5.72.3" then ngx.exit(ngx.HTTP_FORBIDDEN) end - + -- check if the URI contains bad words if ngx.var.uri and string.match(ngx.var.request_body, "evil") then return ngx.redirect("/terms_of_use.html") end - + -- tests passed } - + # proxy_pass/fastcgi_pass/etc settings } } @@ -197,7 +197,7 @@ Nginx cores older than 1.6.0 (exclusive) are *not* supported. = Installation = -It is highly recommended to use the [http://openresty.org OpenResty bundle] that bundles Nginx, ngx_lua, LuaJIT 2.0/2.1 (or the optional standard Lua 5.1 interpreter), as well as a package of powerful companion Nginx modules. The basic installation step is a simple command: ./configure --with-luajit && make && make install. +It is *highly* recommended to use [http://openresty.org OpenResty releases] which integrate Nginx, ngx_lua, LuaJIT 2.1, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. Alternatively, ngx_lua can be manually compiled into Nginx: @@ -220,31 +220,37 @@ Build the source with this module: # tell nginx's build system where to find LuaJIT 2.1: export LUAJIT_LIB=/path/to/luajit/lib export LUAJIT_INC=/path/to/luajit/include/luajit-2.1 - + # or tell where to find Lua if using Lua instead: #export LUA_LIB=/path/to/lua/lib #export LUA_INC=/path/to/lua/include - + # Here we assume Nginx is to be installed under /opt/nginx/. ./configure --prefix=/opt/nginx \ --with-ld-opt="-Wl,-rpath,/path/to/luajit-or-lua/lib" \ --add-module=/path/to/ngx_devel_kit \ --add-module=/path/to/lua-nginx-module - + + # Note that you may also want to add `./configure` options which are used in your + # current nginx build. + # You can get usually those options using command nginx -V + + # you can change the parallism number 2 below to fit the number of spare CPU cores in your + # machine. make -j2 make install == Building as a dynamic module == -Starting from NGINX 1.9.11, you can also compile this module as a dynamic module, by using the `--add-dynamic-module=PATH` option instead of `--add-module=PATH` on the -`./configure` command line above. And then you can explicitly load the module in your `nginx.conf` via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module) +Starting from NGINX 1.9.11, you can also compile this module as a dynamic module, by using the --add-dynamic-module=PATH option instead of --add-module=PATH on the +./configure command line above. And then you can explicitly load the module in your nginx.conf via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module) directive, for example, -```nginx + load_module /path/to/modules/ndk_http_module.so; # assuming NDK is built as a dynamic module too load_module /path/to/modules/ngx_http_lua_module.so; -``` + == C Macro Configurations == @@ -309,13 +315,13 @@ As from the v0.5.0rc32 release, all *_by_lua_file conf Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: - /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.luac + /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.ljbc The -bg option can be used to include debug information in the LuaJIT bytecode file: - /path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.luac + /path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.ljbc Please refer to the official LuaJIT documentation on the -b option for more details: @@ -451,7 +457,7 @@ Here is a complete small example: cat = 4, pig = 5, } - + function _M.get_age(name) return data[name] end @@ -495,9 +501,9 @@ If server-wide data sharing is required, then use one or more of the following a = Known Issues = == TCP socket connect operation issues == -The [[#tcpsock:connect|tcpsock:connect]] method may indicate success despite connection failures such as with Connection Refused errors. +The [[#tcpsock:connect|tcpsock:connect]] method may indicate success despite connection failures such as with Connection Refused errors. -However, later attempts to manipulate the cosocket object will fail and return the actual error status message generated by the failed connect operation. +However, later attempts to manipulate the cosocket object will fail and return the actual error status message generated by the failed connect operation. This issue is due to limitations in the Nginx event model and only appears to affect Mac OS X. @@ -520,15 +526,28 @@ instead of the old deprecated form: Here is the reason: by design, the global environment has exactly the same lifetime as the Nginx request handler associated with it. Each request handler has its own set of Lua global variables and that is the idea of request isolation. The Lua module is actually loaded by the first Nginx request handler and is cached by the require() built-in in the package.loaded table for later reference, and the module() builtin used by some Lua modules has the side effect of setting a global variable to the loaded module table. But this global variable will be cleared at the end of the request handler, and every subsequent request handler all has its own (clean) global environment. So one will get Lua exception for accessing the nil value. -Generally, use of Lua global variables is a really really bad idea in the context of ngx_lua because +The use of Lua global variables is a generally inadvisable in the ngx_lua context as: -# misuse of Lua globals has very bad side effects for concurrent requests when these variables are actually supposed to be local only, -# Lua global variables require Lua table look-up in the global environment (which is just a Lua table), which is kinda expensive, and -# some Lua global variable references are just typos, which are hard to debug. +# the misuse of Lua globals has detrimental side effects on concurrent requests when such variables should instead be local in scope, +# Lua global variables require Lua table look-ups in the global environment which is computationally expensive, and +# some Lua global variable references may include typing errors which make such difficult to debug. -It's *highly* recommended to always declare them via "local" in the scope that is reasonable. +It is therefore *highly* recommended to always declare such within an appropriate local scope instead. -To find out all the uses of Lua global variables in your Lua code, you can run the [https://github.com/openresty/nginx-devel-utils/blob/master/lua-releng lua-releng tool] across all your .lua source files: + + -- Avoid + foo = 123 + -- Recommended + local foo = 123 + + -- Avoid + function foo() return 123 end + -- Recommended + local function foo() return 123 end + + + +To find all instances of Lua global variables in your Lua code, run the [https://github.com/openresty/nginx-devel-utils/blob/master/lua-releng lua-releng tool] across all .lua source files: $ lua-releng Checking use of Lua global variables in file lib/foo/bar.lua ... @@ -565,24 +584,23 @@ will not work as expected. == Cosockets Not Available Everywhere == -Due the internal limitations in the nginx core, the cosocket API are disabled in the following contexts: [[#set_by_lua|set_by_lua*]], [[#log_by_lua|log_by_lua*]], [[#header_filter_by_lua|header_filter_by_lua*]], and [[#body_filter_by_lua|body_filter_by_lua]]. +Due to internal limitations in the nginx core, the cosocket API is disabled in the following contexts: [[#set_by_lua|set_by_lua*]], [[#log_by_lua|log_by_lua*]], [[#header_filter_by_lua|header_filter_by_lua*]], and [[#body_filter_by_lua|body_filter_by_lua]]. The cosockets are currently also disabled in the [[#init_by_lua|init_by_lua*]] and [[#init_worker_by_lua|init_worker_by_lua*]] directive contexts but we may add support for these contexts in the future because there is no limitation in the nginx core (or the limitation might be worked around). -There exists a work-around, however, when the original context does *not* need to wait for the cosocket results. That is, creating a 0-delay timer via the [[#ngx.timer.at|ngx.timer.at]] API and do the cosocket results in the timer handler, which runs asynchronously as to the original context creating the timer. +There exists a work-around, however, when the original context does *not* need to wait for the cosocket results. That is, creating a zero-delay timer via the [[#ngx.timer.at|ngx.timer.at]] API and do the cosocket results in the timer handler, which runs asynchronously as to the original context creating the timer. == Special Escaping Sequences == -'''WARNING''' We no longer suffer from this pitfall since the introduction of the -*_by_lua_block {} configuration directives. +'''NOTE''' Following the v0.9.17 release, this pitfall can be avoided by using the *_by_lua_block {} configuration directives. -PCRE sequences such as \d, \s, or \w, require special attention because in string literals, the backslash character, \, is stripped out by both the Lua language parser and by the Nginx config file parser before processing. So the following snippet will not work as expected: +PCRE sequences such as \d, \s, or \w, require special attention because in string literals, the backslash character, \, is stripped out by both the Lua language parser and by the nginx config file parser before processing if not within a *_by_lua_block {} directive. So the following snippet will not work as expected: # nginx.conf ? location /test { ? content_by_lua ' - ? local regex = "\d+" -- THIS IS WRONG!! + ? local regex = "\d+" -- THIS IS WRONG OUTSIDE OF A *_by_lua_block DIRECTIVE ? local m = ngx.re.match("hello, 1234", regex) ? if m then ngx.say(m[0]) else ngx.say("not matched!") end ? '; @@ -606,7 +624,7 @@ To avoid this, ''double'' escape the backslash: Here, \\\\d+ is stripped down to \\d+ by the Nginx config file parser and this is further stripped down to \d+ by the Lua language parser before running. -Alternatively, the regex pattern can be presented as a long-bracketed Lua string literal by encasing it in "long brackets", [[...]], in which case backslashes have to only be escaped once for the Nginx config file parser. +Alternatively, the regex pattern can be presented as a long-bracketed Lua string literal by encasing it in "long brackets", [[...]], in which case backslashes have to only be escaped once for the Nginx config file parser. # nginx.conf @@ -622,7 +640,7 @@ Alternatively, the regex pattern can be presented as a long-bracketed Lua string Here, [[\\d+]] is stripped down to [[\d+]] by the Nginx config file parser and this is processed correctly. -Note that a longer from of the long bracket, [=[...]=], may be required if the regex pattern contains [...] sequences. +Note that a longer from of the long bracket, [=[...]=], may be required if the regex pattern contains [...] sequences. The [=[...]=] form may be used as the default form if desired. @@ -637,7 +655,7 @@ The [=[...]=] form may be used as the default form if desired. # evaluates to "1234" -An alternative approach to escaping PCRE sequences is to ensure that Lua code is placed in external script files and executed using the various *_by_lua_file directives. +An alternative approach to escaping PCRE sequences is to ensure that Lua code is placed in external script files and executed using the various *_by_lua_file directives. With this approach, the backslashes are only stripped by the Lua language parser and therefore only need to be escaped once each. @@ -648,8 +666,8 @@ With this approach, the backslashes are only stripped by the Lua language parser -- evaluates to "1234" -Within external script files, PCRE sequences presented as long-bracketed Lua string literals do not require modification. - +Within external script files, PCRE sequences presented as long-bracketed Lua string literals do not require modification. + -- test.lua local regex = [[\d+]] @@ -658,6 +676,21 @@ Within external script files, PCRE sequences presented as long-bracketed Lua str -- evaluates to "1234" +As noted earlier, PCRE sequences presented within *_by_lua_block {} directives (available following the v0.9.17 release) do not require modification. + + + # nginx.conf + location /test { + content_by_lua_block { + local regex = "\d+" + local m = ngx.re.match("hello, 1234", regex) + if m then ngx.say(m[0]) else ngx.say("not matched!") end + } + } + # evaluates to "1234" + + + == Mixing with SSI Not Supported == Mixing SSI with ngx_lua in the same Nginx request is not supported at all. Just use ngx_lua exclusively. Everything you can do with SSI can be done atop ngx_lua anyway and it can be more efficient when using ngx_lua. @@ -705,7 +738,6 @@ servers in Lua. For example, * cosocket: pool-based backend concurrency level control: implement automatic connect queueing when the backend concurrency exceeds its connection pool limit. * cosocket: review and merge aviramc's [https://github.com/openresty/lua-nginx-module/pull/290 patch] for adding the bsdrecv method. * add new API function ngx.resp.add_header to emulate the standard add_header config directive. -* review and apply Jader H. Silva's patch for ngx.re.split(). * review and apply vadim-pavlov's patch for [[#ngx.location.capture|ngx.location.capture]]'s extra_headers option * use ngx_hash_t to optimize the built-in header look-up process for [[#ngx.req.set_header|ngx.req.set_header]], [[#ngx.header.HEADER|ngx.header.HEADER]], and etc. * add configure options for different strategies of handling the cosocket connection exceeding in the pools. @@ -713,11 +745,11 @@ servers in Lua. For example, * add ignore_resp_headers, ignore_resp_body, and ignore_resp options to [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] methods, to allow micro performance tuning on the user side. * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add stat mode similar to [https://httpd.apache.org/docs/trunk/mod/mod_lua.html mod_lua]. -* cosocket: add client SSL certificiate support. +* cosocket: add client SSL certificate support. = Changes = -The changes of every release of this module can be obtained from the OpenResty bundle's change logs: +The changes made in every release of this module are listed in the change logs of the OpenResty bundle: http://openresty.org/#Changes @@ -772,7 +804,7 @@ To run specific test files: prove -I/path/to/test-nginx/lib t/002-content.t t/003-errors.t -To run a specific test block in a particular test file, add the line --- ONLY to the test block you want to run, and then use the `prove` utility to run that .t file. +To run a specific test block in a particular test file, add the line --- ONLY to the test block you want to run, and then use the prove utility to run that .t file. There are also various testing modes based on mockeagain, valgrind, and etc. Refer to the [http://search.cpan.org/perldoc?Test::Nginx Test::Nginx documentation] for more details for various advanced testing modes. See also the test reports for the Nginx test cluster running on Amazon EC2: http://qa.openresty.org. @@ -780,9 +812,9 @@ There are also various testing modes based on mockeagain, valgrind, and etc. Ref This module is licensed under the BSD license. -Copyright (C) 2009-2016, by Xiaozhe Wang (chaoslawful) . +Copyright (C) 2009-2017, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2016, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +Copyright (C) 2009-2017, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. All rights reserved. @@ -827,6 +859,52 @@ how the result will be used. Below is a diagram showing the order in which direc ![Lua Nginx Modules Directives](https://cloud.githubusercontent.com/assets/2137369/15272097/77d1c09e-1a37-11e6-97ef-d9767035fc3e.png) +== lua_capture_error_log == +'''syntax:''' ''lua_capture_error_log size'' + +'''default:''' ''none'' + +'''context:''' ''http'' + +Enables a buffer of the specified size for capturing all the nginx error log message data (not just those produced +by this module or the nginx http subsystem, but everything) without touching files or disks. + +You can use units like `k` and `m` in the size value, as in + + + lua_capture_error_log 100k; + + +As a rule of thumb, a 4KB buffer can usually hold about 20 typical error log messages. So do the maths! + +This buffer never grows. If it is full, new error log messages will replace the oldest ones in the buffer. + +The size of the buffer must be bigger than the maximum length of a single error log message (which is 4K in OpenResty and 2K in stock NGINX). + +You can read the messages in the buffer on the Lua land via the +[https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#get_logs get_logs()] +function of the +[https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#readme ngx.errlog] +module of the [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#readme lua-resty-core] +library. This Lua API function will return the captured error log messages and +also remove these already read from the global capturing buffer, making room +for any new error log data. For this reason, the user should not configure this +buffer to be too big if the user read the buffered error log data fast enough. + +Note that the log level specified in the standard [http://nginx.org/r/error_log error_log] directive +''does'' have effect on this capturing facility. It only captures log +messages of a level no lower than the specified log level in the [http://nginx.org/r/error_log error_log] directive. +The user can still choose to set an even higher filtering log level on the fly via the Lua API function +[https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#set_filter_level errlog.set_filter_level]. +So it is more flexible than the static [http://nginx.org/r/error_log error_log] directive. + +It is worth noting that there is no way to capture the debugging logs +without building OpenResty or NGINX with the ./configure +option --with-debug. And enabling debugging logs is +strongly discouraged in production builds due to high overhead. + +This directive was first introduced in the v0.10.9 release. + == lua_use_default_type == '''syntax:''' ''lua_use_default_type on | off'' @@ -834,7 +912,7 @@ how the result will be used. Below is a diagram showing the order in which direc '''context:''' ''http, server, location, location if'' -Specifies whether to use the MIME type specified by the [http://nginx.org/en/docs/http/ngx_http_core_module.html#default_type default_type] directive for the default value of the Content-Type response header. If you do not want a default Content-Type response header for your Lua request handlers, then turn this directive off. +Specifies whether to use the MIME type specified by the [http://nginx.org/en/docs/http/ngx_http_core_module.html#default_type default_type] directive for the default value of the Content-Type response header. Deactivate this directive if a default Content-Type response header for Lua request handlers is not desired. This directive is turned on by default. @@ -898,8 +976,8 @@ The ngx_lua module does not support the stat mode available with th Apache mod_lua module (yet). Disabling the Lua code cache is strongly -discouraged for production use and should only be used during -development as it has a significant negative impact on overall performance. For example, the performance a "hello world" Lua example can drop by an order of magnitude after disabling the Lua code cache. +discouraged for production use and should only be used during +development as it has a significant negative impact on overall performance. For example, the performance of a "hello world" Lua example can drop by an order of magnitude after disabling the Lua code cache. == lua_regex_cache_max_entries == '''syntax:''' ''lua_regex_cache_max_entries '' @@ -918,6 +996,8 @@ The default number of entries allowed is 1024 and when this limit is reached, ne 2011/08/27 23:18:26 [warn] 31997#0: *1 lua exceeding regex cache max entries (1024), ... +If you are using the ngx.re.* implementation of [lua-resty-core](https://github.com/openresty/lua-resty-core) by loading the resty.core.regex module (or just the resty.core module), then an LRU cache is used for the regex cache being used here. + Do not activate the o option for regular expressions (and/or replace string arguments for [[#ngx.re.sub|ngx.re.sub]] and [[#ngx.re.gsub|ngx.re.gsub]]) that are generated ''on the fly'' and give rise to infinite variations to avoid hitting the specified limit. == lua_regex_match_limit == @@ -971,8 +1051,7 @@ As from the v0.5.0rc29 release, the special notation $prefix< '''phase:''' ''loading-config'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; -use the new [[#init_by_lua_block|init_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#init_by_lua_block|init_by_lua_block]] directive instead. Runs the Lua code specified by the argument on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file. @@ -1041,7 +1120,7 @@ This directive was first introduced in the v0.5.5 release. Similar to the [[#init_by_lua|init_by_lua]] directive except that this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping). For instance, @@ -1076,7 +1155,7 @@ This directive was first introduced in the v0.5.5 release. '''phase:''' ''starting-worker'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; use the new [[#init_worker_by_lua_block|init_worker_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#init_worker_by_lua_block|init_worker_by_lua_block]] directive instead. Runs the specified Lua code upon every Nginx worker process's startup when the master process is enabled. When the master process is disabled, this hook will just run after [[#init_by_lua|init_by_lua*]]. @@ -1101,8 +1180,8 @@ This hook is often used to create per-worker reoccurring timers (via the [[#ngx. end end - local ok, err = new_timer(delay, check) - if not ok then + local hdl, err = new_timer(delay, check) + if not hdl then log(ERR, "failed to create timer: ", err) return end @@ -1121,7 +1200,7 @@ This directive was first introduced in the v0.9.5 release. Similar to the [[#init_worker_by_lua|init_worker_by_lua]] directive except that this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping). For instance, @@ -1154,7 +1233,7 @@ This directive was first introduced in the v0.9.5 release. '''phase:''' ''rewrite'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; use the new [[#set_by_lua_block|set_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#set_by_lua_block|set_by_lua_block]] directive instead. Executes code specified in with optional input arguments $arg1 $arg2 ..., and returns string output to $res. The code in can make [[#Nginx API for Lua|API calls]] and can retrieve input arguments from the ngx.arg table (index starts from 1 and increases sequentially). @@ -1177,15 +1256,15 @@ a time. However, a workaround is possible using the [[#ngx.var.VARIABLE|ngx.var. location /foo { set $diff ''; # we have to predefine the $diff variable here - + set_by_lua $sum ' local a = 32 local b = 56 - + ngx.var.diff = a - b; -- write to $diff directly return a + b; -- return the $sum value normally '; - + echo "sum = $sum, diff = $diff"; } @@ -1213,7 +1292,7 @@ This directive requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_ki Similar to the [[#set_by_lua|set_by_lua]] directive except that # this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping), and # this directive does not support extra arguments after the Lua script as in [[#set_by_lua|set_by_lua]]. @@ -1235,15 +1314,15 @@ This directive was first introduced in the v0.9.17 release. '''phase:''' ''rewrite'' -Equivalent to [[#set_by_lua|set_by_lua]], except that the file specified by contains the Lua code, or, as from the v0.5.0rc32 release, the [[#Lua/LuaJIT bytecode support|Lua/LuaJIT bytecode]] to be executed. +Equivalent to [[#set_by_lua|set_by_lua]], except that the file specified by contains the Lua code, or, as from the v0.5.0rc32 release, the [[#Lua/LuaJIT bytecode support|Lua/LuaJIT bytecode]] to be executed. Nginx variable interpolation is supported in the argument string of this directive. But special care must be taken for injection attacks. When a relative path like foo/bar.lua is given, they will be turned into the absolute path relative to the server prefix path determined by the -p PATH command-line option while starting the Nginx server. -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached +When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by +The Lua code cache can be temporarily disabled during development by switching [[#lua_code_cache|lua_code_cache]] off in nginx.conf to avoid reloading Nginx. This directive requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_kit] module. @@ -1256,10 +1335,9 @@ This directive requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_ki '''phase:''' ''content'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; -use the new [[#content_by_lua_block|content_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#content_by_lua_block|content_by_lua_block]] directive instead. -Acts as a "content handler" and executes Lua code string specified in for every request. +Acts as a "content handler" and executes Lua code string specified in for every request. The Lua code may make [[#Nginx API for Lua|API calls]] and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). Do not use this directive and other content handler directives in the same location. For example, this directive and the [[HttpProxyModule#proxy_pass|proxy_pass]] directive should not be used in the same location. @@ -1274,7 +1352,7 @@ Do not use this directive and other content handler directives in the same locat Similar to the [[#content_by_lua|content_by_lua]] directive except that this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping). For instance, @@ -1301,15 +1379,15 @@ Nginx variables can be used in the string When a relative path like foo/bar.lua is given, they will be turned into the absolute path relative to the server prefix path determined by the -p PATH command-line option while starting the Nginx server. -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached +When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by +The Lua code cache can be temporarily disabled during development by switching [[#lua_code_cache|lua_code_cache]] off in nginx.conf to avoid reloading Nginx. Nginx variables are supported in the file path for dynamic dispatch, for example: - # WARNING: contents in nginx var must be carefully filtered, + # CAUTION: contents in nginx var must be carefully filtered, # otherwise there'll be great security risk! location ~ ^/app/([-_a-zA-Z0-9/]+) { set $path $1; @@ -1327,8 +1405,7 @@ But be very careful about malicious user inputs and always carefully validate or '''phase:''' ''rewrite tail'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; -use the new [[#rewrite_by_lua_block|rewrite_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#rewrite_by_lua_block|rewrite_by_lua_block]] directive instead. Acts as a rewrite phase handler and executes Lua code string specified in for every request. The Lua code may make [[#Nginx API for Lua|API calls]] and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). @@ -1376,7 +1453,7 @@ The right way of doing this is as follows: return ngx.redirect("/bar"); end '; - + echo "res = $b"; } @@ -1388,11 +1465,11 @@ Note that the [http://www.grid.net.ru/nginx/eval.en.html ngx_eval] module can be eval $res { proxy_pass http://foo.com/check-spam; } - + if ($res = 'spam') { rewrite ^ /terms-of-use.html redirect; } - + fastcgi_pass ...; } @@ -1404,7 +1481,7 @@ can be implemented in ngx_lua as: internal; proxy_pass http://foo.com/check-spam; } - + location / { rewrite_by_lua ' local res = ngx.location.capture("/check-spam") @@ -1412,7 +1489,7 @@ can be implemented in ngx_lua as: return ngx.redirect("/terms-of-use.html") end '; - + fastcgi_pass ...; }
@@ -1447,7 +1524,7 @@ The rewrite_by_lua code will always run at the end of the rew Similar to the [[#rewrite_by_lua|rewrite_by_lua]] directive except that this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping). For instance, @@ -1488,8 +1565,7 @@ Nginx variables are supported in the file path for dynamic dispatch just as in [ '''phase:''' ''access tail'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; -use the new [[#access_by_lua_block|access_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#access_by_lua_block|access_by_lua_block]] directive instead. Acts as an access phase handler and executes Lua code string specified in for every request. The Lua code may make [[#Nginx API for Lua|API calls]] and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). @@ -1502,12 +1578,12 @@ Note that this handler always runs ''after'' the standard [[HttpAccessModule]]. allow 192.168.1.0/24; allow 10.1.1.0/16; deny all; - + access_by_lua ' local res = ngx.location.capture("/mysql", { ... }) ... '; - + # proxy_pass/fastcgi_pass/... }
@@ -1519,7 +1595,7 @@ Note that the [http://mdounin.ru/hg/ngx_http_auth_request_module/ ngx_auth_reque location / { auth_request /auth; - + # proxy_pass/fastcgi_pass/postgres_pass/... } @@ -1530,18 +1606,18 @@ can be implemented in ngx_lua as: location / { access_by_lua ' local res = ngx.location.capture("/auth") - + if res.status == ngx.HTTP_OK then return end - + if res.status == ngx.HTTP_FORBIDDEN then ngx.exit(res.status) end - + ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) '; - + # proxy_pass/fastcgi_pass/postgres_pass/... }
@@ -1564,7 +1640,7 @@ of NGINX. Similar to the [[#access_by_lua|access_by_lua]] directive except that this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping). For instance, @@ -1591,7 +1667,7 @@ Nginx variables can be used in the string When a relative path like foo/bar.lua is given, they will be turned into the absolute path relative to the server prefix path determined by the -p PATH command-line option while starting the Nginx server. -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached +When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [[#lua_code_cache|lua_code_cache]] off in nginx.conf to avoid repeatedly reloading Nginx. @@ -1605,8 +1681,7 @@ Nginx variables are supported in the file path for dynamic dispatch just as in [ '''phase:''' ''output-header-filter'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; -use the new [[#header_filter_by_lua_block|header_filter_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#header_filter_by_lua_block|header_filter_by_lua_block]] directive instead. Uses Lua code specified in to define an output header filter. @@ -1638,7 +1713,7 @@ This directive was first introduced in the v0.2.1rc20 release. Similar to the [[#header_filter_by_lua|header_filter_by_lua]] directive except that this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping). For instance, @@ -1673,8 +1748,7 @@ This directive was first introduced in the v0.2.1rc20 release. '''phase:''' ''output-body-filter'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; -use the new [[#body_filter_by_lua_block|body_filter_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#body_filter_by_lua_block|body_filter_by_lua_block]] directive instead. Uses Lua code specified in to define an output body filter. @@ -1761,7 +1835,7 @@ This directive was first introduced in the v0.5.0rc32 release. Similar to the [[#body_filter_by_lua|body_filter_by_lua]] directive except that this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping). For instance, @@ -1796,15 +1870,14 @@ This directive was first introduced in the v0.5.0rc32 release. '''phase:''' ''log'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; -use the new [[#log_by_lua_block|log_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#log_by_lua_block|log_by_lua_block]] directive instead. Runs the Lua source code inlined as the at the log request processing phase. This does not replace the current access logs, but runs before. Note that the following API functions are currently disabled within this context: * Output API functions (e.g., [[#ngx.say|ngx.say]] and [[#ngx.send_headers|ngx.send_headers]]) -* Control API functions (e.g., [[#ngx.exit|ngx.exit]]) +* Control API functions (e.g., [[#ngx.exit|ngx.exit]]) * Subrequest API functions (e.g., [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]]) * Cosocket API functions (e.g., [[#ngx.socket.tcp|ngx.socket.tcp]] and [[#ngx.req.socket|ngx.req.socket]]). @@ -1838,7 +1911,7 @@ Here is an example of gathering average data for [[HttpUpstreamModule#$upstream_ local log_dict = ngx.shared.log_dict local sum = log_dict:get("upstream_time-sum") local nb = log_dict:get("upstream_time-nb") - + if nb and sum then ngx.say("average upstream response time: ", sum / nb, " (", nb, " reqs)") @@ -1862,7 +1935,7 @@ This directive was first introduced in the v0.5.0rc31 release. Similar to the [[#log_by_lua|log_by_lua]] directive except that this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping). For instance, @@ -2430,7 +2503,7 @@ See also [[#lua_ssl_trusted_certificate|lua_ssl_trusted_certificate]]. '''context:''' ''http, server, location, location-if'' -Enables or disables automatic response buffering for HTTP 1.0 (or older) requests. This buffering mechanism is mainly used for HTTP 1.0 keep-alive which replies on a proper Content-Length response header. +Enables or disables automatic response buffering for HTTP 1.0 (or older) requests. This buffering mechanism is mainly used for HTTP 1.0 keep-alive which relies on a proper Content-Length response header. If the Lua code explicitly sets a Content-Length response header before sending the headers (either explicitly via [[#ngx.send_headers|ngx.send_headers]] or implicitly via the first [[#ngx.say|ngx.say]] or [[#ngx.print|ngx.print]] call), then the HTTP 1.0 response buffering will be disabled even when this directive is turned on. @@ -2486,7 +2559,7 @@ This directive was first introduced in the v0.5.0rc32 release. This directive controls whether to check for premature client connection abortion. -When this directive is turned on, the ngx_lua module will monitor the premature connection close event on the downstream connections. And when there is such an event, it will call the user Lua function callback (registered by [[#ngx.on_abort|ngx.on_abort]]) or just stop and clean up all the Lua "light threads" running in the current request's request handler when there is no user callback function registered. +When this directive is on, the ngx_lua module will monitor the premature connection close event on the downstream connections and when there is such an event, it will call the user Lua function callback (registered by [[#ngx.on_abort|ngx.on_abort]]) or just stop and clean up all the Lua "light threads" running in the current request's request handler when there is no user callback function registered. According to the current implementation, however, if the client closes the connection before the Lua code finishes reading the request body data via [[#ngx.req.socket|ngx.req.socket]], then ngx_lua will neither stop all the running "light threads" nor call the user callback (if [[#ngx.on_abort|ngx.on_abort]] has been called). Instead, the reading operation on [[#ngx.req.socket|ngx.req.socket]] will just return the error message "client aborted" as the second return value (the first return value is surely nil). @@ -2592,11 +2665,11 @@ Here is an example location /foo { set $a 32; set $b 56; - + set_by_lua $sum 'return tonumber(ngx.arg[1]) + tonumber(ngx.arg[2])' $a $b; - + echo $sum; }
@@ -2646,7 +2719,7 @@ Setting ngx.var.Foo to a nil value will unset the -'''WARNING''' When reading from an Nginx variable, Nginx will allocate memory in the per-request memory pool which is freed only at request termination. So when you need to read from an Nginx variable repeatedly in your Lua code, cache the Nginx variable value to your own Lua variable, for example, +'''CAUTION''' When reading from an Nginx variable, Nginx will allocate memory in the per-request memory pool which is freed only at request termination. So when you need to read from an Nginx variable repeatedly in your Lua code, cache the Nginx variable value to your own Lua variable, for example, local val = ngx.var.some_var @@ -2655,7 +2728,7 @@ Setting ngx.var.Foo to a nil value will unset the nil while uninitialized (but defined) NGINX variables are evaluated to an empty Lua string. This API requires a relatively expensive metamethod call and it is recommended to avoid using it on hot code paths. @@ -2780,7 +2853,7 @@ There is a hard coded 2048 byte limitation on error message lengths == ngx.ctx == '''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*'' -This table can be used to store per-request Lua context data and has a life time identical to the current request (as with the Nginx variables). +This table can be used to store per-request Lua context data and has a life time identical to the current request (as with the Nginx variables). Consider the following example, @@ -2816,7 +2889,7 @@ Every request, including subrequests, has its own copy of the table. For example ngx.say("sub post: ", ngx.ctx.blah) } } - + location /main { content_by_lua_block { ngx.ctx.blah = 73 @@ -2847,7 +2920,7 @@ Internal redirection will destroy the original request ngx.ctx data ngx.say(ngx.ctx.foo) } } - + location /orig { content_by_lua_block { ngx.ctx.foo = "hello" @@ -2876,14 +2949,14 @@ When being used in the context of [[#init_worker_by_lua|init_worker_by_lua*]], t The ngx.ctx lookup requires relatively expensive metamethod calls and it is much slower than explicitly passing per-request data along by your own function arguments. So do not abuse this API for saving your own function arguments because it usually has quite some performance impact. -Because of the metamethod magic, never "local" the ngx.ctx table outside your Lua function scope on the Lua module level level due to [[#Data_Sharing_within_an_Nginx_Worker|worker-level data sharing]]. For example, the following is bad: +Because of the metamethod magic, never "local" the ngx.ctx table outside your Lua function scope on the Lua module level due to [[#Data_Sharing_within_an_Nginx_Worker|worker-level data sharing]]. For example, the following is bad: -- mymodule.lua local _M = {} -- the following line is bad since ngx.ctx is a per-request --- data while this `ctx` variable is on the Lua module level +-- data while this ctx variable is on the Lua module level -- and thus is per-nginx-worker. local ctx = ngx.ctx @@ -2907,7 +2980,7 @@ end return _M -That is, let the caller pass the `ctx` table explicitly via a function argument. +That is, let the caller pass the ctx table explicitly via a function argument. == ngx.location.capture == '''syntax:''' ''res = ngx.location.capture(uri, options?)'' @@ -3024,7 +3097,7 @@ The args option can also take plain query strings: This is functionally identical to the previous examples. -The share_all_vars option controls whether to share nginx variables among the current request and its subrequests. +The share_all_vars option controls whether to share nginx variables among the current request and its subrequests. If this option is set to true, then the current request and associated subrequests will share the same Nginx variable scope. Hence, changes to Nginx variables made by a subrequest will affect the current request. Care should be taken in using this option as variable scope sharing can have unexpected side effects. The args, vars, or copy_all_vars options are generally preferable instead. @@ -3089,7 +3162,7 @@ In addition to the two settings above, it is possible to specify values for variables in the subrequest using the vars option. These variables are set after the sharing or copying of variables has been evaluated, and provides a more efficient method of passing specific -values to a subrequest over encoding them as URL arguments and +values to a subrequest over encoding them as URL arguments and unescaping them in the Nginx config file. @@ -3171,7 +3244,7 @@ Note that subrequests issued by [[#ngx.location.capture|ngx.location.capture]] i request headers of the current request by default and that this may have unexpected side effects on the subrequest responses. For example, when using the standard ngx_proxy module to serve subrequests, an "Accept-Encoding: gzip" header in the main request may result -in gzipped responses that cannot be handled properly in Lua code. Original request headers should be ignored by setting +in gzipped responses that cannot be handled properly in Lua code. Original request headers should be ignored by setting [[HttpProxyModule#proxy_pass_request_headers|proxy_pass_request_headers]] to off in subrequest locations. When the body option is not specified and the always_forward_body option is false (the default value), the POST and PUT subrequests will inherit the request bodies of the parent request (if any). @@ -3201,11 +3274,11 @@ This function issues several parallel subrequests specified by the input table a { "/bar" }, { "/baz", { method = ngx.HTTP_POST, body = "hello" } }, } - + if res1.status == ngx.HTTP_OK then ... end - + if res2.body == "BLAH" then ... end @@ -3223,10 +3296,10 @@ Lua tables can be used for both requests and responses when the number of subreq table.insert(reqs, { "/postgres" }) table.insert(reqs, { "/redis" }) table.insert(reqs, { "/memcached" }) - + -- issue all the requests at once and wait until they all return local resps = { ngx.location.capture_multi(reqs) } - + -- loop over the responses table for i, resp in ipairs(resps) do -- process the response table "resp" @@ -3278,7 +3351,7 @@ The header names are matched case-insensitively. -- equivalent to ngx.header["Content-Type"] = 'text/plain' ngx.header.content_type = 'text/plain'; - + ngx.header["X-My-Header"] = 'blah blah'; @@ -3295,7 +3368,7 @@ will yield Set-Cookie: b=4; path=/ -in the response headers. +in the response headers. Only Lua tables are accepted (Only the last element in the table will take effect for standard headers such as Content-Type that only accept a single value). @@ -3323,7 +3396,7 @@ The same applies to assigning an empty table: Setting ngx.header.HEADER after sending out response headers (either explicitly with [[#ngx.send_headers|ngx.send_headers]] or implicitly with [[#ngx.print|ngx.print]] and similar) will throw out a Lua exception. -Reading ngx.header.HEADER will return the value of the response header named HEADER. +Reading ngx.header.HEADER will return the value of the response header named HEADER. Underscores (_) in the header names will also be replaced by dashes (-) and the header names will be matched case-insensitively. If the response header is not present at all, nil will be returned. @@ -3655,8 +3728,8 @@ Arguments without the = parts are treated as boolean argumen That is, they will take Lua boolean values true. However, they are different from arguments taking empty string values. GET /test?foo=&bar= will give something like - foo: - bar: + foo: + bar: Empty key arguments are discarded. GET /test?=hello&=world will yield an empty output for instance. @@ -3760,13 +3833,13 @@ Arguments without the = parts are treated as boolean argumen That is, they will take Lua boolean values true. However, they are different from arguments taking empty string values. POST /test with request body foo=&bar= will return something like - foo: - bar: + foo: + bar: Empty key arguments are discarded. POST /test with body =hello&=world will yield empty outputs for instance. -Note that a maximum of 100 request arguments are parsed by default (including those with the same name) and that additional request arguments are silently discarded to guard against potential denial of service attacks. +Note that a maximum of 100 request arguments are parsed by default (including those with the same name) and that additional request arguments are silently discarded to guard against potential denial of service attacks. However, the optional max_args function argument can be used to override this limit: @@ -3818,7 +3891,7 @@ the value of ngx.req.get_headers()["Foo"] will be a Lua (array) tab {"foo", "bar", "baz"}
-Note that a maximum of 100 request headers are parsed by default (including those with the same name) and that additional request headers are silently discarded to guard against potential denial of service attacks. +Note that a maximum of 100 request headers are parsed by default (including those with the same name) and that additional request headers are silently discarded to guard against potential denial of service attacks. However, the optional max_headers function argument can be used to override this limit: @@ -4164,6 +4237,7 @@ The optional status parameter specifies the HTTP status code to be * 301 * 302 (default) +* 303 * 307 It is 302 (ngx.HTTP_MOVED_TEMPORARILY) by default. @@ -4367,7 +4441,7 @@ Note that while this method accepts all [[#HTTP status constants|HTTP status con Also note that this method call terminates the processing of the current request and that it is recommended that a coding style that combines this method call with the return statement, i.e., return ngx.exit(...) be used to reinforce the fact that the request processing is being terminated. -When being used in the contexts of [[#header_filter_by_lua|header_filter_by_lua]] and +When being used in the contexts of [[#header_filter_by_lua|header_filter_by_lua*]], [[#balancer_by_lua_block|balancer_by_lua*]], and [[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]], ngx.exit() is an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use return in combination as suggested above. @@ -4378,14 +4452,14 @@ an asynchronous operation and will return immediately. This behavior may change Explicitly specify the end of the response output stream. In the case of HTTP 1.1 chunked encoded output, it will just trigger the Nginx core to send out the "last chunk". -When you disable the HTTP 1.1 keep-alive feature for your downstream connections, you can rely on descent HTTP clients to close the connection actively for you when you call this method. This trick can be used do back-ground jobs without letting the HTTP clients to wait on the connection, as in the following example: +When you disable the HTTP 1.1 keep-alive feature for your downstream connections, you can rely on well written HTTP clients to close the connection actively for you when you call this method. This trick can be used do back-ground jobs without letting the HTTP clients to wait on the connection, as in the following example: location = /async { keepalive_timeout 0; content_by_lua_block { ngx.say("got the task!") - ngx.eof() -- a descent HTTP client will close the connection at this point + ngx.eof() -- well written HTTP clients will close the connection at this point -- access MySQL, PostgreSQL, Redis, Memcached, and etc here... } } @@ -4646,7 +4720,7 @@ This is the local time. Returns the elapsed seconds from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). -Updates of the Nginx time cache an be forced by calling [[#ngx.update_time|ngx.update_time]] first. +Updates of the Nginx time cache can be forced by calling [[#ngx.update_time|ngx.update_time]] first. == ngx.now == '''syntax:''' ''secs = ngx.now()'' @@ -4858,7 +4932,7 @@ The optional fourth argument, ctx, can be a Lua table holding an op local ctx = { pos = 2 } local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) - -- m[0] = "34" + -- m[0] = "234" -- ctx.pos == 5 @@ -5024,7 +5098,7 @@ When the replace is a string, then it is treated as a special templ where $0 referring to the whole substring matched by the pattern and $1 referring to the first parenthesized capturing substring. -Curly braces can also be used to disambiguate variable names from the background string literals: +Curly braces can also be used to disambiguate variable names from the background string literals: local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "${0}00") @@ -5123,6 +5197,8 @@ The resulting object dict has the following methods: * [[#ngx.shared.DICT.flush_expired|flush_expired]] * [[#ngx.shared.DICT.get_keys|get_keys]] +All these methods are ''atomic'' operations, that is, safe from concurrent accesses from multiple nginx worker processes for the same lua_shared_dict zone. + Here is an example: @@ -5343,7 +5419,7 @@ The value argument and init argument can be any valid This method was first introduced in the v0.3.1rc22 release. -The optional `init` parameter was first added in the v0.10.6 release. +The optional init parameter was first added in the v0.10.6 release. See also [[#ngx.shared.DICT|ngx.shared.DICT]]. @@ -5445,7 +5521,7 @@ Fetch a list of the keys from the dictionary, up to . By default, only the first 1024 keys (if any) are returned. When the argument is given the value 0, then all the keys will be returned even there is more than 1024 keys in the dictionary. -'''WARNING''' Be careful when calling this method on dictionaries with a really huge number of keys. This method may lock the dictionary for quite a while and block all the nginx worker processes that are trying to access the dictionary. +'''CAUTION''' Avoid calling this method on dictionaries with a very large number of keys as it may lock the dictionary for significant amount of time and block Nginx worker processes trying to access the dictionary. This feature was first introduced in the v0.7.3 release. @@ -5724,7 +5800,7 @@ session userdata returned by a previous sslhandshake call for exactly the same target. For short-lived connections, reusing SSL sessions can usually speed up the handshake by one order by magnitude but it is not so useful if the connection pool is enabled. This argument defaults to -`nil`. If this argument takes the boolean `false` value, no SSL session +nil. If this argument takes the boolean false value, no SSL session userdata would return by this call and only a Lua boolean will be returned as the first return value; otherwise the current SSL session will always be returned as the first argument in case of successes. @@ -5737,7 +5813,7 @@ also used to validate the server name specified in the server certificate sent f the remote. The optional ssl_verify argument takes a Lua boolean value to -control whether to perform SSL verification. When set to `true`, the server +control whether to perform SSL verification. When set to true, the server certificate will be verified according to the CA certificates specified by the [[#lua_ssl_trusted_certificate|lua_ssl_trusted_certificate]] directive. You may also need to adjust the [[#lua_ssl_verify_depth|lua_ssl_verify_depth]] @@ -6148,7 +6224,7 @@ Then it will generate the output 4 -"Light threads" are mostly useful for doing concurrent upstream requests in a single Nginx request handler, kinda like a generalized version of [[#ngx.location.capture_multi|ngx.location.capture_multi]] that can work with all the [[#Nginx API for Lua|Nginx API for Lua]]. The following example demonstrates parallel requests to MySQL, Memcached, and upstream HTTP services in a single Lua handler, and outputting the results in the order that they actually return (very much like the Facebook BigPipe model): +"Light threads" are mostly useful for making concurrent upstream requests in a single Nginx request handler, much like a generalized version of [[#ngx.location.capture_multi|ngx.location.capture_multi]] that can work with all the [[#Nginx API for Lua|Nginx API for Lua]]. The following example demonstrates parallel requests to MySQL, Memcached, and upstream HTTP services in a single Lua handler, and outputting the results in the order that they actually return (similar to Facebook's BigPipe model): -- query mysql, memcached, and a remote http service at the same time, @@ -6187,7 +6263,7 @@ Then it will generate the output ngx.thread.spawn(query_mysql) -- create thread 1 ngx.thread.spawn(query_memcached) -- create thread 2 - ngx.thread.spawn(query_http) -- create thread 3 + ngx.thread.spawn(query_http) -- create thread 3 This API was first enabled in the v0.7.0 release. @@ -6338,7 +6414,7 @@ This API was first introduced in the v0.7.4 release. See also [[#lua_check_client_abort|lua_check_client_abort]]. == ngx.timer.at == -'''syntax:''' ''ok, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)'' +'''syntax:''' ''hdl, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)'' '''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' @@ -6364,7 +6440,7 @@ Premature timer expiration happens when the Nginx worker process is trying to shut down, as in an Nginx configuration reload triggered by the HUP signal or in an Nginx server shutdown. When the Nginx worker is trying to shut down, one can no longer call ngx.timer.at to -create new timers with nonzero delays and in that case ngx.timer.at will return nil and +create new timers with nonzero delays and in that case ngx.timer.at will return a "conditional false" value and a string describing the error, that is, "process exiting". Starting from the v0.9.3 release, it is allowed to create zero-delay timers even when the Nginx worker process starts shutting down. @@ -6413,7 +6489,7 @@ One can also create infinite re-occurring timers, for instance, a timer getting return end end - + local ok, err = ngx.timer.at(delay, handler) if not ok then ngx.log(ngx.ERR, "failed to create the timer: ", err) @@ -6421,6 +6497,9 @@ One can also create infinite re-occurring timers, for instance, a timer getting end +It is recommended, however, to use the [[#ngx.timer.every|ngx.timer.every]] API function +instead for creating recurring timers since it is more robust. + Because timer callbacks run in the background and their running time will not add to any client request's response time, they can easily accumulate in the server and exhaust system resources due to either @@ -6458,6 +6537,22 @@ You can pass most of the standard Lua values (nils, booleans, numbers, strings, This API was first introduced in the v0.8.0 release. +== ngx.timer.every == +'''syntax:''' ''hdl, err = ngx.timer.every(delay, callback, user_arg1, user_arg2, ...)'' + +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' + +Similar to the [[#ngx.timer.at|ngx.timer.at]] API function, but + +# delay ''cannot'' be zero, +# timer will be created every delay seconds until the current Nginx worker process starts exiting. + +When success, returns a "conditional true" value (but not a true). Otherwise, returns a "conditional false" value and a string describing the error. + +This API also respect the [[#lua_max_pending_timers|lua_max_pending_timers]] and [[#lua_max_running_timers|lua_max_running_timers]]. + +This API was first introduced in the v0.10.9 release. + == ngx.timer.running_count == '''syntax:''' ''count = ngx.timer.running_count()'' @@ -6481,8 +6576,8 @@ This directive was first introduced in the v0.9.20 release. '''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua*'' -This string field indicates the current NGINX subsystem the current Lua environment is based on. For this module, this field always takes the string value `"http"`. For -[https://github.com/openresty/stream-lua-nginx-module#readme ngx_stream_lua_module], however, this field takes the value `"stream"`. +This string field indicates the current NGINX subsystem the current Lua environment is based on. For this module, this field always takes the string value "http". For +[https://github.com/openresty/stream-lua-nginx-module#readme ngx_stream_lua_module], however, this field takes the value "stream". This field was first introduced in the 0.10.1. @@ -6563,7 +6658,7 @@ This API was first introduced in the 0.9.5 release. Returns the total number of the Nginx worker processes (i.e., the value configured by the [http://nginx.org/en/docs/ngx_core_module.html#worker_processes worker_processes] -directive in `nginx.conf`). +directive in nginx.conf). This API was first introduced in the 0.9.20 release. @@ -6575,11 +6670,11 @@ This API was first introduced in the 0.9.20 release. Returns the ordinal number of the current Nginx worker processes (starting from number 0). -So if the total number of workers is `N`, then this method may return a number between 0 -and `N - 1` (inclusive). +So if the total number of workers is N, then this method may return a number between 0 +and N - 1 (inclusive). This function returns meaningful values only for NGINX 1.9.1+. With earlier versions of NGINX, it -always returns `nil`. +always returns nil. See also [[#ngx.worker.count|ngx.worker.count]]. diff --git a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h index 3737149..cd64fc8 100644 --- a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10007 +#define ngx_http_lua_version 10010 typedef struct { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_api.c b/debian/modules/nginx-lua/src/ngx_http_lua_api.c index b72c707..7b590e7 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_api.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_api.c @@ -56,11 +56,10 @@ ngx_http_lua_add_package_preload(ngx_conf_t *cf, const char *package, lua_pushcfunction(L, func); lua_setfield(L, -2, package); lua_pop(L, 2); - - return NGX_OK; } - /* L == NULL */ + /* we always register preload_hooks since we always create new Lua VMs + * when lua code cache is off. */ if (lmcf->preload_hooks == NULL) { lmcf->preload_hooks = @@ -176,7 +175,9 @@ ngx_http_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, void *data) } zone->shm = shm_zone->shm; +#if defined(nginx_version) && nginx_version >= 1009000 zone->noreuse = shm_zone->noreuse; +#endif if (zone->init(zone, odata) != NGX_OK) { return NGX_ERROR; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_args.c b/debian/modules/nginx-lua/src/ngx_http_lua_args.c index 0c307d6..b43697c 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_args.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_args.c @@ -184,7 +184,7 @@ ngx_http_lua_ngx_req_get_post_args(lua_State *L) if (r->request_body->temp_file) { lua_pushnil(L); - lua_pushliteral(L, "requesty body in temp file not supported"); + lua_pushliteral(L, "request body in temp file not supported"); return 2; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c b/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c index 0adf787..2fa634e 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c @@ -314,7 +314,13 @@ ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) if (ctx->exited && ctx->exit_code != NGX_OK) { rc = ctx->exit_code; - if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) { + if (rc == NGX_ERROR + || rc == NGX_BUSY + || rc == NGX_DECLINED +#ifdef HAVE_BALANCER_STATUS_CODE_PATCH + || rc >= NGX_HTTP_SPECIAL_RESPONSE +#endif + ) { return rc; } @@ -640,7 +646,7 @@ ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r, int count, char **err) { #if (nginx_version >= 1007005) - ngx_uint_t max_tries; + ngx_uint_t max_tries, total; #endif ngx_http_lua_ctx_t *ctx; ngx_http_upstream_t *u; @@ -681,9 +687,10 @@ ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r, #if (nginx_version >= 1007005) max_tries = r->upstream->conf->next_upstream_tries; + total = bp->total_tries + r->upstream->peer.tries - 1; - if (bp->total_tries + count > max_tries) { - count = max_tries - bp->total_tries; + if (max_tries && total + count > max_tries) { + count = max_tries - total; *err = "reduced tries due to limit"; } else { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_common.h b/debian/modules/nginx-lua/src/ngx_http_lua_common.h index 267952b..e389783 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_common.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_common.h @@ -22,6 +22,19 @@ #include +#if (NGX_PCRE) + +#include + +#if (PCRE_MAJOR > 8) || (PCRE_MAJOR == 8 && PCRE_MINOR >= 21) +# define LUA_HAVE_PCRE_JIT 1 +#else +# define LUA_HAVE_PCRE_JIT 0 +#endif + +#endif + + #if !defined(nginx_version) || (nginx_version < 1006000) #error at least nginx 1.6.0 is required but found an older version #endif @@ -138,7 +151,7 @@ typedef struct ngx_http_lua_sema_mm_s ngx_http_lua_sema_mm_t; typedef ngx_int_t (*ngx_http_lua_main_conf_handler_pt)(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, lua_State *L); typedef ngx_int_t (*ngx_http_lua_srv_conf_handler_pt)(ngx_http_request_t *r, - ngx_http_lua_srv_conf_t *lmcf, lua_State *L); + ngx_http_lua_srv_conf_t *lscf, lua_State *L); typedef struct { @@ -168,6 +181,11 @@ struct ngx_http_lua_main_conf_s { ngx_int_t regex_cache_entries; ngx_int_t regex_cache_max_entries; ngx_int_t regex_match_limit; + +#if (LUA_HAVE_PCRE_JIT) + pcre_jit_stack *jit_stack; +#endif + #endif ngx_array_t *shm_zones; /* of ngx_shm_zone_t* */ @@ -199,6 +217,12 @@ struct ngx_http_lua_main_conf_s { of reqeusts */ ngx_uint_t malloc_trim_req_count; +#if nginx_version >= 1011011 + /* the following 2 fields are only used by ngx.req.raw_headers() for now */ + ngx_buf_t **busy_buf_ptrs; + ngx_int_t busy_buf_ptr_count; +#endif + unsigned requires_header_filter:1; unsigned requires_body_filter:1; unsigned requires_capture_filter:1; @@ -206,6 +230,7 @@ struct ngx_http_lua_main_conf_s { unsigned requires_access:1; unsigned requires_log:1; unsigned requires_shm:1; + unsigned requires_capture_log:1; }; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_control.c b/debian/modules/nginx-lua/src/ngx_http_lua_control.c index 249d763..ae36505 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_control.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_control.c @@ -212,10 +212,12 @@ ngx_http_lua_ngx_redirect(lua_State *L) if (rc != NGX_HTTP_MOVED_TEMPORARILY && rc != NGX_HTTP_MOVED_PERMANENTLY + && rc != NGX_HTTP_SEE_OTHER && rc != NGX_HTTP_TEMPORARY_REDIRECT) { return luaL_error(L, "only ngx.HTTP_MOVED_TEMPORARILY, " - "ngx.HTTP_MOVED_PERMANENTLY, and " + "ngx.HTTP_MOVED_PERMANENTLY, " + "ngx.HTTP_SEE_OTHER, and " "ngx.HTTP_TEMPORARY_REDIRECT are allowed"); } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c b/debian/modules/nginx-lua/src/ngx_http_lua_directive.c index 862edda..6a562f4 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_directive.c @@ -27,6 +27,8 @@ #include "ngx_http_lua_ssl_certby.h" #include "ngx_http_lua_lex.h" #include "api/ngx_http_lua_api.h" +#include "ngx_http_lua_log_ringbuf.h" +#include "ngx_http_lua_log.h" typedef struct ngx_http_lua_block_parser_ctx_s @@ -1700,6 +1702,71 @@ ngx_http_lua_conf_read_lua_token(ngx_conf_t *cf, } +char * +ngx_http_lua_capture_error_log(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ +#ifndef HAVE_INTERCEPT_ERROR_LOG_PATCH + return "not found: missing the capture error log patch for nginx"; +#else + ngx_str_t *value; + ssize_t size; + u_char *data; + ngx_cycle_t *cycle; + ngx_http_lua_main_conf_t *lmcf = conf; + ngx_http_lua_log_ringbuf_t *ringbuf; + + value = cf->args->elts; + cycle = cf->cycle; + + if (lmcf->requires_capture_log) { + return "is duplicate"; + } + + if (value[1].len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid capture error log size \"%V\"", + &value[1]); + return NGX_CONF_ERROR; + } + + size = ngx_parse_size(&value[1]); + + if (size < NGX_MAX_ERROR_STR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid capture error log size \"%V\", " + "minimum size is %d", &value[1], + NGX_MAX_ERROR_STR); + return NGX_CONF_ERROR; + } + + if (cycle->intercept_error_log_handler) { + return "capture error log handler has been hooked"; + } + + ringbuf = (ngx_http_lua_log_ringbuf_t *) + ngx_palloc(cf->pool, sizeof(ngx_http_lua_log_ringbuf_t)); + if (ringbuf == NULL) { + return NGX_CONF_ERROR; + } + + data = ngx_palloc(cf->pool, size); + if (data == NULL) { + return NGX_CONF_ERROR; + } + + ngx_http_lua_log_ringbuf_init(ringbuf, data, size); + + lmcf->requires_capture_log = 1; + cycle->intercept_error_log_handler = (ngx_log_intercept_pt) + ngx_http_lua_capture_log_handler; + cycle->intercept_error_log_data = ringbuf; + + return NGX_CONF_OK; +#endif +} + + /* * ngx_http_lua_strlstrn() is intended to search for static substring * with known length in string until the argument last. The argument n diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_directive.h b/debian/modules/nginx-lua/src/ngx_http_lua_directive.h index be591f3..5abfe4d 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_directive.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_directive.h @@ -67,9 +67,10 @@ ngx_int_t ngx_http_lua_filter_set_by_lua_file(ngx_http_request_t *r, char *ngx_http_lua_rewrite_no_postpone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); - char *ngx_http_lua_conf_lua_block_parse(ngx_conf_t *cf, ngx_command_t *cmd); +char *ngx_http_lua_capture_error_log(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); #endif /* _NGX_HTTP_LUA_DIRECTIVE_H_INCLUDED_ */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers.c b/debian/modules/nginx-lua/src/ngx_http_lua_headers.c index 0af56f6..6700ce8 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headers.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headers.c @@ -26,6 +26,9 @@ static int ngx_http_lua_ngx_req_get_headers(lua_State *L); static int ngx_http_lua_ngx_req_header_clear(lua_State *L); static int ngx_http_lua_ngx_req_header_set(lua_State *L); static int ngx_http_lua_ngx_resp_get_headers(lua_State *L); +#if nginx_version >= 1011011 +void ngx_http_lua_ngx_raw_header_cleanup(void *data); +#endif static int @@ -77,6 +80,11 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) size_t size; ngx_buf_t *b, *first = NULL; ngx_int_t i, j; +#if nginx_version >= 1011011 + ngx_buf_t **bb; + ngx_chain_t *cl; + ngx_http_lua_main_conf_t *lmcf; +#endif ngx_connection_t *c; ngx_http_request_t *r, *mr; ngx_http_connection_t *hc; @@ -93,6 +101,10 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) return luaL_error(L, "no request object found"); } +#if nginx_version >= 1011011 + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); +#endif + ngx_http_lua_check_fake_request(L, r); mr = r->main; @@ -109,8 +121,13 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) dd("hc->nbusy: %d", (int) hc->nbusy); if (hc->nbusy) { +#if nginx_version >= 1011011 + dd("hc->busy: %p %p %p %p", hc->busy->buf->start, hc->busy->buf->pos, + hc->busy->buf->last, hc->busy->buf->end); +#else dd("hc->busy: %p %p %p %p", hc->busy[0]->start, hc->busy[0]->pos, hc->busy[0]->last, hc->busy[0]->end); +#endif } dd("request line: %p %p", mr->request_line.data, @@ -146,9 +163,37 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) dd("size: %d", (int) size); if (hc->nbusy) { +#if nginx_version >= 1011011 + if (hc->nbusy > lmcf->busy_buf_ptr_count) { + if (lmcf->busy_buf_ptrs) { + ngx_free(lmcf->busy_buf_ptrs); + } + + lmcf->busy_buf_ptrs = ngx_alloc(hc->nbusy * sizeof(ngx_buf_t *), + r->connection->log); + + if (lmcf->busy_buf_ptrs == NULL) { + return luaL_error(L, "no memory"); + } + + lmcf->busy_buf_ptr_count = hc->nbusy; + } + + bb = lmcf->busy_buf_ptrs; + for (cl = hc->busy; cl; cl = cl->next) { + *bb++ = cl->buf; + } +#endif b = NULL; + +#if nginx_version >= 1011011 + bb = lmcf->busy_buf_ptrs; + for (i = hc->nbusy; i > 0; i--) { + b = bb[i - 1]; +#else for (i = 0; i < hc->nbusy; i++) { b = hc->busy[i]; +#endif dd("busy buf: %d: [%.*s]", (int) i, (int) (b->pos - b->start), b->start); @@ -223,8 +268,15 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) } if (hc->nbusy) { + +#if nginx_version >= 1011011 + bb = lmcf->busy_buf_ptrs; + for (i = hc->nbusy - 1; i >= 0; i--) { + b = bb[i]; +#else for (i = 0; i < hc->nbusy; i++) { b = hc->busy[i]; +#endif if (!found) { if (b != first) { @@ -444,6 +496,8 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) ngx_list_part_t *part; ngx_table_elt_t *header; ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; + ngx_int_t rc; u_char *lowcase_key = NULL; size_t lowcase_key_sz = 0; ngx_uint_t i; @@ -475,6 +529,22 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) return luaL_error(L, "no request object found"); } + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return luaL_error(L, "no ctx found"); + } + + if (!ctx->headers_set) { + rc = ngx_http_lua_set_content_type(r); + if (rc != NGX_OK) { + return luaL_error(L, + "failed to set default content type: %d", + (int) rc); + } + + ctx->headers_set = 1; + } + ngx_http_lua_check_fake_request(L, r); part = &r->headers_out.headers.part; @@ -603,12 +673,19 @@ ngx_http_lua_ngx_header_get(lua_State *L) ngx_uint_t i; size_t len; ngx_http_lua_loc_conf_t *llcf; + ngx_http_lua_ctx_t *ctx; + ngx_int_t rc; r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return luaL_error(L, "no ctx found"); + } + ngx_http_lua_check_fake_request(L, r); /* we skip the first argument that is the table */ @@ -640,6 +717,17 @@ ngx_http_lua_ngx_header_get(lua_State *L) key.len = len; + if (!ctx->headers_set) { + rc = ngx_http_lua_set_content_type(r); + if (rc != NGX_OK) { + return luaL_error(L, + "failed to set default content type: %d", + (int) rc); + } + + ctx->headers_set = 1; + } + return ngx_http_lua_get_output_header(L, r, &key); } @@ -718,7 +806,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) ngx_str_null(&value); } else if (lua_type(L, 3) == LUA_TTABLE) { - n = luaL_getn(L, 3); + n = lua_objlen(L, 3); if (n == 0) { ngx_str_null(&value); @@ -852,7 +940,7 @@ ngx_http_lua_ngx_req_header_set_helper(lua_State *L) ngx_str_null(&value); } else if (lua_type(L, 2) == LUA_TTABLE) { - n = luaL_getn(L, 2); + n = lua_objlen(L, 2); if (n == 0) { ngx_str_null(&value); @@ -1262,6 +1350,7 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, ngx_uint_t i; ngx_table_elt_t *h; ngx_list_part_t *part; + ngx_http_lua_ctx_t *ctx; ngx_http_lua_loc_conf_t *llcf; @@ -1269,6 +1358,21 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + /* *errmsg = "no ctx found"; */ + return NGX_ERROR; + } + + if (!ctx->headers_set) { + if (ngx_http_lua_set_content_type(r) != NGX_OK) { + /* *errmsg = "failed to set default content type"; */ + return NGX_ERROR; + } + + ctx->headers_set = 1; + } + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->transform_underscores_in_resp_headers && memchr(key, '_', key_len) != NULL) @@ -1379,4 +1483,20 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, #endif /* NGX_LUA_NO_FFI_API */ +#if nginx_version >= 1011011 +void +ngx_http_lua_ngx_raw_header_cleanup(void *data) +{ + ngx_http_lua_main_conf_t *lmcf; + + lmcf = (ngx_http_lua_main_conf_t *) data; + + if (lmcf->busy_buf_ptrs) { + ngx_free(lmcf->busy_buf_ptrs); + lmcf->busy_buf_ptrs = NULL; + } +} +#endif + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers.h b/debian/modules/nginx-lua/src/ngx_http_lua_headers.h index 39f1114..ee4d21c 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headers.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headers.h @@ -15,6 +15,9 @@ void ngx_http_lua_inject_resp_header_api(lua_State *L); void ngx_http_lua_inject_req_header_api(lua_State *L); void ngx_http_lua_create_headers_metatable(ngx_log_t *log, lua_State *L); +#if nginx_version >= 1011011 +void ngx_http_lua_ngx_raw_header_cleanup(void *data); +#endif #endif /* _NGX_HTTP_LUA_HEADERS_H_INCLUDED_ */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_log.c b/debian/modules/nginx-lua/src/ngx_http_lua_log.c index c2b2269..c18e6b0 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_log.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_log.c @@ -13,6 +13,7 @@ #include "ngx_http_lua_log.h" #include "ngx_http_lua_util.h" +#include "ngx_http_lua_log_ringbuf.h" static int ngx_http_lua_print(lua_State *L); @@ -313,4 +314,120 @@ ngx_http_lua_inject_log_consts(lua_State *L) /* }}} */ } + +#ifdef HAVE_INTERCEPT_ERROR_LOG_PATCH +ngx_int_t +ngx_http_lua_capture_log_handler(ngx_log_t *log, + ngx_uint_t level, u_char *buf, size_t n) +{ + ngx_http_lua_log_ringbuf_t *ringbuf; + + dd("enter"); + + ringbuf = (ngx_http_lua_log_ringbuf_t *) + ngx_cycle->intercept_error_log_data; + + if (level > ringbuf->filter_level) { + return NGX_OK; + } + + ngx_http_lua_log_ringbuf_write(ringbuf, level, buf, n); + + dd("capture log: %s\n", buf); + + return NGX_OK; +} +#endif + + +#ifndef NGX_LUA_NO_FFI_API +int +ngx_http_lua_ffi_errlog_set_filter_level(int level, u_char *err, size_t *errlen) +{ +#ifdef HAVE_INTERCEPT_ERROR_LOG_PATCH + ngx_http_lua_log_ringbuf_t *ringbuf; + + ringbuf = ngx_cycle->intercept_error_log_data; + + if (ringbuf == NULL) { + *errlen = ngx_snprintf(err, *errlen, + "directive \"lua_capture_error_log\" is not set") + - err; + return NGX_ERROR; + } + + if (level > NGX_LOG_DEBUG || level < NGX_LOG_STDERR) { + *errlen = ngx_snprintf(err, *errlen, "bad log level: %d", level) + - err; + return NGX_ERROR; + } + + ringbuf->filter_level = level; + return NGX_OK; +#else + *errlen = ngx_snprintf(err, *errlen, + "missing the capture error log patch for nginx") + - err; + return NGX_ERROR; +#endif +} + + +int +ngx_http_lua_ffi_errlog_get_msg(char **log, int *loglevel, u_char *err, + size_t *errlen, double *log_time) +{ +#ifdef HAVE_INTERCEPT_ERROR_LOG_PATCH + ngx_uint_t loglen; + + ngx_http_lua_log_ringbuf_t *ringbuf; + + ringbuf = ngx_cycle->intercept_error_log_data; + + if (ringbuf == NULL) { + *errlen = ngx_snprintf(err, *errlen, + "directive \"lua_capture_error_log\" is not set") + - err; + return NGX_ERROR; + } + + if (ringbuf->count == 0) { + return NGX_DONE; + } + + ngx_http_lua_log_ringbuf_read(ringbuf, loglevel, (void **) log, &loglen, + log_time); + return loglen; +#else + *errlen = ngx_snprintf(err, *errlen, + "missing the capture error log patch for nginx") + - err; + return NGX_ERROR; +#endif +} + + +int +ngx_http_lua_ffi_errlog_get_sys_filter_level(ngx_http_request_t *r) +{ + ngx_log_t *log; + int log_level; + + if (r && r->connection && r->connection->log) { + log = r->connection->log; + + } else { + log = ngx_cycle->log; + } + + log_level = log->log_level; + if (log_level == NGX_LOG_DEBUG_ALL) { + log_level = NGX_LOG_DEBUG; + } + + return log_level; +} + +#endif + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_log.h b/debian/modules/nginx-lua/src/ngx_http_lua_log.h index 42f1839..56cd771 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_log.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_log.h @@ -13,6 +13,10 @@ void ngx_http_lua_inject_log_api(lua_State *L); +#ifdef HAVE_INTERCEPT_ERROR_LOG_PATCH +ngx_int_t ngx_http_lua_capture_log_handler(ngx_log_t *log, + ngx_uint_t level, u_char *buf, size_t n); +#endif #endif /* _NGX_HTTP_LUA_LOG_H_INCLUDED_ */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.c b/debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.c new file mode 100644 index 0000000..0464069 --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.c @@ -0,0 +1,225 @@ + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_lua_common.h" +#include "ngx_http_lua_log_ringbuf.h" + + +typedef struct { + double time; + unsigned len; + unsigned log_level; +} ngx_http_lua_log_ringbuf_header_t; + + +enum { + HEADER_LEN = sizeof(ngx_http_lua_log_ringbuf_header_t) +}; + + +static void *ngx_http_lua_log_ringbuf_next_header( + ngx_http_lua_log_ringbuf_t *rb); +static void ngx_http_lua_log_ringbuf_append( + ngx_http_lua_log_ringbuf_t *rb, int log_level, void *buf, int n); +static size_t ngx_http_lua_log_ringbuf_free_spaces( + ngx_http_lua_log_ringbuf_t *rb); + + +void +ngx_http_lua_log_ringbuf_init(ngx_http_lua_log_ringbuf_t *rb, void *buf, + size_t len) +{ + rb->data = buf; + rb->size = len; + + rb->tail = rb->data; + rb->head = rb->data; + rb->sentinel = rb->data + rb->size; + rb->count = 0; + rb->filter_level = NGX_LOG_DEBUG; + + return; +} + + +void +ngx_http_lua_log_ringbuf_reset(ngx_http_lua_log_ringbuf_t *rb) +{ + rb->tail = rb->data; + rb->head = rb->data; + rb->sentinel = rb->data + rb->size; + rb->count = 0; + + return; +} + + +/* + * get the next data header, it'll skip the useless data space or + * placehold data + */ +static void * +ngx_http_lua_log_ringbuf_next_header(ngx_http_lua_log_ringbuf_t *rb) +{ + /* useless data */ + if (rb->size - (rb->head - rb->data) < HEADER_LEN) + { + return rb->data; + } + + /* placehold data */ + if (rb->head >= rb->sentinel) { + return rb->data; + } + + return rb->head; +} + + +/* append data to ring buffer directly */ +static void +ngx_http_lua_log_ringbuf_append(ngx_http_lua_log_ringbuf_t *rb, + int log_level, void *buf, int n) +{ + ngx_http_lua_log_ringbuf_header_t *head; + ngx_time_t *tp; + + head = (ngx_http_lua_log_ringbuf_header_t *) rb->tail; + head->len = n; + head->log_level = log_level; + + tp = ngx_timeofday(); + head->time = tp->sec + tp->msec / 1000.0L; + + rb->tail += HEADER_LEN; + ngx_memcpy(rb->tail, buf, n); + rb->tail += n; + rb->count++; + + if (rb->tail > rb->sentinel) { + rb->sentinel = rb->tail; + } + + return; +} + + +/* throw away data at head */ +static void +ngx_http_lua_log_ringbuf_throw_away(ngx_http_lua_log_ringbuf_t *rb) +{ + ngx_http_lua_log_ringbuf_header_t *head; + + if (rb->count == 0) { + return; + } + + head = (ngx_http_lua_log_ringbuf_header_t *) rb->head; + + rb->head += HEADER_LEN + head->len; + rb->count--; + + if (rb->count == 0) { + ngx_http_lua_log_ringbuf_reset(rb); + } + + rb->head = ngx_http_lua_log_ringbuf_next_header(rb); + + return; +} + + +/* size of free spaces */ +static size_t +ngx_http_lua_log_ringbuf_free_spaces(ngx_http_lua_log_ringbuf_t *rb) +{ + if (rb->count == 0) { + return rb->size; + } + + if (rb->tail > rb->head) { + return rb->data + rb->size - rb->tail; + } + + return rb->head - rb->tail; +} + + +/* + * try to write log data to ring buffer, throw away old data + * if there was not enough free spaces. + */ +ngx_int_t +ngx_http_lua_log_ringbuf_write(ngx_http_lua_log_ringbuf_t *rb, int log_level, + void *buf, size_t n) +{ + if (n + HEADER_LEN > rb->size) { + return NGX_ERROR; + } + + if (ngx_http_lua_log_ringbuf_free_spaces(rb) < n + HEADER_LEN) { + /* if the right space is not enough, mark it as placehold data */ + if ((size_t)(rb->data + rb->size - rb->tail) < n + HEADER_LEN) { + + while (rb->head >= rb->tail && rb->count) { + /* head is after tail, so we will throw away all data between + * head and sentinel */ + ngx_http_lua_log_ringbuf_throw_away(rb); + } + + rb->sentinel = rb->tail; + rb->tail = rb->data; + } + + while (ngx_http_lua_log_ringbuf_free_spaces(rb) < n + HEADER_LEN) { + ngx_http_lua_log_ringbuf_throw_away(rb); + } + } + + ngx_http_lua_log_ringbuf_append(rb, log_level, buf, n); + + return NGX_OK; +} + + +/* read log from ring buffer, do reset if all of the logs were readed. */ +ngx_int_t +ngx_http_lua_log_ringbuf_read(ngx_http_lua_log_ringbuf_t *rb, int *log_level, + void **buf, size_t *n, double *log_time) +{ + ngx_http_lua_log_ringbuf_header_t *head; + + if (rb->count == 0) { + return NGX_ERROR; + } + + head = (ngx_http_lua_log_ringbuf_header_t *) rb->head; + + if (rb->head >= rb->sentinel) { + return NGX_ERROR; + } + + *log_level = head->log_level; + *n = head->len; + rb->head += HEADER_LEN; + *buf = rb->head; + rb->head += head->len; + + if (log_time) { + *log_time = head->time; + } + + rb->count--; + + if (rb->count == 0) { + ngx_http_lua_log_ringbuf_reset(rb); + } + + rb->head = ngx_http_lua_log_ringbuf_next_header(rb); + + return NGX_OK; +} diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.h b/debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.h new file mode 100644 index 0000000..c9c2c2d --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.h @@ -0,0 +1,31 @@ + +#ifndef _NGX_HTTP_LUA_RINGBUF_H_INCLUDED_ +#define _NGX_HTTP_LUA_RINGBUF_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +typedef struct { + ngx_uint_t filter_level; + char *tail; /* writed point */ + char *head; /* readed point */ + char *data; /* buffer */ + char *sentinel; + size_t size; /* buffer total size */ + size_t count; /* count of logs */ +} ngx_http_lua_log_ringbuf_t; + + +void ngx_http_lua_log_ringbuf_init(ngx_http_lua_log_ringbuf_t *rb, + void *buf, size_t len); +void ngx_http_lua_log_ringbuf_reset(ngx_http_lua_log_ringbuf_t *rb); +ngx_int_t ngx_http_lua_log_ringbuf_read(ngx_http_lua_log_ringbuf_t *rb, + int *log_level, void **buf, size_t *n, double *log_time); +ngx_int_t ngx_http_lua_log_ringbuf_write(ngx_http_lua_log_ringbuf_t *rb, + int log_level, void *buf, size_t n); + + +#endif /* _NGX_HTTP_LUA_RINGBUF_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_module.c b/debian/modules/nginx-lua/src/ngx_http_lua_module.c index 6e93c8e..9d914e8 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_module.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_module.c @@ -28,6 +28,7 @@ #include "ngx_http_lua_ssl_certby.h" #include "ngx_http_lua_ssl_session_storeby.h" #include "ngx_http_lua_ssl_session_fetchby.h" +#include "ngx_http_lua_headers.h" static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf); @@ -45,14 +46,6 @@ static char *ngx_http_lua_lowat_check(ngx_conf_t *cf, void *post, void *data); static ngx_int_t ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf); #endif -#if (NGX_HTTP_LUA_HAVE_MMAP_SBRK) && (NGX_LINUX) -/* we cannot use "static" for this function since it may lead to compiler - * warnings */ -void ngx_http_lua_limit_data_segment(void); -# if !(NGX_HTTP_LUA_HAVE_CONSTRUCTOR) -static ngx_int_t ngx_http_lua_pre_config(ngx_conf_t *cf); -# endif -#endif static char *ngx_http_lua_malloc_trim(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -101,6 +94,13 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, NULL }, + { ngx_string("lua_capture_error_log"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_http_lua_capture_error_log, + 0, + 0, + NULL }, + #if (NGX_PCRE) { ngx_string("lua_regex_cache_max_entries"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, @@ -592,13 +592,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_module_t ngx_http_lua_module_ctx = { -#if (NGX_HTTP_LUA_HAVE_MMAP_SBRK) \ - && (NGX_LINUX) \ - && !(NGX_HTTP_LUA_HAVE_CONSTRUCTOR) - ngx_http_lua_pre_config, /* preconfiguration */ -#else NULL, /* preconfiguration */ -#endif ngx_http_lua_init, /* postconfiguration */ ngx_http_lua_create_main_conf, /* create main configuration */ @@ -638,7 +632,7 @@ ngx_http_lua_init(ngx_conf_t *cf) volatile ngx_cycle_t *saved_cycle; ngx_http_core_main_conf_t *cmcf; ngx_http_lua_main_conf_t *lmcf; -#ifndef NGX_LUA_NO_FFI_API +#if !defined(NGX_LUA_NO_FFI_API) || nginx_version >= 1011011 ngx_pool_cleanup_t *cln; #endif @@ -730,6 +724,16 @@ ngx_http_lua_init(ngx_conf_t *cf) cln->handler = ngx_http_lua_sema_mm_cleanup; #endif +#if nginx_version >= 1011011 + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->data = lmcf; + cln->handler = ngx_http_lua_ngx_raw_header_cleanup; +#endif + if (lmcf->lua == NULL) { dd("initializing lua vm"); @@ -817,6 +821,7 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) * lmcf->running_timers = 0; * lmcf->watcher = NULL; * lmcf->regex_cache_entries = 0; + * lmcf->jit_stack = NULL; * lmcf->shm_zones = NULL; * lmcf->init_handler = NULL; * lmcf->init_src = { 0, NULL }; @@ -955,7 +960,7 @@ ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) #ifdef LIBRESSL_VERSION_NUMBER ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "LibreSSL does not support ssl_ceritificate_by_lua*"); + "LibreSSL does not support ssl_certificate_by_lua*"); return NGX_CONF_ERROR; #else @@ -967,7 +972,7 @@ ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) # else ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "OpenSSL too old to support ssl_ceritificate_by_lua*"); + "OpenSSL too old to support ssl_certificate_by_lua*"); return NGX_CONF_ERROR; # endif @@ -1267,37 +1272,6 @@ ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf) #endif /* NGX_HTTP_SSL */ -#if (NGX_HTTP_LUA_HAVE_MMAP_SBRK) \ - && (NGX_LINUX) \ - && !(NGX_HTTP_LUA_HAVE_CONSTRUCTOR) -static ngx_int_t -ngx_http_lua_pre_config(ngx_conf_t *cf) -{ - ngx_http_lua_limit_data_segment(); - return NGX_OK; -} -#endif - - -/* - * we simply assume that LuaJIT is used. it does little harm when the - * standard Lua 5.1 interpreter is used instead. - */ -#if (NGX_HTTP_LUA_HAVE_MMAP_SBRK) && (NGX_LINUX) -# if (NGX_HTTP_LUA_HAVE_CONSTRUCTOR) -__attribute__((constructor)) -# endif -void -ngx_http_lua_limit_data_segment(void) -{ - if (sbrk(0) < (void *) 0x40000000LL) { - mmap(ngx_align_ptr(sbrk(0), getpagesize()), 1, PROT_READ, - MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0); - } -} -#endif - - static char * ngx_http_lua_malloc_trim(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c b/debian/modules/nginx-lua/src/ngx_http_lua_regex.c index d882061..80519ec 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_regex.c @@ -17,14 +17,6 @@ #include "ngx_http_lua_script.h" #include "ngx_http_lua_pcrefix.h" #include "ngx_http_lua_util.h" -#include - - -#if (PCRE_MAJOR > 8) || (PCRE_MAJOR == 8 && PCRE_MINOR >= 21) -# define LUA_HAVE_PCRE_JIT 1 -#else -# define LUA_HAVE_PCRE_JIT 0 -#endif #if (PCRE_MAJOR >= 6) @@ -42,6 +34,8 @@ #define NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT (100) +#define NGX_LUA_RE_MIN_JIT_STACK_SIZE 32 * 1024 + typedef struct { #ifndef NGX_LUA_NO_FFI_API @@ -364,6 +358,10 @@ ngx_http_lua_ngx_re_match_helper(lua_State *L, int wantcaps) sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg); + if (sd && lmcf->jit_stack) { + pcre_assign_jit_stack(sd, NULL, lmcf->jit_stack); + } + ngx_http_lua_pcre_malloc_done(old_pool); # if (NGX_DEBUG) @@ -826,6 +824,10 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg); + if (sd && lmcf->jit_stack) { + pcre_assign_jit_stack(sd, NULL, lmcf->jit_stack); + } + ngx_http_lua_pcre_malloc_done(old_pool); # if (NGX_DEBUG) @@ -1922,6 +1924,60 @@ error: } +ngx_int_t +ngx_http_lua_ffi_set_jit_stack_size(int size, u_char *errstr, + size_t *errstr_size) +{ +#if LUA_HAVE_PCRE_JIT + + ngx_http_lua_main_conf_t *lmcf; + ngx_pool_t *pool, *old_pool; + + lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle, + ngx_http_lua_module); + + if (size < NGX_LUA_RE_MIN_JIT_STACK_SIZE) { + size = NGX_LUA_RE_MIN_JIT_STACK_SIZE; + } + + pool = lmcf->pool; + + dd("server pool %p", lmcf->pool); + + if (lmcf->jit_stack) { + old_pool = ngx_http_lua_pcre_malloc_init(pool); + + pcre_jit_stack_free(lmcf->jit_stack); + + ngx_http_lua_pcre_malloc_done(old_pool); + } + + old_pool = ngx_http_lua_pcre_malloc_init(pool); + + lmcf->jit_stack = pcre_jit_stack_alloc(NGX_LUA_RE_MIN_JIT_STACK_SIZE, + size); + + ngx_http_lua_pcre_malloc_done(old_pool); + + if (lmcf->jit_stack == NULL) { + *errstr_size = ngx_snprintf(errstr, *errstr_size, + "pcre jit stack allocation failed") + - errstr; + return NGX_ERROR; + } + + return NGX_OK; + +#else /* LUA_HAVE_PCRE_JIT */ + + *errstr_size = ngx_snprintf(errstr, *errstr_size, + "no pcre jit support found") - errstr; + return NGX_ERROR; + +#endif /* LUA_HAVE_PCRE_JIT */ +} + + void ngx_http_lua_inject_regex_api(lua_State *L) { @@ -2170,6 +2226,9 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, goto error; } + lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle, + ngx_http_lua_module); + #if (LUA_HAVE_PCRE_JIT) if (flags & NGX_LUA_RE_MODE_JIT) { @@ -2205,10 +2264,11 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, ngx_http_lua_pcre_malloc_done(old_pool); } -#endif /* LUA_HAVE_PCRE_JIT */ + if (sd && lmcf->jit_stack) { + pcre_assign_jit_stack(sd, NULL, lmcf->jit_stack); + } - lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle, - ngx_http_lua_module); +#endif /* LUA_HAVE_PCRE_JIT */ if (sd && lmcf && lmcf->regex_match_limit > 0) { sd->flags |= PCRE_EXTRA_MATCH_LIMIT; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_regex.h b/debian/modules/nginx-lua/src/ngx_http_lua_regex.h index f5f8e2f..03dffb8 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_regex.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_regex.h @@ -14,6 +14,8 @@ #if (NGX_PCRE) void ngx_http_lua_inject_regex_api(lua_State *L); +ngx_int_t ngx_http_lua_ffi_set_jit_stack_size(int size, u_char *errstr, + size_t *errstr_size); #endif diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c b/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c index 8a3f832..eda0141 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c @@ -387,8 +387,8 @@ ngx_http_lua_ffi_sema_wait(ngx_http_request_t *r, return NGX_ERROR; } - /* we keep the order, will resume the older waited firtly - * in ngx_http_lua_sema_handler + /* we keep the order, will first resume the thread waiting for the + * longest time in ngx_http_lua_sema_handler */ if (ngx_queue_empty(&sem->wait_queue) && sem->resource_count > 0) { @@ -557,8 +557,11 @@ ngx_http_lua_ffi_sema_gc(ngx_http_lua_sema_t *sem) return; } - if (!ngx_queue_empty(&sem->wait_queue)) { - ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0, + if (!ngx_terminate + && !ngx_quit + && !ngx_queue_empty(&sem->wait_queue)) + { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "in lua semaphore gc wait queue is" " not empty while the semaphore %p is being " "destroyed", sem); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c b/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c index 4c0d016..ffee97f 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c @@ -72,10 +72,25 @@ ngx_http_lua_ngx_sleep(lua_State *L) coctx->sleep.data = coctx; coctx->sleep.log = r->connection->log; - dd("adding timer with delay %lu ms, r:%.*s", (unsigned long) delay, - (int) r->uri.len, r->uri.data); + if (delay == 0) { +#ifdef HAVE_POSTED_DELAYED_EVENTS_PATCH + dd("posting 0 sec sleep event to head of delayed queue"); - ngx_add_timer(&coctx->sleep, (ngx_msec_t) delay); + coctx->sleep.delayed = 1; + ngx_post_event(&coctx->sleep, &ngx_posted_delayed_events); +#else + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "ngx.sleep(0)" + " called without delayed events patch, this will" + " hurt performance"); + ngx_add_timer(&coctx->sleep, (ngx_msec_t) delay); +#endif + + } else { + dd("adding timer with delay %lu ms, r:%.*s", (unsigned long) delay, + (int) r->uri.len, r->uri.data); + + ngx_add_timer(&coctx->sleep, (ngx_msec_t) delay); + } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua ready to sleep for %d ms", delay); @@ -147,6 +162,15 @@ ngx_http_lua_sleep_cleanup(void *data) ngx_del_timer(&coctx->sleep); } + +#ifdef HAVE_POSTED_DELAYED_EVENTS_PATCH + if (coctx->sleep.posted) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua clean up the posted event for pending ngx.sleep"); + + ngx_delete_posted_event(&coctx->sleep); + } +#endif } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c index 6db6e2d..382a94d 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c @@ -69,8 +69,6 @@ static void ngx_http_lua_socket_dummy_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); static ngx_int_t ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); -static void ngx_http_lua_socket_read_handler(ngx_http_request_t *r, - ngx_http_lua_socket_tcp_upstream_t *u); static int ngx_http_lua_socket_tcp_receive_retval_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); static ngx_int_t ngx_http_lua_socket_read_line(void *data, ssize_t bytes); @@ -501,6 +499,12 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) n--; } + /* the fourth argument is not a table */ + if (n == 4) { + lua_pop(L, 1); + n--; + } + if (n == 3) { port = luaL_checkinteger(L, 3); @@ -1208,11 +1212,12 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) ngx_http_lua_socket_tcp_upstream_t *u; - /* Lua function arguments: self [,session] [,host] [,verify] */ + /* Lua function arguments: self [,session] [,host] [,verify] + [,send_status_req] */ n = lua_gettop(L); if (n < 1 || n > 5) { - return luaL_error(L, "ngx.socket connect: expecting 1 ~ 5 " + return luaL_error(L, "ngx.socket sslhandshake: expecting 1 ~ 5 " "arguments (including the object), but seen %d", n); } @@ -1327,7 +1332,8 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - if (SSL_set_tlsext_host_name(c->ssl->connection, name.data) + if (SSL_set_tlsext_host_name(c->ssl->connection, + (char *) name.data) == 0) { lua_pushnil(L); @@ -4412,15 +4418,18 @@ ngx_http_lua_req_socket_rev_handler(ngx_http_request_t *r) ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { + r->read_event_handler = ngx_http_block_reading; return; } u = ctx->downstream; - if (u) { - u->read_event_handler(r, u); + if (u == NULL || u->peer.connection == NULL) { + r->read_event_handler = ngx_http_block_reading; + return; } -} + u->read_event_handler(r, u); +} static int ngx_http_lua_socket_tcp_getreusedtimes(lua_State *L) diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl.h b/debian/modules/nginx-lua/src/ngx_http_lua_ssl.h index 7a245ff..acb8c4b 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ssl.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl.h @@ -12,6 +12,8 @@ #if (NGX_HTTP_SSL) + + typedef struct { ngx_connection_t *connection; /* original true connection */ ngx_http_request_t *request; /* fake request */ @@ -31,7 +33,6 @@ typedef struct { unsigned entered_cert_handler:1; unsigned entered_sess_fetch_handler:1; } ngx_http_lua_ssl_ctx_t; -#endif ngx_int_t ngx_http_lua_ssl_init(ngx_log_t *log); @@ -40,4 +41,7 @@ ngx_int_t ngx_http_lua_ssl_init(ngx_log_t *log); extern int ngx_http_lua_ssl_ctx_index; +#endif + + #endif /* _NGX_HTTP_LUA_SSL_H_INCLUDED_ */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c index aca4735..c3591d1 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c @@ -193,6 +193,7 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) ngx_http_lua_srv_conf_t *lscf; ngx_http_core_loc_conf_t *clcf; ngx_http_lua_ssl_ctx_t *cctx; + ngx_http_core_srv_conf_t *cscf; c = ngx_ssl_get_connection(ssl_conn); @@ -298,6 +299,16 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) c->log->action = "loading SSL certificate by lua"; + if (lscf->srv.ssl_cert_handler == NULL) { + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "no ssl_certificate_by_lua* defined in " + "server %V", &cscf->server_name); + + goto failed; + } + rc = lscf->srv.ssl_cert_handler(r, lscf, L); if (rc >= NGX_OK || rc == NGX_ERROR) { @@ -453,7 +464,9 @@ ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; } } else { @@ -470,7 +483,9 @@ ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua: failed to create new coroutine to handle request"); - return NGX_HTTP_INTERNAL_SERVER_ERROR; + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; } /* move code closure to new coroutine */ @@ -494,7 +509,9 @@ ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; } cln->handler = ngx_http_lua_request_cleanup_handler; @@ -1129,7 +1146,11 @@ ngx_http_lua_ffi_set_cert(ngx_http_request_t *r, # else +#ifdef OPENSSL_IS_BORINGSSL + size_t i; +#else int i; +#endif X509 *x509 = NULL; ngx_ssl_conn_t *ssl_conn; STACK_OF(X509) *chain = cdata; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c index 3904aa8..31b4f24 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c @@ -490,7 +490,6 @@ ngx_http_lua_ffi_ssl_set_ocsp_status_resp(ngx_http_request_t *r, dd("set ocsp resp: resp_len=%d", (int) resp_len); (void) SSL_set_tlsext_status_ocsp_resp(ssl_conn, p, resp_len); - ssl_conn->tlsext_status_expected = 1; return NGX_OK; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.c index 4c450b5..556b732 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.c @@ -107,7 +107,7 @@ ngx_http_lua_ssl_sess_fetch_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, dd("enter"); - /* must specifiy a content handler */ + /* must specify a content handler */ if (cmd->post == NULL) { return NGX_CONF_ERROR; } @@ -468,7 +468,9 @@ ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; } } else { @@ -485,7 +487,9 @@ ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua: failed to create new coroutine to handle request"); - return NGX_HTTP_INTERNAL_SERVER_ERROR; + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; } /* move code closure to new coroutine */ @@ -509,7 +513,9 @@ ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; } cln->handler = ngx_http_lua_request_cleanup_handler; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.c index b5596bc..bae8273 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.c @@ -105,7 +105,7 @@ ngx_http_lua_ssl_sess_store_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, dd("enter"); - /* must specifiy a content handler */ + /* must specify a content handler */ if (cmd->post == NULL) { return NGX_CONF_ERROR; } @@ -351,7 +351,9 @@ ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; } } else { @@ -386,7 +388,7 @@ ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) dd("rc == %d", (int) rc); if (rc != 0) { - /* error occured when running loaded code */ + /* error occurred when running loaded code */ err_msg = (u_char *) lua_tolstring(L, -1, &len); if (err_msg == NULL) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_string.c b/debian/modules/nginx-lua/src/ngx_http_lua_string.c index 22b4c00..239b232 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_string.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_string.c @@ -125,12 +125,13 @@ ngx_http_lua_ngx_escape_uri(lua_State *L) return 1; } - escape = 2 * ngx_http_lua_escape_uri(NULL, src, len, NGX_ESCAPE_URI); + escape = 2 * ngx_http_lua_escape_uri(NULL, src, len, + NGX_ESCAPE_URI_COMPONENT); if (escape) { dlen = escape + len; dst = lua_newuserdata(L, dlen); - ngx_http_lua_escape_uri(dst, src, len, NGX_ESCAPE_URI); + ngx_http_lua_escape_uri(dst, src, len, NGX_ESCAPE_URI_COMPONENT); lua_pushlstring(L, (char *) dst, dlen); } @@ -751,14 +752,14 @@ size_t ngx_http_lua_ffi_uri_escaped_length(const u_char *src, size_t len) { return len + 2 * ngx_http_lua_escape_uri(NULL, (u_char *) src, len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); } void ngx_http_lua_ffi_escape_uri(const u_char *src, size_t len, u_char *dst) { - ngx_http_lua_escape_uri(dst, (u_char *) src, len, NGX_ESCAPE_URI); + ngx_http_lua_escape_uri(dst, (u_char *) src, len, NGX_ESCAPE_URI_COMPONENT); } #endif diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c index 01b4777..596b2f7 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c @@ -21,11 +21,6 @@ typedef struct { void **srv_conf; void **loc_conf; - /* event ident must be after 3 words (i.e. 3 pointers' size) as in - * ngx_connection_t. and we use the Lua coroutine reference number as - * the event ident */ - int co_ref; - unsigned premature; /* :1 */ lua_State *co; ngx_pool_t *pool; @@ -36,12 +31,18 @@ typedef struct { ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_vm_state_t *vm_state; + int co_ref; + unsigned delay:31; + unsigned premature:1; } ngx_http_lua_timer_ctx_t; static int ngx_http_lua_ngx_timer_at(lua_State *L); +static int ngx_http_lua_ngx_timer_every(lua_State *L); +static int ngx_http_lua_ngx_timer_helper(lua_State *L, int every); static int ngx_http_lua_ngx_timer_running_count(lua_State *L); static int ngx_http_lua_ngx_timer_pending_count(lua_State *L); +static ngx_int_t ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx); static void ngx_http_lua_timer_handler(ngx_event_t *ev); static u_char *ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, size_t len); @@ -51,11 +52,14 @@ static void ngx_http_lua_abort_pending_timers(ngx_event_t *ev); void ngx_http_lua_inject_timer_api(lua_State *L) { - lua_createtable(L, 0 /* narr */, 3 /* nrec */); /* ngx.timer. */ + lua_createtable(L, 0 /* narr */, 4 /* nrec */); /* ngx.timer. */ lua_pushcfunction(L, ngx_http_lua_ngx_timer_at); lua_setfield(L, -2, "at"); + lua_pushcfunction(L, ngx_http_lua_ngx_timer_every); + lua_setfield(L, -2, "every"); + lua_pushcfunction(L, ngx_http_lua_ngx_timer_running_count); lua_setfield(L, -2, "running_count"); @@ -106,6 +110,24 @@ ngx_http_lua_ngx_timer_pending_count(lua_State *L) static int ngx_http_lua_ngx_timer_at(lua_State *L) +{ + return ngx_http_lua_ngx_timer_helper(L, 0); +} + + +/* + * TODO: return a timer handler instead which can be passed to + * the ngx.timer.cancel method to cancel the timer. + */ +static int +ngx_http_lua_ngx_timer_every(lua_State *L) +{ + return ngx_http_lua_ngx_timer_helper(L, 1); +} + + +static int +ngx_http_lua_ngx_timer_helper(lua_State *L, int every) { int nargs, co_ref; u_char *p; @@ -134,6 +156,10 @@ ngx_http_lua_ngx_timer_at(lua_State *L) delay = (ngx_msec_t) (luaL_checknumber(L, 1) * 1000); + if (every && delay == 0) { + return luaL_error(L, "delay cannot be zero"); + } + luaL_argcheck(L, lua_isfunction(L, 2) && !lua_iscfunction(L, 2), 2, "Lua function expected"); @@ -233,7 +259,7 @@ ngx_http_lua_ngx_timer_at(lua_State *L) lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); - /* L stack: time func [args] thread corountines */ + /* L stack: time func [args] thread coroutines */ lua_pushvalue(L, -2); @@ -265,6 +291,8 @@ ngx_http_lua_ngx_timer_at(lua_State *L) tctx = (ngx_http_lua_timer_ctx_t *) p; + tctx->delay = every ? delay : 0; + tctx->premature = 0; tctx->co_ref = co_ref; tctx->co = co; @@ -338,6 +366,164 @@ nomem: } +static ngx_int_t +ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) +{ + int nargs, co_ref, i; + u_char *p; + lua_State *vm; /* the main thread */ + lua_State *co; + lua_State *L; + ngx_event_t *ev = NULL; + ngx_http_lua_timer_ctx_t *tctx = NULL; + ngx_http_lua_main_conf_t *lmcf; + + /* L stack: func [args] */ + L = old_tctx->co; + + lmcf = old_tctx->lmcf; + + vm = old_tctx->vm_state ? old_tctx->vm_state->vm : lmcf->lua; + + co = lua_newthread(vm); + + lua_createtable(co, 0, 0); /* the new globals table */ + + /* co stack: global_tb */ + + lua_createtable(co, 0, 1); /* the metatable */ + ngx_http_lua_get_globals_table(co); + lua_setfield(co, -2, "__index"); + lua_setmetatable(co, -2); + + /* co stack: global_tb */ + + ngx_http_lua_set_globals_table(co); + + /* co stack: */ + + dd("stack top: %d", lua_gettop(L)); + + lua_xmove(vm, L, 1); /* move coroutine from main thread to L */ + + /* L stack: func [args] thread */ + /* vm stack: empty */ + + lua_pushvalue(L, 1); /* copy entry function to top of L*/ + + /* L stack: func [args] thread func */ + + lua_xmove(L, co, 1); /* move entry function from L to co */ + + /* L stack: func [args] thread */ + /* co stack: func */ + + ngx_http_lua_get_globals_table(co); + lua_setfenv(co, -2); + + /* co stack: func */ + + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_rawget(L, LUA_REGISTRYINDEX); + + /* L stack: func [args] thread coroutines */ + + lua_pushvalue(L, -2); + + /* L stack: func [args] thread coroutines thread */ + + co_ref = luaL_ref(L, -2); + lua_pop(L, 2); + + /* L stack: func [args] */ + + nargs = lua_gettop(L); + if (nargs > 1) { + for (i = 2; i <= nargs; i++) { + lua_pushvalue(L, i); + } + + /* L stack: func [args] [args] */ + + lua_xmove(L, co, nargs - 1); + + /* L stack: func [args] */ + /* co stack: func [args] */ + } + + p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_http_lua_timer_ctx_t), + ngx_cycle->log); + if (p == NULL) { + goto nomem; + } + + ev = (ngx_event_t *) p; + + ngx_memzero(ev, sizeof(ngx_event_t)); + + p += sizeof(ngx_event_t); + + tctx = (ngx_http_lua_timer_ctx_t *) p; + + ngx_memcpy(tctx, old_tctx, sizeof(ngx_http_lua_timer_ctx_t)); + + tctx->co_ref = co_ref; + tctx->co = co; + + tctx->pool = ngx_create_pool(128, ngx_cycle->log); + if (tctx->pool == NULL) { + goto nomem; + } + + if (tctx->client_addr_text.len) { + tctx->client_addr_text.data = ngx_palloc(tctx->pool, + tctx->client_addr_text.len); + if (tctx->client_addr_text.data == NULL) { + goto nomem; + } + + ngx_memcpy(tctx->client_addr_text.data, old_tctx->client_addr_text.data, + tctx->client_addr_text.len); + } + + if (tctx->vm_state) { + tctx->vm_state->count++; + } + + ev->handler = ngx_http_lua_timer_handler; + ev->data = tctx; + ev->log = ngx_cycle->log; + + lmcf->pending_timers++; + + ngx_add_timer(ev, tctx->delay); + + return NGX_OK; + +nomem: + + if (tctx && tctx->pool) { + ngx_destroy_pool(tctx->pool); + } + + if (ev) { + ngx_free(ev); + } + + /* L stack: func [args] */ + + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_rawget(L, LUA_REGISTRYINDEX); + luaL_unref(L, -1, co_ref); + + /* L stack: func [args] coroutines */ + + lua_pop(L, 1); + + return NGX_ERROR; +} + + static void ngx_http_lua_timer_handler(ngx_event_t *ev) { @@ -364,6 +550,15 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) lmcf->pending_timers--; + if (!ngx_exiting && tctx.delay > 0) { + rc = ngx_http_lua_timer_copy(&tctx); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "failed to create the next timer of delay %ud ms", + (unsigned) tctx.delay); + } + } + if (lmcf->running_timers >= lmcf->max_running_timers) { ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "%i lua_max_running_timers are not enough", diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.c b/debian/modules/nginx-lua/src/ngx_http_lua_util.c index 7f59833..c7bee3e 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_util.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_util.c @@ -51,6 +51,7 @@ #include "ngx_http_lua_socket_tcp.h" #include "ngx_http_lua_ssl_certby.h" #include "ngx_http_lua_ssl.h" +#include "ngx_http_lua_log_ringbuf.h" #if 1 @@ -918,7 +919,11 @@ ngx_http_lua_request_cleanup(ngx_http_lua_ctx_t *ctx, int forcible) #if 1 if (r->connection->fd == (ngx_socket_t) -1) { /* being a fake request */ - lmcf->running_timers--; + + if (ctx->context == NGX_HTTP_LUA_CONTEXT_TIMER) { + /* being a timer handler */ + lmcf->running_timers--; + } } #endif @@ -1835,6 +1840,26 @@ ngx_http_lua_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) /* ~}| {zyx wvut srqp onml kjih gfed cba` */ 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + }; + + /* not ALPHA, DIGIT, "-", ".", "_", "~" */ + + static uint32_t uri_component[] = { + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0xfc00987d, /* 1111 1100 0000 0000 1001 1000 0111 1101 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x78000001, /* 0111 1000 0000 0000 0000 0000 0000 0001 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -1904,8 +1929,7 @@ ngx_http_lua_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) /* mail_auth is the same as memcached */ static uint32_t *map[] = - { uri, args, html, refresh, memcached, memcached }; - + { uri, args, uri_component, html, refresh, memcached, memcached }; escape = map[type]; @@ -2316,7 +2340,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, key = (u_char *) lua_tolstring(L, -2, &key_len); key_escape = 2 * ngx_http_lua_escape_uri(NULL, key, key_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); total_escape += key_escape; switch (lua_type(L, -1)) { @@ -2325,7 +2349,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, value = (u_char *) lua_tolstring(L, -1, &value_len); total_escape += 2 * ngx_http_lua_escape_uri(NULL, value, value_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); len += key_len + value_len + (sizeof("=") - 1); n++; @@ -2366,7 +2390,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, total_escape += 2 * ngx_http_lua_escape_uri(NULL, value, value_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); len += key_len + value_len + (sizeof("=") - 1); } @@ -2423,7 +2447,8 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT + ); } else { dd("shortcut: no escape required"); @@ -2437,7 +2462,8 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, value, value_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT + ); } else { p = ngx_copy(p, value, value_len); @@ -2456,7 +2482,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (lua_toboolean(L, -1)) { if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); } else { dd("shortcut: no escape required"); @@ -2484,7 +2510,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); } else { dd("shortcut: no escape required"); @@ -2503,7 +2529,8 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT + ); } else { dd("shortcut: no escape required"); @@ -2519,7 +2546,8 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, p = (u_char *) ngx_http_lua_escape_uri(p, value, value_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT + ); } else { p = ngx_copy(p, value, value_len); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_worker.c b/debian/modules/nginx-lua/src/ngx_http_lua_worker.c index ff09b5b..e1cfec4 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_worker.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_worker.c @@ -13,6 +13,9 @@ #include "ngx_http_lua_worker.h" +#define NGX_PROCESS_PRIVILEGED_AGENT 99 + + static int ngx_http_lua_ngx_worker_exiting(lua_State *L); static int ngx_http_lua_ngx_worker_pid(lua_State *L); static int ngx_http_lua_ngx_worker_id(lua_State *L); @@ -130,4 +133,46 @@ ngx_http_lua_ffi_worker_count(void) return (int) ccf->worker_processes; } + + +int +ngx_http_lua_ffi_get_process_type(void) +{ +#if defined(HAVE_PRIVILEGED_PROCESS_PATCH) && !NGX_WIN32 + if (ngx_process == NGX_PROCESS_HELPER) { + if (ngx_is_privileged_agent) { + return NGX_PROCESS_PRIVILEGED_AGENT; + } + } +#endif + + return ngx_process; +} + + +int +ngx_http_lua_ffi_enable_privileged_agent(char **err) +{ +#ifdef HAVE_PRIVILEGED_PROCESS_PATCH + ngx_core_conf_t *ccf; + + ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_core_module); + + ccf->privileged_agent = 1; + + return NGX_OK; + +#else + *err = "missing privileged agent process patch in the nginx core"; + return NGX_ERROR; +#endif +} + + +void +ngx_http_lua_ffi_process_signal_graceful_exit(void) +{ + ngx_quit = 1; +} #endif diff --git a/debian/modules/nginx-lua/t/000--init.t b/debian/modules/nginx-lua/t/000--init.t index 364334f..ad2d70e 100644 --- a/debian/modules/nginx-lua/t/000--init.t +++ b/debian/modules/nginx-lua/t/000--init.t @@ -84,4 +84,3 @@ GET /flush --- timeout: 10 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/000-sanity.t b/debian/modules/nginx-lua/t/000-sanity.t index 3f66752..87854ef 100644 --- a/debian/modules/nginx-lua/t/000-sanity.t +++ b/debian/modules/nginx-lua/t/000-sanity.t @@ -31,4 +31,3 @@ GET /lua GET /lua --- response_body helloworld - diff --git a/debian/modules/nginx-lua/t/001-set.t b/debian/modules/nginx-lua/t/001-set.t index 2295a2d..ba8f22c 100644 --- a/debian/modules/nginx-lua/t/001-set.t +++ b/debian/modules/nginx-lua/t/001-set.t @@ -795,4 +795,3 @@ GET /lua?a=1&b=2 --- error_code: 500 --- error_log eval qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ - diff --git a/debian/modules/nginx-lua/t/002-content.t b/debian/modules/nginx-lua/t/002-content.t index e6cb62d..3f2460e 100644 --- a/debian/modules/nginx-lua/t/002-content.t +++ b/debian/modules/nginx-lua/t/002-content.t @@ -836,4 +836,3 @@ GET /lua --- error_code: 500 --- error_log eval qr/failed to load inlined Lua code: / - diff --git a/debian/modules/nginx-lua/t/003-errors.t b/debian/modules/nginx-lua/t/003-errors.t index 764300a..ad3a506 100644 --- a/debian/modules/nginx-lua/t/003-errors.t +++ b/debian/modules/nginx-lua/t/003-errors.t @@ -126,4 +126,3 @@ GET /main GET /main --- response_body 500 - diff --git a/debian/modules/nginx-lua/t/004-require.t b/debian/modules/nginx-lua/t/004-require.t index 3250b2f..ec74116 100644 --- a/debian/modules/nginx-lua/t/004-require.t +++ b/debian/modules/nginx-lua/t/004-require.t @@ -208,4 +208,3 @@ GET /ndk GET /ndk --- response_body %20 - diff --git a/debian/modules/nginx-lua/t/005-exit.t b/debian/modules/nginx-lua/t/005-exit.t index 781531f..a5a28b3 100644 --- a/debian/modules/nginx-lua/t/005-exit.t +++ b/debian/modules/nginx-lua/t/005-exit.t @@ -723,4 +723,3 @@ GET /t --- response_body --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/006-escape.t b/debian/modules/nginx-lua/t/006-escape.t index 7b26bba..a21d3cb 100644 --- a/debian/modules/nginx-lua/t/006-escape.t +++ b/debian/modules/nginx-lua/t/006-escape.t @@ -3,9 +3,8 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -#repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 1); +plan tests => repeat_each() * (blocks() * 2 + 2); no_long_string(); @@ -181,3 +180,20 @@ GET /t --- response_body [32] + + +=== TEST 14: reserved chars +--- config + location /lua { + content_by_lua_block { + ngx.say(ngx.escape_uri("-_.!~*'()")) + ngx.say(ngx.escape_uri(",$@|`")) + } + } +--- request +GET /lua +--- response_body +-_.!~*'() +%2C%24%40%7C%60 +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/007-md5.t b/debian/modules/nginx-lua/t/007-md5.t index 501e3af..2ae9efb 100644 --- a/debian/modules/nginx-lua/t/007-md5.t +++ b/debian/modules/nginx-lua/t/007-md5.t @@ -100,4 +100,3 @@ d41d8cd98f00b204e9800998ecf8427e GET /md5 --- response_body 6c8349cc7260ae62e3b1396831a8398f - diff --git a/debian/modules/nginx-lua/t/008-today.t b/debian/modules/nginx-lua/t/008-today.t index 54bd949..ec2f433 100644 --- a/debian/modules/nginx-lua/t/008-today.t +++ b/debian/modules/nginx-lua/t/008-today.t @@ -36,4 +36,3 @@ GET /today --- request GET /today --- response_body_like: ^\d{4}-\d{2}-\d{2}$ - diff --git a/debian/modules/nginx-lua/t/009-log.t b/debian/modules/nginx-lua/t/009-log.t index 0c6a9a5..68c057f 100644 --- a/debian/modules/nginx-lua/t/009-log.t +++ b/debian/modules/nginx-lua/t/009-log.t @@ -542,4 +542,3 @@ ok [error] --- error_log eval "2: hello\0world, client: " - diff --git a/debian/modules/nginx-lua/t/010-request_body.t b/debian/modules/nginx-lua/t/010-request_body.t index 2640a54..e669d94 100644 --- a/debian/modules/nginx-lua/t/010-request_body.t +++ b/debian/modules/nginx-lua/t/010-request_body.t @@ -270,4 +270,3 @@ Expect: 100-Continue http finalize request: 500, "/echo_body?" a:1, c:2 http finalize request: 500, "/echo_body?" a:1, c:0 --- log_level: debug - diff --git a/debian/modules/nginx-lua/t/012-now.t b/debian/modules/nginx-lua/t/012-now.t index abcb735..5885187 100644 --- a/debian/modules/nginx-lua/t/012-now.t +++ b/debian/modules/nginx-lua/t/012-now.t @@ -116,4 +116,3 @@ GET /time --- request GET /time --- response_body_like: ^\d{10,}(\.\d{1,3})?$ - diff --git a/debian/modules/nginx-lua/t/014-bugs.t b/debian/modules/nginx-lua/t/014-bugs.t index 44337e3..9aadff0 100644 --- a/debian/modules/nginx-lua/t/014-bugs.t +++ b/debian/modules/nginx-lua/t/014-bugs.t @@ -849,7 +849,7 @@ ok "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; set $myhost 'agentzh.org.'; proxy_pass http://$myhost/misc/.vimrc; } @@ -1018,4 +1018,3 @@ write timer set: 1 --- no_error_log [error] [alert] - diff --git a/debian/modules/nginx-lua/t/016-resp-header.t b/debian/modules/nginx-lua/t/016-resp-header.t index 179b411..1fae292 100644 --- a/debian/modules/nginx-lua/t/016-resp-header.t +++ b/debian/modules/nginx-lua/t/016-resp-header.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 38); +plan tests => repeat_each() * (blocks() * 3 + 41); #no_diff(); no_long_string(); @@ -1441,3 +1441,71 @@ Content-Type: ; blah test --- no_error_log [error] + + + +=== TEST 69: return the matched content-type instead of default_type +--- http_config +types { + image/png png; +} +--- config +location /set/ { + default_type text/html; + content_by_lua_block { + ngx.say(ngx.header["content-type"]) + } +} +--- request +GET /set/hello.png +--- response_headers +Content-Type: image/png +--- response_body +image/png +--- no_error_log +[error] + + + +=== TEST 70: always return the matched content-type +--- config + location /set/ { + default_type "image/png"; + content_by_lua_block { + ngx.say(ngx.header["content-type"]) + ngx.say(ngx.header["content-type"]) + } + } +--- request +GET /set/hello.png +--- response_headers +Content-Type: image/png +--- response_body +image/png +image/png +--- no_error_log +[error] + + + +=== TEST 71: return the matched content-type after ngx.resp.get_headers() +--- http_config +types { + image/png png; +} +--- config + location /set/ { + default_type text/html; + content_by_lua_block { + local h = ngx.resp.get_headers() + ngx.say(h["content-type"]) + } + } +--- request +GET /set/hello.png +--- response_headers +Content-Type: image/png +--- response_body +image/png +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/017-exec.t b/debian/modules/nginx-lua/t/017-exec.t index 4c7a918..535c4ab 100644 --- a/debian/modules/nginx-lua/t/017-exec.t +++ b/debian/modules/nginx-lua/t/017-exec.t @@ -572,4 +572,3 @@ hello, bah ["dummy", "dummy"] --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/018-ndk.t b/debian/modules/nginx-lua/t/018-ndk.t index d68306b..1429377 100644 --- a/debian/modules/nginx-lua/t/018-ndk.t +++ b/debian/modules/nginx-lua/t/018-ndk.t @@ -171,4 +171,3 @@ ok foo = a b --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/019-const.t b/debian/modules/nginx-lua/t/019-const.t index fe79bfb..4f9c764 100644 --- a/debian/modules/nginx-lua/t/019-const.t +++ b/debian/modules/nginx-lua/t/019-const.t @@ -44,4 +44,3 @@ GET /read GET /read --- response_body 504 - diff --git a/debian/modules/nginx-lua/t/021-cookie-time.t b/debian/modules/nginx-lua/t/021-cookie-time.t index c00bbea..b05e401 100644 --- a/debian/modules/nginx-lua/t/021-cookie-time.t +++ b/debian/modules/nginx-lua/t/021-cookie-time.t @@ -43,4 +43,3 @@ Thu, 18-Nov-10 11:27:35 GMT GET /lua --- response_body Thu, 18-Nov-10 11:27:35 GMT - diff --git a/debian/modules/nginx-lua/t/022-redirect.t b/debian/modules/nginx-lua/t/022-redirect.t index 57c7add..fae39e3 100644 --- a/debian/modules/nginx-lua/t/022-redirect.t +++ b/debian/modules/nginx-lua/t/022-redirect.t @@ -84,7 +84,7 @@ GET /read --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log -only ngx.HTTP_MOVED_TEMPORARILY, ngx.HTTP_MOVED_PERMANENTLY, and ngx.HTTP_TEMPORARY_REDIRECT are allowed +only ngx.HTTP_MOVED_TEMPORARILY, ngx.HTTP_MOVED_PERMANENTLY, ngx.HTTP_SEE_OTHER, and ngx.HTTP_TEMPORARY_REDIRECT are allowed @@ -218,3 +218,54 @@ GET /read Location: http://agentzh.org/foo?a=b&c=d --- response_body_like: 307 Temporary Redirect --- error_code: 307 + + + +=== TEST 12: explicit 303 +--- config + location /read { + content_by_lua_block { + ngx.redirect("http://agentzh.org/foo", ngx.HTTP_SEE_OTHER); + ngx.say("hi") + } + } +--- request +GET /read +--- response_headers +Location: http://agentzh.org/foo +--- response_body_like: 303 See Other +--- error_code: 303 + + + +=== TEST 13: explicit 303 with args +--- config + location /read { + content_by_lua_block { + ngx.redirect("http://agentzh.org/foo?a=b&c=d", ngx.HTTP_SEE_OTHER); + ngx.say("hi") + } + } +--- request +GET /read +--- response_headers +Location: http://agentzh.org/foo?a=b&c=d +--- response_body_like: 303 See Other +--- error_code: 303 + + + +=== TEST 14: explicit 303 +--- config + location /read { + content_by_lua_block { + ngx.redirect("http://agentzh.org/foo?a=b&c=d", 303); + ngx.say("hi") + } + } +--- request +GET /read +--- response_headers +Location: http://agentzh.org/foo?a=b&c=d +--- response_body_like: 303 See Other +--- error_code: 303 diff --git a/debian/modules/nginx-lua/t/023-rewrite/client-abort.t b/debian/modules/nginx-lua/t/023-rewrite/client-abort.t index e970802..117d17e 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/client-abort.t +++ b/debian/modules/nginx-lua/t/023-rewrite/client-abort.t @@ -848,4 +848,3 @@ delete thread 1 --- no_error_log [error] [alert] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/exec.t b/debian/modules/nginx-lua/t/023-rewrite/exec.t index a063b5b..bd97968 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/exec.t +++ b/debian/modules/nginx-lua/t/023-rewrite/exec.t @@ -376,4 +376,3 @@ ngx.exec("@proxy") GET /main --- response_body hello, bah - diff --git a/debian/modules/nginx-lua/t/023-rewrite/exit.t b/debian/modules/nginx-lua/t/023-rewrite/exit.t index 9d292f7..39ea5cb 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/exit.t +++ b/debian/modules/nginx-lua/t/023-rewrite/exit.t @@ -595,4 +595,3 @@ F(ngx_http_send_header) { --- error_code: 204 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/mixed.t b/debian/modules/nginx-lua/t/023-rewrite/mixed.t index 1156567..0f742b2 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/mixed.t +++ b/debian/modules/nginx-lua/t/023-rewrite/mixed.t @@ -167,4 +167,3 @@ world\x03\x04\xff hello\x00\x01\x02 world\x03\x04\xff " - diff --git a/debian/modules/nginx-lua/t/023-rewrite/multi-capture.t b/debian/modules/nginx-lua/t/023-rewrite/multi-capture.t index 44629b0..083ec78 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/multi-capture.t +++ b/debian/modules/nginx-lua/t/023-rewrite/multi-capture.t @@ -392,4 +392,3 @@ res4.status = 201 res4.body = STORED\r " - diff --git a/debian/modules/nginx-lua/t/023-rewrite/on-abort.t b/debian/modules/nginx-lua/t/023-rewrite/on-abort.t index aca2ab6..336b7ce 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/on-abort.t +++ b/debian/modules/nginx-lua/t/023-rewrite/on-abort.t @@ -654,4 +654,3 @@ delete thread 2 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/redirect.t b/debian/modules/nginx-lua/t/023-rewrite/redirect.t index 8843f1a..99f3fd4 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/redirect.t +++ b/debian/modules/nginx-lua/t/023-rewrite/redirect.t @@ -122,4 +122,3 @@ GET /read --- raw_response_headers_like: Location: /foo\r\n --- response_body_like: 302 Found --- error_code: 302 - diff --git a/debian/modules/nginx-lua/t/023-rewrite/req-body.t b/debian/modules/nginx-lua/t/023-rewrite/req-body.t index 2f42e0a..13bdcb2 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/req-body.t +++ b/debian/modules/nginx-lua/t/023-rewrite/req-body.t @@ -221,4 +221,3 @@ hiya, world"] --- no_error_log [error] [alert] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/req-socket.t b/debian/modules/nginx-lua/t/023-rewrite/req-socket.t index 34aedaa..87cbbbe 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/req-socket.t +++ b/debian/modules/nginx-lua/t/023-rewrite/req-socket.t @@ -532,4 +532,3 @@ Expect: 100-Continue \breceived: hello\b.*?\breceived: worl\b --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/request_body.t b/debian/modules/nginx-lua/t/023-rewrite/request_body.t index 0594001..b867d3a 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/request_body.t +++ b/debian/modules/nginx-lua/t/023-rewrite/request_body.t @@ -170,4 +170,3 @@ Expect: 100-Continue http finalize request: 500, "/echo_body?" a:1, c:2 http finalize request: 500, "/echo_body?" a:1, c:0 --- log_level: debug - diff --git a/debian/modules/nginx-lua/t/023-rewrite/sanity.t b/debian/modules/nginx-lua/t/023-rewrite/sanity.t index 20b00e2..b90aa0e 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/sanity.t +++ b/debian/modules/nginx-lua/t/023-rewrite/sanity.t @@ -799,4 +799,3 @@ test test --- no_error_log [alert] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/sleep.t b/debian/modules/nginx-lua/t/023-rewrite/sleep.t index 1719784..8d4c2da 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/sleep.t +++ b/debian/modules/nginx-lua/t/023-rewrite/sleep.t @@ -219,4 +219,3 @@ hello world hello world --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/socket-keepalive.t b/debian/modules/nginx-lua/t/023-rewrite/socket-keepalive.t index 50de0b3..489a70f 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/socket-keepalive.t +++ b/debian/modules/nginx-lua/t/023-rewrite/socket-keepalive.t @@ -1007,4 +1007,3 @@ Not found, dear... --- error_code: 404 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/subrequest.t b/debian/modules/nginx-lua/t/023-rewrite/subrequest.t index a307388..5d1e8f0 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/subrequest.t +++ b/debian/modules/nginx-lua/t/023-rewrite/subrequest.t @@ -639,4 +639,3 @@ the nginx core requires the patch https://github.com/agentzh/ngx_openresty/blob/ GET /t --- response_body done - diff --git a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket-timeout.t b/debian/modules/nginx-lua/t/023-rewrite/tcp-socket-timeout.t index 79cd0b9..15bec7f 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket-timeout.t +++ b/debian/modules/nginx-lua/t/023-rewrite/tcp-socket-timeout.t @@ -41,7 +41,7 @@ __DATA__ --- config server_tokens off; lua_socket_connect_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t1 { rewrite_by_lua ' @@ -73,7 +73,7 @@ lua tcp socket connect timed out server_tokens off; lua_socket_connect_timeout 60s; lua_socket_log_errors off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t2 { rewrite_by_lua ' @@ -108,7 +108,7 @@ lua tcp socket connect timeout: 150 server_tokens off; lua_socket_log_errors off; lua_socket_connect_timeout 102ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; #resolver_timeout 3s; location /t3 { rewrite_by_lua ' @@ -143,7 +143,7 @@ lua tcp socket connect timeout: 102 server_tokens off; lua_socket_connect_timeout 102ms; lua_socket_log_errors off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t4 { rewrite_by_lua ' @@ -179,7 +179,7 @@ lua tcp socket connect timeout: 102 server_tokens off; lua_socket_connect_timeout 102ms; lua_socket_log_errors off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t5 { rewrite_by_lua ' @@ -251,7 +251,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_read_timeout 60s; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -292,7 +292,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_read_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -333,7 +333,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_read_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -375,7 +375,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_read_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -416,7 +416,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_send_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -455,7 +455,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_send_timeout 60s; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -496,7 +496,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_send_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -537,7 +537,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_send_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -578,7 +578,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_send_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -612,4 +612,3 @@ failed to send: timeout lua tcp socket send timeout: 102 lua tcp socket connect timeout: 60000 lua tcp socket write timed out - diff --git a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t b/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t index cf9d80a..bff69a5 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t +++ b/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t @@ -204,7 +204,7 @@ attempt to send data on a closed socket: --- timeout: 10 --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { rewrite_by_lua ' @@ -296,7 +296,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ === TEST 6: connection timeout (tcp) --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_socket_connect_timeout 100ms; lua_socket_send_timeout 100ms; lua_socket_read_timeout 100ms; @@ -372,7 +372,7 @@ connected: 1 === TEST 8: resolver error (host not found) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { rewrite_by_lua ' @@ -415,7 +415,7 @@ attempt to send data on a closed socket === TEST 9: resolver error (timeout) --- config server_tokens off; - resolver 8.8.8.8; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 1ms; location /t { rewrite_by_lua ' @@ -2390,4 +2390,3 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):16: bad request/ --- no_error_log [alert] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/unix-socket.t b/debian/modules/nginx-lua/t/023-rewrite/unix-socket.t index 098dd67..8a5f000 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/unix-socket.t +++ b/debian/modules/nginx-lua/t/023-rewrite/unix-socket.t @@ -150,4 +150,3 @@ received: received: foo failed to receive a line: closed close: 1 nil - diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t b/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t index 0f125e0..83de1a3 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t +++ b/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t @@ -186,4 +186,3 @@ free request --- error_code: 302 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t b/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t index 58af7d0..5552107 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t +++ b/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t @@ -1449,4 +1449,3 @@ status: 204 --- no_error_log [error] --- timeout: 3 - diff --git a/debian/modules/nginx-lua/t/024-access/auth.t b/debian/modules/nginx-lua/t/024-access/auth.t index 5da09cb..56e9862 100644 --- a/debian/modules/nginx-lua/t/024-access/auth.t +++ b/debian/modules/nginx-lua/t/024-access/auth.t @@ -107,4 +107,3 @@ Location: /terms_of_use\.html GET /lua --- response_body_like: 403 Forbidden --- error_code: 403 - diff --git a/debian/modules/nginx-lua/t/024-access/client-abort.t b/debian/modules/nginx-lua/t/024-access/client-abort.t index a94f822..c16f4ea 100644 --- a/debian/modules/nginx-lua/t/024-access/client-abort.t +++ b/debian/modules/nginx-lua/t/024-access/client-abort.t @@ -850,4 +850,3 @@ delete thread 1 --- no_error_log [error] [alert] - diff --git a/debian/modules/nginx-lua/t/024-access/exit.t b/debian/modules/nginx-lua/t/024-access/exit.t index 8470ab9..d6d66b8 100644 --- a/debian/modules/nginx-lua/t/024-access/exit.t +++ b/debian/modules/nginx-lua/t/024-access/exit.t @@ -545,4 +545,3 @@ Not found, dear... --- response_body Not found, dear... --- error_code: 404 - diff --git a/debian/modules/nginx-lua/t/024-access/multi-capture.t b/debian/modules/nginx-lua/t/024-access/multi-capture.t index 368d401..930b74d 100644 --- a/debian/modules/nginx-lua/t/024-access/multi-capture.t +++ b/debian/modules/nginx-lua/t/024-access/multi-capture.t @@ -392,4 +392,3 @@ res4.status = 201 res4.body = STORED\r " - diff --git a/debian/modules/nginx-lua/t/024-access/on-abort.t b/debian/modules/nginx-lua/t/024-access/on-abort.t index 0c17b55..5bb948b 100644 --- a/debian/modules/nginx-lua/t/024-access/on-abort.t +++ b/debian/modules/nginx-lua/t/024-access/on-abort.t @@ -649,4 +649,3 @@ delete thread 2 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/024-access/redirect.t b/debian/modules/nginx-lua/t/024-access/redirect.t index c7ce512..b45fac7 100644 --- a/debian/modules/nginx-lua/t/024-access/redirect.t +++ b/debian/modules/nginx-lua/t/024-access/redirect.t @@ -122,4 +122,3 @@ GET /read --- raw_response_headers_like: Location: /foo\r\n --- response_body_like: 302 Found --- error_code: 302 - diff --git a/debian/modules/nginx-lua/t/024-access/req-body.t b/debian/modules/nginx-lua/t/024-access/req-body.t index fd33aff..70db85c 100644 --- a/debian/modules/nginx-lua/t/024-access/req-body.t +++ b/debian/modules/nginx-lua/t/024-access/req-body.t @@ -218,4 +218,3 @@ hiya, world"] --- no_error_log [error] [alert] - diff --git a/debian/modules/nginx-lua/t/024-access/request_body.t b/debian/modules/nginx-lua/t/024-access/request_body.t index a6fead2..fa03195 100644 --- a/debian/modules/nginx-lua/t/024-access/request_body.t +++ b/debian/modules/nginx-lua/t/024-access/request_body.t @@ -170,4 +170,3 @@ Expect: 100-Continue http finalize request: 500, "/echo_body?" a:1, c:2 http finalize request: 500, "/echo_body?" a:1, c:0 --- log_level: debug - diff --git a/debian/modules/nginx-lua/t/024-access/sanity.t b/debian/modules/nginx-lua/t/024-access/sanity.t index de63a68..7ff177f 100644 --- a/debian/modules/nginx-lua/t/024-access/sanity.t +++ b/debian/modules/nginx-lua/t/024-access/sanity.t @@ -741,4 +741,3 @@ test test --- no_error_log [alert] - diff --git a/debian/modules/nginx-lua/t/024-access/satisfy.t b/debian/modules/nginx-lua/t/024-access/satisfy.t index 10d3ece..7902f49 100644 --- a/debian/modules/nginx-lua/t/024-access/satisfy.t +++ b/debian/modules/nginx-lua/t/024-access/satisfy.t @@ -209,4 +209,3 @@ something important --- error_code: 200 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/024-access/sleep.t b/debian/modules/nginx-lua/t/024-access/sleep.t index 2eb0822..fc1fc02 100644 --- a/debian/modules/nginx-lua/t/024-access/sleep.t +++ b/debian/modules/nginx-lua/t/024-access/sleep.t @@ -219,4 +219,3 @@ hello world hello world --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/024-access/subrequest.t b/debian/modules/nginx-lua/t/024-access/subrequest.t index bfe96d6..b6ccf11 100644 --- a/debian/modules/nginx-lua/t/024-access/subrequest.t +++ b/debian/modules/nginx-lua/t/024-access/subrequest.t @@ -599,4 +599,3 @@ the nginx core requires the patch https://github.com/agentzh/ngx_openresty/blob/ GET /t --- response_body done - diff --git a/debian/modules/nginx-lua/t/024-access/uthread-exec.t b/debian/modules/nginx-lua/t/024-access/uthread-exec.t index d7c2321..7add3d4 100644 --- a/debian/modules/nginx-lua/t/024-access/uthread-exec.t +++ b/debian/modules/nginx-lua/t/024-access/uthread-exec.t @@ -344,4 +344,3 @@ free request end --- error_log attempt to abort with pending subrequests - diff --git a/debian/modules/nginx-lua/t/024-access/uthread-exit.t b/debian/modules/nginx-lua/t/024-access/uthread-exit.t index da4a9db..7c146ae 100644 --- a/debian/modules/nginx-lua/t/024-access/uthread-exit.t +++ b/debian/modules/nginx-lua/t/024-access/uthread-exit.t @@ -1311,4 +1311,3 @@ free request end --- error_log attempt to abort with pending subrequests - diff --git a/debian/modules/nginx-lua/t/024-access/uthread-redirect.t b/debian/modules/nginx-lua/t/024-access/uthread-redirect.t index 8b030ac..4eb4759 100644 --- a/debian/modules/nginx-lua/t/024-access/uthread-redirect.t +++ b/debian/modules/nginx-lua/t/024-access/uthread-redirect.t @@ -187,4 +187,3 @@ free request --- error_code: 302 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/024-access/uthread-spawn.t b/debian/modules/nginx-lua/t/024-access/uthread-spawn.t index 415e4c0..7c7ba3b 100644 --- a/debian/modules/nginx-lua/t/024-access/uthread-spawn.t +++ b/debian/modules/nginx-lua/t/024-access/uthread-spawn.t @@ -1116,4 +1116,3 @@ body: hello world)$ --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/025-codecache.t b/debian/modules/nginx-lua/t/025-codecache.t index f33452a..0b02a27 100644 --- a/debian/modules/nginx-lua/t/025-codecache.t +++ b/debian/modules/nginx-lua/t/025-codecache.t @@ -1244,4 +1244,3 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/, "decrementing the reference count for Lua VM: 1", "lua close the global Lua VM", ] - diff --git a/debian/modules/nginx-lua/t/026-mysql.t b/debian/modules/nginx-lua/t/026-mysql.t index e14ffb6..569f96f 100644 --- a/debian/modules/nginx-lua/t/026-mysql.t +++ b/debian/modules/nginx-lua/t/026-mysql.t @@ -66,7 +66,7 @@ __DATA__ ^status = 504 thread id = \d+ kill status = 200 -kill body = {"errcode":0}$ +kill body = \{"errcode":0\}$ --- error_log eval qr{upstream timed out \(\d+: Connection timed out\) while sending query to drizzle upstream} @@ -126,6 +126,5 @@ qr{upstream timed out \(\d+: Connection timed out\) while sending query to drizz ^status = 504 thread id = \d+ kill status = 200 -kill body = {"errcode":0}$ +kill body = \{"errcode":0\}$ --- SKIP - diff --git a/debian/modules/nginx-lua/t/027-multi-capture.t b/debian/modules/nginx-lua/t/027-multi-capture.t index 3588c69..9227fe5 100644 --- a/debian/modules/nginx-lua/t/027-multi-capture.t +++ b/debian/modules/nginx-lua/t/027-multi-capture.t @@ -752,4 +752,3 @@ proxy_cache_path conf/cache levels=1:2 keys_zone=STATIC:10m inactive=10m max_siz GET /foo --- response_body ok - diff --git a/debian/modules/nginx-lua/t/029-http-time.t b/debian/modules/nginx-lua/t/029-http-time.t index 71a7758..ecef492 100644 --- a/debian/modules/nginx-lua/t/029-http-time.t +++ b/debian/modules/nginx-lua/t/029-http-time.t @@ -85,4 +85,3 @@ GET /lua GET /lua --- response_body nil - diff --git a/debian/modules/nginx-lua/t/030-uri-args.t b/debian/modules/nginx-lua/t/030-uri-args.t index 8ee8401..96e216c 100644 --- a/debian/modules/nginx-lua/t/030-uri-args.t +++ b/debian/modules/nginx-lua/t/030-uri-args.t @@ -9,7 +9,7 @@ log_level('warn'); repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 17); +plan tests => repeat_each() * (blocks() * 2 + 18); no_root_location(); @@ -1390,3 +1390,19 @@ GET /lua --- response_body_like ^HTTP/1.0 (a=3&b|b&a=3)$ + + +=== TEST 57: ngx.encode_args (escaping) +--- config + location /lua { + content_by_lua_block { + local t = {bar = "-_.!~*'()", foo = ",$@|`"} + ngx.say("args: ", ngx.encode_args(t)) + } + } +--- request +GET /lua +--- response_body +args: foo=%2C%24%40%7C%60&bar=-_.!~*'() +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/031-post-args.t b/debian/modules/nginx-lua/t/031-post-args.t index c2b6b8f..62c88c1 100644 --- a/debian/modules/nginx-lua/t/031-post-args.t +++ b/debian/modules/nginx-lua/t/031-post-args.t @@ -351,6 +351,6 @@ CORE::join("", @k); POST /lua a=3&b=4&c --- response_body -requesty body in temp file not supported +request body in temp file not supported --- no_error_log [error] diff --git a/debian/modules/nginx-lua/t/032-iolist.t b/debian/modules/nginx-lua/t/032-iolist.t index ddf3d7f..3c56032 100644 --- a/debian/modules/nginx-lua/t/032-iolist.t +++ b/debian/modules/nginx-lua/t/032-iolist.t @@ -76,4 +76,3 @@ GET /lua GET /lua --- response_body_like: 500 Internal Server Error --- error_code: 500 - diff --git a/debian/modules/nginx-lua/t/033-ctx.t b/debian/modules/nginx-lua/t/033-ctx.t index eefb216..8fc50aa 100644 --- a/debian/modules/nginx-lua/t/033-ctx.t +++ b/debian/modules/nginx-lua/t/033-ctx.t @@ -440,4 +440,3 @@ lua release ngx.ctx at ref --- response_body --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/034-match.t b/debian/modules/nginx-lua/t/034-match.t index 35149f1..ebe5762 100644 --- a/debian/modules/nginx-lua/t/034-match.t +++ b/debian/modules/nginx-lua/t/034-match.t @@ -1017,7 +1017,7 @@ exec opts: 0 === TEST 45: just hit match limit --- http_config - lua_regex_match_limit 5600; + lua_regex_match_limit 5000; --- config location /re { content_by_lua_file html/a.lua; @@ -1057,7 +1057,7 @@ error: pcre_exec() failed: -8 === TEST 46: just not hit match limit --- http_config - lua_regex_match_limit 5700; + lua_regex_match_limit 5100; --- config location /re { content_by_lua_file html/a.lua; diff --git a/debian/modules/nginx-lua/t/035-gmatch.t b/debian/modules/nginx-lua/t/035-gmatch.t index 69b9512..5b63ae4 100644 --- a/debian/modules/nginx-lua/t/035-gmatch.t +++ b/debian/modules/nginx-lua/t/035-gmatch.t @@ -814,7 +814,7 @@ exec opts: 0 === TEST 30: just hit match limit --- http_config - lua_regex_match_limit 5600; + lua_regex_match_limit 5000; --- config location /re { content_by_lua_file html/a.lua; @@ -860,7 +860,7 @@ error: pcre_exec() failed: -8 === TEST 31: just not hit match limit --- http_config - lua_regex_match_limit 5700; + lua_regex_match_limit 5100; --- config location /re { content_by_lua_file html/a.lua; @@ -901,4 +901,3 @@ end GET /re --- response_body failed to match - diff --git a/debian/modules/nginx-lua/t/036-sub.t b/debian/modules/nginx-lua/t/036-sub.t index f08c50f..2b4b075 100644 --- a/debian/modules/nginx-lua/t/036-sub.t +++ b/debian/modules/nginx-lua/t/036-sub.t @@ -580,7 +580,7 @@ s: a好 === TEST 28: just hit match limit --- http_config - lua_regex_match_limit 5600; + lua_regex_match_limit 5000; --- config location /re { content_by_lua_file html/a.lua; @@ -617,7 +617,7 @@ error: pcre_exec() failed: -8 === TEST 29: just not hit match limit --- http_config - lua_regex_match_limit 5700; + lua_regex_match_limit 5100; --- config location /re { content_by_lua_file html/a.lua; diff --git a/debian/modules/nginx-lua/t/037-gsub.t b/debian/modules/nginx-lua/t/037-gsub.t index 2a1e00f..4c5810d 100644 --- a/debian/modules/nginx-lua/t/037-gsub.t +++ b/debian/modules/nginx-lua/t/037-gsub.t @@ -501,7 +501,7 @@ s: aa === TEST 23: just hit match limit --- http_config - lua_regex_match_limit 5600; + lua_regex_match_limit 5000; --- config location /re { content_by_lua_file html/a.lua; @@ -538,7 +538,7 @@ error: pcre_exec() failed: -8 === TEST 24: just not hit match limit --- http_config - lua_regex_match_limit 5700; + lua_regex_match_limit 5100; --- config location /re { content_by_lua_file html/a.lua; diff --git a/debian/modules/nginx-lua/t/038-match-o.t b/debian/modules/nginx-lua/t/038-match-o.t index 628e27f..d61ff1f 100644 --- a/debian/modules/nginx-lua/t/038-match-o.t +++ b/debian/modules/nginx-lua/t/038-match-o.t @@ -740,4 +740,3 @@ false hello false false - diff --git a/debian/modules/nginx-lua/t/039-sub-o.t b/debian/modules/nginx-lua/t/039-sub-o.t index a861b6c..580a671 100644 --- a/debian/modules/nginx-lua/t/039-sub-o.t +++ b/debian/modules/nginx-lua/t/039-sub-o.t @@ -578,4 +578,3 @@ a [b c] [b] [c] [] [] d --- response_body a [b c] [b] [c] d 1 - diff --git a/debian/modules/nginx-lua/t/040-gsub-o.t b/debian/modules/nginx-lua/t/040-gsub-o.t index 90619b0..5347266 100644 --- a/debian/modules/nginx-lua/t/040-gsub-o.t +++ b/debian/modules/nginx-lua/t/040-gsub-o.t @@ -198,4 +198,3 @@ hello, world --- response_body [hello,h], [world,w] 2 - diff --git a/debian/modules/nginx-lua/t/041-header-filter.t b/debian/modules/nginx-lua/t/041-header-filter.t index 553ee43..9cca3b7 100644 --- a/debian/modules/nginx-lua/t/041-header-filter.t +++ b/debian/modules/nginx-lua/t/041-header-filter.t @@ -790,4 +790,3 @@ GET /t --- error_code: 302 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/042-crc32.t b/debian/modules/nginx-lua/t/042-crc32.t index 86d9201..73aa1f4 100644 --- a/debian/modules/nginx-lua/t/042-crc32.t +++ b/debian/modules/nginx-lua/t/042-crc32.t @@ -54,4 +54,3 @@ GET /test GET /test --- response_body 0 - diff --git a/debian/modules/nginx-lua/t/045-ngx-var.t b/debian/modules/nginx-lua/t/045-ngx-var.t index 8f2dcb3..6475f1e 100644 --- a/debian/modules/nginx-lua/t/045-ngx-var.t +++ b/debian/modules/nginx-lua/t/045-ngx-var.t @@ -154,14 +154,15 @@ invalid referer: 1 -=== TEST 8: $proxy_host & $proxy_port +=== TEST 8: $proxy_host & $proxy_port & $proxy_add_x_forwarded_for --- config location = /t { proxy_pass http://127.0.0.1:$server_port/back; - header_filter_by_lua ' + header_filter_by_lua_block { ngx.header["Proxy-Host"] = ngx.var.proxy_host ngx.header["Proxy-Port"] = ngx.var.proxy_port - '; + ngx.header["Proxy-Add-X-Forwarded-For"] = ngx.var.proxy_add_x_forwarded_for + } } location = /back { @@ -172,6 +173,7 @@ GET /t --- raw_response_headers_like Proxy-Host: 127.0.0.1\:\d+\r Proxy-Port: \d+\r +Proxy-Add-X-Forwarded-For: 127.0.0.1\r --- response_body hello --- no_error_log @@ -226,4 +228,3 @@ GET /test?hello --- error_log variable "query_string" not changeable --- error_code: 500 - diff --git a/debian/modules/nginx-lua/t/046-hmac.t b/debian/modules/nginx-lua/t/046-hmac.t index 686b479..32e222b 100644 --- a/debian/modules/nginx-lua/t/046-hmac.t +++ b/debian/modules/nginx-lua/t/046-hmac.t @@ -29,4 +29,3 @@ __DATA__ GET /lua --- response_body R/pvxzHC4NLtj7S+kXFg/NePTmk= - diff --git a/debian/modules/nginx-lua/t/047-match-jit.t b/debian/modules/nginx-lua/t/047-match-jit.t index 077ebb6..2417a63 100644 --- a/debian/modules/nginx-lua/t/047-match-jit.t +++ b/debian/modules/nginx-lua/t/047-match-jit.t @@ -212,4 +212,3 @@ end GET /re --- response_body failed to match - diff --git a/debian/modules/nginx-lua/t/048-match-dfa.t b/debian/modules/nginx-lua/t/048-match-dfa.t index 8a0a328..28b5a60 100644 --- a/debian/modules/nginx-lua/t/048-match-dfa.t +++ b/debian/modules/nginx-lua/t/048-match-dfa.t @@ -207,4 +207,3 @@ exec opts: 0 你 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/049-gmatch-jit.t b/debian/modules/nginx-lua/t/049-gmatch-jit.t index 614c440..5134d52 100644 --- a/debian/modules/nginx-lua/t/049-gmatch-jit.t +++ b/debian/modules/nginx-lua/t/049-gmatch-jit.t @@ -226,4 +226,3 @@ qr/pcre JIT compiling result: \d+/ error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/051-sub-jit.t b/debian/modules/nginx-lua/t/051-sub-jit.t index 789e897..c8a49c0 100644 --- a/debian/modules/nginx-lua/t/051-sub-jit.t +++ b/debian/modules/nginx-lua/t/051-sub-jit.t @@ -147,4 +147,3 @@ error: pcre_compile() failed: missing ) in "(abc" error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/053-gsub-jit.t b/debian/modules/nginx-lua/t/053-gsub-jit.t index 3a2a1aa..3efc0a2 100644 --- a/debian/modules/nginx-lua/t/053-gsub-jit.t +++ b/debian/modules/nginx-lua/t/053-gsub-jit.t @@ -147,4 +147,3 @@ error: pcre_compile() failed: missing ) in "(abc" error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/055-subreq-vars.t b/debian/modules/nginx-lua/t/055-subreq-vars.t index 2fc6960..eb5e24d 100644 --- a/debian/modules/nginx-lua/t/055-subreq-vars.t +++ b/debian/modules/nginx-lua/t/055-subreq-vars.t @@ -336,4 +336,3 @@ dog = hiya cat = 56 parent dog: blah parent cat: foo - diff --git a/debian/modules/nginx-lua/t/056-flush.t b/debian/modules/nginx-lua/t/056-flush.t index d189cd5..6b697a4 100644 --- a/debian/modules/nginx-lua/t/056-flush.t +++ b/debian/modules/nginx-lua/t/056-flush.t @@ -520,4 +520,3 @@ qr/lua flush requires waiting: buffered 0x[0-9a-f]+, delayed:1/, --- no_error_log [error] --- timeout: 4 - diff --git a/debian/modules/nginx-lua/t/057-flush-timeout.t b/debian/modules/nginx-lua/t/057-flush-timeout.t index d6e0f86..a046539 100644 --- a/debian/modules/nginx-lua/t/057-flush-timeout.t +++ b/debian/modules/nginx-lua/t/057-flush-timeout.t @@ -318,4 +318,3 @@ qr/failed to flush: client aborted/, --- timeout: 0.2 --- abort --- wait: 1 - diff --git a/debian/modules/nginx-lua/t/058-tcp-socket.t b/debian/modules/nginx-lua/t/058-tcp-socket.t index acf69f0..1ee113b 100644 --- a/debian/modules/nginx-lua/t/058-tcp-socket.t +++ b/debian/modules/nginx-lua/t/058-tcp-socket.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 187; +plan tests => repeat_each() * 190; our $HtmlDir = html_dir; @@ -200,7 +200,7 @@ attempt to send data on a closed socket: --- timeout: 10 --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { content_by_lua ' @@ -290,7 +290,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ === TEST 6: connection timeout (tcp) --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_socket_connect_timeout 100ms; lua_socket_send_timeout 100ms; lua_socket_read_timeout 100ms; @@ -362,7 +362,7 @@ connected: 1 === TEST 8: resolver error (host not found) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { content_by_lua ' @@ -403,7 +403,7 @@ attempt to send data on a closed socket === TEST 9: resolver error (timeout) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 1ms; location /t { content_by_lua ' @@ -1995,7 +1995,7 @@ close: 1 nil === TEST 33: github issue #215: Handle the posted requests in lua cosocket api (failed to resolve) --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location = /sub { content_by_lua ' @@ -2038,7 +2038,7 @@ resolve name done === TEST 34: github issue #215: Handle the posted requests in lua cosocket api (successfully resolved) --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 5s; location = /sub { @@ -2136,7 +2136,7 @@ close: nil closed --- config server_tokens off; lua_socket_read_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -2178,7 +2178,7 @@ lua tcp socket read timed out === TEST 37: successful reread after a read time out happen (receive -> receive) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -2255,7 +2255,7 @@ lua tcp socket read timed out === TEST 38: successful reread after a read time out happen (receive -> receiveuntil) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -2335,7 +2335,7 @@ lua tcp socket read timed out === TEST 39: successful reread after a read time out happen (receiveuntil -> receiveuntil) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -2417,7 +2417,7 @@ lua tcp socket read timed out === TEST 40: successful reread after a read time out happen (receiveuntil -> receive) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -3015,7 +3015,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):16: bad request/ === TEST 50: cosocket resolving aborted by coroutine yielding failures (require) --- http_config lua_package_path "$prefix/html/?.lua;;"; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; --- config location = /t { @@ -3049,7 +3049,7 @@ runtime error: attempt to yield across C-call boundary === TEST 51: cosocket resolving aborted by coroutine yielding failures (xpcall err) --- http_config lua_package_path "$prefix/html/?.lua;;"; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; --- config location = /t { @@ -3307,7 +3307,7 @@ close: 1 nil --- config server_tokens off; lua_socket_connect_timeout 1s; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { content_by_lua ' @@ -3640,3 +3640,53 @@ failed to receive a line: closed [] close: 1 nil --- error_log lua http cleanup reuse + + + +=== TEST 60: options_table is nil +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local sock = ngx.socket.tcp() + local port = ngx.var.port + + local ok, err = sock:connect("127.0.0.1", port, nil) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local req = "flush_all\r\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + ngx.say("request sent: ", bytes) + + local line, err, part = sock:receive() + if line then + ngx.say("received: ", line) + + else + ngx.say("failed to receive a line: ", err, " [", part, "]") + end + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + } + } +--- request +GET /t +--- response_body +connected: 1 +request sent: 11 +received: OK +close: 1 nil +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/060-lua-memcached.t b/debian/modules/nginx-lua/t/060-lua-memcached.t index e1ebb92..0751238 100644 --- a/debian/modules/nginx-lua/t/060-lua-memcached.t +++ b/debian/modules/nginx-lua/t/060-lua-memcached.t @@ -166,4 +166,3 @@ some_key: hello 1234 [error] --- error_log lua reuse free buf memory - diff --git a/debian/modules/nginx-lua/t/061-lua-redis.t b/debian/modules/nginx-lua/t/061-lua-redis.t index d7b1876..ebfa6d1 100644 --- a/debian/modules/nginx-lua/t/061-lua-redis.t +++ b/debian/modules/nginx-lua/t/061-lua-redis.t @@ -182,4 +182,3 @@ abort: function msg type: nil --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/062-count.t b/debian/modules/nginx-lua/t/062-count.t index c3973ad..a69c33e 100644 --- a/debian/modules/nginx-lua/t/062-count.t +++ b/debian/modules/nginx-lua/t/062-count.t @@ -323,7 +323,7 @@ ngx. entry count: 116 --- request GET /test --- response_body -n = 3 +n = 4 --- no_error_log [error] diff --git a/debian/modules/nginx-lua/t/063-abort.t b/debian/modules/nginx-lua/t/063-abort.t index c112ee1..411a07e 100644 --- a/debian/modules/nginx-lua/t/063-abort.t +++ b/debian/modules/nginx-lua/t/063-abort.t @@ -1017,4 +1017,3 @@ foo --- no_error_log [error] --- timeout: 2 - diff --git a/debian/modules/nginx-lua/t/064-pcall.t b/debian/modules/nginx-lua/t/064-pcall.t index cf90a07..3011f3e 100644 --- a/debian/modules/nginx-lua/t/064-pcall.t +++ b/debian/modules/nginx-lua/t/064-pcall.t @@ -104,4 +104,3 @@ $/ --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/065-tcp-socket-timeout.t b/debian/modules/nginx-lua/t/065-tcp-socket-timeout.t index ec79891..212766e 100644 --- a/debian/modules/nginx-lua/t/065-tcp-socket-timeout.t +++ b/debian/modules/nginx-lua/t/065-tcp-socket-timeout.t @@ -46,7 +46,7 @@ __DATA__ --- config server_tokens off; lua_socket_connect_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { content_by_lua ' @@ -75,7 +75,7 @@ lua tcp socket connect timed out --- config server_tokens off; lua_socket_connect_timeout 60s; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { content_by_lua ' @@ -105,7 +105,7 @@ lua tcp socket connect timed out --- config server_tokens off; lua_socket_connect_timeout 102ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -133,7 +133,7 @@ lua tcp socket connect timed out --- config server_tokens off; lua_socket_connect_timeout 102ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { content_by_lua ' @@ -163,7 +163,7 @@ lua tcp socket connect timed out --- config server_tokens off; lua_socket_connect_timeout 102ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -191,7 +191,7 @@ lua tcp socket connect timed out --- config server_tokens off; lua_socket_read_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -228,7 +228,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_read_timeout 60s; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -267,7 +267,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_read_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -306,7 +306,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_read_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -346,7 +346,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_read_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -385,7 +385,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_send_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -436,7 +436,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_send_timeout 60s; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -475,7 +475,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_send_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -514,7 +514,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_send_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -553,7 +553,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_send_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -686,7 +686,7 @@ after --- config server_tokens off; lua_socket_connect_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { content_by_lua ' @@ -724,7 +724,7 @@ lua tcp socket connect timed out --- config server_tokens off; lua_socket_send_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -779,7 +779,7 @@ lua tcp socket write timed out === TEST 19: abort when upstream sockets pending on writes --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -832,7 +832,7 @@ lua tcp socket write timed out === TEST 20: abort when downstream socket pending on writes --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' ngx.send_headers() @@ -888,7 +888,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_read_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -994,4 +994,3 @@ close: 1 nil --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/066-socket-receiveuntil.t b/debian/modules/nginx-lua/t/066-socket-receiveuntil.t index 3bf5229..ffe74aa 100644 --- a/debian/modules/nginx-lua/t/066-socket-receiveuntil.t +++ b/debian/modules/nginx-lua/t/066-socket-receiveuntil.t @@ -1329,4 +1329,3 @@ this exposed a memory leak in receiveuntil ok --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/067-req-socket.t b/debian/modules/nginx-lua/t/067-req-socket.t index 30a653a..229d5cc 100644 --- a/debian/modules/nginx-lua/t/067-req-socket.t +++ b/debian/modules/nginx-lua/t/067-req-socket.t @@ -1096,4 +1096,3 @@ done --- grep_error_log_out lua finalize socket GC cycle done - diff --git a/debian/modules/nginx-lua/t/069-null.t b/debian/modules/nginx-lua/t/069-null.t index 7761c91..e4c26af 100644 --- a/debian/modules/nginx-lua/t/069-null.t +++ b/debian/modules/nginx-lua/t/069-null.t @@ -93,4 +93,3 @@ done ngx.null: null --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/071-idle-socket.t b/debian/modules/nginx-lua/t/071-idle-socket.t index 55d25c6..c9002be 100644 --- a/debian/modules/nginx-lua/t/071-idle-socket.t +++ b/debian/modules/nginx-lua/t/071-idle-socket.t @@ -431,4 +431,3 @@ failed to set keepalive: unread data in buffer } --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/072-conditional-get.t b/debian/modules/nginx-lua/t/072-conditional-get.t index 4bb567a..7cf2dcd 100644 --- a/debian/modules/nginx-lua/t/072-conditional-get.t +++ b/debian/modules/nginx-lua/t/072-conditional-get.t @@ -88,4 +88,3 @@ delete thread 1 say failed: nginx output filter error --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/073-backtrace.t b/debian/modules/nginx-lua/t/073-backtrace.t index aae4bae..6c54692 100644 --- a/debian/modules/nginx-lua/t/073-backtrace.t +++ b/debian/modules/nginx-lua/t/073-backtrace.t @@ -187,4 +187,3 @@ probe process("$LIBLUA_PATH").function("lua_concat") { :79: in function 'func20' :83: in function 'func21' ... - diff --git a/debian/modules/nginx-lua/t/074-prefix-var.t b/debian/modules/nginx-lua/t/074-prefix-var.t index 3cc4587..c116d84 100644 --- a/debian/modules/nginx-lua/t/074-prefix-var.t +++ b/debian/modules/nginx-lua/t/074-prefix-var.t @@ -64,4 +64,3 @@ GET /t Greetings from module foo. --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/075-logby.t b/debian/modules/nginx-lua/t/075-logby.t index f987c8e..520c62e 100644 --- a/debian/modules/nginx-lua/t/075-logby.t +++ b/debian/modules/nginx-lua/t/075-logby.t @@ -581,4 +581,3 @@ qr{log_by_lua\(nginx\.conf:\d+\):1: content-type: text/plain} --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/077-sleep.t b/debian/modules/nginx-lua/t/077-sleep.t index a7c251a..96f04bd 100644 --- a/debian/modules/nginx-lua/t/077-sleep.t +++ b/debian/modules/nginx-lua/t/077-sleep.t @@ -9,10 +9,10 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * 63; +plan tests => repeat_each() * 71; #no_diff(); -#no_long_string(); +no_long_string(); run_tests(); __DATA__ @@ -405,3 +405,98 @@ ok [error] [alert] + + +=== TEST 16: sleep 0 +--- config + location /t { + content_by_lua_block { + local function f (n) + print("f begin ", n) + ngx.sleep(0) + print("f middle ", n) + ngx.sleep(0) + print("f end ", n) + ngx.sleep(0) + end + + for i = 1, 3 do + assert(ngx.thread.spawn(f, i)) + end + + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +ok +--- no_error_log +[error] +--- grep_error_log eval: qr/\bf (?:begin|middle|end)\b|\bworker cycle$|\be?poll timer: \d+$/ +--- grep_error_log_out eval +qr/f begin +f begin +f begin +worker cycle +e?poll timer: 0 +f middle +f middle +f middle +worker cycle +e?poll timer: 0 +f end +f end +f end +worker cycle +e?poll timer: 0 +/ + + + +=== TEST 17: sleep short times less than 1ms +--- config + location /t { + content_by_lua_block { + local delay = 0.0005 + + local function f (n) + print("f begin ", n) + ngx.sleep(delay) + print("f middle ", n) + ngx.sleep(delay) + print("f end ", n) + ngx.sleep(delay) + end + + for i = 1, 3 do + assert(ngx.thread.spawn(f, i)) + end + + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +ok +--- no_error_log +[error] +--- grep_error_log eval: qr/\bf (?:begin|middle|end)\b|\bworker cycle$|\be?poll timer: \d+$/ +--- grep_error_log_out eval +qr/f begin +f begin +f begin +worker cycle +e?poll timer: 0 +f middle +f middle +f middle +worker cycle +e?poll timer: 0 +f end +f end +f end +worker cycle +e?poll timer: 0 +/ diff --git a/debian/modules/nginx-lua/t/078-hup-vars.t b/debian/modules/nginx-lua/t/078-hup-vars.t index 8acc346..5072c4d 100644 --- a/debian/modules/nginx-lua/t/078-hup-vars.t +++ b/debian/modules/nginx-lua/t/078-hup-vars.t @@ -62,4 +62,3 @@ GET /t localhost --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/079-unused-directives.t b/debian/modules/nginx-lua/t/079-unused-directives.t index cba0e41..aacd0d3 100644 --- a/debian/modules/nginx-lua/t/079-unused-directives.t +++ b/debian/modules/nginx-lua/t/079-unused-directives.t @@ -340,4 +340,3 @@ GET /t sub: sub --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/080-hup-shdict.t b/debian/modules/nginx-lua/t/080-hup-shdict.t index f9a0278..c762556 100644 --- a/debian/modules/nginx-lua/t/080-hup-shdict.t +++ b/debian/modules/nginx-lua/t/080-hup-shdict.t @@ -82,4 +82,3 @@ GET /test 10502 number --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/083-bad-sock-self.t b/debian/modules/nginx-lua/t/083-bad-sock-self.t index b93849f..7a76752 100644 --- a/debian/modules/nginx-lua/t/083-bad-sock-self.t +++ b/debian/modules/nginx-lua/t/083-bad-sock-self.t @@ -136,4 +136,3 @@ bad argument #1 to 'close' (table expected, got number) --- error_code: 500 --- error_log bad argument #1 to 'setkeepalive' (table expected, got number) - diff --git a/debian/modules/nginx-lua/t/084-inclusive-receiveuntil.t b/debian/modules/nginx-lua/t/084-inclusive-receiveuntil.t index c966015..f7d5d3d 100644 --- a/debian/modules/nginx-lua/t/084-inclusive-receiveuntil.t +++ b/debian/modules/nginx-lua/t/084-inclusive-receiveuntil.t @@ -743,4 +743,3 @@ close: 1 nil } --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/085-if.t b/debian/modules/nginx-lua/t/085-if.t index e08b43c..33f57ca 100644 --- a/debian/modules/nginx-lua/t/085-if.t +++ b/debian/modules/nginx-lua/t/085-if.t @@ -198,4 +198,3 @@ GET /proxy-pass-uri --- response_body_like: It works! --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/086-init-by.t b/debian/modules/nginx-lua/t/086-init-by.t index 3a474fe..bea34a4 100644 --- a/debian/modules/nginx-lua/t/086-init-by.t +++ b/debian/modules/nginx-lua/t/086-init-by.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 3); +plan tests => repeat_each() * (blocks() * 3 + 2); #no_diff(); #no_long_string(); @@ -304,3 +304,20 @@ INIT 2: foo = 3 ", "", ] + + + +=== TEST 12: error in init +--- http_config + init_by_lua_block { + error("failed to init") + } +--- config + location /t { + echo ok; + } +--- must_die +--- error_log +failed to init +--- error_log +[error] diff --git a/debian/modules/nginx-lua/t/087-udp-socket.t b/debian/modules/nginx-lua/t/087-udp-socket.t index 79ba452..a847031 100644 --- a/debian/modules/nginx-lua/t/087-udp-socket.t +++ b/debian/modules/nginx-lua/t/087-udp-socket.t @@ -596,6 +596,7 @@ received a good response. --- log_level: debug --- error_log lua udp socket receive buffer size: 8192 +--- no_check_leak @@ -662,12 +663,14 @@ received a good response. --- log_level: debug --- error_log lua udp socket receive buffer size: 8192 +--- no_check_leak === TEST 12: github issue #215: Handle the posted requests in lua cosocket api (failed to resolve) --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; + resolver_timeout 5s; location = /sub { content_by_lua ' @@ -704,12 +707,13 @@ resolve name done --- no_error_log [error] +--- timeout: 10 === TEST 13: github issue #215: Handle the posted requests in lua cosocket api (successfully resolved) --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 5s; location = /sub { @@ -1100,4 +1104,3 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ --- no_error_log [alert] - diff --git a/debian/modules/nginx-lua/t/088-req-method.t b/debian/modules/nginx-lua/t/088-req-method.t index 9ced40c..198b3b3 100644 --- a/debian/modules/nginx-lua/t/088-req-method.t +++ b/debian/modules/nginx-lua/t/088-req-method.t @@ -262,4 +262,3 @@ method: PATCH method: TRACE --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/089-phase.t b/debian/modules/nginx-lua/t/089-phase.t index 57921fc..94b7619 100644 --- a/debian/modules/nginx-lua/t/089-phase.t +++ b/debian/modules/nginx-lua/t/089-phase.t @@ -176,4 +176,3 @@ GET /lua init_worker --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/090-log-socket-errors.t b/debian/modules/nginx-lua/t/090-log-socket-errors.t index a5943c2..8e498cd 100644 --- a/debian/modules/nginx-lua/t/090-log-socket-errors.t +++ b/debian/modules/nginx-lua/t/090-log-socket-errors.t @@ -11,6 +11,8 @@ repeat_each(2); plan tests => repeat_each() * (blocks() * 3); +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; + #no_diff(); #no_long_string(); run_tests(); @@ -19,12 +21,14 @@ __DATA__ === TEST 1: log socket errors off (tcp) --- config + resolver $TEST_NGINX_RESOLVER ipv6=off; + location /t { lua_socket_connect_timeout 1ms; lua_socket_log_errors off; content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("8.8.8.8", 80) + local ok, err = sock:connect("agentzh.org", 12345) ngx.say(err) '; } @@ -39,12 +43,14 @@ timeout === TEST 2: log socket errors on (tcp) --- config + resolver $TEST_NGINX_RESOLVER ipv6=off; + location /t { lua_socket_connect_timeout 1ms; lua_socket_log_errors on; content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("8.8.8.8", 80) + local ok, err = sock:connect("agentzh.org", 12345) ngx.say(err) '; } @@ -59,12 +65,14 @@ lua tcp socket connect timed out === TEST 3: log socket errors on (udp) --- config + resolver $TEST_NGINX_RESOLVER ipv6=off; + location /t { lua_socket_log_errors on; lua_socket_read_timeout 1ms; content_by_lua ' local sock = ngx.socket.udp() - local ok, err = sock:setpeername("8.8.8.8", 80) + local ok, err = sock:setpeername("agentzh.org", 12345) ok, err = sock:receive() ngx.say(err) '; @@ -80,12 +88,14 @@ lua udp socket read timed out === TEST 4: log socket errors off (udp) --- config + resolver $TEST_NGINX_RESOLVER ipv6=off; + location /t { lua_socket_log_errors off; lua_socket_read_timeout 1ms; content_by_lua ' local sock = ngx.socket.udp() - local ok, err = sock:setpeername("8.8.8.8", 80) + local ok, err = sock:setpeername("agentzh.org", 12345) ok, err = sock:receive() ngx.say(err) '; @@ -96,4 +106,3 @@ GET /t timeout --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/091-coroutine.t b/debian/modules/nginx-lua/t/091-coroutine.t index b047ccb..bceb512 100644 --- a/debian/modules/nginx-lua/t/091-coroutine.t +++ b/debian/modules/nginx-lua/t/091-coroutine.t @@ -160,7 +160,7 @@ cc3: 2 === TEST 3: basic coroutine and cosocket --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' function worker(url) @@ -359,7 +359,7 @@ GET /lua === TEST 7: coroutine wrap and cosocket --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' function worker(url) @@ -987,7 +987,7 @@ test10 --- http_config init_by_lua 'return'; --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' function worker(url) @@ -1041,7 +1041,7 @@ successfully connected to: agentzh.org init_by_lua_file html/init.lua; --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' function worker(url) @@ -1315,4 +1315,3 @@ co yield: 2 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/092-eof.t b/debian/modules/nginx-lua/t/092-eof.t index a75711f..86778de 100644 --- a/debian/modules/nginx-lua/t/092-eof.t +++ b/debian/modules/nginx-lua/t/092-eof.t @@ -80,4 +80,3 @@ GET /t --- error_log hello, tom hello, jim - diff --git a/debian/modules/nginx-lua/t/093-uthread-spawn.t b/debian/modules/nginx-lua/t/093-uthread-spawn.t index 772e866..b622d30 100644 --- a/debian/modules/nginx-lua/t/093-uthread-spawn.t +++ b/debian/modules/nginx-lua/t/093-uthread-spawn.t @@ -1672,4 +1672,3 @@ delete thread 2 f --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/094-uthread-exit.t b/debian/modules/nginx-lua/t/094-uthread-exit.t index cd678c0..a623773 100644 --- a/debian/modules/nginx-lua/t/094-uthread-exit.t +++ b/debian/modules/nginx-lua/t/094-uthread-exit.t @@ -1648,4 +1648,3 @@ free request [alert] [error] [warn] - diff --git a/debian/modules/nginx-lua/t/095-uthread-exec.t b/debian/modules/nginx-lua/t/095-uthread-exec.t index 4459360..56156c4 100644 --- a/debian/modules/nginx-lua/t/095-uthread-exec.t +++ b/debian/modules/nginx-lua/t/095-uthread-exec.t @@ -423,4 +423,3 @@ attempt to abort with pending subrequests --- no_error_log [alert] [warn] - diff --git a/debian/modules/nginx-lua/t/096-uthread-redirect.t b/debian/modules/nginx-lua/t/096-uthread-redirect.t index b0258fb..003c642 100644 --- a/debian/modules/nginx-lua/t/096-uthread-redirect.t +++ b/debian/modules/nginx-lua/t/096-uthread-redirect.t @@ -277,4 +277,3 @@ attempt to abort with pending subrequests --- no_error_log [alert] [warn] - diff --git a/debian/modules/nginx-lua/t/097-uthread-rewrite.t b/debian/modules/nginx-lua/t/097-uthread-rewrite.t index 178a374..a93adc8 100644 --- a/debian/modules/nginx-lua/t/097-uthread-rewrite.t +++ b/debian/modules/nginx-lua/t/097-uthread-rewrite.t @@ -344,4 +344,3 @@ free request end --- error_log attempt to abort with pending subrequests - diff --git a/debian/modules/nginx-lua/t/098-uthread-wait.t b/debian/modules/nginx-lua/t/098-uthread-wait.t index aaf020a..4948596 100644 --- a/debian/modules/nginx-lua/t/098-uthread-wait.t +++ b/debian/modules/nginx-lua/t/098-uthread-wait.t @@ -1321,4 +1321,3 @@ $s; --- no_error_log [error] [alert] - diff --git a/debian/modules/nginx-lua/t/100-client-abort.t b/debian/modules/nginx-lua/t/100-client-abort.t index cd46859..89c1f6a 100644 --- a/debian/modules/nginx-lua/t/100-client-abort.t +++ b/debian/modules/nginx-lua/t/100-client-abort.t @@ -1064,4 +1064,3 @@ GET /t eof succeeded --- error_log eof failed: nginx output filter error - diff --git a/debian/modules/nginx-lua/t/101-on-abort.t b/debian/modules/nginx-lua/t/101-on-abort.t index 81cec78..182d12c 100644 --- a/debian/modules/nginx-lua/t/101-on-abort.t +++ b/debian/modules/nginx-lua/t/101-on-abort.t @@ -846,4 +846,3 @@ done client prematurely closed connection on abort called main handler done - diff --git a/debian/modules/nginx-lua/t/102-req-start-time.t b/debian/modules/nginx-lua/t/102-req-start-time.t index 1d5fe28..3b041af 100644 --- a/debian/modules/nginx-lua/t/102-req-start-time.t +++ b/debian/modules/nginx-lua/t/102-req-start-time.t @@ -113,4 +113,3 @@ true$ --- no_error_log [error] --- SKIP - diff --git a/debian/modules/nginx-lua/t/103-req-http-ver.t b/debian/modules/nginx-lua/t/103-req-http-ver.t index 6ded75a..e6de238 100644 --- a/debian/modules/nginx-lua/t/103-req-http-ver.t +++ b/debian/modules/nginx-lua/t/103-req-http-ver.t @@ -46,4 +46,3 @@ GET /t HTTP/1.0 1 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/104-req-raw-header.t b/debian/modules/nginx-lua/t/104-req-raw-header.t index 439b9de..efea03c 100644 --- a/debian/modules/nginx-lua/t/104-req-raw-header.t +++ b/debian/modules/nginx-lua/t/104-req-raw-header.t @@ -876,4 +876,3 @@ Foo: bar\r --- no_error_log [error] --- timeout: 5 - diff --git a/debian/modules/nginx-lua/t/105-pressure.t b/debian/modules/nginx-lua/t/105-pressure.t index 10f495e..9d1ba1f 100644 --- a/debian/modules/nginx-lua/t/105-pressure.t +++ b/debian/modules/nginx-lua/t/105-pressure.t @@ -51,4 +51,3 @@ $::Id = int rand 10000; --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/106-timer.t b/debian/modules/nginx-lua/t/106-timer.t index d0f6f36..04a532e 100644 --- a/debian/modules/nginx-lua/t/106-timer.t +++ b/debian/modules/nginx-lua/t/106-timer.t @@ -2193,4 +2193,3 @@ ok --- error_log Bad bad bad --- skip_nginx: 4: < 1.7.1 - diff --git a/debian/modules/nginx-lua/t/107-timer-errors.t b/debian/modules/nginx-lua/t/107-timer-errors.t index 9ed1334..3201612 100644 --- a/debian/modules/nginx-lua/t/107-timer-errors.t +++ b/debian/modules/nginx-lua/t/107-timer-errors.t @@ -1420,4 +1420,3 @@ qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disable "lua ngx.timer expired", "http lua close fake http connection" ] - diff --git a/debian/modules/nginx-lua/t/108-timer-safe.t b/debian/modules/nginx-lua/t/108-timer-safe.t index 19c9f6d..2795998 100644 --- a/debian/modules/nginx-lua/t/108-timer-safe.t +++ b/debian/modules/nginx-lua/t/108-timer-safe.t @@ -1395,4 +1395,3 @@ registered timer lua ngx.timer expired http lua close fake http connection trace: [m][f][g] - diff --git a/debian/modules/nginx-lua/t/109-timer-hup.t b/debian/modules/nginx-lua/t/109-timer-hup.t index 15aaa0e..0864046 100644 --- a/debian/modules/nginx-lua/t/109-timer-hup.t +++ b/debian/modules/nginx-lua/t/109-timer-hup.t @@ -500,4 +500,3 @@ ok --- grep_error_log_out lua found 8191 pending timers --- timeout: 20 - diff --git a/debian/modules/nginx-lua/t/110-etag.t b/debian/modules/nginx-lua/t/110-etag.t index 351fec4..0a94d3d 100644 --- a/debian/modules/nginx-lua/t/110-etag.t +++ b/debian/modules/nginx-lua/t/110-etag.t @@ -81,4 +81,3 @@ If-Modified-Since: Thu, 10 May 2012 07:50:59 GMT --- no_error_log [error] --- skip_nginx: 3: < 1.3.3 - diff --git a/debian/modules/nginx-lua/t/111-req-header-ua.t b/debian/modules/nginx-lua/t/111-req-header-ua.t index 7c980d0..9e501e3 100644 --- a/debian/modules/nginx-lua/t/111-req-header-ua.t +++ b/debian/modules/nginx-lua/t/111-req-header-ua.t @@ -673,4 +673,3 @@ content: konqueror: 1 User-Agent: Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.10 (like Gecko) (Kubuntu) --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/112-req-header-conn.t b/debian/modules/nginx-lua/t/112-req-header-conn.t index 51df730..51bc8a4 100644 --- a/debian/modules/nginx-lua/t/112-req-header-conn.t +++ b/debian/modules/nginx-lua/t/112-req-header-conn.t @@ -146,4 +146,3 @@ content: conn type: 0 connection: bad --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/113-req-header-cookie.t b/debian/modules/nginx-lua/t/113-req-header-cookie.t index b26b709..4a93053 100644 --- a/debian/modules/nginx-lua/t/113-req-header-cookie.t +++ b/debian/modules/nginx-lua/t/113-req-header-cookie.t @@ -247,4 +247,3 @@ Cookie: boo=123; foo=bar --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/115-quote-sql-str.t b/debian/modules/nginx-lua/t/115-quote-sql-str.t index 0c20dfb..66553b1 100644 --- a/debian/modules/nginx-lua/t/115-quote-sql-str.t +++ b/debian/modules/nginx-lua/t/115-quote-sql-str.t @@ -74,4 +74,3 @@ GET /set 'a\Zb\Z' --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/116-raw-req-socket.t b/debian/modules/nginx-lua/t/116-raw-req-socket.t index 6518f0e..ab06ee4 100644 --- a/debian/modules/nginx-lua/t/116-raw-req-socket.t +++ b/debian/modules/nginx-lua/t/116-raw-req-socket.t @@ -876,4 +876,3 @@ request body: hey, hello world --- no_error_log [error] [alert] - diff --git a/debian/modules/nginx-lua/t/117-raw-req-socket-timeout.t b/debian/modules/nginx-lua/t/117-raw-req-socket-timeout.t index 4e3929b..07abadc 100644 --- a/debian/modules/nginx-lua/t/117-raw-req-socket-timeout.t +++ b/debian/modules/nginx-lua/t/117-raw-req-socket-timeout.t @@ -114,4 +114,3 @@ lua tcp socket write timed out server: failed to send: timeout --- no_error_log [alert] - diff --git a/debian/modules/nginx-lua/t/119-config-prefix.t b/debian/modules/nginx-lua/t/119-config-prefix.t index 4581aa1..3f79320 100644 --- a/debian/modules/nginx-lua/t/119-config-prefix.t +++ b/debian/modules/nginx-lua/t/119-config-prefix.t @@ -30,4 +30,3 @@ GET /lua ^prefix: \/\S+$ --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/120-re-find.t b/debian/modules/nginx-lua/t/120-re-find.t index 34c0207..73e6134 100644 --- a/debian/modules/nginx-lua/t/120-re-find.t +++ b/debian/modules/nginx-lua/t/120-re-find.t @@ -612,7 +612,7 @@ matched: 你 === TEST 22: just hit match limit --- http_config - lua_regex_match_limit 5600; + lua_regex_match_limit 5000; --- config location /re { content_by_lua_file html/a.lua; @@ -654,7 +654,7 @@ error: pcre_exec() failed: -8 === TEST 23: just not hit match limit --- http_config - lua_regex_match_limit 5700; + lua_regex_match_limit 5100; --- config location /re { content_by_lua_file html/a.lua; @@ -891,3 +891,29 @@ not matched! --- no_error_log [error] + + +=== TEST 31: match with ctx and a pos (anchored by \G) +--- config + location /re { + content_by_lua ' + local ctx = { pos = 3 } + local from, to, err = ngx.re.find("1234, hello", [[(\G[0-9]+)]], "", ctx) + if from then + ngx.say("from: ", from) + ngx.say("to: ", to) + ngx.say("pos: ", ctx.pos) + else + ngx.say("not matched!") + ngx.say("pos: ", ctx.pos) + end + '; + } +--- request + GET /re +--- response_body +from: 3 +to: 4 +pos: 5 +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/121-version.t b/debian/modules/nginx-lua/t/121-version.t index 2b7a306..9000eb3 100644 --- a/debian/modules/nginx-lua/t/121-version.t +++ b/debian/modules/nginx-lua/t/121-version.t @@ -46,4 +46,3 @@ GET /lua ^version: \d+$ --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/122-worker.t b/debian/modules/nginx-lua/t/122-worker.t index fa42b1d..b74c81f 100644 --- a/debian/modules/nginx-lua/t/122-worker.t +++ b/debian/modules/nginx-lua/t/122-worker.t @@ -79,4 +79,3 @@ worker pid: \d+ worker pid is correct\. --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/123-lua-path.t b/debian/modules/nginx-lua/t/123-lua-path.t index da97909..23681a9 100644 --- a/debian/modules/nginx-lua/t/123-lua-path.t +++ b/debian/modules/nginx-lua/t/123-lua-path.t @@ -68,4 +68,3 @@ GET /lua [error] --- error_log eval qr/\[alert\] .*? lua_code_cache is off/ - diff --git a/debian/modules/nginx-lua/t/124-init-worker.t b/debian/modules/nginx-lua/t/124-init-worker.t index d6ea675..22a943e 100644 --- a/debian/modules/nginx-lua/t/124-init-worker.t +++ b/debian/modules/nginx-lua/t/124-init-worker.t @@ -447,7 +447,7 @@ warn(): Thu, 01 Jan 1970 01:34:38 GMT --- timeout: 10 --- http_config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; init_worker_by_lua ' -- global diff --git a/debian/modules/nginx-lua/t/125-configure-args.t b/debian/modules/nginx-lua/t/125-configure-args.t index adec129..4160d4e 100644 --- a/debian/modules/nginx-lua/t/125-configure-args.t +++ b/debian/modules/nginx-lua/t/125-configure-args.t @@ -29,4 +29,3 @@ GET /configure_args ^\s*\-\-[^-]+ --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/126-shdict-frag.t b/debian/modules/nginx-lua/t/126-shdict-frag.t index 94422fb..5a2aff8 100644 --- a/debian/modules/nginx-lua/t/126-shdict-frag.t +++ b/debian/modules/nginx-lua/t/126-shdict-frag.t @@ -1264,4 +1264,3 @@ ok --- no_error_log [error] --- timeout: 60 - diff --git a/debian/modules/nginx-lua/t/127-uthread-kill.t b/debian/modules/nginx-lua/t/127-uthread-kill.t index 2ab8abe..cc43c62 100644 --- a/debian/modules/nginx-lua/t/127-uthread-kill.t +++ b/debian/modules/nginx-lua/t/127-uthread-kill.t @@ -190,7 +190,7 @@ resolve name done: -2 === TEST 4: kill pending connect --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' local ready = false @@ -505,4 +505,3 @@ thread created: zombie [alert] lua tcp socket abort resolver --- error_log - diff --git a/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t b/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t index d3ef3f5..e8434a3 100644 --- a/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t +++ b/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t @@ -315,19 +315,24 @@ failed to send request: closed)$ local data = "" local ntm = 0 - local done = false + local aborted = false for i = 1, 3 do - local res, err, part = sock:receive(1) - if not res then - ngx.say("failed to receive: ", err) - return - else - data = data .. res + if not aborted then + local res, err, part = sock:receive(1) + if not res then + ngx.say("failed to receive: ", err) + aborted = true + else + data = data .. res + end end + ngx.sleep(0.001) end - ngx.say("received: ", data) + if not aborted then + ngx.say("received: ", data) + end '; } @@ -350,6 +355,7 @@ F(ngx_http_lua_socket_tcp_finalize_write_part) { --- tcp_query_len: 11 --- no_error_log [error] +--- wait: 0.05 @@ -623,4 +629,3 @@ close: 1 nil --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/129-ssl-socket.t b/debian/modules/nginx-lua/t/129-ssl-socket.t index 9da9a5c..1c3f7cd 100644 --- a/debian/modules/nginx-lua/t/129-ssl-socket.t +++ b/debian/modules/nginx-lua/t/129-ssl-socket.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 219; +plan tests => repeat_each() * 217; $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); @@ -26,7 +26,7 @@ sub read_file { $cert; } -our $StartComRootCertificate = read_file("t/cert/startcom.crt"); +our $ComodoRootCertificate = read_file("t/cert/comodo-ca.crt"); our $EquifaxRootCertificate = read_file("t/cert/equifax.crt"); our $TestCertificate = read_file("t/cert/test.crt"); our $TestCertificateKey = read_file("t/cert/test.key"); @@ -125,7 +125,7 @@ SSL reused session === TEST 2: no SNI, no verify --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -135,7 +135,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("g.sregex.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -151,7 +151,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: g.sregex.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -179,21 +179,14 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata -sent http request: 57 bytes. -received: HTTP/1.1 401 Unauthorized -close: 1 nil +failed to do SSL handshake: handshake failed --- log_level: debug --- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ---- grep_error_log_out eval -qr/^lua ssl save session: ([0-9A-F]+):2 -lua ssl free session: ([0-9A-F]+):1 -$/ +--- grep_error_log_out --- no_error_log lua ssl server name: SSL reused session -[error] [alert] --- timeout: 5 @@ -202,17 +195,17 @@ SSL reused session === TEST 3: SNI, no verify --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; - content_by_lua ' + content_by_lua_block { local sock = ngx.socket.tcp() sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -220,7 +213,7 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org") + local session, err = sock:sslhandshake(nil, "openresty.org") if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -228,7 +221,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\r\nHost: openresty.org\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -249,7 +242,7 @@ SSL reused session ngx.say("close: ", ok, " ", err) end -- do collectgarbage() - '; + } } --- request @@ -257,8 +250,8 @@ GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 59 bytes. -received: HTTP/1.1 200 OK +sent http request: 58 bytes. +received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -268,7 +261,7 @@ qr/^lua ssl save session: ([0-9A-F]+):2 lua ssl free session: ([0-9A-F]+):1 $/ --- error_log -lua ssl server name: "iscribblet.org" +lua ssl server name: "openresty.org" --- no_error_log SSL reused session [error] @@ -280,7 +273,8 @@ SSL reused session === TEST 4: ssl session reuse --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; + lua_ssl_protocols TLSv1.2; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -293,7 +287,7 @@ SSL reused session local session for i = 1, 2 do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("agentzh.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -301,7 +295,7 @@ SSL reused session ngx.say("connected: ", ok) - session, err = sock:sslhandshake(session, "iscribblet.org") + session, err = sock:sslhandshake(session, "agentzh.org") if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -309,7 +303,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: agentzh.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -340,12 +334,12 @@ GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 59 bytes. +sent http request: 56 bytes. received: HTTP/1.1 200 OK close: 1 nil connected: 1 ssl handshake: userdata -sent http request: 59 bytes. +sent http request: 56 bytes. received: HTTP/1.1 200 OK close: 1 nil @@ -371,10 +365,10 @@ lua ssl free session === TEST 5: certificate does not match host name (verify) -The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.org". +The certificate of "openresty.org" does not contain the name "blah.openresty.org". --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 5; location /t { @@ -386,7 +380,7 @@ The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.o sock:settimeout(2000) do - local ok, err = sock:connect("agentzh.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -394,13 +388,171 @@ The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.o ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "blah.agentzh.org", true) + local session, err = sock:sslhandshake(nil, "blah.openresty.org", true) if not session then ngx.say("failed to do SSL handshake: ", err) else ngx.say("ssl handshake: ", type(session)) end + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + local line, err = sock:receive() + if not line then + ngx.say("failed to receive response status line: ", err) + return + end + + ngx.say("received: ", line) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + collectgarbage() + '; + } + +--- user_files eval +">>> trusted.crt +$::ComodoRootCertificate" + +--- request +GET /t +--- response_body_like chomp +\Aconnected: 1 +failed to do SSL handshake: (?:handshake failed|certificate host mismatch) +failed to send http request: closed +\z + +--- log_level: debug +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ +--- grep_error_log_out +--- error_log +lua ssl server name: "blah.openresty.org" +--- no_error_log +SSL reused session +[alert] +--- timeout: 5 + + + +=== TEST 6: certificate does not match host name (verify, no log socket errors) +The certificate for "openresty.org" does not contain the name "blah.openresty.org". +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER ipv6=off; + lua_ssl_trusted_certificate ../html/trusted.crt; + lua_socket_log_errors off; + lua_ssl_verify_depth 2; + location /t { + #set $port 5000; + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua ' + local sock = ngx.socket.tcp() + sock:settimeout(2000) + + do + local ok, err = sock:connect("openresty.org", 443) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local session, err = sock:sslhandshake(nil, "blah.openresty.org", true) + if not session then + ngx.say("failed to do SSL handshake: ", err) + else + ngx.say("ssl handshake: ", type(session)) + end + + local req = "GET / HTTP/1.1\\r\\nHost: blah.openresty.org\\r\\nConnection: close\\r\\n\\r\\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + local line, err = sock:receive() + if not line then + ngx.say("failed to receive response status line: ", err) + return + end + + ngx.say("received: ", line) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + collectgarbage() + '; + } + +--- user_files eval +">>> trusted.crt +$::ComodoRootCertificate" + +--- request +GET /t +--- response_body_like chomp +\Aconnected: 1 +failed to do SSL handshake: (?:handshake failed|certificate host mismatch) +failed to send http request: closed +\z + +--- log_level: debug +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ +--- grep_error_log_out +--- error_log +lua ssl server name: "blah.openresty.org" +--- no_error_log +lua ssl certificate does not match host +SSL reused session +[alert] +--- timeout: 5 + + + +=== TEST 7: certificate does not match host name (no verify) +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER ipv6=off; + location /t { + #set $port 5000; + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua ' + local sock = ngx.socket.tcp() + sock:settimeout(2000) + + do + local ok, err = sock:connect("openresty.org", 443) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local session, err = sock:sslhandshake(nil, "openresty.org", false) + if not session then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(session)) + local req = "GET / HTTP/1.1\\r\\nHost: agentzh.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then @@ -425,170 +577,13 @@ The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.o '; } ---- user_files eval -">>> trusted.crt -$::StartComRootCertificate" - ---- request -GET /t ---- response_body -connected: 1 -failed to do SSL handshake: certificate host mismatch -failed to send http request: closed - ---- log_level: debug ---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ---- grep_error_log_out ---- error_log -lua ssl server name: "blah.agentzh.org" -lua ssl certificate does not match host "blah.agentzh.org" ---- no_error_log -SSL reused session -[alert] ---- timeout: 5 - - - -=== TEST 6: certificate does not match host name (verify, no log socket errors) -The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.org". ---- config - server_tokens off; - resolver $TEST_NGINX_RESOLVER; - lua_ssl_trusted_certificate ../html/trusted.crt; - lua_socket_log_errors off; - lua_ssl_verify_depth 2; - location /t { - #set $port 5000; - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua ' - local sock = ngx.socket.tcp() - sock:settimeout(2000) - - do - local ok, err = sock:connect("agentzh.org", 443) - if not ok then - ngx.say("failed to connect: ", err) - return - end - - ngx.say("connected: ", ok) - - local session, err = sock:sslhandshake(nil, "blah.agentzh.org", true) - if not session then - ngx.say("failed to do SSL handshake: ", err) - else - ngx.say("ssl handshake: ", type(session)) - end - - local req = "GET / HTTP/1.1\\r\\nHost: blah.agentzh.org\\r\\nConnection: close\\r\\n\\r\\n" - local bytes, err = sock:send(req) - if not bytes then - ngx.say("failed to send http request: ", err) - return - end - - ngx.say("sent http request: ", bytes, " bytes.") - - local line, err = sock:receive() - if not line then - ngx.say("failed to receive response status line: ", err) - return - end - - ngx.say("received: ", line) - - local ok, err = sock:close() - ngx.say("close: ", ok, " ", err) - end -- do - collectgarbage() - '; - } - ---- user_files eval -">>> trusted.crt -$::StartComRootCertificate" - ---- request -GET /t ---- response_body -connected: 1 -failed to do SSL handshake: certificate host mismatch -failed to send http request: closed - ---- log_level: debug ---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ---- grep_error_log_out ---- error_log -lua ssl server name: "blah.agentzh.org" ---- no_error_log -lua ssl certificate does not match host -SSL reused session -[alert] ---- timeout: 5 - - - -=== TEST 7: certificate does not match host name (no verify) ---- config - server_tokens off; - resolver $TEST_NGINX_RESOLVER; - location /t { - #set $port 5000; - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua ' - local sock = ngx.socket.tcp() - sock:settimeout(2000) - - do - local ok, err = sock:connect("agentzh.org", 443) - if not ok then - ngx.say("failed to connect: ", err) - return - end - - ngx.say("connected: ", ok) - - local session, err = sock:sslhandshake(nil, "agentzh.org", false) - if not session then - ngx.say("failed to do SSL handshake: ", err) - return - end - - ngx.say("ssl handshake: ", type(session)) - - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" - local bytes, err = sock:send(req) - if not bytes then - ngx.say("failed to send http request: ", err) - return - end - - ngx.say("sent http request: ", bytes, " bytes.") - - local line, err = sock:receive() - if not line then - ngx.say("failed to receive response status line: ", err) - return - end - - ngx.say("received: ", line) - - local ok, err = sock:close() - ngx.say("close: ", ok, " ", err) - end -- do - collectgarbage() - '; - } - --- request GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 59 bytes. -received: HTTP/1.1 200 OK +sent http request: 56 bytes. +received: HTTP/1.1 404 Not Found close: 1 nil --- log_level: debug @@ -599,7 +594,7 @@ lua ssl free session: ([0-9A-F]+):1 $/ --- error_log -lua ssl server name: "agentzh.org" +lua ssl server name: "openresty.org" --- no_error_log SSL reused session [error] @@ -608,10 +603,10 @@ SSL reused session -=== TEST 8: iscribblet.org: passing SSL verify +=== TEST 8: openresty.org: passing SSL verify --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 2; location /t { @@ -623,7 +618,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -631,7 +626,7 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org", true) + local session, err = sock:sslhandshake(nil, "openresty.org", true) if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -639,7 +634,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -665,15 +660,15 @@ SSL reused session --- user_files eval ">>> trusted.crt -$::StartComRootCertificate" +$::ComodoRootCertificate" --- request GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 59 bytes. -received: HTTP/1.1 200 OK +sent http request: 58 bytes. +received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -684,7 +679,7 @@ lua ssl free session: ([0-9A-F]+):1 $/ --- error_log -lua ssl server name: "iscribblet.org" +lua ssl server name: "openresty.org" --- no_error_log SSL reused session [error] @@ -696,7 +691,7 @@ SSL reused session === TEST 9: ssl verify depth not enough (with automatic error logging) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 1; location /t { @@ -708,7 +703,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -716,14 +711,14 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org", true) + local session, err = sock:sslhandshake(nil, "openresty.org", true) if not session then ngx.say("failed to do SSL handshake: ", err) else ngx.say("ssl handshake: ", type(session)) end - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -749,7 +744,7 @@ SSL reused session --- user_files eval ">>> trusted.crt -$::StartComRootCertificate" +$::ComodoRootCertificate" --- request GET /t @@ -762,7 +757,7 @@ failed to send http request: closed --- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ --- grep_error_log_out --- error_log -lua ssl server name: "iscribblet.org" +lua ssl server name: "openresty.org" lua ssl certificate verify error: (20: unable to get local issuer certificate) --- no_error_log SSL reused session @@ -774,7 +769,7 @@ SSL reused session === TEST 10: ssl verify depth not enough (without automatic error logging) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 1; lua_socket_log_errors off; @@ -787,7 +782,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -795,14 +790,14 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org", true) + local session, err = sock:sslhandshake(nil, "openresty.org", true) if not session then ngx.say("failed to do SSL handshake: ", err) else ngx.say("ssl handshake: ", type(session)) end - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -828,7 +823,7 @@ SSL reused session --- user_files eval ">>> trusted.crt -$::StartComRootCertificate" +$::ComodoRootCertificate" --- request GET /t @@ -841,7 +836,7 @@ failed to send http request: closed --- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ --- grep_error_log_out --- error_log -lua ssl server name: "iscribblet.org" +lua ssl server name: "openresty.org" --- no_error_log lua ssl certificate verify error SSL reused session @@ -1010,7 +1005,7 @@ SSL reused session --- user_files eval ">>> trusted.crt -$::StartComRootCertificate" +$::ComodoRootCertificate" --- request GET /t @@ -1030,10 +1025,10 @@ SSL reused session -=== TEST 13: iscribblet.org: passing SSL verify with multiple certificates +=== TEST 13: openresty.org: passing SSL verify with multiple certificates --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 2; location /t { @@ -1045,7 +1040,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -1053,7 +1048,7 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org", true) + local session, err = sock:sslhandshake(nil, "openresty.org", true) if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -1061,7 +1056,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -1088,15 +1083,15 @@ SSL reused session --- user_files eval ">>> trusted.crt $::EquifaxRootCertificate -$::StartComRootCertificate" +$::ComodoRootCertificate" --- request GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 59 bytes. -received: HTTP/1.1 200 OK +sent http request: 58 bytes. +received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -1107,7 +1102,7 @@ lua ssl free session: ([0-9A-F]+):1 $/ --- error_log -lua ssl server name: "iscribblet.org" +lua ssl server name: "openresty.org" --- no_error_log SSL reused session [error] @@ -1119,7 +1114,7 @@ SSL reused session === TEST 14: default cipher --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1129,7 +1124,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -1137,7 +1132,7 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org") + local session, err = sock:sslhandshake(nil, "openresty.org") if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -1145,7 +1140,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -1174,8 +1169,8 @@ GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 59 bytes. -received: HTTP/1.1 200 OK +sent http request: 58 bytes. +received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -1185,8 +1180,8 @@ qr/^lua ssl save session: ([0-9A-F]+):2 lua ssl free session: ([0-9A-F]+):1 $/ --- error_log -lua ssl server name: "iscribblet.org" -SSL: TLSv1.2, cipher: "ECDHE-RSA-RC4-SHA SSLv3 +lua ssl server name: "openresty.org" +SSL: TLSv1.2, cipher: "ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 --- no_error_log SSL reused session [error] @@ -1198,8 +1193,8 @@ SSL reused session === TEST 15: explicit cipher configuration --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; - lua_ssl_ciphers RC4-SHA; + resolver $TEST_NGINX_RESOLVER ipv6=off; + lua_ssl_ciphers ECDHE-RSA-AES256-SHA; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1209,7 +1204,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -1217,7 +1212,7 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org") + local session, err = sock:sslhandshake(nil, "openresty.org") if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -1225,7 +1220,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -1254,8 +1249,8 @@ GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 59 bytes. -received: HTTP/1.1 200 OK +sent http request: 58 bytes. +received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -1265,8 +1260,8 @@ qr/^lua ssl save session: ([0-9A-F]+):2 lua ssl free session: ([0-9A-F]+):1 $/ --- error_log -lua ssl server name: "iscribblet.org" -SSL: TLSv1.2, cipher: "RC4-SHA SSLv3 +lua ssl server name: "openresty.org" +SSL: TLSv1.2, cipher: "ECDHE-RSA-AES256-SHA --- no_error_log SSL reused session [error] @@ -1278,7 +1273,7 @@ SSL reused session === TEST 16: explicit ssl protocol configuration --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_protocols TLSv1; location /t { #set $port 5000; @@ -1289,7 +1284,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -1297,7 +1292,7 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org") + local session, err = sock:sslhandshake(nil, "openresty.org") if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -1305,7 +1300,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -1334,8 +1329,8 @@ GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 59 bytes. -received: HTTP/1.1 200 OK +sent http request: 58 bytes. +received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -1345,8 +1340,8 @@ qr/^lua ssl save session: ([0-9A-F]+):2 lua ssl free session: ([0-9A-F]+):1 $/ --- error_log -lua ssl server name: "iscribblet.org" -SSL: TLSv1, cipher: "ECDHE-RSA-RC4-SHA SSLv3 +lua ssl server name: "openresty.org" +SSL: TLSv1, cipher: "ECDHE-RSA-AES256-SHA --- no_error_log SSL reused session [error] @@ -1358,7 +1353,7 @@ SSL reused session === TEST 17: unsupported ssl protocol --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_protocols SSLv2; lua_socket_log_errors off; location /t { @@ -1370,7 +1365,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -1378,14 +1373,14 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org") + local session, err = sock:sslhandshake(nil, "openresty.org") if not session then ngx.say("failed to do SSL handshake: ", err) else ngx.say("ssl handshake: ", type(session)) end - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -1422,7 +1417,7 @@ failed to send http request: closed --- error_log eval [ qr/\[crit\] .*?SSL_do_handshake\(\) failed .*?unsupported protocol/, -'lua ssl server name: "iscribblet.org"', +'lua ssl server name: "openresty.org"', ] --- no_error_log SSL reused session @@ -1432,10 +1427,10 @@ SSL reused session -=== TEST 18: iscribblet.org: passing SSL verify: keepalive (reuse the ssl session) +=== TEST 18: openresty.org: passing SSL verify: keepalive (reuse the ssl session) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 2; location /t { @@ -1450,7 +1445,7 @@ SSL reused session local session for i = 1, 3 do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -1458,7 +1453,7 @@ SSL reused session ngx.say("connected: ", ok) - session, err = sock:sslhandshake(session, "iscribblet.org", true) + session, err = sock:sslhandshake(session, "openresty.org", true) if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -1477,7 +1472,7 @@ SSL reused session --- user_files eval ">>> trusted.crt -$::StartComRootCertificate" +$::ComodoRootCertificate" --- request GET /t @@ -1509,10 +1504,10 @@ SSL reused session -=== TEST 19: iscribblet.org: passing SSL verify: keepalive (no reusing the ssl session) +=== TEST 19: openresty.org: passing SSL verify: keepalive (no reusing the ssl session) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 2; location /t { @@ -1526,7 +1521,7 @@ SSL reused session do for i = 1, 3 do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -1534,7 +1529,7 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org", true) + local session, err = sock:sslhandshake(nil, "openresty.org", true) if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -1553,7 +1548,7 @@ SSL reused session --- user_files eval ">>> trusted.crt -$::StartComRootCertificate" +$::ComodoRootCertificate" --- request GET /t @@ -1592,7 +1587,7 @@ SSL reused session === TEST 20: downstream cosockets do not support ssl handshake --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 2; location /t { @@ -1612,7 +1607,7 @@ SSL reused session --- user_files eval ">>> trusted.crt -$::StartComRootCertificate" +$::ComodoRootCertificate" --- request POST /t @@ -1647,7 +1642,7 @@ attempt to call method 'sslhandshake' (a nil value) } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1750,7 +1745,7 @@ SSL reused session } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/test.crt; location /t { @@ -1854,7 +1849,7 @@ SSL reused session } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1946,7 +1941,7 @@ SSL reused session } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_crl ../html/test.crl; lua_ssl_trusted_certificate ../html/test.crt; lua_socket_log_errors off; @@ -2031,7 +2026,7 @@ SSL reused session === TEST 25: multiple handshake calls --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -2042,7 +2037,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -2051,7 +2046,7 @@ SSL reused session ngx.say("connected: ", ok) for i = 1, 2 do - local session, err = sock:sslhandshake(nil, "iscribblet.org") + local session, err = sock:sslhandshake(nil, "openresty.org") if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -2060,7 +2055,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) end - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -2090,8 +2085,8 @@ GET /t connected: 1 ssl handshake: userdata ssl handshake: userdata -sent http request: 59 bytes. -received: HTTP/1.1 200 OK +sent http request: 58 bytes. +received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -2103,7 +2098,7 @@ lua ssl free session: ([0-9A-F]+):2 lua ssl free session: ([0-9A-F]+):1 $/ --- error_log -lua ssl server name: "iscribblet.org" +lua ssl server name: "openresty.org" --- no_error_log SSL reused session [error] @@ -2115,7 +2110,7 @@ SSL reused session === TEST 26: handshake timed out --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -2126,7 +2121,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -2135,7 +2130,7 @@ SSL reused session ngx.say("connected: ", ok) sock:settimeout(1); -- should timeout immediately - local session, err = sock:sslhandshake(nil, "iscribblet.org") + local session, err = sock:sslhandshake(nil, "openresty.org") if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -2157,7 +2152,7 @@ failed to do SSL handshake: timeout --- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ --- grep_error_log_out --- error_log -lua ssl server name: "iscribblet.org" +lua ssl server name: "openresty.org" --- no_error_log SSL reused session [error] @@ -2183,7 +2178,7 @@ SSL reused session } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -2254,7 +2249,7 @@ SSL reused session } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -2328,7 +2323,7 @@ SSL reused session } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -2405,7 +2400,7 @@ SSL reused session } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/test.crt; location /t { @@ -2510,7 +2505,7 @@ SSL reused session } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; #lua_ssl_trusted_certificate ../html/test.crt; location /t { @@ -2589,7 +2584,7 @@ SSL reused session === TEST 32: handshake, too many arguments --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -2598,7 +2593,7 @@ SSL reused session local sock = ngx.socket.tcp() sock:settimeout(2000) - local ok, err = sock:connect("g.sregex.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -2614,7 +2609,7 @@ SSL reused session GET /t --- ignore_response --- error_log eval -qr/\[error\] .* ngx.socket connect: expecting 1 ~ 5 arguments \(including the object\), but seen 0/ +qr/\[error\] .* ngx.socket sslhandshake: expecting 1 ~ 5 arguments \(including the object\), but seen 0/ --- no_error_log [alert] --- timeout: 5 diff --git a/debian/modules/nginx-lua/t/130-internal-api.t b/debian/modules/nginx-lua/t/130-internal-api.t index d641ab5..eba0980 100644 --- a/debian/modules/nginx-lua/t/130-internal-api.t +++ b/debian/modules/nginx-lua/t/130-internal-api.t @@ -47,4 +47,3 @@ content req=0x[a-f0-9]{4,} $ --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/135-worker-id.t b/debian/modules/nginx-lua/t/135-worker-id.t index 3c1f24d..984f446 100644 --- a/debian/modules/nginx-lua/t/135-worker-id.t +++ b/debian/modules/nginx-lua/t/135-worker-id.t @@ -54,7 +54,7 @@ GET /lua content_by_lua_block { local counters = ngx.shared.counters local ok, c - for i = 1, 45 do + for i = 1, 100 do c = counters:get("c") if c >= 4 then ok = true diff --git a/debian/modules/nginx-lua/t/137-req-misc.t b/debian/modules/nginx-lua/t/137-req-misc.t index 20ada3c..d56f80e 100644 --- a/debian/modules/nginx-lua/t/137-req-misc.t +++ b/debian/modules/nginx-lua/t/137-req-misc.t @@ -59,4 +59,3 @@ not internal GET /test --- response_body internal - diff --git a/debian/modules/nginx-lua/t/138-balancer.t b/debian/modules/nginx-lua/t/138-balancer.t index 8d45c24..ddd0da5 100644 --- a/debian/modules/nginx-lua/t/138-balancer.t +++ b/debian/modules/nginx-lua/t/138-balancer.t @@ -58,8 +58,8 @@ qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\ } --- request GET /t ---- response_body_like: 500 Internal Server Error ---- error_code: 500 +--- response_body_like: 403 Forbidden +--- error_code: 403 --- error_log [lua] balancer_by_lua:2: hello from balancer by lua! while connecting to upstream, --- no_error_log eval @@ -431,3 +431,98 @@ qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\ ] --- no_error_log [warn] + + + +=== TEST 15: test if execeed proxy_next_upstream_limit +--- http_config + lua_package_path "../lua-resty-core/lib/?.lua;;"; + + proxy_next_upstream_tries 5; + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + local b = require "ngx.balancer" + + if not ngx.ctx.tries then + ngx.ctx.tries = 0 + end + + if ngx.ctx.tries >= 6 then + ngx.log(ngx.ERR, "retry count exceed limit") + ngx.exit(500) + end + + ngx.ctx.tries = ngx.ctx.tries + 1 + print("retry counter: ", ngx.ctx.tries) + + local ok, err = b.set_more_tries(2) + if not ok then + return error("failed to set more tries: ", err) + elseif err then + ngx.log(ngx.WARN, "set more tries: ", err) + end + + assert(b.set_current_peer("127.0.0.1", 81)) + } + } +--- config + location = /t { + proxy_pass http://backend/back; + } + + location = /back { + return 404; + } +--- request + GET /t +--- response_body_like: 502 Bad Gateway +--- error_code: 502 +--- grep_error_log eval: qr/\bretry counter: \w+/ +--- grep_error_log_out +retry counter: 1 +retry counter: 2 +retry counter: 3 +retry counter: 4 +retry counter: 5 + +--- error_log +set more tries: reduced tries due to limit + + + +=== TEST 16: set_more_tries bugfix +--- http_config + lua_package_path "../lua-resty-core/lib/?.lua;;"; + proxy_next_upstream_tries 0; + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + local balancer = require "ngx.balancer" + local ctx = ngx.ctx + if not ctx.has_run then + ctx.has_run = true + local _, err = balancer.set_more_tries(3) + if err then + ngx.log(ngx.ERR, "failed to set more tries: ", err) + end + end + balancer.set_current_peer("127.0.0.1", 81) + } + } +--- config + location = /t { + proxy_pass http://backend; + } +--- request + GET /t +--- error_code: 502 +--- grep_error_log eval: qr/http next upstream, \d+/ +--- grep_error_log_out +http next upstream, 2 +http next upstream, 2 +http next upstream, 2 +http next upstream, 2 +--- no_error_log +failed to set more tries: reduced tries due to limit +[alert] diff --git a/debian/modules/nginx-lua/t/139-ssl-cert-by.t b/debian/modules/nginx-lua/t/139-ssl-cert-by.t index b9fd60d..c13044f 100644 --- a/debian/modules/nginx-lua/t/139-ssl-cert-by.t +++ b/debian/modules/nginx-lua/t/139-ssl-cert-by.t @@ -11,7 +11,7 @@ my $openssl_version = eval { `$NginxBinary -V 2>&1` }; if ($openssl_version =~ m/built with OpenSSL (0|1\.0\.(?:0|1[^\d]|2[a-d]).*)/) { plan(skip_all => "too old OpenSSL, need 1.0.2e, was $1"); } else { - plan tests => repeat_each() * (blocks() * 6 + 10); + plan tests => repeat_each() * (blocks() * 6 + 6); } $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); @@ -1383,7 +1383,7 @@ uthread: done -=== TEST 17: simple logging - use ssl_certificiate_by_lua* on the http {} level +=== TEST 17: simple logging - use ssl_certificate_by_lua* on the http {} level GitHub openresty/lua-resty-core#42 --- http_config ssl_certificate_by_lua_block { print("ssl cert by lua is running!") } @@ -1574,3 +1574,295 @@ qr/\[error\] .*? send\(\) failed/, --- no_error_log [alert] ssl_certificate_by_lua:1: ssl cert by lua is running! + + + +=== TEST 19: check the count of running timers +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate_by_lua_block { print("ssl cert by lua is running!") } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /timers { + default_type 'text/plain'; + content_by_lua_block { + ngx.timer.at(0.1, function() ngx.sleep(0.3) end) + ngx.timer.at(0.11, function() ngx.sleep(0.3) end) + ngx.timer.at(0.09, function() ngx.sleep(0.3) end) + ngx.sleep(0.2) + ngx.say(ngx.timer.running_count()) + } + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /timers HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to receive response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +sent http request: 59 bytes. +received: HTTP/1.1 200 OK +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 2 +received: Connection: close +received: +received: 3 +close: 1 nil + +--- error_log eval +[ +'ssl_certificate_by_lua:1: ssl cert by lua is running!', +'lua ssl server name: "test.com"', +] +--- no_error_log +[error] +[alert] + + + +=== TEST 20: some server {} block missing ssl_certificate_by_lua* handlers (literal server name) +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate_by_lua_block { print("ssl cert by lua is running!") } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /timers { + default_type 'text/plain'; + content_by_lua_block { + ngx.timer.at(0.1, function() ngx.sleep(0.3) end) + ngx.timer.at(0.11, function() ngx.sleep(0.3) end) + ngx.timer.at(0.09, function() ngx.sleep(0.3) end) + ngx.sleep(0.2) + ngx.say(ngx.timer.running_count()) + } + more_clear_headers Date; + } + } + + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test2.com; + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test2.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /timers HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to receive response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +failed to do SSL handshake: handshake failed + +--- error_log eval +[ +qr/\[alert\] .*? no ssl_certificate_by_lua\* defined in server test2\.com\b/, +qr/\[crit\] .*? SSL_do_handshake\(\) failed\b/, +] + + + +=== TEST 21: some server {} block missing ssl_certificate_by_lua* handlers (regex server name) +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate_by_lua_block { print("ssl cert by lua is running!") } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /timers { + default_type 'text/plain'; + content_by_lua_block { + ngx.timer.at(0.1, function() ngx.sleep(0.3) end) + ngx.timer.at(0.11, function() ngx.sleep(0.3) end) + ngx.timer.at(0.09, function() ngx.sleep(0.3) end) + ngx.sleep(0.2) + ngx.say(ngx.timer.running_count()) + } + more_clear_headers Date; + } + } + + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name ~test2\.com; + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test2.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /timers HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to receive response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +failed to do SSL handshake: handshake failed + +--- error_log eval +[ +qr/\[alert\] .*? no ssl_certificate_by_lua\* defined in server ~test2\\\.com\b/, +qr/\[crit\] .*? SSL_do_handshake\(\) failed\b/, +] diff --git a/debian/modules/nginx-lua/t/140-ssl-c-api.t b/debian/modules/nginx-lua/t/140-ssl-c-api.t index 44ad93d..8734d14 100644 --- a/debian/modules/nginx-lua/t/140-ssl-c-api.t +++ b/debian/modules/nginx-lua/t/140-ssl-c-api.t @@ -561,7 +561,7 @@ failed to parse PEM priv key: PEM_read_bio_PrivateKey() failed f:close() local pkey = ffi.C.ngx_http_lua_ffi_parse_pem_priv_key(pkey_data, #pkey_data, errmsg) - if not pkey then + if pkey == nil then ngx.log(ngx.ERR, "failed to parse PEM priv key: ", ffi.string(errmsg[0])) return @@ -626,7 +626,7 @@ failed to parse PEM priv key: PEM_read_bio_PrivateKey() failed while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -711,7 +711,7 @@ lua ssl server name: "test.com" f:close() local pkey = ffi.C.ngx_http_lua_ffi_parse_pem_priv_key(pkey_data, #pkey_data, errmsg) - if not pkey then + if pkey == nil then ngx.log(ngx.ERR, "failed to parse PEM priv key: ", ffi.string(errmsg[0])) return @@ -776,7 +776,7 @@ lua ssl server name: "test.com" while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end diff --git a/debian/modules/nginx-lua/t/141-luajit.t b/debian/modules/nginx-lua/t/141-luajit.t index be03fe3..36418d1 100644 --- a/debian/modules/nginx-lua/t/141-luajit.t +++ b/debian/modules/nginx-lua/t/141-luajit.t @@ -1,6 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use Test::Nginx::Socket::Lua; +use Test::Nginx::Socket::Lua + skip_all => 'no mmap(sbrk(0)) trick since glibc leaks memory in this case'; #worker_connections(1014); #master_on(); diff --git a/debian/modules/nginx-lua/t/142-ssl-session-store.t b/debian/modules/nginx-lua/t/142-ssl-session-store.t index 5c9fad3..73b6e19 100644 --- a/debian/modules/nginx-lua/t/142-ssl-session-store.t +++ b/debian/modules/nginx-lua/t/142-ssl-session-store.t @@ -38,7 +38,7 @@ __DATA__ } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -108,7 +108,7 @@ ssl_session_store_by_lua_block:1: ssl session store by lua is running! } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -183,7 +183,7 @@ API disabled in the context of ssl_session_store_by_lua* } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -275,7 +275,7 @@ my timer run! } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -343,7 +343,7 @@ API disabled in the context of ssl_session_store_by_lua* } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -415,7 +415,7 @@ ngx.exit does not yield and the error code is eaten. } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -488,7 +488,7 @@ ssl_session_store_by_lua*: handler return value: 0, sess new cb exit code: 0 } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -556,7 +556,7 @@ should never reached here } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -627,7 +627,7 @@ get_phase: ssl_session_store } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -696,7 +696,7 @@ qr/elapsed in ssl cert by lua: 0.(?:09|1[01])\d+,/, } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -778,7 +778,7 @@ a.lua:1: ssl store session by lua is running! } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -849,7 +849,7 @@ qr/\[emerg\] .*? "ssl_session_store_by_lua_block" directive is not allowed here } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { diff --git a/debian/modules/nginx-lua/t/143-ssl-session-fetch.t b/debian/modules/nginx-lua/t/143-ssl-session-fetch.t index bd800ff..701ead7 100644 --- a/debian/modules/nginx-lua/t/143-ssl-session-fetch.t +++ b/debian/modules/nginx-lua/t/143-ssl-session-fetch.t @@ -39,7 +39,7 @@ __DATA__ } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -120,7 +120,7 @@ qr/ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!/s } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -204,7 +204,7 @@ qr/elapsed in ssl fetch session by lua: 0.(?:09|1[01])\d+,/, } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -305,7 +305,7 @@ qr/my timer run!/s } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -385,7 +385,7 @@ qr/received memc reply: OK/s } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -466,7 +466,7 @@ should never reached here } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -548,7 +548,7 @@ should never reached here } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -629,7 +629,7 @@ should never reached here } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -712,7 +712,7 @@ should never reached here } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -793,7 +793,7 @@ should never reached here } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -879,7 +879,7 @@ qr/get_phase: ssl_session_fetch/s --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -1049,7 +1049,7 @@ qr/\S+:\d+: ssl fetch sess by lua is running!/s } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { diff --git a/debian/modules/nginx-lua/t/146-malloc-trim.t b/debian/modules/nginx-lua/t/146-malloc-trim.t index 45fb9f2..fc425ce 100644 --- a/debian/modules/nginx-lua/t/146-malloc-trim.t +++ b/debian/modules/nginx-lua/t/146-malloc-trim.t @@ -43,8 +43,9 @@ ok ok ok --- grep_error_log eval: qr/malloc_trim\(\d+\) returned \d+/ ---- grep_error_log_out -malloc_trim(1) returned 0 +--- grep_error_log_out eval +qr/\Amalloc_trim\(1\) returned [01] +\z/ --- wait: 0.2 --- no_error_log [error] @@ -76,13 +77,14 @@ ok ok ok --- grep_error_log eval: qr/malloc_trim\(\d+\) returned \d+/ ---- grep_error_log_out -malloc_trim(1) returned 0 -malloc_trim(1) returned 0 -malloc_trim(1) returned 0 -malloc_trim(1) returned 0 -malloc_trim(1) returned 0 -malloc_trim(1) returned 0 +--- grep_error_log_out eval +qr/\Amalloc_trim\(1\) returned [01] +malloc_trim\(1\) returned [01] +malloc_trim\(1\) returned [01] +malloc_trim\(1\) returned [01] +malloc_trim\(1\) returned [01] +malloc_trim\(1\) returned [01] +\z/ --- wait: 0.2 --- no_error_log [error] @@ -114,10 +116,11 @@ ok ok ok --- grep_error_log eval: qr/malloc_trim\(\d+\) returned \d+/ ---- grep_error_log_out -malloc_trim(1) returned 0 -malloc_trim(1) returned 0 -malloc_trim(1) returned 0 +--- grep_error_log_out eval +qr/\Amalloc_trim\(1\) returned [01] +malloc_trim\(1\) returned [01] +malloc_trim\(1\) returned [01] +\z/ --- wait: 0.2 --- no_error_log [error] @@ -149,9 +152,10 @@ ok ok ok --- grep_error_log eval: qr/malloc_trim\(\d+\) returned \d+/ ---- grep_error_log_out -malloc_trim(1) returned 0 -malloc_trim(1) returned 0 +--- grep_error_log_out eval +qr/\Amalloc_trim\(1\) returned [01] +malloc_trim\(1\) returned [01] +\z/ --- wait: 0.2 --- no_error_log [error] @@ -330,8 +334,9 @@ ok ok ok --- grep_error_log eval: qr/malloc_trim\(\d+\) returned \d+/ ---- grep_error_log_out -malloc_trim(1) returned 0 +--- grep_error_log_out eval +qr/\Amalloc_trim\(1\) returned [01] +\z/ --- wait: 0.2 --- no_error_log [error] diff --git a/debian/modules/nginx-lua/t/147-tcp-socket-timeouts.t b/debian/modules/nginx-lua/t/147-tcp-socket-timeouts.t index 52f015a..0689a9b 100644 --- a/debian/modules/nginx-lua/t/147-tcp-socket-timeouts.t +++ b/debian/modules/nginx-lua/t/147-tcp-socket-timeouts.t @@ -315,7 +315,7 @@ lua tcp socket write timed out === TEST 5: connection timeout (tcp) --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /test { content_by_lua_block { diff --git a/debian/modules/nginx-lua/t/150-fake-delayed-load.t b/debian/modules/nginx-lua/t/150-fake-delayed-load.t new file mode 100644 index 0000000..232bbf3 --- /dev/null +++ b/debian/modules/nginx-lua/t/150-fake-delayed-load.t @@ -0,0 +1,56 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_process_enabled(1); +#log_level('warn'); + +#repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +#no_diff(); +no_long_string(); +#master_on(); +#workers(2); + +run_tests(); + +__DATA__ + +=== TEST 1: lua code cache on +--- http_config + lua_code_cache on; +--- config + location = /cache_on { + content_by_lua_block { + local delayed_load = require("ngx.delayed_load") + ngx.say(type(delayed_load.get_function)) + } + } +--- request +GET /cache_on +--- response_body +function +--- no_error_log +[error] + + + +=== TEST 2: lua code cache off +--- http_config + lua_code_cache off; +--- config + location = /cache_off { + content_by_lua_block { + local delayed_load = require("ngx.delayed_load") + ngx.say(type(delayed_load.get_function)) + } + } +--- request +GET /cache_off +--- response_body +function +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/151-initby-hup.t b/debian/modules/nginx-lua/t/151-initby-hup.t new file mode 100644 index 0000000..f278867 --- /dev/null +++ b/debian/modules/nginx-lua/t/151-initby-hup.t @@ -0,0 +1,168 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +our $SkipReason; + +BEGIN { + if ($ENV{TEST_NGINX_CHECK_LEAK}) { + $SkipReason = "unavailable for the hup tests"; + + } else { + $ENV{TEST_NGINX_USE_HUP} = 1; + undef $ENV{TEST_NGINX_USE_STAP}; + } +} + +use Test::Nginx::Socket::Lua 'no_plan'; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(1); + +#plan tests => repeat_each() * (blocks() * 3 + 3); + +#no_diff(); +#no_long_string(); +no_shuffle(); + +run_tests(); + +__DATA__ + +=== TEST 1: no error in init before HUP +--- http_config + init_by_lua_block { + foo = "hello, FOO" + } +--- config + location /lua { + content_by_lua_block { + ngx.say(foo) + } + } +--- request +GET /lua +--- response_body +hello, FOO +--- no_error_log +[error] + + + +=== TEST 2: error in init after HUP (master still alive, worker process still the same as before) +--- http_config + init_by_lua_block { + error("failed to init") + } +--- config + location /lua { + content_by_lua_block { + ngx.say(foo) + } + } +--- request +GET /lua +--- response_body +hello, FOO +--- error_log +failed to init +--- reload_fails + + + +=== TEST 3: no error in init again +--- http_config + init_by_lua_block { + foo = "hello, foo" + } +--- config + location /lua { + content_by_lua_block { + ngx.say(foo) + } + } +--- request +GET /lua +--- response_body +hello, foo +--- no_error_log +[error] + + + +=== TEST 4: no error in init before HUP, used ngx.shared.DICT +--- http_config + lua_shared_dict dogs 1m; + + init_by_lua_block { + local dogs = ngx.shared.dogs + dogs:set("foo", "hello, FOO") + } +--- config + location /lua { + content_by_lua_block { + local dogs = ngx.shared.dogs + local foo = dogs:get("foo") + ngx.say(foo) + } + } +--- request +GET /lua +--- response_body +hello, FOO +--- no_error_log +[error] + + + +=== TEST 5: error in init after HUP, not reloaded but foo have changed. +--- http_config + lua_shared_dict dogs 1m; + + init_by_lua_block { + local dogs = ngx.shared.dogs + dogs:set("foo", "foo have changed") + + error("failed to init") + } +--- config + location /lua { + content_by_lua_block { + ngx.say("HUP reload failed") + } + } +--- request +GET /lua +--- response_body +foo have changed +--- error_log +failed to init +--- reload_fails + + + +=== TEST 6: no error in init again, reload success and foo still have changed. +--- http_config + lua_shared_dict dogs 1m; + + init_by_lua_block { + -- do nothing + } +--- config + location /lua { + content_by_lua_block { + local dogs = ngx.shared.dogs + local foo = dogs:get("foo") + ngx.say(foo) + ngx.say("reload success") + } + } +--- request +GET /lua +--- response_body +foo have changed +reload success +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/152-timer-every.t b/debian/modules/nginx-lua/t/152-timer-every.t new file mode 100644 index 0000000..c8d62e7 --- /dev/null +++ b/debian/modules/nginx-lua/t/152-timer-every.t @@ -0,0 +1,385 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 7 + 2); + +#no_diff(); +no_long_string(); + +our $HtmlDir = html_dir; + +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +$ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; + +worker_connections(1024); +run_tests(); + +__DATA__ + +=== TEST 1: simple very +--- config + location /t { + content_by_lua_block { + local begin = ngx.now() + local function f(premature) + print("elapsed: ", ngx.now() - begin) + print("timer prematurely expired: ", premature) + end + + local ok, err = ngx.timer.every(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + + ngx.say("registered timer") + } + } +--- request +GET /t +--- response_body +registered timer +--- wait: 0.11 +--- no_error_log +[error] +[alert] +[crit] +timer prematurely expired: true +--- error_log eval +[ +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])\d*, context: ngx\.timer, client: \d+\.\d+\.\d+\.\d+, server: 0\.0\.0\.0:\d+/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.(?:09|10)\d*, context: ngx\.timer, client: \d+\.\d+\.\d+\.\d+, server: 0\.0\.0\.0:\d+/, +"lua ngx.timer expired", +"http lua close fake http connection", +"timer prematurely expired: false", +] + + + +=== TEST 2: separated global env +--- config + location /t { + content_by_lua_block { + local begin = ngx.now() + local function f() + foo = 3 + print("foo in timer: ", foo) + end + local ok, err = ngx.timer.every(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.sleep(0.11) + ngx.say("foo = ", foo) + } + } +--- request +GET /t +--- response_body +foo = nil +--- wait: 0.12 +--- no_error_log +[error] +[alert] +[crit] +--- error_log eval +[ +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: foo in timer: 3/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 3: lua variable sharing via upvalue +--- config + location /t { + content_by_lua_block { + local begin = ngx.now() + local foo = 0 + local function f() + foo = foo + 3 + print("foo in timer: ", foo) + end + local ok, err = ngx.timer.every(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + ngx.sleep(0.11) + ngx.say("foo = ", foo) + } + } +--- request +GET /t +--- response_body +registered timer +foo = 6 +--- wait: 0.12 +--- no_error_log +[error] +[alert] +[crit] +--- error_log eval +[ +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: foo in timer: 3/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: foo in timer: 6/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 4: create the next timer immediately when timer start running +--- config + location /t { + content_by_lua_block { + local begin = ngx.now() + local foo = 0 + local function f() + foo = foo + 3 + print("foo in timer: ", foo) + + ngx.sleep(0.1) + end + local ok, err = ngx.timer.every(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + ngx.sleep(0.11) + ngx.say("foo = ", foo) + } + } +--- request +GET /t +--- response_body +registered timer +foo = 6 +--- wait: 0.12 +--- no_error_log +[error] +[alert] +[crit] +--- error_log eval +[ +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: foo in timer: 3/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: foo in timer: 6/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 5: callback args +--- config + location /t { + content_by_lua_block { + local n = 0 + + local function f(premature, a, b, c) + n = n + 1 + print("the ", n, " time, args: ", a, ", ", b, ", ", c) + + a, b, c = 0, 0, 0 + end + + local ok, err = ngx.timer.every(0.05, f, 1, 2) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + + ngx.say("registered timer") + ngx.sleep(0.11) + } + } +--- request +GET /t +--- response_body +registered timer +--- wait: 0.12 +--- no_error_log +[error] +[alert] +[crit] +--- error_log eval +[ +"the 1 time, args: 1, 2, nil", +"the 2 time, args: 1, 2, nil", +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 6: memory leak check +--- config + location /t { + content_by_lua_block { + local function f() + local a = 1 + -- do nothing + end + + for i = 1, 100 do + local ok, err = ngx.timer.every(0.1, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + end + + ngx.say("registered timer") + + collectgarbage("collect") + local start = collectgarbage("count") + + ngx.sleep(0.21) + + collectgarbage("collect") + local growth1 = collectgarbage("count") - start + + ngx.sleep(0.51) + + collectgarbage("collect") + local growth2 = collectgarbage("count") - start + + ngx.say("growth1 == growth2: ", growth1 == growth2) + } + } +--- request +GET /t +--- response_body +registered timer +growth1 == growth2: true +--- no_error_log +[error] +[alert] +[crit] +--- timeout: 8 + + + +=== TEST 7: respect lua_max_pending_timers +--- http_config + lua_max_pending_timers 10; +--- config + location /t { + content_by_lua_block { + local function f() + local a = 1 + -- do nothing + end + + for i = 1, 11 do + local ok, err = ngx.timer.every(0.1, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + end + + ngx.say("registered 10 timers") + } + } +--- request +GET /t +--- response_body +failed to set timer: too many pending timers +--- no_error_log +[error] +[alert] +[crit] + + + +=== TEST 8: respect lua_max_running_timers +--- http_config + lua_max_pending_timers 100; + lua_max_running_timers 9; +--- config + location /t { + content_by_lua_block { + local function f() + local a = 1 + ngx.sleep(0.02) + -- do nothing + end + + for i = 1, 10 do + local ok, err = ngx.timer.every(0.01, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + end + + ngx.say("registered 10 timers") + + ngx.sleep(0.03) + } + } +--- request +GET /t +--- response_body +registered 10 timers +--- no_error_log +[error] +[crit] +--- error_log +lua_max_running_timers are not enough + + + +=== TEST 9: lua_code_cache off +FIXME: it is know that this test case leaks memory. +so we skip it in the "check leak" testing mode. +--- http_config + lua_code_cache off; +--- config + location /t { + content_by_lua_block { + local function f() + local a = 1 + -- do nothing + end + + local ok, err = ngx.timer.every(0.01, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + + collectgarbage("collect") + ngx.say("registered timer") + + ngx.sleep(0.03) + + collectgarbage("collect") + + ngx.sleep(0.03) + + collectgarbage("collect") + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +registered timer +ok +--- no_error_log +[error] +[crit] +--- no_check_leak diff --git a/debian/modules/nginx-lua/t/153-semaphore-hup.t b/debian/modules/nginx-lua/t/153-semaphore-hup.t new file mode 100644 index 0000000..c85a21d --- /dev/null +++ b/debian/modules/nginx-lua/t/153-semaphore-hup.t @@ -0,0 +1,154 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use Test::Nginx::Socket::Lua; + +#worker_connections(10140); +#workers(1); +log_level('warn'); +master_process_enabled(1); +repeat_each(1); + +plan tests => repeat_each() * (blocks() * 3); + +no_long_string(); +#no_diff(); + +add_block_preprocessor(sub { + my $block = shift; + + my $http_config = $block->http_config || ''; + $http_config .= <<'_EOC_'; + lua_package_path "../lua-resty-core/lib/?.lua;../lua-resty-lrucache/lib/?.lua;;"; + lua_shared_dict shdict 4m; + + init_by_lua_block { + require "resty.core" + local process = require "ngx.process" + local ok, err = process.enable_privileged_agent() + if not ok then + ngx.log(ngx.ERR, "failed to enable_privileged_agent: ", err) + end + } + + init_worker_by_lua_block { + local function test(pre) + if pre then + return + end + + local semaphore = require "ngx.semaphore" + local sem = semaphore.new() + + ngx.log(ngx.ERR, "created semaphore object") + + local function sem_wait() + + local ok, err = sem:wait(100) + if not ok then + ngx.log(ngx.ERR, "err: ", err) + else + ngx.log(ngx.ERR, "wait success") + end + end + + while not ngx.worker.exiting() do + local co = ngx.thread.spawn(sem_wait) + ngx.thread.wait(co) + end + end + + local ok, err = ngx.timer.at(0, test) + if not ok then + ngx.log(ngx.ERR, "failed to create semaphore timer err: ", err) + end + + local function reload(pre) + if pre then + return + end + + shdict = ngx.shared.shdict + local success = shdict:add("reloaded", 1) + if not success then + return + end + + ngx.log(ngx.ERR, "try to reload nginx") + + local f, err = io.open(ngx.config.prefix() .. "/logs/nginx.pid", "r") + if not f then + ngx.say("failed to open nginx.pid: ", err) + return + end + + local pid = f:read() + + f:close() + os.execute("kill -HUP " .. pid) + end + + local typ = require "ngx.process".type + if typ() == "privileged agent" then + local ok, err = ngx.timer.at(0.1, reload) + if not ok then + ngx.log(ngx.ERR, "failed to create semaphore timer err: ", err) + end + end + } +_EOC_ + $block->set_value("http_config", $http_config); +}); + +run_tests(); + +__DATA__ + +=== TEST 1: timer + reload +--- config + location /test { + content_by_lua_block { + ngx.sleep(1) + ngx.say("hello") + } + } +--- request +GET /test +--- response_body +hello +--- grep_error_log eval: qr/created semaphore object|try to reload nginx|semaphore gc wait queue is not empty/ +--- grep_error_log_out +created semaphore object +created semaphore object +try to reload nginx +created semaphore object +created semaphore object +--- skip_nginx: 3: < 1.11.2 +--- no_check_leak +--- wait: 0.2 + + + +=== TEST 2: timer + reload (lua code cache off) +--- http_config + lua_code_cache off; +--- config + location /test { + content_by_lua_block { + ngx.sleep(1) + ngx.say("hello") + } + } +--- request +GET /test +--- response_body +hello +--- grep_error_log eval: qr/created semaphore object|try to reload nginx|semaphore gc wait queue is not empty/ +--- grep_error_log_out +created semaphore object +created semaphore object +try to reload nginx +created semaphore object +created semaphore object +--- skip_nginx: 3: < 1.11.2 +--- no_check_leak +--- wait: 0.2 diff --git a/debian/modules/nginx-lua/t/154-semaphore.t b/debian/modules/nginx-lua/t/154-semaphore.t new file mode 100644 index 0000000..3c1f004 --- /dev/null +++ b/debian/modules/nginx-lua/t/154-semaphore.t @@ -0,0 +1,118 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use Test::Nginx::Socket::Lua; + +#worker_connections(10140); +#workers(1); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3) + blocks(); + +no_long_string(); +#no_diff(); + +add_block_preprocessor(sub { + my $block = shift; + + my $http_config = $block->http_config || ''; + $http_config .= <<'_EOC_'; + lua_package_path "../lua-resty-core/lib/?.lua;../lua-resty-lrucache/lib/?.lua;;"; + + init_by_lua_block { + require "resty.core" + } +_EOC_ + $block->set_value("http_config", $http_config); +}); + +run_tests(); + +__DATA__ + +=== TEST 1: timer + shutdown error log +--- config + location /test { + content_by_lua_block { + local function test(pre) + + local semaphore = require "ngx.semaphore" + local sem = semaphore.new() + + local function sem_wait() + + local ok, err = sem:wait(10) + if not ok then + ngx.log(ngx.ERR, "err: ", err) + else + ngx.log(ngx.ERR, "wait success") + end + end + + while not ngx.worker.exiting() do + local co = ngx.thread.spawn(sem_wait) + ngx.thread.wait(co) + end + end + + local ok, err = ngx.timer.at(0, test) + ngx.log(ngx.ERR, "hello, world") + ngx.say("time: ", ok) + } + } +--- request +GET /test +--- response_body +time: 1 +--- grep_error_log eval: qr/hello, world|semaphore gc wait queue is not empty/ +--- grep_error_log_out +hello, world +--- shutdown_error_log +--- no_shutdown_error_log +semaphore gc wait queue is not empty + + + +=== TEST 2: timer + shutdown error log (lua code cache off) +--- http_config + lua_code_cache off; +--- config + location /test { + content_by_lua_block { + local function test(pre) + + local semaphore = require "ngx.semaphore" + local sem = semaphore.new() + + local function sem_wait() + + local ok, err = sem:wait(10) + if not ok then + ngx.log(ngx.ERR, "err: ", err) + else + ngx.log(ngx.ERR, "wait success") + end + end + + while not ngx.worker.exiting() do + local co = ngx.thread.spawn(sem_wait) + ngx.thread.wait(co) + end + end + + local ok, err = ngx.timer.at(0, test) + ngx.log(ngx.ERR, "hello, world") + ngx.say("time: ", ok) + } + } +--- request +GET /test +--- response_body +time: 1 +--- grep_error_log eval: qr/hello, world|semaphore gc wait queue is not empty/ +--- grep_error_log_out +hello, world +--- shutdown_error_log +--- no_shutdown_error_log +semaphore gc wait queue is not empty diff --git a/debian/modules/nginx-lua/t/cert/comodo-ca.crt b/debian/modules/nginx-lua/t/cert/comodo-ca.crt new file mode 100644 index 0000000..444461b --- /dev/null +++ b/debian/modules/nginx-lua/t/cert/comodo-ca.crt @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn +dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ +FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+ +5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG +x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX +2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL +OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3 +sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C +GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5 +WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w +DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt +rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+ +nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg +tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW +sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp +pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA +zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq +ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52 +7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I +LaZRfyHBNVOFBkpdn627G190 +-----END CERTIFICATE----- diff --git a/debian/modules/nginx-lua/t/cert/startcom.crt b/debian/modules/nginx-lua/t/cert/startcom.crt deleted file mode 100644 index a5185ca..0000000 --- a/debian/modules/nginx-lua/t/cert/startcom.crt +++ /dev/null @@ -1,87 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW -MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg -Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9 -MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi -U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh -cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk -pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf -OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C -Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT -Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi -HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM -Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w -+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ -Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 -Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B -26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID -AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD -VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul -F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC -ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w -ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk -aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0 -YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg -c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93 -d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG -CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1 -dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF -wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS -Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst -0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc -pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl -CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF -P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK -1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm -KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE -JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ -8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm -fyWl8kgAwKQB2j8= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW -MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg -Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 -MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi -U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh -cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk -pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf -OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C -Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT -Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi -HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM -Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w -+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ -Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 -Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B -26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID -AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE -FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j -ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js -LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM -BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 -Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy -dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh -cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh -YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg -dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp -bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ -YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT -TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ -9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 -jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW -FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz -ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 -ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L -EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu -L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq -yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC -O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V -um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh -NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= ------END CERTIFICATE----- diff --git a/debian/modules/nginx-lua/t/data/fake-delayed-load-module/config b/debian/modules/nginx-lua/t/data/fake-delayed-load-module/config new file mode 100644 index 0000000..a5fa6fb --- /dev/null +++ b/debian/modules/nginx-lua/t/data/fake-delayed-load-module/config @@ -0,0 +1,3 @@ +ngx_addon_name="ngx_http_lua_fake_delayed_load_module" +HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_lua_fake_delayed_load_module" +NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_lua_fake_delayed_load_module.c" diff --git a/debian/modules/nginx-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c b/debian/modules/nginx-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c new file mode 100644 index 0000000..2898255 --- /dev/null +++ b/debian/modules/nginx-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c @@ -0,0 +1,77 @@ +/* + * This fake_delayed_load delayed load module was used to reproduce + * a bug in ngx_lua's function ngx_http_lua_add_package_preload. + */ + + +#include +#include +#include +#include + + +#include "ngx_http_lua_api.h" + + +static ngx_int_t ngx_http_lua_fake_delayed_load_init(ngx_conf_t *cf); +static int ngx_http_lua_fake_delayed_load_preload(lua_State *L); +static int ngx_http_lua_fake_delayed_load_function(lua_State * L); + + +static ngx_http_module_t ngx_http_lua_fake_delayed_load_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_lua_fake_delayed_load_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL, /* merge location configuration */ +}; + +/* flow identify module struct */ +ngx_module_t ngx_http_lua_fake_delayed_load_module = { + NGX_MODULE_V1, + &ngx_http_lua_fake_delayed_load_module_ctx, /* module context */ + NULL, /* 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_lua_fake_delayed_load_init(ngx_conf_t *cf) +{ + ngx_http_lua_add_package_preload(cf, "ngx.delayed_load", + ngx_http_lua_fake_delayed_load_preload); + return NGX_OK; +} + + +static int +ngx_http_lua_fake_delayed_load_preload(lua_State *L) +{ + lua_createtable(L, 0, 1); + + lua_pushcfunction(L, ngx_http_lua_fake_delayed_load_function); + lua_setfield(L, -2, "get_function"); + + return 1; +} + + +static int +ngx_http_lua_fake_delayed_load_function(lua_State * L) +{ + return 0; +} diff --git a/debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c b/debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c index 42cde55..650f4f7 100644 --- a/debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c +++ b/debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c @@ -1,5 +1,4 @@ -/* Copyright (C) ZHANG Heng (chiyouhen) - * +/* * This fake module was used to reproduce a bug in ngx_lua's * init_worker_by_lua implementation. */ diff --git a/debian/modules/nginx-lua/util/build.sh b/debian/modules/nginx-lua/util/build.sh index 7887fe9..e45c00a 100755 --- a/debian/modules/nginx-lua/util/build.sh +++ b/debian/modules/nginx-lua/util/build.sh @@ -52,6 +52,7 @@ time ngx-build $force $version \ --add-module=$root/../redis2-nginx-module \ --add-module=$root/t/data/fake-module \ --add-module=$root/t/data/fake-shm-module \ + --add-module=$root/t/data/fake-delayed-load-module \ --with-http_gunzip_module \ --with-http_dav_module \ --with-select_module \ diff --git a/debian/modules/nginx-lua/util/gdbinit b/debian/modules/nginx-lua/util/gdbinit deleted file mode 100644 index 1508c64..0000000 --- a/debian/modules/nginx-lua/util/gdbinit +++ /dev/null @@ -1,415 +0,0 @@ -# This gdb script provides several useful routines for debugging ngx_lua or -# standalone Lua/LuaJIT. -# -# You need gdb >= v7.3 to make this script working correctly. -# -# Installation: place it at $HOME/.gdbinit -# -# -- chaoslawful gmail com - -#### Lua type defines #### - -set $__LUA_TNONE = -1 -set $__LUA_TNIL = 0 -set $__LUA_TBOOLEAN = 1 -set $__LUA_TLIGHTUSERDATA = 2 -set $__LUA_TNUMBER = 3 -set $__LUA_TSTRING = 4 -set $__LUA_TTABLE = 5 -set $__LUA_TFUNCTION = 6 -set $__LUA_TUSERDATA = 7 -set $__LUA_TTHREAD = 8 - -#### Lua constants #### - -set $__LUA_GLOBALSINDEX = -10002 -set $__LUA_ENVIRONINDEX = -10001 -set $__LUA_REGISTRYINDEX = -10000 - -#### Auxiliary methods #### - -define __lua_debug_instance - if !$__lua_debug_instance - set $__lua_debug_instance = (lua_Debug*)malloc(sizeof(lua_Debug)) - end -end - -define __free_lua_debug_instance - if $__lua_debug_instance - set $rc = free($__lua_debug_instance) - set $__lua_debug_instance = 0 - end -end - -set $__BUCKET_SIZE = 16 -define __set_instance - if !$__set_instance - set $__set_instance = (void*(*(*))[2])malloc($__BUCKET_SIZE*sizeof(void*(*)[2])) - set $rc = memset($__set_instance, 0, $__BUCKET_SIZE*sizeof(void*(*)[2])) - end -end - -define __free_set_instance - if $__set_instance - __set_clean - set $rc = free($__set_instance) - set $__set_instance = 0 - end -end - -define __set_add - set $p = (void*)$arg0 - set $__bkt_idx = (int)$p%$__BUCKET_SIZE - - __set_instance - set $__elem = (void*(*)[2])$__set_instance[$__bkt_idx] - set $__found = 0 - while $__elem - if (*$__elem)[0] == $p - set $__found = 1 - loop_break - end - set $__elem = (void*(*)[2])(*$__elem)[1] - end - if $__found - set $existed_in_set = 1 - else - set $existed_in_set = 0 - - set $rc = (void*(*)[2])calloc(1, sizeof(void*)*2) - set (*$rc)[0] = $p - set (*$rc)[1] = $__set_instance[$__bkt_idx] - set $__set_instance[$__bkt_idx] = $rc - end -end - -define __set_is_exist - set $p = (void*)$arg0 - set $__bkt_idx = (int)$p%$__BUCKET_SIZE - - __set_instance - set $__elem = (void*(*)[2])$__set_instance[$__bkt_idx] - set $__found = 0 - while $__elem - if (*$__elem)[0] == $p - set $__found = 1 - loop_break - end - set $__elem = (void*(*)[2])(*$__elem)[1] - end - if $__found - set $existed_in_set = 1 - else - set $existed_in_set = 0 - end -end - -define __set_clean - __set_instance - - set $__bkt_idx = 0 - while $__bkt_idx < $__BUCKET_SIZE - set $__elem = (void*(*)[2])$__set_instance[$__bkt_idx] - while $__elem - set $__next = (void*(*)[2])(*$__elem)[1] - set $rc = free($__elem) - set $__elem = $__next - end - set $__set_instance[$__bkt_idx] = 0 - set $__bkt_idx = $__bkt_idx+1 - end -end - -define hook-quit - __free_lua_debug_instance - __free_set_instance -end - -define hook-detach - __free_lua_debug_instance - __free_set_instance -end - -define hook-disconnect - __free_lua_debug_instance - __free_set_instance -end - -define _lua_pop - set $l = (lua_State*)$arg0 - set $_n = (int)$arg1 - set $_rc = lua_settop($l, -$_n-1) -end - -define _lua_dump_locals - set $l = (lua_State*)$arg0 - set $dbg = (lua_Debug*)$arg1 - set $idx = 1 - - set $rc = lua_getlocal($l, $dbg, $idx) - if $rc - printf "\t----[[ Locals ]]----\n" - while $rc - printf "\t%d:\t'%s' = ", $idx, $rc - __lua_dump_stack $l -1 - printf "\n" - - _lua_pop $l 1 - set $idx = $idx + 1 - set $rc = lua_getlocal($l, $dbg, $idx) - end - else - printf "\tNo locals!\n" - end - printf "\n" -end - -define _lua_dump_upvalues - set $l = (lua_State*)$arg0 - set $dbg = (lua_Debug*)$arg1 - set $idx = 1 - - set $rc = lua_getinfo($l, "f", $dbg) - if $rc - set $rc = lua_getupvalue($l, -1, $idx) - if $rc - printf "\t----[[ Upvalues ]]----\n" - while $rc - printf "\t%d:\t'%s' = ", $idx, $rc - __lua_dump_stack $l -1 - printf "\n" - - _lua_pop $l 1 - set $idx = $idx + 1 - set $rc = lua_getupvalue($l, -1, $idx) - end - else - printf "\tNo upvalues!\n" - end - _lua_pop $l 1 - else - printf "\tFailed to get function closure!\n" - end - printf "\n" -end - -define __lua_dump_stack - __set_clean - __lua_dump_stack_aux $arg0 $arg1 0 -end - -define __lua_dump_stack_aux - set $l = (lua_State*)$arg0 - set $nidx_$arg2 = (int)$arg1 - set $cidx_$arg2 = (int)$arg2+1 - - # relative stack index to absolute index - if $nidx_$arg2 < 0 && $nidx_$arg2 > $__LUA_REGISTRYINDEX - set $nidx_$arg2 = $nidx_$arg2 + (int)lua_gettop($l) + 1 - end - - set $vt_$arg2 = (int)lua_type($l, $nidx_$arg2) - - if $vt_$arg2 == $__LUA_TNONE - echo - end - if $vt_$arg2 == $__LUA_TNIL - echo (nil) - end - if $vt_$arg2 == $__LUA_TBOOLEAN - printf "(bool) %d", lua_toboolean($l, $nidx_$arg2) - end - if $vt_$arg2 == $__LUA_TLIGHTUSERDATA - printf "(ludata) %p", lua_touserdata($l, $nidx_$arg2) - end - if $vt_$arg2 == $__LUA_TNUMBER - printf "%g", lua_tonumber($l, $nidx_$arg2) - end - if $vt_$arg2 == $__LUA_TSTRING - set $tmplen = (size_t*)malloc(sizeof(size_t)) - set $tmp = lua_pushvalue($l, $nidx_$arg2) - set $tmp = lua_tolstring($l, -1, $tmplen) -#printf "(string:%d) ", *$tmplen - eval "output/r *(const char (*)[%d])$tmp", *$tmplen - _lua_pop $l 1 - set $tmp = free($tmplen) - end - if $vt_$arg2 == $__LUA_TTABLE - set $rc = lua_topointer($l, $nidx_$arg2) -#printf "(table) %p { ", $rc - printf "{ " - __set_add $rc - if $existed_in_set - printf "... " - else - set $rc = lua_pushnil($l) - set $rc = lua_next($l, $nidx_$arg2) - while $rc != 0 - printf "[" - __lua_dump_stack_aux $l -2 $cidx_$arg2 - printf "]" - printf " = " - __lua_dump_stack_aux $l -1 $cidx_$arg2 - printf ", " - _lua_pop $l 1 - set $rc = lua_next($l, $nidx_$arg2) - end - end - printf "}" - end - if $vt_$arg2 == $__LUA_TFUNCTION - printf "(func) %p", lua_topointer($l, $nidx_$arg2) - end - if $vt_$arg2 == $__LUA_TUSERDATA - printf "(udata) %p", lua_topointer($l, $nidx_$arg2) - end - if $vt_$arg2 == $__LUA_TTHREAD - printf "(thread) %p", lua_topointer($l, $nidx_$arg2) - else - if $vt_$arg2 > $__LUA_TTHREAD || $vt_$arg2 < 0 - echo - end - end -end - -#### Command methods #### - -define lbt - if $argc < 1 - echo Please specify Lua state and/or dump flag!\n - else - set $l = (lua_State*)$arg0 - if $argc > 1 - set $dump_local = ($arg1&1)==1 - set $dump_upvalue = ($arg1&2)==2 - else - set $dump_local = 0 - set $dump_upvalue = 0 - end - - __lua_debug_instance - set $dbg = $__lua_debug_instance - - set $level = 0 - set $rc = lua_getstack($l, $level, $dbg) - while $rc > 0 - set $rc = lua_getinfo($l, "Sln", $dbg) - set $name = $dbg->name - if !$name - set $name = "???" - end - - printf "#%d\t%s\t[%s]\tat %s:%d\n", $level, $name, $dbg->what, $dbg->source, $dbg->currentline - - if $dump_local - _lua_dump_locals $l $dbg - end - if $dump_upvalue - _lua_dump_upvalues $l $dbg - end - - set $level = $level+1 - set $rc = lua_getstack($l, $level, $dbg) - end - end -end - -document lbt -lbt []: Dump the backtrace of the specified Lua state. is a mask value, whose bit 1/2 controls the dump of locals/upvalues at each stack frame correspondingly. So set to 1 dumps only locals; set to 2 dumps only upvalues; and set to 3 dumps both locals and upvalues. -end - -define ll - if $argc != 2 - echo Please specify Lua state and stack frame number (0-based)!\n - else - set $l = (lua_State*)$arg0 - set $level = (int)$arg1 - - __lua_debug_instance - set $dbg = $__lua_debug_instance - - set $rc = lua_getstack($l, $level, $dbg) - if $rc > 0 - _lua_dump_locals $l $dbg - else - echo Failed to get Lua stack frame!\n - end - end -end - -document ll -ll : Dump all local vars in the specified Lua stack frame (0-based). -end - -define lu - if $argc != 2 - echo Please specify Lua state and stack frame number (0-based)!\n - else - set $l = (lua_State*)$arg0 - set $level = (int)$arg1 - - __lua_debug_instance - set $dbg = $__lua_debug_instance - - set $rc = lua_getstack($l, $level, $dbg) - if $rc > 0 - _lua_dump_upvalues $l $dbg - else - echo Failed to get Lua stack frame!\n - end - end -end - -document lu -lu : Dump all upvalues in the specified Lua stack frame (0-based). -end - -define lg - if $argc != 1 - echo Please specify Lua state!\n - else - set $l = (lua_State*)$arg0 - __lua_dump_stack $l $__LUA_GLOBALSINDEX - printf "\n" - end -end - -document lg -lg : Dump all entries in Lua global table. -end - -define lr - if $argc != 1 - echo Please specify Lua state!\n - else - set $l = (lua_State*)$arg0 - __lua_dump_stack $l $__LUA_REGISTRYINDEX - printf "\n" - end -end - -document lr -lr : Dump all entries in Lua registry table. -end - -define ls - if $argc != 1 - echo Please specify Lua state!\n - else - set $l = (lua_State*)$arg0 - set $idx = lua_gettop($l) - while $idx >= 1 - printf "#%d ", $idx - __lua_dump_stack $l $idx - printf "\n" - set $idx = $idx - 1 - end - end -end - -document ls -ls : Dump all entries in call stack. -end - -# vi:ft=gdb ts=4 sw=4 - diff --git a/debian/modules/nginx-lua/util/reindex b/debian/modules/nginx-lua/util/reindex deleted file mode 100755 index bd54c9d..0000000 --- a/debian/modules/nginx-lua/util/reindex +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/perl -#: reindex.pl -#: reindex .t files for Test::Base based test files -#: Copyright (c) 2006 Agent Zhang -#: 2006-04-27 2006-05-09 - -use strict; -use warnings; - -#use File::Copy; -use Getopt::Std; - -my %opts; -getopts('hb:', \%opts); -if ($opts{h} or ! @ARGV) { - die "Usage: reindex [-b 0] t/*.t\n"; -} - -my $init = $opts{b}; -$init = 1 if not defined $init; - -my @files = map glob, @ARGV; -for my $file (@files) { - next if -d $file or $file !~ /\.t_?$/; - reindex($file); -} - -sub reindex { - my $file = $_[0]; - open my $in, $file or - die "Can't open $file for reading: $!"; - my @lines; - my $counter = $init; - my $changed; - while (<$in>) { - s/\r$//; - my $num; - s/ ^ === \s+ TEST \s+ (\d+)/$num=$1; "=== TEST " . $counter++/xie; - next if !defined $num; - if ($num != $counter-1) { - $changed++; - } - } continue { - push @lines, $_; - } - close $in; - my $text = join '', @lines; - $text =~ s/(?x) \n+ === \s+ TEST/\n\n\n\n=== TEST/ixsg; - $text =~ s/__(DATA|END)__\n+=== TEST/__${1}__\n\n=== TEST/; - #$text =~ s/\n+$/\n\n/s; - if (! $changed and $text eq join '', @lines) { - warn "reindex: $file:\tskipped.\n"; - return; - } - #File::Copy::copy( $file, "$file.bak" ); - open my $out, "> $file" or - die "Can't open $file for writing: $!"; - binmode $out; - print $out $text; - close $out; - - warn "reindex: $file:\tdone.\n"; -} - diff --git a/debian/modules/nginx-lua/valgrind.suppress b/debian/modules/nginx-lua/valgrind.suppress index fe161e8..d0bcc56 100644 --- a/debian/modules/nginx-lua/valgrind.suppress +++ b/debian/modules/nginx-lua/valgrind.suppress @@ -149,3 +149,18 @@ fun:main fun:__libc_res_nquerydomain fun:__libc_res_nsearch } +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_single_process_cycle + fun:main +} +{ + + Memcheck:Cond + obj:* +} From 70cb0befe7496ee84ef10792d03e9f8adc07679b Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 15:16:06 +0300 Subject: [PATCH 258/651] Update OpenSSL 1.1 patch for v0.10.10 --- .../patches/nginx-lua/openssl-1.1.0.patch | 264 +++++------------- 1 file changed, 69 insertions(+), 195 deletions(-) diff --git a/debian/modules/patches/nginx-lua/openssl-1.1.0.patch b/debian/modules/patches/nginx-lua/openssl-1.1.0.patch index a4e42e5..431031b 100644 --- a/debian/modules/patches/nginx-lua/openssl-1.1.0.patch +++ b/debian/modules/patches/nginx-lua/openssl-1.1.0.patch @@ -1,7 +1,7 @@ -From 2f281b9def161d195da4d795fa916b686ac9fd87 Mon Sep 17 00:00:00 2001 +From 525d5a550f5f256af01de1264358086a4cd1ac4a Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Tue, 13 Sep 2016 22:31:32 +0100 -Subject: [PATCH 1/6] bugfix: ssl: don't use SSLv3 in tests +Subject: [PATCH 1/4] bugfix: ssl: don't use SSLv3 in tests. OpenSSL 1.1.0 disables SSLv3 by default. In order to disable SSL session tickets set ssl_session_tickets to off instead. @@ -11,7 +11,7 @@ tickets set ssl_session_tickets to off instead. 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/t/142-ssl-session-store.t b/t/142-ssl-session-store.t -index 5c9fad35..b5955199 100644 +index 73b6e197..260fe490 100644 --- a/t/142-ssl-session-store.t +++ b/t/142-ssl-session-store.t @@ -32,7 +32,7 @@ __DATA__ @@ -140,7 +140,7 @@ index 5c9fad35..b5955199 100644 server_tokens off; } diff --git a/t/143-ssl-session-fetch.t b/t/143-ssl-session-fetch.t -index bd800ff8..54f7a4a3 100644 +index 701ead72..3626f0fb 100644 --- a/t/143-ssl-session-fetch.t +++ b/t/143-ssl-session-fetch.t @@ -33,7 +33,7 @@ __DATA__ @@ -273,25 +273,25 @@ index bd800ff8..54f7a4a3 100644 server_tokens off; } -- -2.11.0 +2.14.1 -From ad8df79bccef37a0bbfd8e40283f3b81cd867760 Mon Sep 17 00:00:00 2001 +From d308b44b3daf7702d9218e2a5620a89a5eca8389 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Thu, 12 May 2016 13:12:23 +0100 -Subject: [PATCH 2/6] bugfix: ssl: do not access SSL_SESSION struct directly +Subject: [PATCH 2/4] bugfix: ssl: do not access SSL_SESSION struct directly. In OpenSSL 1.1.0 it was made opaque. --- src/ngx_http_lua_socket_tcp.c | 15 ++--- - t/129-ssl-socket.t | 152 +++++++++++++++++++++--------------------- - 2 files changed, 82 insertions(+), 85 deletions(-) + t/129-ssl-socket.t | 148 +++++++++++++++++++++--------------------- + 2 files changed, 80 insertions(+), 83 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c -index 6db6e2da..18352bfe 100644 +index 382a94de..07164746 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c -@@ -1311,9 +1311,8 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) +@@ -1316,9 +1316,8 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) return 2; } @@ -303,7 +303,7 @@ index 6db6e2da..18352bfe 100644 } } -@@ -1577,9 +1576,8 @@ ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, +@@ -1583,9 +1582,8 @@ ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, } else { *ud = ssl_session; @@ -315,7 +315,7 @@ index 6db6e2da..18352bfe 100644 /* set up the __gc metamethod */ lua_pushlightuserdata(L, &ngx_http_lua_ssl_session_metatable_key); -@@ -5356,9 +5354,8 @@ ngx_http_lua_ssl_free_session(lua_State *L) +@@ -5365,9 +5363,8 @@ ngx_http_lua_ssl_free_session(lua_State *L) psession = lua_touserdata(L, 1); if (psession && *psession != NULL) { @@ -328,7 +328,7 @@ index 6db6e2da..18352bfe 100644 ngx_ssl_free_session(*psession); } diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t -index 9da9a5c2..98fb5a2b 100644 +index 1c3f7cd0..0cd1f52f 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -108,10 +108,10 @@ sent http request: 59 bytes. @@ -345,21 +345,16 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- no_error_log lua ssl server name: -@@ -185,10 +185,10 @@ received: HTTP/1.1 401 Unauthorized - close: 1 nil +@@ -182,7 +182,7 @@ connected: 1 + failed to do SSL handshake: handshake failed --- log_level: debug ---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ - --- grep_error_log_out eval --qr/^lua ssl save session: ([0-9A-F]+):2 --lua ssl free session: ([0-9A-F]+):1 -+qr/^lua ssl save session: ([0-9A-F]+) -+lua ssl free session: ([0-9A-F]+) - $/ + --- grep_error_log_out --- no_error_log lua ssl server name: -@@ -262,10 +262,10 @@ received: HTTP/1.1 200 OK +@@ -255,10 +255,10 @@ received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -372,8 +367,8 @@ index 9da9a5c2..98fb5a2b 100644 +lua ssl free session: ([0-9A-F]+) $/ --- error_log - lua ssl server name: "iscribblet.org" -@@ -349,13 +349,13 @@ sent http request: 59 bytes. + lua ssl server name: "openresty.org" +@@ -343,13 +343,13 @@ sent http request: 56 bytes. received: HTTP/1.1 200 OK close: 1 nil @@ -393,25 +388,25 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log -@@ -437,7 +437,7 @@ failed to do SSL handshake: certificate host mismatch - failed to send http request: closed +@@ -432,7 +432,7 @@ failed to send http request: closed + \z --- log_level: debug ---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ --- grep_error_log_out --- error_log - lua ssl server name: "blah.agentzh.org" -@@ -517,7 +517,7 @@ failed to do SSL handshake: certificate host mismatch - failed to send http request: closed + lua ssl server name: "blah.openresty.org" +@@ -512,7 +512,7 @@ failed to send http request: closed + \z --- log_level: debug ---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ --- grep_error_log_out --- error_log - lua ssl server name: "blah.agentzh.org" -@@ -592,10 +592,10 @@ received: HTTP/1.1 200 OK + lua ssl server name: "blah.openresty.org" +@@ -587,10 +587,10 @@ received: HTTP/1.1 404 Not Found close: 1 nil --- log_level: debug @@ -425,7 +420,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log -@@ -677,10 +677,10 @@ received: HTTP/1.1 200 OK +@@ -672,10 +672,10 @@ received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -439,7 +434,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log -@@ -759,7 +759,7 @@ failed to do SSL handshake: 20: unable to get local issuer certificate +@@ -754,7 +754,7 @@ failed to do SSL handshake: 20: unable to get local issuer certificate failed to send http request: closed --- log_level: debug @@ -447,8 +442,8 @@ index 9da9a5c2..98fb5a2b 100644 +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ --- grep_error_log_out --- error_log - lua ssl server name: "iscribblet.org" -@@ -838,7 +838,7 @@ failed to do SSL handshake: 20: unable to get local issuer certificate + lua ssl server name: "openresty.org" +@@ -833,7 +833,7 @@ failed to do SSL handshake: 20: unable to get local issuer certificate failed to send http request: closed --- log_level: debug @@ -456,8 +451,8 @@ index 9da9a5c2..98fb5a2b 100644 +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ --- grep_error_log_out --- error_log - lua ssl server name: "iscribblet.org" -@@ -928,10 +928,10 @@ sent http request: 59 bytes. + lua ssl server name: "openresty.org" +@@ -923,10 +923,10 @@ sent http request: 59 bytes. received: HTTP/1.1 (?:200 OK|302 Found) close: 1 nil \z @@ -471,7 +466,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log lua ssl server name: "www.google.com" -@@ -1018,7 +1018,7 @@ GET /t +@@ -1013,7 +1013,7 @@ GET /t connected: 1 failed to do SSL handshake: 20: unable to get local issuer certificate @@ -480,7 +475,7 @@ index 9da9a5c2..98fb5a2b 100644 --- grep_error_log_out --- error_log lua ssl server name: "www.google.com" -@@ -1100,10 +1100,10 @@ received: HTTP/1.1 200 OK +@@ -1095,10 +1095,10 @@ received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -494,7 +489,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log -@@ -1179,10 +1179,10 @@ received: HTTP/1.1 200 OK +@@ -1174,10 +1174,10 @@ received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -507,8 +502,8 @@ index 9da9a5c2..98fb5a2b 100644 +lua ssl free session: ([0-9A-F]+) $/ --- error_log - lua ssl server name: "iscribblet.org" -@@ -1259,10 +1259,10 @@ received: HTTP/1.1 200 OK + lua ssl server name: "openresty.org" +@@ -1254,10 +1254,10 @@ received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -521,8 +516,8 @@ index 9da9a5c2..98fb5a2b 100644 +lua ssl free session: ([0-9A-F]+) $/ --- error_log - lua ssl server name: "iscribblet.org" -@@ -1339,10 +1339,10 @@ received: HTTP/1.1 200 OK + lua ssl server name: "openresty.org" +@@ -1334,10 +1334,10 @@ received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -535,8 +530,8 @@ index 9da9a5c2..98fb5a2b 100644 +lua ssl free session: ([0-9A-F]+) $/ --- error_log - lua ssl server name: "iscribblet.org" -@@ -1417,7 +1417,7 @@ failed to do SSL handshake: handshake failed + lua ssl server name: "openresty.org" +@@ -1412,7 +1412,7 @@ failed to do SSL handshake: handshake failed failed to send http request: closed --- log_level: debug @@ -545,7 +540,7 @@ index 9da9a5c2..98fb5a2b 100644 --- grep_error_log_out --- error_log eval [ -@@ -1493,10 +1493,10 @@ ssl handshake: userdata +@@ -1488,10 +1488,10 @@ ssl handshake: userdata set keepalive: 1 nil --- log_level: debug @@ -559,7 +554,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log -@@ -1569,14 +1569,14 @@ ssl handshake: userdata +@@ -1564,14 +1564,14 @@ ssl handshake: userdata set keepalive: 1 nil --- log_level: debug @@ -581,7 +576,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log -@@ -1620,7 +1620,7 @@ hello world +@@ -1615,7 +1615,7 @@ hello world --- response_body_like: 500 Internal Server Error --- error_code: 500 --- log_level: debug @@ -590,7 +585,7 @@ index 9da9a5c2..98fb5a2b 100644 --- grep_error_log_out --- error_log attempt to call method 'sslhandshake' (a nil value) -@@ -1719,10 +1719,10 @@ $::TestCertificateKey +@@ -1714,10 +1714,10 @@ $::TestCertificateKey >>> test.crt $::TestCertificate" @@ -604,7 +599,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- no_error_log lua ssl server name: -@@ -1824,10 +1824,10 @@ $::TestCertificateKey +@@ -1819,10 +1819,10 @@ $::TestCertificateKey >>> test.crt $::TestCertificate" @@ -618,7 +613,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log lua ssl server name: "test.com" -@@ -1917,7 +1917,7 @@ failed to do SSL handshake: handshake failed +@@ -1912,7 +1912,7 @@ failed to do SSL handshake: handshake failed ">>> test.crt $::TestCertificate" @@ -627,7 +622,7 @@ index 9da9a5c2..98fb5a2b 100644 --- grep_error_log_out --- error_log eval qr/SSL_do_handshake\(\) failed .*?unknown protocol/ -@@ -2016,7 +2016,7 @@ $::TestCertificate +@@ -2011,7 +2011,7 @@ $::TestCertificate >>> test.crl $::TestCRL" @@ -636,7 +631,7 @@ index 9da9a5c2..98fb5a2b 100644 --- grep_error_log_out --- error_log lua ssl server name: "test.com" -@@ -2095,12 +2095,12 @@ received: HTTP/1.1 200 OK +@@ -2090,12 +2090,12 @@ received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -653,8 +648,8 @@ index 9da9a5c2..98fb5a2b 100644 +lua ssl free session: ([0-9A-F]+) $/ --- error_log - lua ssl server name: "iscribblet.org" -@@ -2154,7 +2154,7 @@ connected: 1 + lua ssl server name: "openresty.org" +@@ -2149,7 +2149,7 @@ connected: 1 failed to do SSL handshake: timeout --- log_level: debug @@ -662,8 +657,8 @@ index 9da9a5c2..98fb5a2b 100644 +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ --- grep_error_log_out --- error_log - lua ssl server name: "iscribblet.org" -@@ -2226,7 +2226,7 @@ $::TestCertificateKey + lua ssl server name: "openresty.org" +@@ -2221,7 +2221,7 @@ $::TestCertificateKey >>> test.crt $::TestCertificate" @@ -672,7 +667,7 @@ index 9da9a5c2..98fb5a2b 100644 --- grep_error_log_out --- no_error_log lua ssl server name: -@@ -2297,10 +2297,10 @@ $::TestCertificateKey +@@ -2292,10 +2292,10 @@ $::TestCertificateKey >>> test.crt $::TestCertificate" @@ -686,7 +681,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- no_error_log lua ssl server name: -@@ -2377,7 +2377,7 @@ $::TestCertificateKey +@@ -2372,7 +2372,7 @@ $::TestCertificateKey >>> test.crt $::TestCertificate" @@ -695,7 +690,7 @@ index 9da9a5c2..98fb5a2b 100644 --- grep_error_log_out --- no_error_log lua ssl server name: -@@ -2479,10 +2479,10 @@ $::TestCertificateKey +@@ -2474,10 +2474,10 @@ $::TestCertificateKey >>> test.crt $::TestCertificate" @@ -709,7 +704,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log --- no_error_log -@@ -2575,7 +2575,7 @@ $::TestCertificateKey +@@ -2570,7 +2570,7 @@ $::TestCertificateKey >>> test.crt $::TestCertificate" @@ -719,43 +714,14 @@ index 9da9a5c2..98fb5a2b 100644 --- error_log lua ssl certificate verify error: (18: self signed certificate) -- -2.11.0 +2.14.1 -From ee94698edd219607adbd4807f4e5173f6e51ad51 Mon Sep 17 00:00:00 2001 -From: Alessandro Ghedini -Date: Thu, 12 May 2016 13:17:52 +0100 -Subject: [PATCH 3/6] bugfix: ssl: do not set tlsext_status_expected flag - -In OpenSSL 1.1.0 the SSL struct was made opaque, and setting this -flag manually is not required anyway since OpenSSL already does that -automatically when ngx_http_lua_ssl_empty_status_callback() returns -"OK" (which is always), and an OCSP response has been set. ---- - src/ngx_http_lua_ssl_ocsp.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/src/ngx_http_lua_ssl_ocsp.c b/src/ngx_http_lua_ssl_ocsp.c -index 3904aa8e..31b4f243 100644 ---- a/src/ngx_http_lua_ssl_ocsp.c -+++ b/src/ngx_http_lua_ssl_ocsp.c -@@ -490,7 +490,6 @@ ngx_http_lua_ffi_ssl_set_ocsp_status_resp(ngx_http_request_t *r, - - dd("set ocsp resp: resp_len=%d", (int) resp_len); - (void) SSL_set_tlsext_status_ocsp_resp(ssl_conn, p, resp_len); -- ssl_conn->tlsext_status_expected = 1; - - return NGX_OK; - --- -2.11.0 - - -From 9794d2d1ba577fe4dd8771d69d1ca4a688efe36c Mon Sep 17 00:00:00 2001 +From 473c121668c658140dffdbeb70aa7df1fc48d2a7 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Fri, 10 Jun 2016 13:23:21 +0100 -Subject: [PATCH 4/6] bugfix: ssl: do not access SSL struct directly for - tlsext_status_type +Subject: [PATCH 3/4] bugfix: ssl: do not access SSL struct directly for + tlsext_status_type. In OpenSSL 1.1.0 it was made opaque, and a getter function was added. --- @@ -779,14 +745,14 @@ index 31b4f243..9ec8b509 100644 return NGX_DECLINED; } -- -2.11.0 +2.14.1 -From 4d1f5bdcdade5e3c6ac0c09446ac1dcd8b4006b0 Mon Sep 17 00:00:00 2001 +From 44988918835b8b41e51e75c1618250a560bc11ca Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Tue, 13 Sep 2016 22:19:10 +0100 -Subject: [PATCH 5/6] bugfix: ssl: make SSL session callback build with OpenSSL - 1.1.0 +Subject: [PATCH 4/4] bugfix: ssl: make SSL session callback build with OpenSSL + 1.1.0. --- src/ngx_http_lua_ssl_session_fetchby.c | 9 ++++++--- @@ -795,7 +761,7 @@ Subject: [PATCH 5/6] bugfix: ssl: make SSL session callback build with OpenSSL 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/ngx_http_lua_ssl_session_fetchby.c b/src/ngx_http_lua_ssl_session_fetchby.c -index 4c450b56..6212c60d 100644 +index 556b7320..5289cb92 100644 --- a/src/ngx_http_lua_ssl_session_fetchby.c +++ b/src/ngx_http_lua_ssl_session_fetchby.c @@ -171,8 +171,11 @@ ngx_http_lua_ssl_sess_fetch_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, @@ -839,7 +805,7 @@ index 5a6f96f5..50c6616d 100644 diff --git a/src/ngx_http_lua_ssl_session_storeby.c b/src/ngx_http_lua_ssl_session_storeby.c -index b5596bc7..85dbece1 100644 +index bae8273d..dc1fad9b 100644 --- a/src/ngx_http_lua_ssl_session_storeby.c +++ b/src/ngx_http_lua_ssl_session_storeby.c @@ -172,6 +172,8 @@ int @@ -868,97 +834,5 @@ index b5596bc7..85dbece1 100644 dd("setting cctx"); -- -2.11.0 - - -From 97ca52b469fcf4881c06ab26fbc46cbd37d8cf9f Mon Sep 17 00:00:00 2001 -From: Alessandro Ghedini -Date: Mon, 28 Nov 2016 21:01:00 +0000 -Subject: [PATCH 6/6] bugfix: ssl: don't use RC4 in tests - -RC4 ciphers are deprecated and disabled by default in OpenSSL 1.1.0. ---- - t/129-ssl-socket.t | 18 +++++++++--------- - 1 file changed, 9 insertions(+), 9 deletions(-) - -diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t -index 98fb5a2b..1d9c5710 100644 ---- a/t/129-ssl-socket.t -+++ b/t/129-ssl-socket.t -@@ -1129,7 +1129,7 @@ SSL reused session - sock:settimeout(2000) - - do -- local ok, err = sock:connect("iscribblet.org", 443) -+ local ok, err = sock:connect("openresty.org", 443) - if not ok then - ngx.say("failed to connect: ", err) - return -@@ -1137,7 +1137,7 @@ SSL reused session - - ngx.say("connected: ", ok) - -- local session, err = sock:sslhandshake(nil, "iscribblet.org") -+ local session, err = sock:sslhandshake(nil, "openresty.org") - if not session then - ngx.say("failed to do SSL handshake: ", err) - return -@@ -1145,7 +1145,7 @@ SSL reused session - - ngx.say("ssl handshake: ", type(session)) - -- local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" -+ local req = "GET /en/ HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" - local bytes, err = sock:send(req) - if not bytes then - ngx.say("failed to send http request: ", err) -@@ -1174,7 +1174,7 @@ GET /t - --- response_body - connected: 1 - ssl handshake: userdata --sent http request: 59 bytes. -+sent http request: 61 bytes. - received: HTTP/1.1 200 OK - close: 1 nil - -@@ -1185,8 +1185,8 @@ qr/^lua ssl save session: ([0-9A-F]+) - lua ssl free session: ([0-9A-F]+) - $/ - --- error_log --lua ssl server name: "iscribblet.org" --SSL: TLSv1.2, cipher: "ECDHE-RSA-RC4-SHA SSLv3 -+lua ssl server name: "openresty.org" -+SSL: TLSv1.2, cipher: "ECDHE-RSA-AES128-GCM-SHA256 - --- no_error_log - SSL reused session - [error] -@@ -1199,7 +1199,7 @@ SSL reused session - --- config - server_tokens off; - resolver $TEST_NGINX_RESOLVER; -- lua_ssl_ciphers RC4-SHA; -+ lua_ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256; - location /t { - #set $port 5000; - set $port $TEST_NGINX_MEMCACHED_PORT; -@@ -1266,7 +1266,7 @@ lua ssl free session: ([0-9A-F]+) - $/ - --- error_log - lua ssl server name: "iscribblet.org" --SSL: TLSv1.2, cipher: "RC4-SHA SSLv3 -+SSL: TLSv1.2, cipher: "ECDHE-RSA-AES128-GCM-SHA256 - --- no_error_log - SSL reused session - [error] -@@ -1346,7 +1346,7 @@ lua ssl free session: ([0-9A-F]+) - $/ - --- error_log - lua ssl server name: "iscribblet.org" --SSL: TLSv1, cipher: "ECDHE-RSA-RC4-SHA SSLv3 -+SSL: TLSv1 - --- no_error_log - SSL reused session - [error] --- -2.11.0 +2.14.1 From 7614ff61a9d2985f19dea05d21bfd207bbd7d6e1 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 16:05:03 +0300 Subject: [PATCH 259/651] lua: Drop patch to build against nginx 1.11.11, now included upstream --- debian/modules/README.Modules-versions | 1 - .../nginx-lua/build-nginx-1.1.11.patch | 217 ------------------ debian/modules/patches/nginx-lua/series | 1 - 3 files changed, 219 deletions(-) delete mode 100644 debian/modules/patches/nginx-lua/build-nginx-1.1.11.patch diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index 6b581cd..ff5f63b 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -25,7 +25,6 @@ README for Modules versions Homepage: https://github.com/openresty/lua-nginx-module Version: v0.10.10 Patch: openssl-1.1.0.patch - Patch: build-nginx-1.11.11.patch Patch: discover-luajit-2.1.patch nginx-upstream-fair diff --git a/debian/modules/patches/nginx-lua/build-nginx-1.1.11.patch b/debian/modules/patches/nginx-lua/build-nginx-1.1.11.patch deleted file mode 100644 index 597cbf8..0000000 --- a/debian/modules/patches/nginx-lua/build-nginx-1.1.11.patch +++ /dev/null @@ -1,217 +0,0 @@ -From 0459a285ca0159d45e73da8bd1164edb5c57cde3 Mon Sep 17 00:00:00 2001 -From: Andrei Belov -Date: Wed, 22 Mar 2017 07:50:57 +0300 -Subject: [PATCH] feature: nginx 1.11.11+ can now build with this module. - -Note: nginx 1.11.11+ are still not an officially supported target yet. -More work needed. - -Closes openresty/lua-nginx-module#1016 - -See also: -http://hg.nginx.org/nginx/rev/e662cbf1b932 ---- - src/ngx_http_lua_common.h | 6 ++++ - src/ngx_http_lua_headers.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++ - src/ngx_http_lua_headers.h | 3 ++ - src/ngx_http_lua_module.c | 13 ++++++++- - 4 files changed, 89 insertions(+), 1 deletion(-) - -diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h -index 079a4dc3..f37d776a 100644 ---- a/src/ngx_http_lua_common.h -+++ b/src/ngx_http_lua_common.h -@@ -199,6 +199,12 @@ struct ngx_http_lua_main_conf_s { - of reqeusts */ - ngx_uint_t malloc_trim_req_count; - -+#if nginx_version >= 1011011 -+ /* the following 2 fields are only used by ngx.req.raw_headers() for now */ -+ ngx_buf_t **busy_buf_ptrs; -+ ngx_int_t busy_buf_ptr_count; -+#endif -+ - unsigned requires_header_filter:1; - unsigned requires_body_filter:1; - unsigned requires_capture_filter:1; -diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c -index 23925984..6700ce80 100644 ---- a/src/ngx_http_lua_headers.c -+++ b/src/ngx_http_lua_headers.c -@@ -26,6 +26,9 @@ static int ngx_http_lua_ngx_req_get_headers(lua_State *L); - static int ngx_http_lua_ngx_req_header_clear(lua_State *L); - static int ngx_http_lua_ngx_req_header_set(lua_State *L); - static int ngx_http_lua_ngx_resp_get_headers(lua_State *L); -+#if nginx_version >= 1011011 -+void ngx_http_lua_ngx_raw_header_cleanup(void *data); -+#endif - - - static int -@@ -77,6 +80,11 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) - size_t size; - ngx_buf_t *b, *first = NULL; - ngx_int_t i, j; -+#if nginx_version >= 1011011 -+ ngx_buf_t **bb; -+ ngx_chain_t *cl; -+ ngx_http_lua_main_conf_t *lmcf; -+#endif - ngx_connection_t *c; - ngx_http_request_t *r, *mr; - ngx_http_connection_t *hc; -@@ -93,6 +101,10 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) - return luaL_error(L, "no request object found"); - } - -+#if nginx_version >= 1011011 -+ lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); -+#endif -+ - ngx_http_lua_check_fake_request(L, r); - - mr = r->main; -@@ -109,8 +121,13 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) - dd("hc->nbusy: %d", (int) hc->nbusy); - - if (hc->nbusy) { -+#if nginx_version >= 1011011 -+ dd("hc->busy: %p %p %p %p", hc->busy->buf->start, hc->busy->buf->pos, -+ hc->busy->buf->last, hc->busy->buf->end); -+#else - dd("hc->busy: %p %p %p %p", hc->busy[0]->start, hc->busy[0]->pos, - hc->busy[0]->last, hc->busy[0]->end); -+#endif - } - - dd("request line: %p %p", mr->request_line.data, -@@ -146,9 +163,37 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) - dd("size: %d", (int) size); - - if (hc->nbusy) { -+#if nginx_version >= 1011011 -+ if (hc->nbusy > lmcf->busy_buf_ptr_count) { -+ if (lmcf->busy_buf_ptrs) { -+ ngx_free(lmcf->busy_buf_ptrs); -+ } -+ -+ lmcf->busy_buf_ptrs = ngx_alloc(hc->nbusy * sizeof(ngx_buf_t *), -+ r->connection->log); -+ -+ if (lmcf->busy_buf_ptrs == NULL) { -+ return luaL_error(L, "no memory"); -+ } -+ -+ lmcf->busy_buf_ptr_count = hc->nbusy; -+ } -+ -+ bb = lmcf->busy_buf_ptrs; -+ for (cl = hc->busy; cl; cl = cl->next) { -+ *bb++ = cl->buf; -+ } -+#endif - b = NULL; -+ -+#if nginx_version >= 1011011 -+ bb = lmcf->busy_buf_ptrs; -+ for (i = hc->nbusy; i > 0; i--) { -+ b = bb[i - 1]; -+#else - for (i = 0; i < hc->nbusy; i++) { - b = hc->busy[i]; -+#endif - - dd("busy buf: %d: [%.*s]", (int) i, (int) (b->pos - b->start), - b->start); -@@ -223,8 +268,15 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) - } - - if (hc->nbusy) { -+ -+#if nginx_version >= 1011011 -+ bb = lmcf->busy_buf_ptrs; -+ for (i = hc->nbusy - 1; i >= 0; i--) { -+ b = bb[i]; -+#else - for (i = 0; i < hc->nbusy; i++) { - b = hc->busy[i]; -+#endif - - if (!found) { - if (b != first) { -@@ -1431,4 +1483,20 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, - #endif /* NGX_LUA_NO_FFI_API */ - - -+#if nginx_version >= 1011011 -+void -+ngx_http_lua_ngx_raw_header_cleanup(void *data) -+{ -+ ngx_http_lua_main_conf_t *lmcf; -+ -+ lmcf = (ngx_http_lua_main_conf_t *) data; -+ -+ if (lmcf->busy_buf_ptrs) { -+ ngx_free(lmcf->busy_buf_ptrs); -+ lmcf->busy_buf_ptrs = NULL; -+ } -+} -+#endif -+ -+ - /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ -diff --git a/src/ngx_http_lua_headers.h b/src/ngx_http_lua_headers.h -index 39f1114c..ee4d21c1 100644 ---- a/src/ngx_http_lua_headers.h -+++ b/src/ngx_http_lua_headers.h -@@ -15,6 +15,9 @@ - void ngx_http_lua_inject_resp_header_api(lua_State *L); - void ngx_http_lua_inject_req_header_api(lua_State *L); - void ngx_http_lua_create_headers_metatable(ngx_log_t *log, lua_State *L); -+#if nginx_version >= 1011011 -+void ngx_http_lua_ngx_raw_header_cleanup(void *data); -+#endif - - - #endif /* _NGX_HTTP_LUA_HEADERS_H_INCLUDED_ */ -diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c -index 3dc2817b..875f9334 100644 ---- a/src/ngx_http_lua_module.c -+++ b/src/ngx_http_lua_module.c -@@ -28,6 +28,7 @@ - #include "ngx_http_lua_ssl_certby.h" - #include "ngx_http_lua_ssl_session_storeby.h" - #include "ngx_http_lua_ssl_session_fetchby.h" -+#include "ngx_http_lua_headers.h" - - - static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf); -@@ -624,7 +625,7 @@ ngx_http_lua_init(ngx_conf_t *cf) - volatile ngx_cycle_t *saved_cycle; - ngx_http_core_main_conf_t *cmcf; - ngx_http_lua_main_conf_t *lmcf; --#ifndef NGX_LUA_NO_FFI_API -+#if !defined(NGX_LUA_NO_FFI_API) || nginx_version >= 1011011 - ngx_pool_cleanup_t *cln; - #endif - -@@ -716,6 +717,16 @@ ngx_http_lua_init(ngx_conf_t *cf) - cln->handler = ngx_http_lua_sema_mm_cleanup; - #endif - -+#if nginx_version >= 1011011 -+ cln = ngx_pool_cleanup_add(cf->pool, 0); -+ if (cln == NULL) { -+ return NGX_ERROR; -+ } -+ -+ cln->data = lmcf; -+ cln->handler = ngx_http_lua_ngx_raw_header_cleanup; -+#endif -+ - if (lmcf->lua == NULL) { - dd("initializing lua vm"); - --- -2.11.0 - diff --git a/debian/modules/patches/nginx-lua/series b/debian/modules/patches/nginx-lua/series index 8edeaf5..7d0f424 100644 --- a/debian/modules/patches/nginx-lua/series +++ b/debian/modules/patches/nginx-lua/series @@ -1,3 +1,2 @@ openssl-1.1.0.patch -build-nginx-1.1.11.patch discover-luajit-2.1.patch From e60711fcc72e83d560fa250fba484f3d541cb5b4 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 16:35:53 +0300 Subject: [PATCH 260/651] tests: Fix race between reload and curl's http request Restart nginx to make sure it uses the new configuration. --- debian/tests/ec-x25519 | 2 +- debian/tests/lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/tests/ec-x25519 b/debian/tests/ec-x25519 index a01bc0d..edd4e2f 100644 --- a/debian/tests/ec-x25519 +++ b/debian/tests/ec-x25519 @@ -17,5 +17,5 @@ server { EOF nginx -t -nginx -s reload +invoke-rc.d nginx restart curl --insecure --silent --fail -o /dev/null -w "response_code: %{http_code}\n" https://127.0.0.1/ diff --git a/debian/tests/lua b/debian/tests/lua index 396d8a9..82c1820 100644 --- a/debian/tests/lua +++ b/debian/tests/lua @@ -14,5 +14,5 @@ server { EOF nginx -t -nginx -s reload +invoke-rc.d nginx restart curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ping From 2005e7e35d4c99863c55019cca2a4675f57d8ee0 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 16:53:56 +0300 Subject: [PATCH 261/651] Explicitly disable autoreconf (debhelper 10) Since debhelper 10 systemd & autoreconf are enabled by default, we need systemd and not autoconf so we reverse the logic. While at it, drop not needed autotools dependency. --- debian/control | 3 +-- debian/rules | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/debian/control b/debian/control index ccb769d..9d46418 100644 --- a/debian/control +++ b/debian/control @@ -5,8 +5,7 @@ Maintainer: Debian Nginx Maintainers , Michael Lustfield , Christos Trochalakis -Build-Depends: autotools-dev, - debhelper (>= 10), +Build-Depends: debhelper (>= 10), po-debconf, dh-systemd (>= 1.5), dpkg-dev (>= 1.15.5), diff --git a/debian/rules b/debian/rules index 3951529..a852d02 100755 --- a/debian/rules +++ b/debian/rules @@ -138,7 +138,7 @@ extras_configure_flags := \ --add-dynamic-module=$(MODULESDIR)/ngx_http_substitutions_filter_module %: - dh $@ --with systemd + dh $@ --without autoreconf override_dh_auto_configure: config_patch_modules $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) override_dh_auto_build: $(foreach flavour,$(FLAVOURS),build.arch.$(flavour)) From 22aae236484ddf9ace687ee7a846e8420e9927a6 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 17:03:49 +0300 Subject: [PATCH 262/651] Drop Upstart configuration Upstart was removed in Debian stretch --- debian/nginx-common.nginx.upstart | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 debian/nginx-common.nginx.upstart diff --git a/debian/nginx-common.nginx.upstart b/debian/nginx-common.nginx.upstart deleted file mode 100644 index 317bcb0..0000000 --- a/debian/nginx-common.nginx.upstart +++ /dev/null @@ -1,16 +0,0 @@ -description "nginx - small, powerful, scalable web/proxy server" - -start on filesystem and static-network-up -stop on runlevel [016] - -expect fork -respawn - -pre-start script - [ -x /usr/sbin/nginx ] || { stop; exit 0; } - /usr/sbin/nginx -q -t -g 'daemon on; master_process on;' || { stop; exit 0; } -end script - -exec /usr/sbin/nginx -g 'daemon on; master_process on;' - -pre-stop exec /usr/sbin/nginx -s quit From 9ad7cddbce6fae45691b58421e362c579a4e4370 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 17:11:10 +0300 Subject: [PATCH 263/651] Bump Standards to 4.1.0 o Switch all packages to Priority optional, extra is considered deprecated and should be treated as equivalent to optional. nginx-light & extras now inherit optional from the source package. --- debian/control | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/debian/control b/debian/control index 9d46418..e7a598a 100644 --- a/debian/control +++ b/debian/control @@ -24,7 +24,7 @@ Build-Depends: debhelper (>= 10), po-debconf, quilt, zlib1g-dev -Standards-Version: 4.0.0 +Standards-Version: 4.1.0 Homepage: http://nginx.net Vcs-Git: https://anonscm.debian.org/cgit/pkg-nginx/nginx.git Vcs-Browser: https://anonscm.debian.org/cgit/pkg-nginx/nginx.git @@ -111,7 +111,6 @@ Description: nginx web/proxy server (standard version) Package: nginx-light Architecture: any -Priority: extra Depends: libnginx-mod-http-echo (= ${binary:Version}), nginx-common (= ${source:Version}), ${misc:Depends}, @@ -139,7 +138,6 @@ Description: nginx web/proxy server (basic version) Package: nginx-extras Architecture: any -Priority: extra Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), libnginx-mod-http-cache-purge (= ${binary:Version}), libnginx-mod-http-dav-ext (= ${binary:Version}), From ee4f08f8b48651eb584373af0bb71afd5a4d3c1d Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 29 Aug 2017 10:50:48 +0300 Subject: [PATCH 264/651] Release 1.13.4-1 --- debian/changelog | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/debian/changelog b/debian/changelog index 7d350cf..3e671b0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,20 @@ +nginx (1.13.4-1) unstable; urgency=medium + + * New upstream version 1.13.4 + * nginx-lua: + + Add a simple lua autopkgtest + + Discover LuaJIT 2.1 (FTBFS) (Closes: #873319) + + Update to v0.10.10 + + Update OpenSSL 1.1 patch + + Drop patch to build against Nginx 1.11.11, now included upstream + * tests: Fix race between reload and curl's http request + * Explicitly disable autoreconf (debhelper 10) + * Drop Upstart configuration + * Bump Standards to 4.1.0 + + Switch all packages to Priority optional, extra is considered deprecated + + -- Christos Trochalakis Tue, 29 Aug 2017 10:49:03 +0300 + nginx (1.13.3-1) unstable; urgency=high * New upstream version 1.13.3. From 3ebf96c773e9685d526ebe77daaf0baa91e73e04 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 29 Aug 2017 13:04:11 +0300 Subject: [PATCH 265/651] doc: Improve example WordPress configuration Closes: #863343 Thanks: Larry Holish --- debian/help/examples/wordpress | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/debian/help/examples/wordpress b/debian/help/examples/wordpress index 6faf918..2d4c0ab 100644 --- a/debian/help/examples/wordpress +++ b/debian/help/examples/wordpress @@ -34,8 +34,8 @@ server { } # This location block protects against a known attack. It happens if - # the attacker uploads a non-php file and attempts to run it as a - # php file on the server. + # the attacker uploads a non-PHP file and attempts to run it as a + # PHP file on the server. location ~ \..*/.*\.php$ { return 403; } @@ -43,7 +43,7 @@ server { # This is our primary location block. The try_files directive will # attempt to serve the data in the order listed. First try the exact # request (such as an image or text file). If it doesn't exist, see if - # the directory exists. If not, then we move to the last options which + # the directory exists. If not, then we move to the last option which # passes the request to /index.php with the requested query. location / { try_files $uri $uri/ /index.php?q=$uri&$args; @@ -51,7 +51,7 @@ server { # If a PHP file is served, this block will handle the request. This block # works on the assumption you are using php-cgi listening on /tmp/phpcgi.socket. - # Please see the php example (usr/share/doc/nginx/exmaples/php) for more + # Please see the PHP example (/usr/share/doc/nginx-doc/php) for more # information about setting up PHP. # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini location ~ \.php$ { @@ -61,12 +61,11 @@ server { fastcgi_intercept_errors on; fastcgi_pass unix:/tmp/phpcgi.socket; } - - # As mentioned above, Nignx is king of static. If we're serving a static - # file that ends with one of the following extensions, it is best to set - # a very high expires time. This will generate fewer requests for the - # file. These requests will be logged if found, but not if they don't - # exist. + + # If we're serving a static file that ends with one of the following + # extensions, it is best to set a very high expires time. This will + # generate fewer requests for the file. These requests will be logged if + # found, but not if they don't exist. location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { expires max; log_not_found off; From 3582062c0e7359e6fe9bd08f6b0cea332491554c Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 5 Sep 2017 10:29:14 +0300 Subject: [PATCH 266/651] Remove upstart configuration file Close: #874319 --- debian/nginx-common.postinst | 4 ++++ debian/nginx-common.postrm | 4 ++++ debian/nginx-common.preinst | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/debian/nginx-common.postinst b/debian/nginx-common.postinst index 2b176f8..f996cec 100644 --- a/debian/nginx-common.postinst +++ b/debian/nginx-common.postinst @@ -13,6 +13,10 @@ dpkg-maintscript-helper rm_conffile \ dpkg-maintscript-helper rm_conffile \ /etc/nginx/naxsi-ui.conf 1.6.2-2~ -- "$@" +# Handle upstart removal +dpkg-maintscript-helper rm_conffile \ + /etc/init/nginx.conf 1.13.4-2~ -- "$@" + case "$1" in configure) logdir="/var/log/nginx" diff --git a/debian/nginx-common.postrm b/debian/nginx-common.postrm index b0f2e30..9aa06d0 100644 --- a/debian/nginx-common.postrm +++ b/debian/nginx-common.postrm @@ -11,6 +11,10 @@ dpkg-maintscript-helper rm_conffile \ dpkg-maintscript-helper rm_conffile \ /etc/nginx/naxsi-ui.conf 1.6.2-2~ -- "$@" +# Handle upstart removal +dpkg-maintscript-helper rm_conffile \ + /etc/init/nginx.conf 1.13.4-2~ -- "$@" + case "$1" in purge) rm -rf /var/lib/nginx /var/log/nginx /etc/nginx diff --git a/debian/nginx-common.preinst b/debian/nginx-common.preinst index 037c80f..0d2737f 100644 --- a/debian/nginx-common.preinst +++ b/debian/nginx-common.preinst @@ -11,6 +11,10 @@ dpkg-maintscript-helper rm_conffile \ dpkg-maintscript-helper rm_conffile \ /etc/nginx/naxsi-ui.conf 1.6.2-2~ -- "$@" +# Handle upstart removal +dpkg-maintscript-helper rm_conffile \ + /etc/init/nginx.conf 1.13.4-2~ -- "$@" + case "$1" in install) # If we are doing a fresh install, then these files are no longer needed. From 2a7340c231ffc083156ad1af0691c3f25309ecc4 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 6 Sep 2017 10:06:33 +0300 Subject: [PATCH 267/651] New upstream version 1.13.5 --- CHANGES | 15 +++++ CHANGES.ru | 15 +++++ src/core/nginx.h | 4 +- src/core/ngx_conf_file.c | 1 + src/core/ngx_regex.c | 4 +- src/event/ngx_event.h | 4 +- src/event/ngx_event_openssl.c | 56 ++++++++++++++++--- src/event/ngx_event_openssl.h | 2 + src/http/modules/ngx_http_geo_module.c | 3 +- .../modules/ngx_http_range_filter_module.c | 17 +++--- src/http/modules/ngx_http_scgi_module.c | 2 +- .../modules/ngx_http_secure_link_module.c | 3 +- src/http/modules/ngx_http_ssl_module.c | 4 ++ src/http/modules/ngx_http_uwsgi_module.c | 8 +-- src/http/ngx_http_upstream.c | 20 +------ src/os/unix/ngx_files.c | 1 + src/stream/ngx_stream_geo_module.c | 3 +- src/stream/ngx_stream_ssl_module.c | 4 ++ 18 files changed, 119 insertions(+), 47 deletions(-) diff --git a/CHANGES b/CHANGES index cc22571..e46199b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,19 @@ +Changes with nginx 1.13.5 05 Sep 2017 + + *) Feature: the $ssl_client_escaped_cert variable. + + *) Bugfix: the "ssl_session_ticket_key" directive and the "include" + parameter of the "geo" directive did not work on Windows. + + *) Bugfix: incorrect response length was returned on 32-bit platforms + when requesting more than 4 gigabytes with multiple ranges. + + *) Bugfix: the "expires modified" directive and processing of the + "If-Range" request header line did not use the response last + modification time if proxying without caching was used. + + Changes with nginx 1.13.4 08 Aug 2017 *) Feature: the ngx_http_mirror_module. diff --git a/CHANGES.ru b/CHANGES.ru index f466c4d..73c4164 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,19 @@ +Изменения в nginx 1.13.5 05.09.2017 + + *) Добавление: переменная $ssl_client_escaped_cert. + + *) Исправление: директива ssl_session_ticket_key и параметр include + директивы geo не работали на Windows. + + *) Исправление: на 32-битных платформах при запросе более 4 гигабайт с + помощью нескольких диапазонов возвращалась некорректная длина ответа. + + *) Исправление: директива "expires modified" и обработка строки If-Range + заголовка запроса не учитывали время последнего изменения ответа, + если использовалось проксирование без кэширования. + + Изменения в nginx 1.13.4 08.08.2017 *) Добавление: модуль ngx_http_mirror_module. diff --git a/src/core/nginx.h b/src/core/nginx.h index 3649945..a3c0ef8 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1013004 -#define NGINX_VERSION "1.13.4" +#define nginx_version 1013005 +#define NGINX_VERSION "1.13.5" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c index ce8c602..fb28a5a 100644 --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -178,6 +178,7 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) /* open configuration file */ fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (fd == NGX_INVALID_FILE) { ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, ngx_open_file_n " \"%s\" failed", diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c index 9939dce..52169f6 100644 --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -262,7 +262,7 @@ ngx_pcre_free_studies(void *data) part = &studies->part; elts = part->elts; - for (i = 0 ; /* void */ ; i++) { + for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { @@ -326,7 +326,7 @@ ngx_regex_module_init(ngx_cycle_t *cycle) part = &ngx_pcre_studies->part; elts = part->elts; - for (i = 0 ; /* void */ ; i++) { + for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index 053bd16..19fec68 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -152,12 +152,12 @@ struct ngx_event_aio_s { ngx_event_handler_pt handler; ngx_file_t *file; + ngx_fd_t fd; + #if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) ssize_t (*preload_handler)(ngx_buf_t *file); #endif - ngx_fd_t fd; - #if (NGX_HAVE_EVENTFD) int64_t res; #endif diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 07646b6..88a6dbe 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -924,6 +924,7 @@ ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file) cln->data = passwords; fd = ngx_open_file(file->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (fd == NGX_INVALID_FILE) { ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, ngx_open_file_n " \"%s\" failed", file->data); @@ -2905,7 +2906,9 @@ ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) file.name = path[i]; file.log = cf->log; - file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, 0, 0); + file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, + NGX_FILE_OPEN, 0); + if (file.fd == NGX_INVALID_FILE) { ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, ngx_open_file_n " \"%V\" failed", &file.name); @@ -3548,13 +3551,22 @@ ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - const char *servername; + size_t len; + const char *name; + + name = SSL_get_servername(c->ssl->connection, TLSEXT_NAMETYPE_host_name); + + if (name) { + len = ngx_strlen(name); + + s->len = len; + s->data = ngx_pnalloc(pool, len); + if (s->data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(s->data, name, len); - servername = SSL_get_servername(c->ssl->connection, - TLSEXT_NAMETYPE_host_name); - if (servername) { - s->data = (u_char *) servername; - s->len = ngx_strlen(servername); return NGX_OK; } @@ -3659,6 +3671,36 @@ ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } +ngx_int_t +ngx_ssl_get_escaped_certificate(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s) +{ + ngx_str_t cert; + uintptr_t n; + + if (ngx_ssl_get_raw_certificate(c, pool, &cert) != NGX_OK) { + return NGX_ERROR; + } + + if (cert.len == 0) { + s->len = 0; + return NGX_OK; + } + + n = ngx_escape_uri(NULL, cert.data, cert.len, NGX_ESCAPE_URI_COMPONENT); + + s->len = cert.len + n * 2; + s->data = ngx_pnalloc(pool, s->len); + if (s->data == NULL) { + return NGX_ERROR; + } + + ngx_escape_uri(s->data, cert.data, cert.len, NGX_ESCAPE_URI_COMPONENT); + + return NGX_OK; +} + + ngx_int_t ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 2a14980..b9a3a96 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -212,6 +212,8 @@ ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_escaped_certificate(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c index 46a8d7c..8262c9d 100644 --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -1400,7 +1400,8 @@ ngx_http_geo_include_binary_base(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, file.name = *name; file.log = cf->log; - file.fd = ngx_open_file(name->data, NGX_FILE_RDONLY, 0, 0); + file.fd = ngx_open_file(name->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (file.fd == NGX_INVALID_FILE) { err = ngx_errno; if (err != NGX_ENOENT) { diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index 6256b13..819c5c9 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -463,23 +463,24 @@ static ngx_int_t ngx_http_range_multipart_header(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx) { - size_t len; + off_t len; + size_t size; ngx_uint_t i; ngx_http_range_t *range; ngx_atomic_uint_t boundary; - len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN - + sizeof(CRLF "Content-Type: ") - 1 - + r->headers_out.content_type.len - + sizeof(CRLF "Content-Range: bytes ") - 1; + size = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + + sizeof(CRLF "Content-Type: ") - 1 + + r->headers_out.content_type.len + + sizeof(CRLF "Content-Range: bytes ") - 1; if (r->headers_out.content_type_len == r->headers_out.content_type.len && r->headers_out.charset.len) { - len += sizeof("; charset=") - 1 + r->headers_out.charset.len; + size += sizeof("; charset=") - 1 + r->headers_out.charset.len; } - ctx->boundary_header.data = ngx_pnalloc(r->pool, len); + ctx->boundary_header.data = ngx_pnalloc(r->pool, size); if (ctx->boundary_header.data == NULL) { return NGX_ERROR; } @@ -569,7 +570,7 @@ ngx_http_range_multipart_header(ngx_http_request_t *r, - range[i].content_range.data; len += ctx->boundary_header.len + range[i].content_range.len - + (size_t) (range[i].end - range[i].start); + + (range[i].end - range[i].start); } r->headers_out.content_length_n = len; diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index 9204af4..3fb227b 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -819,7 +819,7 @@ ngx_http_scgi_create_request(ngx_http_request_t *r) key = e.pos; #endif code = *(ngx_http_script_code_pt *) e.ip; - code((ngx_http_script_engine_t *) & e); + code((ngx_http_script_engine_t *) &e); #if (NGX_DEBUG) val = e.pos; diff --git a/src/http/modules/ngx_http_secure_link_module.c b/src/http/modules/ngx_http_secure_link_module.c index 907ba6e..536e09a 100644 --- a/src/http/modules/ngx_http_secure_link_module.c +++ b/src/http/modules/ngx_http_secure_link_module.c @@ -107,7 +107,7 @@ ngx_http_secure_link_variable(ngx_http_request_t *r, ngx_md5_t md5; ngx_http_secure_link_ctx_t *ctx; ngx_http_secure_link_conf_t *conf; - u_char hash_buf[16], md5_buf[16]; + u_char hash_buf[18], md5_buf[16]; conf = ngx_http_get_module_loc_conf(r, ngx_http_secure_link_module); @@ -154,7 +154,6 @@ ngx_http_secure_link_variable(ngx_http_request_t *r, goto not_found; } - hash.len = 16; hash.data = hash_buf; if (ngx_decode_base64url(&hash, &val) != NGX_OK) { diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 4370275..7d62176 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -299,6 +299,10 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { (uintptr_t) ngx_ssl_get_raw_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_escaped_cert"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_escaped_certificate, + NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_s_dn"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_subject_dn, NGX_HTTP_VAR_CHANGEABLE, 0 }, diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index a2bec4c..124da4d 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -865,7 +865,7 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) 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)) { + 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); @@ -990,7 +990,7 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; - key_len = (u_char) lcode (&le); + key_len = (u_char) lcode(&le); lcode = *(ngx_http_script_len_code_pt *) le.ip; skip_empty = lcode(&le); @@ -1018,14 +1018,14 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) *e.pos++ = (u_char) ((key_len >> 8) & 0xff); code = *(ngx_http_script_code_pt *) e.ip; - code((ngx_http_script_engine_t *) & e); + code((ngx_http_script_engine_t *) &e); *e.pos++ = (u_char) (val_len & 0xff); *e.pos++ = (u_char) ((val_len >> 8) & 0xff); while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; - code((ngx_http_script_engine_t *) & e); + code((ngx_http_script_engine_t *) &e); } e.ip += sizeof(uintptr_t); diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 6a2b322..73a5882 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -4390,15 +4390,8 @@ ngx_http_upstream_process_last_modified(ngx_http_request_t *r, u = r->upstream; u->headers_in.last_modified = h; - -#if (NGX_HTTP_CACHE) - - if (u->cacheable) { - u->headers_in.last_modified_time = ngx_parse_http_time(h->value.data, - h->value.len); - } - -#endif + u->headers_in.last_modified_time = ngx_parse_http_time(h->value.data, + h->value.len); return NGX_OK; } @@ -4940,15 +4933,8 @@ ngx_http_upstream_copy_last_modified(ngx_http_request_t *r, ngx_table_elt_t *h, *ho = *h; r->headers_out.last_modified = ho; - -#if (NGX_HTTP_CACHE) - - if (r->upstream->cacheable) { - r->headers_out.last_modified_time = + r->headers_out.last_modified_time = r->upstream->headers_in.last_modified_time; - } - -#endif return NGX_OK; } diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c index 7fbb7c9..482d327 100644 --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -620,6 +620,7 @@ ngx_create_file_mapping(ngx_file_mapping_t *fm) { fm->fd = ngx_open_file(fm->name, NGX_FILE_RDWR, NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); + if (fm->fd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, ngx_open_file_n " \"%s\" failed", fm->name); diff --git a/src/stream/ngx_stream_geo_module.c b/src/stream/ngx_stream_geo_module.c index 2204546..632fa5a 100644 --- a/src/stream/ngx_stream_geo_module.c +++ b/src/stream/ngx_stream_geo_module.c @@ -1326,7 +1326,8 @@ ngx_stream_geo_include_binary_base(ngx_conf_t *cf, file.name = *name; file.log = cf->log; - file.fd = ngx_open_file(name->data, NGX_FILE_RDONLY, 0, 0); + file.fd = ngx_open_file(name->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (file.fd == NGX_INVALID_FILE) { err = ngx_errno; if (err != NGX_ENOENT) { diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index 010b98b..1e9973f 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -249,6 +249,10 @@ static ngx_stream_variable_t ngx_stream_ssl_vars[] = { (uintptr_t) ngx_ssl_get_raw_certificate, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_escaped_cert"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_escaped_certificate, + NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_s_dn"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_subject_dn, NGX_STREAM_VAR_CHANGEABLE, 0 }, From 1c5a8493cae9ec2fd6f1e258d077bea1a7c01475 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 6 Sep 2017 10:09:50 +0300 Subject: [PATCH 268/651] Adjust rm_conffile to the new version Gbp-Dch: Ignore --- debian/nginx-common.postinst | 2 +- debian/nginx-common.postrm | 2 +- debian/nginx-common.preinst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/nginx-common.postinst b/debian/nginx-common.postinst index f996cec..f83032d 100644 --- a/debian/nginx-common.postinst +++ b/debian/nginx-common.postinst @@ -15,7 +15,7 @@ dpkg-maintscript-helper rm_conffile \ # Handle upstart removal dpkg-maintscript-helper rm_conffile \ - /etc/init/nginx.conf 1.13.4-2~ -- "$@" + /etc/init/nginx.conf 1.13.5-1~ -- "$@" case "$1" in configure) diff --git a/debian/nginx-common.postrm b/debian/nginx-common.postrm index 9aa06d0..d6f313a 100644 --- a/debian/nginx-common.postrm +++ b/debian/nginx-common.postrm @@ -13,7 +13,7 @@ dpkg-maintscript-helper rm_conffile \ # Handle upstart removal dpkg-maintscript-helper rm_conffile \ - /etc/init/nginx.conf 1.13.4-2~ -- "$@" + /etc/init/nginx.conf 1.13.5-1~ -- "$@" case "$1" in purge) diff --git a/debian/nginx-common.preinst b/debian/nginx-common.preinst index 0d2737f..27f21da 100644 --- a/debian/nginx-common.preinst +++ b/debian/nginx-common.preinst @@ -13,7 +13,7 @@ dpkg-maintscript-helper rm_conffile \ # Handle upstart removal dpkg-maintscript-helper rm_conffile \ - /etc/init/nginx.conf 1.13.4-2~ -- "$@" + /etc/init/nginx.conf 1.13.5-1~ -- "$@" case "$1" in install) From cacbf319dba8b15bd02710ad5065516892148a5a Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 6 Sep 2017 10:10:41 +0300 Subject: [PATCH 269/651] Release 1.13.5-1 --- debian/changelog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/debian/changelog b/debian/changelog index 3e671b0..396226e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +nginx (1.13.5-1) unstable; urgency=medium + + * New upstream version 1.13.5 + * doc: Improve example WordPress configuration + Thanks to Larry Holish (Closes: #863343) + * Remove upstart conffile (Closes: #874319) + + -- Christos Trochalakis Wed, 06 Sep 2017 10:10:24 +0300 + nginx (1.13.4-1) unstable; urgency=medium * New upstream version 1.13.4 From a5c72db78304846c75c7da22a26e539d4fb07874 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 11 Oct 2017 10:33:46 +0300 Subject: [PATCH 270/651] New upstream version 1.13.6 --- CHANGES | 36 ++++ CHANGES.ru | 36 ++++ conf/mime.types | 166 +++++++++--------- src/core/nginx.h | 4 +- src/core/ngx_connection.c | 4 + src/core/ngx_inet.c | 8 +- src/core/ngx_inet.h | 5 +- src/core/ngx_parse_time.c | 5 +- src/core/ngx_string.c | 16 ++ src/core/ngx_string.h | 2 + src/core/ngx_times.c | 30 +++- src/event/ngx_event_accept.c | 8 + src/http/modules/ngx_http_auth_basic_module.c | 70 ++------ .../modules/ngx_http_upstream_hash_module.c | 24 +-- .../modules/ngx_http_upstream_zone_module.c | 2 +- src/http/ngx_http_upstream.c | 73 ++++++-- src/http/ngx_http_upstream.h | 2 +- src/http/ngx_http_variables.c | 12 ++ src/http/v2/ngx_http_v2.c | 32 ++-- src/http/v2/ngx_http_v2.h | 1 + src/http/v2/ngx_http_v2_filter_module.c | 16 +- src/http/v2/ngx_http_v2_table.c | 6 +- src/os/unix/ngx_user.c | 10 -- src/stream/ngx_stream_proxy_module.c | 14 +- src/stream/ngx_stream_upstream.h | 2 +- src/stream/ngx_stream_upstream_hash_module.c | 24 +-- src/stream/ngx_stream_upstream_zone_module.c | 2 +- src/stream/ngx_stream_variables.c | 14 +- 28 files changed, 408 insertions(+), 216 deletions(-) diff --git a/CHANGES b/CHANGES index e46199b..6a9fdcc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,40 @@ +Changes with nginx 1.13.6 10 Oct 2017 + + *) Bugfix: switching to the next upstream server in the stream module + did not work when using the "ssl_preread" directive. + + *) Bugfix: in the ngx_http_v2_module. + Thanks to Piotr Sikora. + + *) Bugfix: nginx did not support dates after the year 2038 on 32-bit + platforms with 64-bit time_t. + + *) Bugfix: in handling of dates prior to the year 1970 and after the + year 10000. + + *) Bugfix: in the stream module timeouts waiting for UDP datagrams from + upstream servers were not logged or logged at the "info" level + instead of "error". + + *) Bugfix: when using HTTP/2 nginx might return the 400 response without + logging the reason. + + *) Bugfix: in processing of corrupted cache files. + + *) Bugfix: cache control headers were ignored when caching errors + intercepted by error_page. + + *) Bugfix: when using HTTP/2 client request body might be corrupted. + + *) Bugfix: in handling of client addresses when using unix domain + sockets. + + *) Bugfix: nginx hogged CPU when using the "hash ... consistent" + directive in the upstream block if large weights were used and all or + most of the servers were unavailable. + + Changes with nginx 1.13.5 05 Sep 2017 *) Feature: the $ssl_client_escaped_cert variable. diff --git a/CHANGES.ru b/CHANGES.ru index 73c4164..6ea87c9 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,40 @@ +Изменения в nginx 1.13.6 10.10.2017 + + *) Исправление: при использовании директивы ssl_preread в модуле stream + не работало переключение на следующий бэкенд. + + *) Исправление: в модуле ngx_http_v2_module. + Спасибо Piotr Sikora. + + *) Исправление: nginx не поддерживал даты после 2038 года на 32-битных + платформах с 64-битным time_t. + + *) Исправление: в обработке дат до 1970 года и после 10000 года. + + *) Исправление: в модуле stream таймауты ожидания UDP-пакетов от + бэкендов не логгировались или логгировались на уровне info вместо + error. + + *) Исправление: при использовании HTTP/2 nginx мог вернуть ошибку 400, + не указав в логе причину. + + *) Исправление: в обработке повреждённых файлов кэша. + + *) Исправление: при кэшировании ошибок, перехваченных error_page, не + учитывались заголовки управления кэшированием. + + *) Исправление: при использовании HTTP/2 тело запроса могло быть + повреждено. + + *) Исправление: в обработке адресов клиентов при использовании unix + domain сокетов. + + *) Исправление: при использовании директивы "hash ... consistent" в + блоке upstream nginx нагружал процессор, если использовались большие + веса и все или почти все бэкенды были недоступны. + + Изменения в nginx 1.13.5 05.09.2017 *) Добавление: переменная $ssl_client_escaped_cert. diff --git a/conf/mime.types b/conf/mime.types index 89be9a4..8a2348a 100644 --- a/conf/mime.types +++ b/conf/mime.types @@ -1,89 +1,95 @@ types { - text/html html htm shtml; - text/css css; - text/xml xml; - image/gif gif; - image/jpeg jpeg jpg; - application/javascript js; - application/atom+xml atom; - application/rss+xml rss; + text/html html htm shtml; + text/css css; + text/xml xml; + image/gif gif; + image/jpeg jpeg jpg; + application/javascript js; + application/atom+xml atom; + application/rss+xml rss; - text/mathml mml; - text/plain txt; - text/vnd.sun.j2me.app-descriptor jad; - text/vnd.wap.wml wml; - text/x-component htc; + text/mathml mml; + text/plain txt; + text/vnd.sun.j2me.app-descriptor jad; + text/vnd.wap.wml wml; + text/x-component htc; - image/png png; - image/tiff tif tiff; - image/vnd.wap.wbmp wbmp; - image/x-icon ico; - image/x-jng jng; - image/x-ms-bmp bmp; - image/svg+xml svg svgz; - image/webp webp; + image/png png; + image/svg+xml svg svgz; + image/tiff tif tiff; + image/vnd.wap.wbmp wbmp; + image/webp webp; + image/x-icon ico; + image/x-jng jng; + image/x-ms-bmp bmp; - application/font-woff woff; - application/java-archive jar war ear; - application/json json; - application/mac-binhex40 hqx; - application/msword doc; - application/pdf pdf; - application/postscript ps eps ai; - application/rtf rtf; - application/vnd.apple.mpegurl m3u8; - application/vnd.ms-excel xls; - application/vnd.ms-fontobject eot; - application/vnd.ms-powerpoint ppt; - application/vnd.wap.wmlc wmlc; - application/vnd.google-earth.kml+xml kml; - application/vnd.google-earth.kmz kmz; - application/x-7z-compressed 7z; - application/x-cocoa cco; - application/x-java-archive-diff jardiff; - application/x-java-jnlp-file jnlp; - application/x-makeself run; - application/x-perl pl pm; - application/x-pilot prc pdb; - application/x-rar-compressed rar; - application/x-redhat-package-manager rpm; - application/x-sea sea; - application/x-shockwave-flash swf; - application/x-stuffit sit; - application/x-tcl tcl tk; - application/x-x509-ca-cert der pem crt; - application/x-xpinstall xpi; - application/xhtml+xml xhtml; - application/xspf+xml xspf; - application/zip zip; + application/font-woff woff; + application/java-archive jar war ear; + application/json json; + application/mac-binhex40 hqx; + application/msword doc; + application/pdf pdf; + application/postscript ps eps ai; + application/rtf rtf; + application/vnd.apple.mpegurl m3u8; + application/vnd.google-earth.kml+xml kml; + application/vnd.google-earth.kmz kmz; + application/vnd.ms-excel xls; + application/vnd.ms-fontobject eot; + application/vnd.ms-powerpoint ppt; + application/vnd.oasis.opendocument.graphics odg; + application/vnd.oasis.opendocument.presentation odp; + application/vnd.oasis.opendocument.spreadsheet ods; + application/vnd.oasis.opendocument.text odt; + application/vnd.openxmlformats-officedocument.presentationml.presentation + pptx; + application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + xlsx; + application/vnd.openxmlformats-officedocument.wordprocessingml.document + docx; + application/vnd.wap.wmlc wmlc; + application/x-7z-compressed 7z; + application/x-cocoa cco; + application/x-java-archive-diff jardiff; + application/x-java-jnlp-file jnlp; + application/x-makeself run; + application/x-perl pl pm; + application/x-pilot prc pdb; + application/x-rar-compressed rar; + application/x-redhat-package-manager rpm; + application/x-sea sea; + application/x-shockwave-flash swf; + application/x-stuffit sit; + application/x-tcl tcl tk; + application/x-x509-ca-cert der pem crt; + application/x-xpinstall xpi; + application/xhtml+xml xhtml; + application/xspf+xml xspf; + application/zip zip; - application/octet-stream bin exe dll; - application/octet-stream deb; - application/octet-stream dmg; - application/octet-stream iso img; - application/octet-stream msi msp msm; + application/octet-stream bin exe dll; + application/octet-stream deb; + application/octet-stream dmg; + application/octet-stream iso img; + application/octet-stream msi msp msm; - application/vnd.openxmlformats-officedocument.wordprocessingml.document docx; - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx; - application/vnd.openxmlformats-officedocument.presentationml.presentation pptx; + audio/midi mid midi kar; + audio/mpeg mp3; + audio/ogg ogg; + audio/x-m4a m4a; + audio/x-realaudio ra; - audio/midi mid midi kar; - audio/mpeg mp3; - audio/ogg ogg; - audio/x-m4a m4a; - audio/x-realaudio ra; - - video/3gpp 3gpp 3gp; - video/mp2t ts; - video/mp4 mp4; - video/mpeg mpeg mpg; - video/quicktime mov; - video/webm webm; - video/x-flv flv; - video/x-m4v m4v; - video/x-mng mng; - video/x-ms-asf asx asf; - video/x-ms-wmv wmv; - video/x-msvideo avi; + video/3gpp 3gpp 3gp; + video/mp2t ts; + video/mp4 mp4; + video/mpeg mpeg mpg; + video/quicktime mov; + video/webm webm; + video/x-flv flv; + video/x-m4v m4v; + video/x-mng mng; + video/x-ms-asf asx asf; + video/x-ms-wmv wmv; + video/x-msvideo avi; } diff --git a/src/core/nginx.h b/src/core/nginx.h index a3c0ef8..5806837 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1013005 -#define NGINX_VERSION "1.13.5" +#define nginx_version 1013006 +#define NGINX_VERSION "1.13.6" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 392fc35..9a74758 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -165,6 +165,10 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) continue; } + if (ls[i].socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { + ls[i].socklen = sizeof(ngx_sockaddr_t); + } + switch (ls[i].sockaddr->sa_family) { #if (NGX_HAVE_INET6) diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c index 3bcd3e7..db48b93 100644 --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -182,9 +182,11 @@ ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text, size_t len, ngx_uint_t port) { u_char *p; +#if (NGX_HAVE_INET6 || NGX_HAVE_UNIX_DOMAIN) + size_t n; +#endif struct sockaddr_in *sin; #if (NGX_HAVE_INET6) - size_t n; struct sockaddr_in6 *sin6; #endif #if (NGX_HAVE_UNIX_DOMAIN) @@ -241,7 +243,9 @@ ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text, size_t len, p = ngx_snprintf(text, len, "unix:%Z"); } else { - p = ngx_snprintf(text, len, "unix:%s%Z", saun->sun_path); + n = ngx_strnlen((u_char *) saun->sun_path, + socklen - offsetof(struct sockaddr_un, sun_path)); + p = ngx_snprintf(text, len, "unix:%*s%Z", n, saun->sun_path); } /* we do not include trailing zero in address length */ diff --git a/src/core/ngx_inet.h b/src/core/ngx_inet.h index 538771e..a3b392e 100644 --- a/src/core/ngx_inet.h +++ b/src/core/ngx_inet.h @@ -17,10 +17,11 @@ #define NGX_INET6_ADDRSTRLEN \ (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - 1) #define NGX_UNIX_ADDRSTRLEN \ - (sizeof(struct sockaddr_un) - offsetof(struct sockaddr_un, sun_path)) + (sizeof("unix:") - 1 + \ + sizeof(struct sockaddr_un) - offsetof(struct sockaddr_un, sun_path)) #if (NGX_HAVE_UNIX_DOMAIN) -#define NGX_SOCKADDR_STRLEN (sizeof("unix:") - 1 + NGX_UNIX_ADDRSTRLEN) +#define NGX_SOCKADDR_STRLEN NGX_UNIX_ADDRSTRLEN #elif (NGX_HAVE_INET6) #define NGX_SOCKADDR_STRLEN (NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1) #else diff --git a/src/core/ngx_parse_time.c b/src/core/ngx_parse_time.c index a5c5034..232ac91 100644 --- a/src/core/ngx_parse_time.c +++ b/src/core/ngx_parse_time.c @@ -44,14 +44,15 @@ ngx_parse_http_time(u_char *value, size_t len) } } - for (p++; p < end; p++) + for (p++; p < end; p++) { if (*p != ' ') { break; } + } if (end - p < 18) { return NGX_ERROR; - } + } if (fmt != isoc) { if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') { diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index de10a06..2ee07bf 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -29,6 +29,22 @@ ngx_strlow(u_char *dst, u_char *src, size_t n) } +size_t +ngx_strnlen(u_char *p, size_t n) +{ + size_t i; + + for (i = 0; i < n; i++) { + + if (p[i] == '\0') { + return i; + } + } + + return n; +} + + u_char * ngx_cpystrn(u_char *dst, u_char *src, size_t n) { diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h index 7363bd2..882ae7c 100644 --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -60,6 +60,8 @@ void ngx_strlow(u_char *dst, u_char *src, size_t n); #define ngx_strstr(s1, s2) strstr((const char *) s1, (const char *) s2) #define ngx_strlen(s) strlen((const char *) s) +size_t ngx_strnlen(u_char *p, size_t n); + #define ngx_strchr(s1, c) strchr((const char *) s1, (int) c) static ngx_inline u_char * diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c index 843314a..b2edf1a 100644 --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -300,27 +300,39 @@ void ngx_gmtime(time_t t, ngx_tm_t *tp) { ngx_int_t yday; - ngx_uint_t n, sec, min, hour, mday, mon, year, wday, days, leap; + ngx_uint_t sec, min, hour, mday, mon, year, wday, days, leap; /* the calculation is valid for positive time_t only */ - n = (ngx_uint_t) t; + if (t < 0) { + t = 0; + } - days = n / 86400; + days = t / 86400; + sec = t % 86400; + + /* + * no more than 4 year digits supported, + * truncate to December 31, 9999, 23:59:59 + */ + + if (days > 2932896) { + days = 2932896; + sec = 86399; + } /* January 1, 1970 was Thursday */ wday = (4 + days) % 7; - n %= 86400; - hour = n / 3600; - n %= 3600; - min = n / 60; - sec = n % 60; + hour = sec / 3600; + sec %= 3600; + min = sec / 60; + sec %= 60; /* * the algorithm based on Gauss' formula, - * see src/http/ngx_http_parse_time.c + * see src/core/ngx_parse_time.c */ /* days since March 1, 1 BC */ diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index 87447d0..7756370 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -164,6 +164,10 @@ ngx_event_accept(ngx_event_t *ev) return; } + if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { + socklen = sizeof(ngx_sockaddr_t); + } + c->sockaddr = ngx_palloc(c->pool, socklen); if (c->sockaddr == NULL) { ngx_close_accepted_connection(c); @@ -440,6 +444,10 @@ ngx_event_recvmsg(ngx_event_t *ev) c->type = SOCK_DGRAM; c->socklen = msg.msg_namelen; + if (c->socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { + c->socklen = sizeof(ngx_sockaddr_t); + } + #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, 1); #endif diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c index 4aa684f..2f345b6 100644 --- a/src/http/modules/ngx_http_auth_basic_module.c +++ b/src/http/modules/ngx_http_auth_basic_module.c @@ -14,11 +14,6 @@ #define NGX_HTTP_AUTH_BUF_SIZE 2048 -typedef struct { - ngx_str_t passwd; -} ngx_http_auth_basic_ctx_t; - - typedef struct { ngx_http_complex_value_t *realm; ngx_http_complex_value_t user_file; @@ -27,7 +22,7 @@ typedef struct { static ngx_int_t ngx_http_auth_basic_handler(ngx_http_request_t *r); static ngx_int_t ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r, - ngx_http_auth_basic_ctx_t *ctx, ngx_str_t *passwd, ngx_str_t *realm); + ngx_str_t *passwd, ngx_str_t *realm); static ngx_int_t ngx_http_auth_basic_set_realm(ngx_http_request_t *r, ngx_str_t *realm); static void ngx_http_auth_basic_close(ngx_file_t *file); @@ -103,7 +98,6 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r) ngx_str_t pwd, realm, user_file; ngx_uint_t i, level, login, left, passwd; ngx_file_t file; - ngx_http_auth_basic_ctx_t *ctx; ngx_http_auth_basic_loc_conf_t *alcf; u_char buf[NGX_HTTP_AUTH_BUF_SIZE]; enum { @@ -126,13 +120,6 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r) return NGX_DECLINED; } - ctx = ngx_http_get_module_ctx(r, ngx_http_auth_basic_module); - - if (ctx) { - return ngx_http_auth_basic_crypt_handler(r, ctx, &ctx->passwd, - &realm); - } - rc = ngx_http_auth_basic_user(r); if (rc == NGX_DECLINED) { @@ -237,8 +224,7 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r) pwd.len = i - passwd; pwd.data = &buf[passwd]; - return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd, - &realm); + return ngx_http_auth_basic_crypt_handler(r, &pwd, &realm); } break; @@ -276,7 +262,7 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r) ngx_cpystrn(pwd.data, &buf[passwd], pwd.len + 1); - return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd, &realm); + return ngx_http_auth_basic_crypt_handler(r, &pwd, &realm); } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, @@ -288,8 +274,8 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r) static ngx_int_t -ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r, - ngx_http_auth_basic_ctx_t *ctx, ngx_str_t *passwd, ngx_str_t *realm) +ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r, ngx_str_t *passwd, + ngx_str_t *realm) { ngx_int_t rc; u_char *encrypted; @@ -301,48 +287,22 @@ ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r, "rc: %i user: \"%V\" salt: \"%s\"", rc, &r->headers_in.user, passwd->data); - if (rc == NGX_OK) { - if (ngx_strcmp(encrypted, passwd->data) == 0) { - return NGX_OK; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "encrypted: \"%s\"", encrypted); - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "user \"%V\": password mismatch", - &r->headers_in.user); - - return ngx_http_auth_basic_set_realm(r, realm); - } - - if (rc == NGX_ERROR) { + if (rc != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - /* rc == NGX_AGAIN */ - - if (ctx == NULL) { - ctx = ngx_palloc(r->pool, sizeof(ngx_http_auth_basic_ctx_t)); - if (ctx == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_http_set_ctx(r, ctx, ngx_http_auth_basic_module); - - ctx->passwd.len = passwd->len; - passwd->len++; - - ctx->passwd.data = ngx_pstrdup(r->pool, passwd); - if (ctx->passwd.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - + if (ngx_strcmp(encrypted, passwd->data) == 0) { + return NGX_OK; } - /* TODO: add mutex event */ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "encrypted: \"%s\"", encrypted); - return rc; + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "user \"%V\": password mismatch", + &r->headers_in.user); + + return ngx_http_auth_basic_set_realm(r, realm); } diff --git a/src/http/modules/ngx_http_upstream_hash_module.c b/src/http/modules/ngx_http_upstream_hash_module.c index 6c28c64..d67f34d 100644 --- a/src/http/modules/ngx_http_upstream_hash_module.c +++ b/src/http/modules/ngx_http_upstream_hash_module.c @@ -503,6 +503,11 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) ngx_http_upstream_rr_peers_wlock(hp->rrp.peers); + if (hp->tries > 20 || hp->rrp.peers->single) { + ngx_http_upstream_rr_peers_unlock(hp->rrp.peers); + return hp->get_rr_peer(pc, &hp->rrp); + } + pc->cached = 0; pc->connection = NULL; @@ -538,13 +543,6 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) continue; } - if (peer->server.len != server->len - || ngx_strncmp(peer->server.data, server->data, server->len) - != 0) - { - continue; - } - if (peer->max_fails && peer->fails >= peer->max_fails && now - peer->checked <= peer->fail_timeout) @@ -556,6 +554,13 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) continue; } + if (peer->server.len != server->len + || ngx_strncmp(peer->server.data, server->data, server->len) + != 0) + { + continue; + } + peer->current_weight += peer->effective_weight; total += peer->effective_weight; @@ -577,10 +582,9 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) hp->hash++; hp->tries++; - if (hp->tries >= points->number) { - pc->name = hp->rrp.peers->name; + if (hp->tries > 20) { ngx_http_upstream_rr_peers_unlock(hp->rrp.peers); - return NGX_BUSY; + return hp->get_rr_peer(pc, &hp->rrp); } } diff --git a/src/http/modules/ngx_http_upstream_zone_module.c b/src/http/modules/ngx_http_upstream_zone_module.c index d340b48..3229cfe 100644 --- a/src/http/modules/ngx_http_upstream_zone_module.c +++ b/src/http/modules/ngx_http_upstream_zone_module.c @@ -281,7 +281,7 @@ ngx_http_upstream_zone_copy_peer(ngx_http_upstream_rr_peers_t *peers, dst->server.data = NULL; } - dst->sockaddr = ngx_slab_calloc_locked(pool, NGX_SOCKADDRLEN); + dst->sockaddr = ngx_slab_calloc_locked(pool, sizeof(ngx_sockaddr_t)); if (dst->sockaddr == NULL) { goto failed; } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 73a5882..2ea521b 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -582,6 +582,9 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) { rc = NGX_DECLINED; r->cached = 0; + u->buffer.start = NULL; + u->cache_status = NGX_HTTP_CACHE_MISS; + u->request_sent = 1; } if (ngx_http_upstream_cache_background_update(r, u) != NGX_OK) { @@ -1059,8 +1062,16 @@ ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u) return NGX_ERROR; } + if (rc == NGX_AGAIN) { + rc = NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + /* rc == NGX_HTTP_UPSTREAM_INVALID_HEADER */ + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + "cache file \"%s\" contains invalid header", + c->file.name.data); + /* TODO: delete file */ return rc; @@ -2393,9 +2404,20 @@ ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u) rc = u->reinit_request(r); - if (rc == NGX_OK) { - u->cache_status = NGX_HTTP_CACHE_STALE; - rc = ngx_http_upstream_cache_send(r, u); + if (rc != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, rc); + return NGX_OK; + } + + u->cache_status = NGX_HTTP_CACHE_STALE; + rc = ngx_http_upstream_cache_send(r, u); + + if (rc == NGX_DONE) { + return NGX_OK; + } + + if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) { + rc = NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_upstream_finalize_request(r, u, rc); @@ -2433,6 +2455,14 @@ ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u) u->cache_status = NGX_HTTP_CACHE_REVALIDATED; rc = ngx_http_upstream_cache_send(r, u); + if (rc == NGX_DONE) { + return NGX_OK; + } + + if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) { + rc = NGX_HTTP_INTERNAL_SERVER_ERROR; + } + if (valid == 0) { valid = r->cache->valid_sec; updating = r->cache->updating_sec; @@ -2518,13 +2548,23 @@ ngx_http_upstream_intercept_errors(ngx_http_request_t *r, #if (NGX_HTTP_CACHE) if (r->cache) { - time_t valid; - valid = ngx_http_file_cache_valid(u->conf->cache_valid, status); + if (u->cacheable) { + time_t valid; - if (valid) { - r->cache->valid_sec = ngx_time() + valid; - r->cache->error = status; + valid = r->cache->valid_sec; + + if (valid == 0) { + valid = ngx_http_file_cache_valid(u->conf->cache_valid, + status); + if (valid) { + r->cache->valid_sec = ngx_time() + valid; + } + } + + if (valid) { + r->cache->error = status; + } } ngx_http_file_cache_free(r->cache, u->pipe->temp_file); @@ -4129,9 +4169,20 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, rc = u->reinit_request(r); - if (rc == NGX_OK) { - u->cache_status = NGX_HTTP_CACHE_STALE; - rc = ngx_http_upstream_cache_send(r, u); + if (rc != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, rc); + return; + } + + u->cache_status = NGX_HTTP_CACHE_STALE; + rc = ngx_http_upstream_cache_send(r, u); + + if (rc == NGX_DONE) { + return; + } + + if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) { + rc = NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_upstream_finalize_request(r, u, rc); diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index c552ac0..3e714e5 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -98,8 +98,8 @@ typedef struct { ngx_uint_t max_fails; time_t fail_timeout; ngx_msec_t slow_start; + ngx_uint_t down; - unsigned down:1; unsigned backup:1; NGX_COMPAT_BEGIN(6) diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index afeb4ce..ab82177 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -1240,6 +1240,18 @@ ngx_http_variable_binary_remote_addr(ngx_http_request_t *r, break; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + + v->len = r->connection->addr_text.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = r->connection->addr_text.data; + + break; +#endif + default: /* AF_INET */ sin = (struct sockaddr_in *) r->connection->sockaddr; diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 7725616..2c62190 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -245,6 +245,8 @@ ngx_http_v2_init(ngx_event_t *rev) h2c->frame_size = NGX_HTTP_V2_DEFAULT_FRAME_SIZE; + h2c->table_update = 1; + h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module); h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); @@ -746,7 +748,7 @@ ngx_http_v2_state_head(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) type = ngx_http_v2_parse_type(head); ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "process http2 frame type:%ui f:%Xd l:%uz sid:%ui", + "http2 frame type:%ui f:%Xd l:%uz sid:%ui", type, h2c->state.flags, h2c->state.length, h2c->state.sid); if (type >= NGX_HTTP_V2_FRAME_STATES) { @@ -1314,7 +1316,7 @@ ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c, u_char *pos, } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2 hpack %s string length: %i", + "http2 %s string, len:%i", huff ? "encoded" : "raw", len); h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, @@ -1569,7 +1571,7 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, if (rc == NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http2 pseudo-header: \":%V: %V\"", + "http2 header: \":%V: %V\"", &header->name, &header->value); return ngx_http_v2_state_header_complete(h2c, pos, end); @@ -1645,7 +1647,7 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http2 http header: \"%V: %V\"", + "http2 header: \"%V: %V\"", &header->name, &header->value); return ngx_http_v2_state_header_complete(h2c, pos, end); @@ -3335,6 +3337,19 @@ ngx_http_v2_construct_request_line(ngx_http_request_t *r) || r->schema_start == NULL || r->unparsed_uri.len == 0) { + if (r->method_name.len == 0) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent no :method header"); + + } else if (r->schema_start == NULL) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent no :schema header"); + + } else { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent no :path header"); + } + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); return NGX_ERROR; } @@ -3360,7 +3375,7 @@ ngx_http_v2_construct_request_line(ngx_http_request_t *r) ngx_memcpy(p, ending, sizeof(ending)); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http2 http request line: \"%V\"", &r->request_line); + "http2 request line: \"%V\"", &r->request_line); return NGX_OK; } @@ -3574,11 +3589,6 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r) rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); } else { - if (stream->preread) { - /* enforce writing preread buffer to file */ - r->request_body_in_file_only = 1; - } - rb->buf = ngx_calloc_buf(r->pool); if (rb->buf != NULL) { @@ -3679,6 +3689,8 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, buf->pos = buf->start = pos; buf->last = buf->end = pos + size; + r->request_body_in_file_only = 1; + } else { if (size > (size_t) (buf->end - buf->last)) { ngx_log_error(NGX_LOG_INFO, fc->log, 0, diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 4804658..42e0eb1 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -144,6 +144,7 @@ struct ngx_http_v2_connection_s { unsigned closed_nodes:8; unsigned settings_ack:1; + unsigned table_update:1; unsigned blocked:1; unsigned goaway:1; }; diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index 8621e7a..9070785 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -139,6 +139,7 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) ngx_connection_t *fc; ngx_http_cleanup_t *cln; ngx_http_v2_out_frame_t *frame; + ngx_http_v2_connection_t *h2c; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; u_char addr[NGX_SOCKADDR_STRLEN]; @@ -235,7 +236,11 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) } } - len = status ? 1 : 1 + ngx_http_v2_literal_size("418"); + h2c = r->stream->connection; + + len = h2c->table_update ? 1 : 0; + + len += status ? 1 : 1 + ngx_http_v2_literal_size("418"); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); @@ -423,6 +428,13 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) start = pos; + if (h2c->table_update) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 table size update: 0"); + *pos++ = (1 << 5) | 0; + h2c->table_update = 0; + } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, "http2 output header: \":status: %03ui\"", r->headers_out.status); @@ -1257,7 +1269,7 @@ ngx_http_v2_flow_control(ngx_http_v2_connection_t *h2c, ngx_http_v2_stream_t *stream) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2:%ui available windows: conn:%uz stream:%z", + "http2:%ui windows: conn:%uz stream:%z", stream->node->id, h2c->send_window, stream->send_window); if (stream->send_window <= 0) { diff --git a/src/http/v2/ngx_http_v2_table.c b/src/http/v2/ngx_http_v2_table.c index a73748a..62025c4 100644 --- a/src/http/v2/ngx_http_v2_table.c +++ b/src/http/v2/ngx_http_v2_table.c @@ -102,7 +102,7 @@ ngx_http_v2_get_indexed_header(ngx_http_v2_connection_t *h2c, ngx_uint_t index, ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, "http2 get indexed %s: %ui", - name_only ? "header" : "header name", index); + name_only ? "name" : "header", index); index--; @@ -180,7 +180,7 @@ ngx_http_v2_add_header(ngx_http_v2_connection_t *h2c, ngx_http_v2_header_t *entry, **entries; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2 add header to hpack table: \"%V: %V\"", + "http2 table add: \"%V: %V\"", &header->name, &header->value); if (h2c->hpack.entries == NULL) { @@ -293,7 +293,7 @@ ngx_http_v2_table_account(ngx_http_v2_connection_t *h2c, size_t size) size += 32; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2 hpack table account: %uz free:%uz", + "http2 table account: %uz free:%uz", size, h2c->hpack.free); if (size <= h2c->hpack.free) { diff --git a/src/os/unix/ngx_user.c b/src/os/unix/ngx_user.c index 27c76ef..7ebe2b5 100644 --- a/src/os/unix/ngx_user.c +++ b/src/os/unix/ngx_user.c @@ -9,16 +9,6 @@ #include -/* - * Solaris has thread-safe crypt() - * Linux has crypt_r(); "struct crypt_data" is more than 128K - * FreeBSD needs the mutex to protect crypt() - * - * TODO: - * ngx_crypt_init() to init mutex - */ - - #if (NGX_CRYPT) #if (NGX_HAVE_GNU_CRYPT_R) diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 0afde1c..9d4b075 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -1331,13 +1331,17 @@ ngx_stream_proxy_process_connection(ngx_event_t *ev, ngx_uint_t from_upstream) return; } + ngx_connection_error(pc, NGX_ETIMEDOUT, "upstream timed out"); + if (u->received == 0) { ngx_stream_proxy_next_upstream(s); return; } + + } else { + ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); } - ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); ngx_stream_proxy_finalize(s, NGX_STREAM_OK); return; } @@ -1665,13 +1669,17 @@ ngx_stream_proxy_next_upstream(ngx_stream_session_t *s) u = s->upstream; pc = u->peer.connection; - if (u->upstream_out || u->upstream_busy || (pc && pc->buffered)) { + if (pc && pc->buffered) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, - "pending buffers on next upstream"); + "buffered data on next upstream"); ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } + if (s->connection->type == SOCK_DGRAM) { + u->upstream_out = NULL; + } + if (u->peer.sockaddr) { u->peer.free(&u->peer, u->peer.data, NGX_PEER_FAILED); u->peer.sockaddr = NULL; diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h index 90076e0..73947f4 100644 --- a/src/stream/ngx_stream_upstream.h +++ b/src/stream/ngx_stream_upstream.h @@ -58,8 +58,8 @@ typedef struct { ngx_uint_t max_fails; time_t fail_timeout; ngx_msec_t slow_start; + ngx_uint_t down; - unsigned down:1; unsigned backup:1; NGX_COMPAT_BEGIN(4) diff --git a/src/stream/ngx_stream_upstream_hash_module.c b/src/stream/ngx_stream_upstream_hash_module.c index cb44fcd..79ad742 100644 --- a/src/stream/ngx_stream_upstream_hash_module.c +++ b/src/stream/ngx_stream_upstream_hash_module.c @@ -505,6 +505,11 @@ ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) ngx_stream_upstream_rr_peers_wlock(hp->rrp.peers); + if (hp->tries > 20 || hp->rrp.peers->single) { + ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers); + return hp->get_rr_peer(pc, &hp->rrp); + } + pc->connection = NULL; now = ngx_time(); @@ -539,13 +544,6 @@ ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) continue; } - if (peer->server.len != server->len - || ngx_strncmp(peer->server.data, server->data, server->len) - != 0) - { - continue; - } - if (peer->max_fails && peer->fails >= peer->max_fails && now - peer->checked <= peer->fail_timeout) @@ -557,6 +555,13 @@ ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) continue; } + if (peer->server.len != server->len + || ngx_strncmp(peer->server.data, server->data, server->len) + != 0) + { + continue; + } + peer->current_weight += peer->effective_weight; total += peer->effective_weight; @@ -578,10 +583,9 @@ ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) hp->hash++; hp->tries++; - if (hp->tries >= points->number) { - pc->name = hp->rrp.peers->name; + if (hp->tries > 20) { ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers); - return NGX_BUSY; + return hp->get_rr_peer(pc, &hp->rrp); } } diff --git a/src/stream/ngx_stream_upstream_zone_module.c b/src/stream/ngx_stream_upstream_zone_module.c index 4f72188..80d42fa 100644 --- a/src/stream/ngx_stream_upstream_zone_module.c +++ b/src/stream/ngx_stream_upstream_zone_module.c @@ -278,7 +278,7 @@ ngx_stream_upstream_zone_copy_peer(ngx_stream_upstream_rr_peers_t *peers, dst->server.data = NULL; } - dst->sockaddr = ngx_slab_calloc_locked(pool, NGX_SOCKADDRLEN); + dst->sockaddr = ngx_slab_calloc_locked(pool, sizeof(ngx_sockaddr_t)); if (dst->sockaddr == NULL) { goto failed; } diff --git a/src/stream/ngx_stream_variables.c b/src/stream/ngx_stream_variables.c index 45d6e60..95ae12b 100644 --- a/src/stream/ngx_stream_variables.c +++ b/src/stream/ngx_stream_variables.c @@ -460,7 +460,7 @@ ngx_stream_get_variable(ngx_stream_session_t *s, ngx_str_t *name, static ngx_int_t ngx_stream_variable_binary_remote_addr(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) - { +{ struct sockaddr_in *sin; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; @@ -481,6 +481,18 @@ ngx_stream_variable_binary_remote_addr(ngx_stream_session_t *s, break; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + + v->len = s->connection->addr_text.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = s->connection->addr_text.data; + + break; +#endif + default: /* AF_INET */ sin = (struct sockaddr_in *) s->connection->sockaddr; From 515a80bc0a2ead9c5b7b8c5db9172869c0a0eab9 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 11 Sep 2017 17:55:23 +0300 Subject: [PATCH 271/651] mod: Normalize module locations Use the package name to infer module location. This will make it easier to script our maintaining tasks. --- debian/copyright | 28 +++++++-------- .../ChangeLog | 0 .../{nginx-auth-pam => http-auth-pam}/LICENSE | 0 .../README.md | 0 .../{nginx-auth-pam => http-auth-pam}/VERSION | 0 .../{nginx-auth-pam => http-auth-pam}/config | 0 .../ngx_http_auth_pam_module.c | 0 .../CHANGES | 0 .../LICENSE | 0 .../README.md | 0 .../TODO.md | 0 .../config | 0 .../ngx_cache_purge_module.c | 0 .../t/proxy1.t | 0 .../t/proxy1_vars.t | 0 .../t/proxy2.t | 0 .../t/proxy2_vars.t | 0 .../README | 0 .../config | 0 .../ngx_http_dav_ext_module.c | 0 .../modules/{nginx-echo => http-echo}/LICENSE | 0 .../{nginx-echo => http-echo}/README.markdown | 0 .../modules/{nginx-echo => http-echo}/config | 0 .../{nginx-echo => http-echo}/src/ddebug.h | 0 .../src/ngx_http_echo_echo.c | 0 .../src/ngx_http_echo_echo.h | 0 .../src/ngx_http_echo_filter.c | 0 .../src/ngx_http_echo_filter.h | 0 .../src/ngx_http_echo_foreach.c | 0 .../src/ngx_http_echo_foreach.h | 0 .../src/ngx_http_echo_handler.c | 0 .../src/ngx_http_echo_handler.h | 0 .../src/ngx_http_echo_location.c | 0 .../src/ngx_http_echo_location.h | 0 .../src/ngx_http_echo_module.c | 0 .../src/ngx_http_echo_module.h | 0 .../src/ngx_http_echo_request_info.c | 0 .../src/ngx_http_echo_request_info.h | 0 .../src/ngx_http_echo_sleep.c | 0 .../src/ngx_http_echo_sleep.h | 0 .../src/ngx_http_echo_subrequest.c | 0 .../src/ngx_http_echo_subrequest.h | 0 .../src/ngx_http_echo_timer.c | 0 .../src/ngx_http_echo_timer.h | 0 .../src/ngx_http_echo_util.c | 0 .../src/ngx_http_echo_util.h | 0 .../src/ngx_http_echo_var.c | 0 .../src/ngx_http_echo_var.h | 0 .../t/abort-parent.t | 0 .../t/blocking-sleep.t | 0 .../t/echo-after-body.t | 0 .../t/echo-before-body.t | 0 .../t/echo-duplicate.t | 0 .../{nginx-echo => http-echo}/t/echo-timer.t | 0 .../{nginx-echo => http-echo}/t/echo.t | 0 .../{nginx-echo => http-echo}/t/exec.t | 0 .../{nginx-echo => http-echo}/t/filter-used.t | 0 .../t/foreach-split.t | 0 .../{nginx-echo => http-echo}/t/gzip.t | 0 .../modules/{nginx-echo => http-echo}/t/if.t | 0 .../{nginx-echo => http-echo}/t/incr.t | 0 .../t/location-async.t | 0 .../{nginx-echo => http-echo}/t/location.t | 0 .../{nginx-echo => http-echo}/t/mixed.t | 0 .../t/request-body.t | 0 .../t/request-info.t | 0 .../{nginx-echo => http-echo}/t/sleep.t | 0 .../{nginx-echo => http-echo}/t/status.t | 0 .../t/subrequest-async.t | 0 .../{nginx-echo => http-echo}/t/subrequest.t | 0 .../{nginx-echo => http-echo}/t/unused.t | 0 .../{nginx-echo => http-echo}/util/build.sh | 0 .../{nginx-echo => http-echo}/util/releng | 0 .../util/wiki2pod.pl | 0 .../valgrind.suppress | 0 .../CHANGELOG.md | 0 .../HACKING.md | 0 .../LICENSE | 0 .../README.rst | 0 .../config | 0 .../nginx-0.6-support.patch | 0 .../ngx_http_fancyindex_module.c | 0 .../t/00-build-artifacts.test | 0 .../t/01-smoke-hasindex.test | 0 .../t/02-smoke-indexisfancy.test | 0 .../t/build-and-run | 0 .../t/has-index.test | 0 .../t/has-index/index.html | 0 .../t/nginx.conf | 0 .../t/preamble | 0 .../{ngx-fancyindex => http-fancyindex}/t/run | 0 .../template.awk | 0 .../template.h | 0 .../template.html | 0 .../README.markdown | 0 .../config | 0 .../src/ddebug.h | 0 .../src/ngx_http_headers_more_filter_module.c | 0 .../src/ngx_http_headers_more_filter_module.h | 0 .../src/ngx_http_headers_more_headers_in.c | 0 .../src/ngx_http_headers_more_headers_in.h | 0 .../src/ngx_http_headers_more_headers_out.c | 0 .../src/ngx_http_headers_more_headers_out.h | 0 .../src/ngx_http_headers_more_util.c | 0 .../src/ngx_http_headers_more_util.h | 0 .../t/bug.t | 0 .../t/builtin.t | 0 .../t/eval.t | 0 .../t/input-conn.t | 0 .../t/input-cookie.t | 0 .../t/input-ua.t | 0 .../t/input.t | 0 .../t/phase.t | 0 .../t/sanity.t | 0 .../t/subrequest.t | 0 .../t/unused.t | 0 .../t/vars.t | 0 .../util/build.sh | 0 .../valgrind.suppress | 0 .../{nginx-lua => http-lua}/README.markdown | 0 debian/modules/{nginx-lua => http-lua}/config | 0 .../doc/HttpLuaModule.wiki | 0 .../dtrace/ngx_lua_provider.d | 0 .../misc/recv-until-pm/Makefile | 0 .../misc/recv-until-pm/lib/RecvUntil.pm | 0 .../misc/recv-until-pm/t/sanity.t | 0 .../src/api/ngx_http_lua_api.h | 0 .../{nginx-lua => http-lua}/src/ddebug.h | 0 .../src/ngx_http_lua_accessby.c | 0 .../src/ngx_http_lua_accessby.h | 0 .../src/ngx_http_lua_api.c | 0 .../src/ngx_http_lua_args.c | 0 .../src/ngx_http_lua_args.h | 0 .../src/ngx_http_lua_balancer.c | 0 .../src/ngx_http_lua_balancer.h | 0 .../src/ngx_http_lua_bodyfilterby.c | 0 .../src/ngx_http_lua_bodyfilterby.h | 0 .../src/ngx_http_lua_cache.c | 0 .../src/ngx_http_lua_cache.h | 0 .../src/ngx_http_lua_capturefilter.c | 0 .../src/ngx_http_lua_capturefilter.h | 0 .../src/ngx_http_lua_clfactory.c | 0 .../src/ngx_http_lua_clfactory.h | 0 .../src/ngx_http_lua_common.h | 0 .../src/ngx_http_lua_config.c | 0 .../src/ngx_http_lua_config.h | 0 .../src/ngx_http_lua_consts.c | 0 .../src/ngx_http_lua_consts.h | 0 .../src/ngx_http_lua_contentby.c | 0 .../src/ngx_http_lua_contentby.h | 0 .../src/ngx_http_lua_control.c | 0 .../src/ngx_http_lua_control.h | 0 .../src/ngx_http_lua_coroutine.c | 0 .../src/ngx_http_lua_coroutine.h | 0 .../src/ngx_http_lua_ctx.c | 0 .../src/ngx_http_lua_ctx.h | 0 .../src/ngx_http_lua_directive.c | 0 .../src/ngx_http_lua_directive.h | 0 .../src/ngx_http_lua_exception.c | 0 .../src/ngx_http_lua_exception.h | 0 .../src/ngx_http_lua_headerfilterby.c | 0 .../src/ngx_http_lua_headerfilterby.h | 0 .../src/ngx_http_lua_headers.c | 0 .../src/ngx_http_lua_headers.h | 0 .../src/ngx_http_lua_headers_in.c | 0 .../src/ngx_http_lua_headers_in.h | 0 .../src/ngx_http_lua_headers_out.c | 0 .../src/ngx_http_lua_headers_out.h | 0 .../src/ngx_http_lua_initby.c | 0 .../src/ngx_http_lua_initby.h | 0 .../src/ngx_http_lua_initworkerby.c | 0 .../src/ngx_http_lua_initworkerby.h | 0 .../src/ngx_http_lua_lex.c | 0 .../src/ngx_http_lua_lex.h | 0 .../src/ngx_http_lua_log.c | 0 .../src/ngx_http_lua_log.h | 0 .../src/ngx_http_lua_log_ringbuf.c | 0 .../src/ngx_http_lua_log_ringbuf.h | 0 .../src/ngx_http_lua_logby.c | 0 .../src/ngx_http_lua_logby.h | 0 .../src/ngx_http_lua_misc.c | 0 .../src/ngx_http_lua_misc.h | 0 .../src/ngx_http_lua_module.c | 0 .../src/ngx_http_lua_ndk.c | 0 .../src/ngx_http_lua_ndk.h | 0 .../src/ngx_http_lua_output.c | 0 .../src/ngx_http_lua_output.h | 0 .../src/ngx_http_lua_pcrefix.c | 0 .../src/ngx_http_lua_pcrefix.h | 0 .../src/ngx_http_lua_phase.c | 0 .../src/ngx_http_lua_phase.h | 0 .../src/ngx_http_lua_probe.h | 0 .../src/ngx_http_lua_regex.c | 0 .../src/ngx_http_lua_regex.h | 0 .../src/ngx_http_lua_req_body.c | 0 .../src/ngx_http_lua_req_body.h | 0 .../src/ngx_http_lua_req_method.c | 0 .../src/ngx_http_lua_req_method.h | 0 .../src/ngx_http_lua_rewriteby.c | 0 .../src/ngx_http_lua_rewriteby.h | 0 .../src/ngx_http_lua_script.c | 0 .../src/ngx_http_lua_script.h | 0 .../src/ngx_http_lua_semaphore.c | 0 .../src/ngx_http_lua_semaphore.h | 0 .../src/ngx_http_lua_setby.c | 0 .../src/ngx_http_lua_setby.h | 0 .../src/ngx_http_lua_shdict.c | 0 .../src/ngx_http_lua_shdict.h | 0 .../src/ngx_http_lua_sleep.c | 0 .../src/ngx_http_lua_sleep.h | 0 .../src/ngx_http_lua_socket_tcp.c | 0 .../src/ngx_http_lua_socket_tcp.h | 0 .../src/ngx_http_lua_socket_udp.c | 0 .../src/ngx_http_lua_socket_udp.h | 0 .../src/ngx_http_lua_ssl.c | 0 .../src/ngx_http_lua_ssl.h | 0 .../src/ngx_http_lua_ssl_certby.c | 0 .../src/ngx_http_lua_ssl_certby.h | 0 .../src/ngx_http_lua_ssl_ocsp.c | 0 .../src/ngx_http_lua_ssl_session_fetchby.c | 0 .../src/ngx_http_lua_ssl_session_fetchby.h | 0 .../src/ngx_http_lua_ssl_session_storeby.c | 0 .../src/ngx_http_lua_ssl_session_storeby.h | 0 .../src/ngx_http_lua_string.c | 0 .../src/ngx_http_lua_string.h | 0 .../src/ngx_http_lua_subrequest.c | 0 .../src/ngx_http_lua_subrequest.h | 0 .../src/ngx_http_lua_time.c | 0 .../src/ngx_http_lua_time.h | 0 .../src/ngx_http_lua_timer.c | 0 .../src/ngx_http_lua_timer.h | 0 .../src/ngx_http_lua_uri.c | 0 .../src/ngx_http_lua_uri.h | 0 .../src/ngx_http_lua_uthread.c | 0 .../src/ngx_http_lua_uthread.h | 0 .../src/ngx_http_lua_util.c | 0 .../src/ngx_http_lua_util.h | 0 .../src/ngx_http_lua_variable.c | 0 .../src/ngx_http_lua_variable.h | 0 .../src/ngx_http_lua_worker.c | 0 .../src/ngx_http_lua_worker.h | 0 .../{nginx-lua => http-lua}/t/.gitignore | 0 .../{nginx-lua => http-lua}/t/000--init.t | 0 .../{nginx-lua => http-lua}/t/000-sanity.t | 0 .../{nginx-lua => http-lua}/t/001-set.t | 0 .../{nginx-lua => http-lua}/t/002-content.t | 0 .../{nginx-lua => http-lua}/t/003-errors.t | 0 .../{nginx-lua => http-lua}/t/004-require.t | 0 .../{nginx-lua => http-lua}/t/005-exit.t | 0 .../{nginx-lua => http-lua}/t/006-escape.t | 0 .../{nginx-lua => http-lua}/t/007-md5.t | 0 .../{nginx-lua => http-lua}/t/008-today.t | 0 .../{nginx-lua => http-lua}/t/009-log.t | 0 .../t/010-request_body.t | 0 .../{nginx-lua => http-lua}/t/011-md5_bin.t | 0 .../{nginx-lua => http-lua}/t/012-now.t | 0 .../{nginx-lua => http-lua}/t/013-base64.t | 0 .../{nginx-lua => http-lua}/t/014-bugs.t | 0 .../{nginx-lua => http-lua}/t/015-status.t | 0 .../t/016-resp-header.t | 0 .../{nginx-lua => http-lua}/t/017-exec.t | 0 .../{nginx-lua => http-lua}/t/018-ndk.t | 0 .../{nginx-lua => http-lua}/t/019-const.t | 0 .../t/020-subrequest.t | 0 .../t/021-cookie-time.t | 0 .../{nginx-lua => http-lua}/t/022-redirect.t | 0 .../t/023-rewrite/client-abort.t | 0 .../t/023-rewrite/exec.t | 0 .../t/023-rewrite/exit.t | 0 .../t/023-rewrite/mixed.t | 0 .../t/023-rewrite/multi-capture.t | 0 .../t/023-rewrite/on-abort.t | 0 .../t/023-rewrite/redirect.t | 0 .../t/023-rewrite/req-body.t | 0 .../t/023-rewrite/req-socket.t | 0 .../t/023-rewrite/request_body.t | 0 .../t/023-rewrite/sanity.t | 0 .../t/023-rewrite/sleep.t | 0 .../t/023-rewrite/socket-keepalive.t | 0 .../t/023-rewrite/subrequest.t | 0 .../t/023-rewrite/tcp-socket-timeout.t | 0 .../t/023-rewrite/tcp-socket.t | 0 .../t/023-rewrite/unix-socket.t | 0 .../t/023-rewrite/uthread-exec.t | 0 .../t/023-rewrite/uthread-exit.t | 0 .../t/023-rewrite/uthread-redirect.t | 0 .../t/023-rewrite/uthread-spawn.t | 0 .../t/024-access/auth.t | 0 .../t/024-access/client-abort.t | 0 .../t/024-access/exec.t | 0 .../t/024-access/exit.t | 0 .../t/024-access/mixed.t | 0 .../t/024-access/multi-capture.t | 0 .../t/024-access/on-abort.t | 0 .../t/024-access/redirect.t | 0 .../t/024-access/req-body.t | 0 .../t/024-access/request_body.t | 0 .../t/024-access/sanity.t | 0 .../t/024-access/satisfy.t | 0 .../t/024-access/sleep.t | 0 .../t/024-access/subrequest.t | 0 .../t/024-access/uthread-exec.t | 0 .../t/024-access/uthread-exit.t | 0 .../t/024-access/uthread-redirect.t | 0 .../t/024-access/uthread-spawn.t | 0 .../{nginx-lua => http-lua}/t/025-codecache.t | 0 .../{nginx-lua => http-lua}/t/026-mysql.t | 0 .../t/027-multi-capture.t | 0 .../t/028-req-header.t | 0 .../{nginx-lua => http-lua}/t/029-http-time.t | 0 .../{nginx-lua => http-lua}/t/030-uri-args.t | 0 .../{nginx-lua => http-lua}/t/031-post-args.t | 0 .../{nginx-lua => http-lua}/t/032-iolist.t | 0 .../{nginx-lua => http-lua}/t/033-ctx.t | 0 .../{nginx-lua => http-lua}/t/034-match.t | 0 .../{nginx-lua => http-lua}/t/035-gmatch.t | 0 .../{nginx-lua => http-lua}/t/036-sub.t | 0 .../{nginx-lua => http-lua}/t/037-gsub.t | 0 .../{nginx-lua => http-lua}/t/038-match-o.t | 0 .../{nginx-lua => http-lua}/t/039-sub-o.t | 0 .../{nginx-lua => http-lua}/t/040-gsub-o.t | 0 .../t/041-header-filter.t | 0 .../{nginx-lua => http-lua}/t/042-crc32.t | 0 .../{nginx-lua => http-lua}/t/043-shdict.t | 0 .../{nginx-lua => http-lua}/t/044-req-body.t | 0 .../{nginx-lua => http-lua}/t/045-ngx-var.t | 0 .../{nginx-lua => http-lua}/t/046-hmac.t | 0 .../{nginx-lua => http-lua}/t/047-match-jit.t | 0 .../{nginx-lua => http-lua}/t/048-match-dfa.t | 0 .../t/049-gmatch-jit.t | 0 .../t/050-gmatch-dfa.t | 0 .../{nginx-lua => http-lua}/t/051-sub-jit.t | 0 .../{nginx-lua => http-lua}/t/052-sub-dfa.t | 0 .../{nginx-lua => http-lua}/t/053-gsub-jit.t | 0 .../{nginx-lua => http-lua}/t/054-gsub-dfa.t | 0 .../t/055-subreq-vars.t | 0 .../{nginx-lua => http-lua}/t/056-flush.t | 0 .../t/057-flush-timeout.t | 0 .../t/058-tcp-socket.t | 0 .../t/059-unix-socket.t | 0 .../t/060-lua-memcached.t | 0 .../{nginx-lua => http-lua}/t/061-lua-redis.t | 0 .../{nginx-lua => http-lua}/t/062-count.t | 0 .../{nginx-lua => http-lua}/t/063-abort.t | 0 .../{nginx-lua => http-lua}/t/064-pcall.t | 0 .../t/065-tcp-socket-timeout.t | 0 .../t/066-socket-receiveuntil.t | 0 .../t/067-req-socket.t | 0 .../t/068-socket-keepalive.t | 0 .../{nginx-lua => http-lua}/t/069-null.t | 0 .../{nginx-lua => http-lua}/t/070-sha1.t | 0 .../t/071-idle-socket.t | 0 .../t/072-conditional-get.t | 0 .../{nginx-lua => http-lua}/t/073-backtrace.t | 0 .../t/074-prefix-var.t | 0 .../{nginx-lua => http-lua}/t/075-logby.t | 0 .../t/076-no-postpone.t | 0 .../{nginx-lua => http-lua}/t/077-sleep.t | 0 .../{nginx-lua => http-lua}/t/078-hup-vars.t | 0 .../t/079-unused-directives.t | 0 .../t/080-hup-shdict.t | 0 .../{nginx-lua => http-lua}/t/081-bytecode.t | 0 .../t/082-body-filter.t | 0 .../t/083-bad-sock-self.t | 0 .../t/084-inclusive-receiveuntil.t | 0 .../{nginx-lua => http-lua}/t/085-if.t | 0 .../{nginx-lua => http-lua}/t/086-init-by.t | 0 .../t/087-udp-socket.t | 0 .../t/088-req-method.t | 0 .../{nginx-lua => http-lua}/t/089-phase.t | 0 .../t/090-log-socket-errors.t | 0 .../{nginx-lua => http-lua}/t/091-coroutine.t | 0 .../{nginx-lua => http-lua}/t/092-eof.t | 0 .../t/093-uthread-spawn.t | 0 .../t/094-uthread-exit.t | 0 .../t/095-uthread-exec.t | 0 .../t/096-uthread-redirect.t | 0 .../t/097-uthread-rewrite.t | 0 .../t/098-uthread-wait.t | 0 .../{nginx-lua => http-lua}/t/099-c-api.t | 0 .../t/100-client-abort.t | 0 .../{nginx-lua => http-lua}/t/101-on-abort.t | 0 .../t/102-req-start-time.t | 0 .../t/103-req-http-ver.t | 0 .../t/104-req-raw-header.t | 0 .../{nginx-lua => http-lua}/t/105-pressure.t | 0 .../{nginx-lua => http-lua}/t/106-timer.t | 0 .../t/107-timer-errors.t | 0 .../t/108-timer-safe.t | 0 .../{nginx-lua => http-lua}/t/109-timer-hup.t | 0 .../{nginx-lua => http-lua}/t/110-etag.t | 0 .../t/111-req-header-ua.t | 0 .../t/112-req-header-conn.t | 0 .../t/113-req-header-cookie.t | 0 .../{nginx-lua => http-lua}/t/114-config.t | 0 .../t/115-quote-sql-str.t | 0 .../t/116-raw-req-socket.t | 0 .../t/117-raw-req-socket-timeout.t | 0 .../t/118-use-default-type.t | 0 .../t/119-config-prefix.t | 0 .../{nginx-lua => http-lua}/t/120-re-find.t | 0 .../{nginx-lua => http-lua}/t/121-version.t | 0 .../{nginx-lua => http-lua}/t/122-worker.t | 0 .../{nginx-lua => http-lua}/t/123-lua-path.t | 0 .../t/124-init-worker.t | 0 .../t/125-configure-args.t | 0 .../t/126-shdict-frag.t | 0 .../t/127-uthread-kill.t | 0 .../t/128-duplex-tcp-socket.t | 0 .../t/129-ssl-socket.t | 0 .../t/130-internal-api.t | 0 .../t/131-duplex-req-socket.t | 0 .../t/132-lua-blocks.t | 0 .../t/133-worker-count.t | 0 .../t/134-worker-count-5.t | 0 .../{nginx-lua => http-lua}/t/135-worker-id.t | 0 .../t/136-timer-counts.t | 0 .../{nginx-lua => http-lua}/t/137-req-misc.t | 0 .../{nginx-lua => http-lua}/t/138-balancer.t | 0 .../t/139-ssl-cert-by.t | 0 .../{nginx-lua => http-lua}/t/140-ssl-c-api.t | 0 .../{nginx-lua => http-lua}/t/141-luajit.t | 0 .../t/142-ssl-session-store.t | 0 .../t/143-ssl-session-fetch.t | 0 .../t/144-shdict-incr-init.t | 0 .../t/145-shdict-list.t | 0 .../t/146-malloc-trim.t | 0 .../t/147-tcp-socket-timeouts.t | 0 .../t/148-fake-shm-zone.t | 0 .../t/149-hup-fake-shm-zone.t | 0 .../t/150-fake-delayed-load.t | 0 .../t/151-initby-hup.t | 0 .../t/152-timer-every.t | 0 .../t/153-semaphore-hup.t | 0 .../{nginx-lua => http-lua}/t/154-semaphore.t | 0 .../{nginx-lua => http-lua}/t/StapThread.pm | 0 .../t/cert/comodo-ca.crt | 0 .../t/cert/equifax.crt | 0 .../{nginx-lua => http-lua}/t/cert/test.crl | 0 .../{nginx-lua => http-lua}/t/cert/test.crt | 0 .../{nginx-lua => http-lua}/t/cert/test.key | 0 .../{nginx-lua => http-lua}/t/cert/test2.crt | 0 .../{nginx-lua => http-lua}/t/cert/test2.key | 0 .../t/cert/test_ecdsa.crt | 0 .../t/cert/test_ecdsa.key | 0 .../t/data/fake-delayed-load-module/config | 0 .../ngx_http_lua_fake_delayed_load_module.c | 0 .../t/data/fake-module/config | 0 .../t/data/fake-module/ngx_http_fake_module.c | 0 .../t/data/fake-shm-module/config | 0 .../ngx_http_lua_fake_shm_module.c | 0 .../{nginx-lua => http-lua}/t/lib/CRC32.lua | 0 .../t/lib/Memcached.lua | 0 .../{nginx-lua => http-lua}/t/lib/Redis.lua | 0 .../{nginx-lua => http-lua}/t/lib/ljson.lua | 0 .../tapset/ngx_lua.stp | 0 .../{nginx-lua => http-lua}/util/build.sh | 0 .../{nginx-lua => http-lua}/util/fix-comments | 0 .../{nginx-lua => http-lua}/util/gen-lexer-c | 0 .../{nginx-lua => http-lua}/util/ngx-links | 0 .../{nginx-lua => http-lua}/util/releng | 0 .../{nginx-lua => http-lua}/util/retab | 0 .../{nginx-lua => http-lua}/util/revim | 0 .../{nginx-lua => http-lua}/util/run_test.sh | 0 .../util/update-readme.sh | 0 .../{nginx-lua => http-lua}/valgrind.suppress | 0 .../LICENSE | 0 .../README.md | 0 .../README_AUTO_LIB | 0 .../{nginx-development-kit => http-ndk}/TODO | 0 .../auto/actions/array | 0 .../auto/actions/palloc | 0 .../auto/build | 0 .../auto/data/action_replacements | 0 .../auto/data/action_types | 0 .../auto/data/conf_args | 0 .../auto/data/conf_locs | 0 .../auto/data/conf_macros | 0 .../auto/data/contexts | 0 .../auto/data/header_files | 0 .../auto/data/headers | 0 .../auto/data/module_dependencies | 0 .../auto/data/modules_optional | 0 .../auto/data/prefixes | 0 .../auto/src/array.h | 0 .../auto/src/conf_cmd_basic.h | 0 .../auto/src/conf_merge.h | 0 .../auto/src/palloc.h | 0 .../auto/text/autogen | 0 .../config | 0 .../docs/core/action_macros | 0 .../docs/core/conf_cmds | 0 .../docs/modules/set_var | 0 .../docs/patches/more_logging_info | 0 .../docs/upstream/list | 0 .../examples/README | 0 .../examples/http/set_var/config | 0 .../ngx_http_set_var_examples_module.c | 0 .../ngx_auto_lib_core | 0 .../notes/CHANGES | 0 .../notes/LICENSE | 0 .../objs/ndk_array.h | 0 .../objs/ndk_conf_cmd_basic.h | 0 .../objs/ndk_conf_cmd_extra.h | 0 .../objs/ndk_conf_merge.h | 0 .../objs/ndk_config.c | 0 .../objs/ndk_config.h | 0 .../objs/ndk_includes.h | 0 .../objs/ndk_palloc.h | 0 .../patches/auto_config | 0 .../patches/expose_rewrite_functions | 0 .../patches/rewrite_phase_handler | 0 .../src/hash/md5.h | 0 .../src/hash/murmurhash2.c | 0 .../src/hash/sha.h | 0 .../src/ndk.c | 0 .../src/ndk.h | 0 .../src/ndk_buf.c | 0 .../src/ndk_buf.h | 0 .../src/ndk_complex_path.c | 0 .../src/ndk_complex_path.h | 0 .../src/ndk_complex_value.c | 0 .../src/ndk_complex_value.h | 0 .../src/ndk_conf_file.c | 0 .../src/ndk_conf_file.h | 0 .../src/ndk_debug.c | 0 .../src/ndk_debug.h | 0 .../src/ndk_encoding.c | 0 .../src/ndk_encoding.h | 0 .../src/ndk_hash.c | 0 .../src/ndk_hash.h | 0 .../src/ndk_http.c | 0 .../src/ndk_http.h | 0 .../src/ndk_http_headers.h | 0 .../src/ndk_log.c | 0 .../src/ndk_log.h | 0 .../src/ndk_parse.h | 0 .../src/ndk_path.c | 0 .../src/ndk_path.h | 0 .../src/ndk_process.c | 0 .../src/ndk_process.h | 0 .../src/ndk_regex.c | 0 .../src/ndk_regex.h | 0 .../src/ndk_rewrite.c | 0 .../src/ndk_rewrite.h | 0 .../src/ndk_set_var.c | 0 .../src/ndk_set_var.h | 0 .../src/ndk_string.c | 0 .../src/ndk_string.h | 0 .../src/ndk_string_util.h | 0 .../src/ndk_upstream_list.c | 0 .../src/ndk_upstream_list.h | 0 .../src/ndk_uri.c | 0 .../src/ndk_uri.h | 0 .../CHANGES | 0 .../README | 0 .../config | 0 .../doc/README.google_code_home_page.wiki | 0 .../doc/README.html | 0 .../doc/README.wiki | 0 .../ngx_http_subs_filter_module.c | 0 .../test/README | 0 .../test/inc/Module/AutoInstall.pm | 0 .../test/inc/Module/Install.pm | 0 .../test/inc/Module/Install/AutoInstall.pm | 0 .../test/inc/Module/Install/Base.pm | 0 .../test/inc/Module/Install/Can.pm | 0 .../test/inc/Module/Install/Fetch.pm | 0 .../test/inc/Module/Install/Include.pm | 0 .../test/inc/Module/Install/Makefile.pm | 0 .../test/inc/Module/Install/Metadata.pm | 0 .../test/inc/Module/Install/TestBase.pm | 0 .../test/inc/Module/Install/Win32.pm | 0 .../test/inc/Module/Install/WriteAll.pm | 0 .../test/inc/Spiffy.pm | 0 .../test/inc/Test/Base.pm | 0 .../test/inc/Test/Base/Filter.pm | 0 .../test/inc/Test/Builder.pm | 0 .../test/inc/Test/Builder/Module.pm | 0 .../test/inc/Test/More.pm | 0 .../test/lib/Test/Nginx.pm | 0 .../test/lib/Test/Nginx/LWP.pm | 0 .../test/lib/Test/Nginx/Socket.pm | 0 .../test/lib/Test/Nginx/Util.pm | 0 .../test/t/subs.t | 0 .../test/t/subs_capture.t | 0 .../test/t/subs_fix_string.t | 0 .../test/t/subs_regex.t | 0 .../test/t/subs_types.t | 0 .../test/test.sh | 0 .../util/update-readme.sh | 0 .../util/wiki2google_code_homepage.pl | 0 .../util/wiki2pod.pl | 0 .../CHANGES | 0 .../LICENSE | 0 .../Makefile | 0 .../README | 0 .../config | 0 .../ngx_http_uploadprogress_module.c | 0 .../test/client.sh | 0 .../test/stress.sh | 0 .../.gdbinit | 0 .../README | 0 .../config | 0 .../ngx_http_upstream_fair_module.c | 0 .../dynamic-module.patch | 0 .../segfault-1.11.6.patch | 0 .../series | 0 .../dynamic-module.patch | 0 .../series | 0 .../build-nginx-1.11.11.patch | 0 .../patches/{nginx-echo => http-echo}/series | 0 .../discover-luajit-2.1.patch | 0 .../openssl-1.1.0.patch | 0 .../patches/{nginx-lua => http-lua}/series | 0 .../dynamic-module.patch | 0 .../series | 0 .../drop-default-port.patch | 0 .../dynamic-module.patch | 0 .../openssl-1.1.0.patch | 0 .../series | 0 debian/modules/{nginx-rtmp => rtmp}/AUTHORS | 0 debian/modules/{nginx-rtmp => rtmp}/LICENSE | 0 debian/modules/{nginx-rtmp => rtmp}/README.md | 0 debian/modules/{nginx-rtmp => rtmp}/config | 0 .../dash/ngx_rtmp_dash_module.c | 0 .../{nginx-rtmp => rtmp}/dash/ngx_rtmp_mp4.c | 0 .../{nginx-rtmp => rtmp}/dash/ngx_rtmp_mp4.h | 0 .../{nginx-rtmp => rtmp}/doc/README.md | 0 .../hls/ngx_rtmp_hls_module.c | 0 .../hls/ngx_rtmp_mpegts.c | 0 .../hls/ngx_rtmp_mpegts.h | 0 .../modules/{nginx-rtmp => rtmp}/ngx_rtmp.c | 0 .../modules/{nginx-rtmp => rtmp}/ngx_rtmp.h | 0 .../ngx_rtmp_access_module.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_amf.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_amf.h | 0 .../ngx_rtmp_auto_push_module.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_bandwidth.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_bandwidth.h | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_bitop.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_bitop.h | 0 .../ngx_rtmp_cmd_module.c | 0 .../ngx_rtmp_cmd_module.h | 0 .../ngx_rtmp_codec_module.c | 0 .../ngx_rtmp_codec_module.h | 0 .../ngx_rtmp_control_module.c | 0 .../ngx_rtmp_core_module.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_eval.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_eval.h | 0 .../ngx_rtmp_exec_module.c | 0 .../ngx_rtmp_flv_module.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_handler.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_handshake.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_init.c | 0 .../ngx_rtmp_limit_module.c | 0 .../ngx_rtmp_live_module.c | 0 .../ngx_rtmp_live_module.h | 0 .../ngx_rtmp_log_module.c | 0 .../ngx_rtmp_mp4_module.c | 0 .../ngx_rtmp_netcall_module.c | 0 .../ngx_rtmp_netcall_module.h | 0 .../ngx_rtmp_notify_module.c | 0 .../ngx_rtmp_play_module.c | 0 .../ngx_rtmp_play_module.h | 0 .../ngx_rtmp_proxy_protocol.c | 0 .../ngx_rtmp_proxy_protocol.h | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_receive.c | 0 .../ngx_rtmp_record_module.c | 0 .../ngx_rtmp_record_module.h | 0 .../ngx_rtmp_relay_module.c | 0 .../ngx_rtmp_relay_module.h | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_send.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_shared.c | 0 .../ngx_rtmp_stat_module.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_streams.h | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_version.h | 0 debian/modules/{nginx-rtmp => rtmp}/stat.xsl | 0 debian/rules | 36 +++++++++---------- 679 files changed, 32 insertions(+), 32 deletions(-) rename debian/modules/{nginx-auth-pam => http-auth-pam}/ChangeLog (100%) rename debian/modules/{nginx-auth-pam => http-auth-pam}/LICENSE (100%) rename debian/modules/{nginx-auth-pam => http-auth-pam}/README.md (100%) rename debian/modules/{nginx-auth-pam => http-auth-pam}/VERSION (100%) rename debian/modules/{nginx-auth-pam => http-auth-pam}/config (100%) rename debian/modules/{nginx-auth-pam => http-auth-pam}/ngx_http_auth_pam_module.c (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/CHANGES (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/LICENSE (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/README.md (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/TODO.md (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/config (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/ngx_cache_purge_module.c (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/t/proxy1.t (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/t/proxy1_vars.t (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/t/proxy2.t (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/t/proxy2_vars.t (100%) rename debian/modules/{nginx-dav-ext-module => http-dav-ext}/README (100%) rename debian/modules/{nginx-dav-ext-module => http-dav-ext}/config (100%) rename debian/modules/{nginx-dav-ext-module => http-dav-ext}/ngx_http_dav_ext_module.c (100%) rename debian/modules/{nginx-echo => http-echo}/LICENSE (100%) rename debian/modules/{nginx-echo => http-echo}/README.markdown (100%) rename debian/modules/{nginx-echo => http-echo}/config (100%) rename debian/modules/{nginx-echo => http-echo}/src/ddebug.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_echo.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_echo.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_filter.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_filter.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_foreach.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_foreach.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_handler.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_handler.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_location.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_location.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_module.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_module.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_request_info.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_request_info.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_sleep.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_sleep.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_subrequest.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_subrequest.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_timer.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_timer.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_util.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_util.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_var.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_var.h (100%) rename debian/modules/{nginx-echo => http-echo}/t/abort-parent.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/blocking-sleep.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/echo-after-body.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/echo-before-body.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/echo-duplicate.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/echo-timer.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/echo.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/exec.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/filter-used.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/foreach-split.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/gzip.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/if.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/incr.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/location-async.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/location.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/mixed.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/request-body.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/request-info.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/sleep.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/status.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/subrequest-async.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/subrequest.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/unused.t (100%) rename debian/modules/{nginx-echo => http-echo}/util/build.sh (100%) rename debian/modules/{nginx-echo => http-echo}/util/releng (100%) rename debian/modules/{nginx-echo => http-echo}/util/wiki2pod.pl (100%) rename debian/modules/{nginx-echo => http-echo}/valgrind.suppress (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/CHANGELOG.md (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/HACKING.md (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/LICENSE (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/README.rst (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/config (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/nginx-0.6-support.patch (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/ngx_http_fancyindex_module.c (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/00-build-artifacts.test (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/01-smoke-hasindex.test (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/02-smoke-indexisfancy.test (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/build-and-run (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/has-index.test (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/has-index/index.html (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/nginx.conf (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/preamble (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/run (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/template.awk (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/template.h (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/template.html (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/README.markdown (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/config (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ddebug.h (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ngx_http_headers_more_filter_module.c (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ngx_http_headers_more_filter_module.h (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ngx_http_headers_more_headers_in.c (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ngx_http_headers_more_headers_in.h (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ngx_http_headers_more_headers_out.c (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ngx_http_headers_more_headers_out.h (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ngx_http_headers_more_util.c (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ngx_http_headers_more_util.h (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/bug.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/builtin.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/eval.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/input-conn.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/input-cookie.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/input-ua.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/input.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/phase.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/sanity.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/subrequest.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/unused.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/vars.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/util/build.sh (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/valgrind.suppress (100%) rename debian/modules/{nginx-lua => http-lua}/README.markdown (100%) rename debian/modules/{nginx-lua => http-lua}/config (100%) rename debian/modules/{nginx-lua => http-lua}/doc/HttpLuaModule.wiki (100%) rename debian/modules/{nginx-lua => http-lua}/dtrace/ngx_lua_provider.d (100%) rename debian/modules/{nginx-lua => http-lua}/misc/recv-until-pm/Makefile (100%) rename debian/modules/{nginx-lua => http-lua}/misc/recv-until-pm/lib/RecvUntil.pm (100%) rename debian/modules/{nginx-lua => http-lua}/misc/recv-until-pm/t/sanity.t (100%) rename debian/modules/{nginx-lua => http-lua}/src/api/ngx_http_lua_api.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ddebug.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_accessby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_accessby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_api.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_args.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_args.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_balancer.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_balancer.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_bodyfilterby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_bodyfilterby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_cache.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_cache.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_capturefilter.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_capturefilter.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_clfactory.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_clfactory.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_common.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_config.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_config.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_consts.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_consts.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_contentby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_contentby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_control.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_control.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_coroutine.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_coroutine.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ctx.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ctx.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_directive.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_directive.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_exception.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_exception.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_headerfilterby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_headerfilterby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_headers.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_headers.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_headers_in.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_headers_in.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_headers_out.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_headers_out.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_initby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_initby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_initworkerby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_initworkerby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_lex.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_lex.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_log.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_log.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_log_ringbuf.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_log_ringbuf.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_logby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_logby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_misc.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_misc.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_module.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ndk.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ndk.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_output.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_output.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_pcrefix.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_pcrefix.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_phase.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_phase.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_probe.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_regex.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_regex.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_req_body.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_req_body.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_req_method.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_req_method.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_rewriteby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_rewriteby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_script.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_script.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_semaphore.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_semaphore.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_setby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_setby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_shdict.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_shdict.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_sleep.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_sleep.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_socket_tcp.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_socket_tcp.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_socket_udp.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_socket_udp.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl_certby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl_certby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl_ocsp.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl_session_fetchby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl_session_fetchby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl_session_storeby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl_session_storeby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_string.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_string.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_subrequest.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_subrequest.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_time.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_time.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_timer.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_timer.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_uri.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_uri.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_uthread.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_uthread.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_util.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_util.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_variable.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_variable.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_worker.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_worker.h (100%) rename debian/modules/{nginx-lua => http-lua}/t/.gitignore (100%) rename debian/modules/{nginx-lua => http-lua}/t/000--init.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/000-sanity.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/001-set.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/002-content.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/003-errors.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/004-require.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/005-exit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/006-escape.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/007-md5.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/008-today.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/009-log.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/010-request_body.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/011-md5_bin.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/012-now.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/013-base64.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/014-bugs.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/015-status.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/016-resp-header.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/017-exec.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/018-ndk.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/019-const.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/020-subrequest.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/021-cookie-time.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/022-redirect.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/client-abort.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/exec.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/exit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/mixed.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/multi-capture.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/on-abort.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/redirect.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/req-body.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/req-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/request_body.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/sanity.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/sleep.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/socket-keepalive.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/subrequest.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/tcp-socket-timeout.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/tcp-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/unix-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/uthread-exec.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/uthread-exit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/uthread-redirect.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/uthread-spawn.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/auth.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/client-abort.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/exec.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/exit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/mixed.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/multi-capture.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/on-abort.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/redirect.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/req-body.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/request_body.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/sanity.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/satisfy.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/sleep.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/subrequest.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/uthread-exec.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/uthread-exit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/uthread-redirect.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/uthread-spawn.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/025-codecache.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/026-mysql.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/027-multi-capture.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/028-req-header.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/029-http-time.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/030-uri-args.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/031-post-args.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/032-iolist.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/033-ctx.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/034-match.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/035-gmatch.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/036-sub.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/037-gsub.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/038-match-o.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/039-sub-o.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/040-gsub-o.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/041-header-filter.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/042-crc32.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/043-shdict.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/044-req-body.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/045-ngx-var.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/046-hmac.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/047-match-jit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/048-match-dfa.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/049-gmatch-jit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/050-gmatch-dfa.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/051-sub-jit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/052-sub-dfa.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/053-gsub-jit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/054-gsub-dfa.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/055-subreq-vars.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/056-flush.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/057-flush-timeout.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/058-tcp-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/059-unix-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/060-lua-memcached.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/061-lua-redis.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/062-count.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/063-abort.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/064-pcall.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/065-tcp-socket-timeout.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/066-socket-receiveuntil.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/067-req-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/068-socket-keepalive.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/069-null.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/070-sha1.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/071-idle-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/072-conditional-get.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/073-backtrace.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/074-prefix-var.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/075-logby.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/076-no-postpone.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/077-sleep.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/078-hup-vars.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/079-unused-directives.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/080-hup-shdict.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/081-bytecode.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/082-body-filter.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/083-bad-sock-self.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/084-inclusive-receiveuntil.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/085-if.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/086-init-by.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/087-udp-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/088-req-method.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/089-phase.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/090-log-socket-errors.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/091-coroutine.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/092-eof.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/093-uthread-spawn.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/094-uthread-exit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/095-uthread-exec.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/096-uthread-redirect.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/097-uthread-rewrite.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/098-uthread-wait.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/099-c-api.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/100-client-abort.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/101-on-abort.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/102-req-start-time.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/103-req-http-ver.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/104-req-raw-header.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/105-pressure.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/106-timer.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/107-timer-errors.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/108-timer-safe.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/109-timer-hup.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/110-etag.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/111-req-header-ua.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/112-req-header-conn.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/113-req-header-cookie.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/114-config.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/115-quote-sql-str.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/116-raw-req-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/117-raw-req-socket-timeout.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/118-use-default-type.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/119-config-prefix.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/120-re-find.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/121-version.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/122-worker.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/123-lua-path.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/124-init-worker.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/125-configure-args.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/126-shdict-frag.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/127-uthread-kill.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/128-duplex-tcp-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/129-ssl-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/130-internal-api.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/131-duplex-req-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/132-lua-blocks.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/133-worker-count.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/134-worker-count-5.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/135-worker-id.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/136-timer-counts.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/137-req-misc.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/138-balancer.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/139-ssl-cert-by.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/140-ssl-c-api.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/141-luajit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/142-ssl-session-store.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/143-ssl-session-fetch.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/144-shdict-incr-init.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/145-shdict-list.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/146-malloc-trim.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/147-tcp-socket-timeouts.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/148-fake-shm-zone.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/149-hup-fake-shm-zone.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/150-fake-delayed-load.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/151-initby-hup.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/152-timer-every.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/153-semaphore-hup.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/154-semaphore.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/StapThread.pm (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/comodo-ca.crt (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/equifax.crt (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/test.crl (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/test.crt (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/test.key (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/test2.crt (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/test2.key (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/test_ecdsa.crt (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/test_ecdsa.key (100%) rename debian/modules/{nginx-lua => http-lua}/t/data/fake-delayed-load-module/config (100%) rename debian/modules/{nginx-lua => http-lua}/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c (100%) rename debian/modules/{nginx-lua => http-lua}/t/data/fake-module/config (100%) rename debian/modules/{nginx-lua => http-lua}/t/data/fake-module/ngx_http_fake_module.c (100%) rename debian/modules/{nginx-lua => http-lua}/t/data/fake-shm-module/config (100%) rename debian/modules/{nginx-lua => http-lua}/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c (100%) rename debian/modules/{nginx-lua => http-lua}/t/lib/CRC32.lua (100%) rename debian/modules/{nginx-lua => http-lua}/t/lib/Memcached.lua (100%) rename debian/modules/{nginx-lua => http-lua}/t/lib/Redis.lua (100%) rename debian/modules/{nginx-lua => http-lua}/t/lib/ljson.lua (100%) rename debian/modules/{nginx-lua => http-lua}/tapset/ngx_lua.stp (100%) rename debian/modules/{nginx-lua => http-lua}/util/build.sh (100%) rename debian/modules/{nginx-lua => http-lua}/util/fix-comments (100%) rename debian/modules/{nginx-lua => http-lua}/util/gen-lexer-c (100%) rename debian/modules/{nginx-lua => http-lua}/util/ngx-links (100%) rename debian/modules/{nginx-lua => http-lua}/util/releng (100%) rename debian/modules/{nginx-lua => http-lua}/util/retab (100%) rename debian/modules/{nginx-lua => http-lua}/util/revim (100%) rename debian/modules/{nginx-lua => http-lua}/util/run_test.sh (100%) rename debian/modules/{nginx-lua => http-lua}/util/update-readme.sh (100%) rename debian/modules/{nginx-lua => http-lua}/valgrind.suppress (100%) rename debian/modules/{nginx-development-kit => http-ndk}/LICENSE (100%) rename debian/modules/{nginx-development-kit => http-ndk}/README.md (100%) rename debian/modules/{nginx-development-kit => http-ndk}/README_AUTO_LIB (100%) rename debian/modules/{nginx-development-kit => http-ndk}/TODO (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/actions/array (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/actions/palloc (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/build (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/action_replacements (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/action_types (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/conf_args (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/conf_locs (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/conf_macros (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/contexts (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/header_files (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/headers (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/module_dependencies (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/modules_optional (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/prefixes (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/src/array.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/src/conf_cmd_basic.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/src/conf_merge.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/src/palloc.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/text/autogen (100%) rename debian/modules/{nginx-development-kit => http-ndk}/config (100%) rename debian/modules/{nginx-development-kit => http-ndk}/docs/core/action_macros (100%) rename debian/modules/{nginx-development-kit => http-ndk}/docs/core/conf_cmds (100%) rename debian/modules/{nginx-development-kit => http-ndk}/docs/modules/set_var (100%) rename debian/modules/{nginx-development-kit => http-ndk}/docs/patches/more_logging_info (100%) rename debian/modules/{nginx-development-kit => http-ndk}/docs/upstream/list (100%) rename debian/modules/{nginx-development-kit => http-ndk}/examples/README (100%) rename debian/modules/{nginx-development-kit => http-ndk}/examples/http/set_var/config (100%) rename debian/modules/{nginx-development-kit => http-ndk}/examples/http/set_var/ngx_http_set_var_examples_module.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/ngx_auto_lib_core (100%) rename debian/modules/{nginx-development-kit => http-ndk}/notes/CHANGES (100%) rename debian/modules/{nginx-development-kit => http-ndk}/notes/LICENSE (100%) rename debian/modules/{nginx-development-kit => http-ndk}/objs/ndk_array.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/objs/ndk_conf_cmd_basic.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/objs/ndk_conf_cmd_extra.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/objs/ndk_conf_merge.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/objs/ndk_config.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/objs/ndk_config.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/objs/ndk_includes.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/objs/ndk_palloc.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/patches/auto_config (100%) rename debian/modules/{nginx-development-kit => http-ndk}/patches/expose_rewrite_functions (100%) rename debian/modules/{nginx-development-kit => http-ndk}/patches/rewrite_phase_handler (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/hash/md5.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/hash/murmurhash2.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/hash/sha.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_buf.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_buf.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_complex_path.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_complex_path.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_complex_value.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_complex_value.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_conf_file.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_conf_file.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_debug.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_debug.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_encoding.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_encoding.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_hash.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_hash.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_http.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_http.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_http_headers.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_log.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_log.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_parse.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_path.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_path.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_process.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_process.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_regex.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_regex.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_rewrite.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_rewrite.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_set_var.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_set_var.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_string.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_string.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_string_util.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_upstream_list.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_upstream_list.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_uri.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_uri.h (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/CHANGES (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/README (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/config (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/doc/README.google_code_home_page.wiki (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/doc/README.html (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/doc/README.wiki (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/ngx_http_subs_filter_module.c (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/README (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/AutoInstall.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/AutoInstall.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/Base.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/Can.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/Fetch.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/Include.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/Makefile.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/Metadata.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/TestBase.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/Win32.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/WriteAll.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Spiffy.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Test/Base.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Test/Base/Filter.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Test/Builder.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Test/Builder/Module.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Test/More.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/lib/Test/Nginx.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/lib/Test/Nginx/LWP.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/lib/Test/Nginx/Socket.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/lib/Test/Nginx/Util.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/t/subs.t (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/t/subs_capture.t (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/t/subs_fix_string.t (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/t/subs_regex.t (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/t/subs_types.t (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/test.sh (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/util/update-readme.sh (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/util/wiki2google_code_homepage.pl (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/util/wiki2pod.pl (100%) rename debian/modules/{nginx-upload-progress => http-uploadprogress}/CHANGES (100%) rename debian/modules/{nginx-upload-progress => http-uploadprogress}/LICENSE (100%) rename debian/modules/{nginx-upload-progress => http-uploadprogress}/Makefile (100%) rename debian/modules/{nginx-upload-progress => http-uploadprogress}/README (100%) rename debian/modules/{nginx-upload-progress => http-uploadprogress}/config (100%) rename debian/modules/{nginx-upload-progress => http-uploadprogress}/ngx_http_uploadprogress_module.c (100%) rename debian/modules/{nginx-upload-progress => http-uploadprogress}/test/client.sh (100%) rename debian/modules/{nginx-upload-progress => http-uploadprogress}/test/stress.sh (100%) rename debian/modules/{nginx-upstream-fair => http-upstream-fair}/.gdbinit (100%) rename debian/modules/{nginx-upstream-fair => http-upstream-fair}/README (100%) rename debian/modules/{nginx-upstream-fair => http-upstream-fair}/config (100%) rename debian/modules/{nginx-upstream-fair => http-upstream-fair}/ngx_http_upstream_fair_module.c (100%) rename debian/modules/patches/{nginx-cache-purge => http-cache-purge}/dynamic-module.patch (100%) rename debian/modules/patches/{nginx-cache-purge => http-cache-purge}/segfault-1.11.6.patch (100%) rename debian/modules/patches/{nginx-cache-purge => http-cache-purge}/series (100%) rename debian/modules/patches/{nginx-dav-ext-module => http-dav-ext}/dynamic-module.patch (100%) rename debian/modules/patches/{nginx-dav-ext-module => http-dav-ext}/series (100%) rename debian/modules/patches/{nginx-echo => http-echo}/build-nginx-1.11.11.patch (100%) rename debian/modules/patches/{nginx-echo => http-echo}/series (100%) rename debian/modules/patches/{nginx-lua => http-lua}/discover-luajit-2.1.patch (100%) rename debian/modules/patches/{nginx-lua => http-lua}/openssl-1.1.0.patch (100%) rename debian/modules/patches/{nginx-lua => http-lua}/series (100%) rename debian/modules/patches/{ngx_http_substitutions_filter_module => http-subs-filter}/dynamic-module.patch (100%) rename debian/modules/patches/{ngx_http_substitutions_filter_module => http-subs-filter}/series (100%) rename debian/modules/patches/{nginx-upstream-fair => http-upstream-fair}/drop-default-port.patch (100%) rename debian/modules/patches/{nginx-upstream-fair => http-upstream-fair}/dynamic-module.patch (100%) rename debian/modules/patches/{nginx-upstream-fair => http-upstream-fair}/openssl-1.1.0.patch (100%) rename debian/modules/patches/{nginx-upstream-fair => http-upstream-fair}/series (100%) rename debian/modules/{nginx-rtmp => rtmp}/AUTHORS (100%) rename debian/modules/{nginx-rtmp => rtmp}/LICENSE (100%) rename debian/modules/{nginx-rtmp => rtmp}/README.md (100%) rename debian/modules/{nginx-rtmp => rtmp}/config (100%) rename debian/modules/{nginx-rtmp => rtmp}/dash/ngx_rtmp_dash_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/dash/ngx_rtmp_mp4.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/dash/ngx_rtmp_mp4.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/doc/README.md (100%) rename debian/modules/{nginx-rtmp => rtmp}/hls/ngx_rtmp_hls_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/hls/ngx_rtmp_mpegts.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/hls/ngx_rtmp_mpegts.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_access_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_amf.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_amf.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_auto_push_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_bandwidth.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_bandwidth.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_bitop.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_bitop.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_cmd_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_cmd_module.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_codec_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_codec_module.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_control_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_core_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_eval.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_eval.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_exec_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_flv_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_handler.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_handshake.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_init.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_limit_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_live_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_live_module.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_log_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_mp4_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_netcall_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_netcall_module.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_notify_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_play_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_play_module.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_proxy_protocol.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_proxy_protocol.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_receive.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_record_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_record_module.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_relay_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_relay_module.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_send.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_shared.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_stat_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_streams.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_version.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/stat.xsl (100%) diff --git a/debian/copyright b/debian/copyright index 3d1b4c5..7bba41c 100644 --- a/debian/copyright +++ b/debian/copyright @@ -37,35 +37,35 @@ Copyright: 2007-2009, Fabio Tranchitella 2013-2016, Christos Trochalakis License: BSD-2-clause -Files: debian/modules/headers-more-nginx-module/* +Files: debian/modules/http-headers-more-filter/* Copyright: Copyright (c) 2009-2014, Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. Copyright (c) 2010-2013, Bernd Dorn Copyright (c) Igor Sysoev License: BSD-2-clause -Files: debian/modules/nginx-development-kit/* +Files: debian/modules/http-ndk/* Copyright: Marcus Clyne License: BSD-3-clause -Files: debian/modules/nginx-development-kit/src/hash/md5.h - debian/modules/nginx-development-kit/src/hash/sha.h +Files: debian/modules/http-ndk/src/hash/md5.h + debian/modules/http-ndk/src/hash/sha.h Copyright: Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) License: BSD-4-clause -Files: debian/modules/nginx-auth-pam/* +Files: debian/modules/http-auth-pam/* Copyright: 2008-2013, Sergio Talens Oliag License: BSD-2-clause -Files: debian/modules/nginx-echo/* +Files: debian/modules/http-echo/* Copyright: Copyright (c) 2009-2014, Yichun "agentzh" Zhang License: BSD-2-clause -Files: debian/modules/nginx-lua/* +Files: debian/modules/http-lua/* Copyright: Copyright (C) 2009-2014, by Xiaozhe Wang (chaoslawful) . Copyright (C) 2009-2014, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. License: BSD-2-clause -Files: debian/modules/nginx-upstream-fair/* +Files: debian/modules/http-upstream-fair/* Copyright: Copyright (c) 2007 Grzegorz Nosek Igor Sysoev License: BSD-2-clause @@ -85,29 +85,29 @@ Copyright: 2009-2011, Salvatore Sanfilippo Jan-Erik Rediger License: BSD-3-clause -Files: debian/modules/nginx-upload-progress/* +Files: debian/modules/http-uploadprogress/* Copyright: Brice Figureau 2002-2007, Igor Sysoev License: BSD-2-clause -Files: debian/modules/nginx-cache-purge/* +Files: debian/modules/http-cache-purge/* Copyright: 2009-2012, FRiCKLE , 2009-2012, Piotr Sikora License: BSD-2-clause -Files: debian/modules/nginx-dav-ext-module/* +Files: debian/modules/http-dav-ext/* Copyright: Arutyunyan Roman License: BSD-2-clause -Files: debian/modules/ngx-fancyindex/* +Files: debian/modules/http-fancyindex/* Copyright: Copyright (c) Adrian Perez License: BSD-2-clause -Files: debian/modules/ngx_http_substitutions_filter_module/* +Files: debian/modules/http-subs-filter/* Copyright: Copyright (C) 2014 by Weibin Yao License: BSD-2-clause -Files: debian/modules/nginx-rtmp/* +Files: debian/modules/rtmp/* Copyright: Copyright (C) 2012-2014, Roman Arutyunyan License: BSD-2-clause diff --git a/debian/modules/nginx-auth-pam/ChangeLog b/debian/modules/http-auth-pam/ChangeLog similarity index 100% rename from debian/modules/nginx-auth-pam/ChangeLog rename to debian/modules/http-auth-pam/ChangeLog diff --git a/debian/modules/nginx-auth-pam/LICENSE b/debian/modules/http-auth-pam/LICENSE similarity index 100% rename from debian/modules/nginx-auth-pam/LICENSE rename to debian/modules/http-auth-pam/LICENSE diff --git a/debian/modules/nginx-auth-pam/README.md b/debian/modules/http-auth-pam/README.md similarity index 100% rename from debian/modules/nginx-auth-pam/README.md rename to debian/modules/http-auth-pam/README.md diff --git a/debian/modules/nginx-auth-pam/VERSION b/debian/modules/http-auth-pam/VERSION similarity index 100% rename from debian/modules/nginx-auth-pam/VERSION rename to debian/modules/http-auth-pam/VERSION diff --git a/debian/modules/nginx-auth-pam/config b/debian/modules/http-auth-pam/config similarity index 100% rename from debian/modules/nginx-auth-pam/config rename to debian/modules/http-auth-pam/config diff --git a/debian/modules/nginx-auth-pam/ngx_http_auth_pam_module.c b/debian/modules/http-auth-pam/ngx_http_auth_pam_module.c similarity index 100% rename from debian/modules/nginx-auth-pam/ngx_http_auth_pam_module.c rename to debian/modules/http-auth-pam/ngx_http_auth_pam_module.c diff --git a/debian/modules/nginx-cache-purge/CHANGES b/debian/modules/http-cache-purge/CHANGES similarity index 100% rename from debian/modules/nginx-cache-purge/CHANGES rename to debian/modules/http-cache-purge/CHANGES diff --git a/debian/modules/nginx-cache-purge/LICENSE b/debian/modules/http-cache-purge/LICENSE similarity index 100% rename from debian/modules/nginx-cache-purge/LICENSE rename to debian/modules/http-cache-purge/LICENSE diff --git a/debian/modules/nginx-cache-purge/README.md b/debian/modules/http-cache-purge/README.md similarity index 100% rename from debian/modules/nginx-cache-purge/README.md rename to debian/modules/http-cache-purge/README.md diff --git a/debian/modules/nginx-cache-purge/TODO.md b/debian/modules/http-cache-purge/TODO.md similarity index 100% rename from debian/modules/nginx-cache-purge/TODO.md rename to debian/modules/http-cache-purge/TODO.md diff --git a/debian/modules/nginx-cache-purge/config b/debian/modules/http-cache-purge/config similarity index 100% rename from debian/modules/nginx-cache-purge/config rename to debian/modules/http-cache-purge/config diff --git a/debian/modules/nginx-cache-purge/ngx_cache_purge_module.c b/debian/modules/http-cache-purge/ngx_cache_purge_module.c similarity index 100% rename from debian/modules/nginx-cache-purge/ngx_cache_purge_module.c rename to debian/modules/http-cache-purge/ngx_cache_purge_module.c diff --git a/debian/modules/nginx-cache-purge/t/proxy1.t b/debian/modules/http-cache-purge/t/proxy1.t similarity index 100% rename from debian/modules/nginx-cache-purge/t/proxy1.t rename to debian/modules/http-cache-purge/t/proxy1.t diff --git a/debian/modules/nginx-cache-purge/t/proxy1_vars.t b/debian/modules/http-cache-purge/t/proxy1_vars.t similarity index 100% rename from debian/modules/nginx-cache-purge/t/proxy1_vars.t rename to debian/modules/http-cache-purge/t/proxy1_vars.t diff --git a/debian/modules/nginx-cache-purge/t/proxy2.t b/debian/modules/http-cache-purge/t/proxy2.t similarity index 100% rename from debian/modules/nginx-cache-purge/t/proxy2.t rename to debian/modules/http-cache-purge/t/proxy2.t diff --git a/debian/modules/nginx-cache-purge/t/proxy2_vars.t b/debian/modules/http-cache-purge/t/proxy2_vars.t similarity index 100% rename from debian/modules/nginx-cache-purge/t/proxy2_vars.t rename to debian/modules/http-cache-purge/t/proxy2_vars.t diff --git a/debian/modules/nginx-dav-ext-module/README b/debian/modules/http-dav-ext/README similarity index 100% rename from debian/modules/nginx-dav-ext-module/README rename to debian/modules/http-dav-ext/README diff --git a/debian/modules/nginx-dav-ext-module/config b/debian/modules/http-dav-ext/config similarity index 100% rename from debian/modules/nginx-dav-ext-module/config rename to debian/modules/http-dav-ext/config diff --git a/debian/modules/nginx-dav-ext-module/ngx_http_dav_ext_module.c b/debian/modules/http-dav-ext/ngx_http_dav_ext_module.c similarity index 100% rename from debian/modules/nginx-dav-ext-module/ngx_http_dav_ext_module.c rename to debian/modules/http-dav-ext/ngx_http_dav_ext_module.c diff --git a/debian/modules/nginx-echo/LICENSE b/debian/modules/http-echo/LICENSE similarity index 100% rename from debian/modules/nginx-echo/LICENSE rename to debian/modules/http-echo/LICENSE diff --git a/debian/modules/nginx-echo/README.markdown b/debian/modules/http-echo/README.markdown similarity index 100% rename from debian/modules/nginx-echo/README.markdown rename to debian/modules/http-echo/README.markdown diff --git a/debian/modules/nginx-echo/config b/debian/modules/http-echo/config similarity index 100% rename from debian/modules/nginx-echo/config rename to debian/modules/http-echo/config diff --git a/debian/modules/nginx-echo/src/ddebug.h b/debian/modules/http-echo/src/ddebug.h similarity index 100% rename from debian/modules/nginx-echo/src/ddebug.h rename to debian/modules/http-echo/src/ddebug.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_echo.c b/debian/modules/http-echo/src/ngx_http_echo_echo.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_echo.c rename to debian/modules/http-echo/src/ngx_http_echo_echo.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_echo.h b/debian/modules/http-echo/src/ngx_http_echo_echo.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_echo.h rename to debian/modules/http-echo/src/ngx_http_echo_echo.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_filter.c b/debian/modules/http-echo/src/ngx_http_echo_filter.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_filter.c rename to debian/modules/http-echo/src/ngx_http_echo_filter.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_filter.h b/debian/modules/http-echo/src/ngx_http_echo_filter.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_filter.h rename to debian/modules/http-echo/src/ngx_http_echo_filter.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_foreach.c b/debian/modules/http-echo/src/ngx_http_echo_foreach.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_foreach.c rename to debian/modules/http-echo/src/ngx_http_echo_foreach.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_foreach.h b/debian/modules/http-echo/src/ngx_http_echo_foreach.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_foreach.h rename to debian/modules/http-echo/src/ngx_http_echo_foreach.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_handler.c b/debian/modules/http-echo/src/ngx_http_echo_handler.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_handler.c rename to debian/modules/http-echo/src/ngx_http_echo_handler.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_handler.h b/debian/modules/http-echo/src/ngx_http_echo_handler.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_handler.h rename to debian/modules/http-echo/src/ngx_http_echo_handler.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_location.c b/debian/modules/http-echo/src/ngx_http_echo_location.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_location.c rename to debian/modules/http-echo/src/ngx_http_echo_location.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_location.h b/debian/modules/http-echo/src/ngx_http_echo_location.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_location.h rename to debian/modules/http-echo/src/ngx_http_echo_location.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_module.c b/debian/modules/http-echo/src/ngx_http_echo_module.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_module.c rename to debian/modules/http-echo/src/ngx_http_echo_module.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_module.h b/debian/modules/http-echo/src/ngx_http_echo_module.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_module.h rename to debian/modules/http-echo/src/ngx_http_echo_module.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_request_info.c b/debian/modules/http-echo/src/ngx_http_echo_request_info.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_request_info.c rename to debian/modules/http-echo/src/ngx_http_echo_request_info.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_request_info.h b/debian/modules/http-echo/src/ngx_http_echo_request_info.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_request_info.h rename to debian/modules/http-echo/src/ngx_http_echo_request_info.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_sleep.c b/debian/modules/http-echo/src/ngx_http_echo_sleep.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_sleep.c rename to debian/modules/http-echo/src/ngx_http_echo_sleep.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_sleep.h b/debian/modules/http-echo/src/ngx_http_echo_sleep.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_sleep.h rename to debian/modules/http-echo/src/ngx_http_echo_sleep.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_subrequest.c b/debian/modules/http-echo/src/ngx_http_echo_subrequest.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_subrequest.c rename to debian/modules/http-echo/src/ngx_http_echo_subrequest.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_subrequest.h b/debian/modules/http-echo/src/ngx_http_echo_subrequest.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_subrequest.h rename to debian/modules/http-echo/src/ngx_http_echo_subrequest.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_timer.c b/debian/modules/http-echo/src/ngx_http_echo_timer.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_timer.c rename to debian/modules/http-echo/src/ngx_http_echo_timer.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_timer.h b/debian/modules/http-echo/src/ngx_http_echo_timer.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_timer.h rename to debian/modules/http-echo/src/ngx_http_echo_timer.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_util.c b/debian/modules/http-echo/src/ngx_http_echo_util.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_util.c rename to debian/modules/http-echo/src/ngx_http_echo_util.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_util.h b/debian/modules/http-echo/src/ngx_http_echo_util.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_util.h rename to debian/modules/http-echo/src/ngx_http_echo_util.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_var.c b/debian/modules/http-echo/src/ngx_http_echo_var.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_var.c rename to debian/modules/http-echo/src/ngx_http_echo_var.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_var.h b/debian/modules/http-echo/src/ngx_http_echo_var.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_var.h rename to debian/modules/http-echo/src/ngx_http_echo_var.h diff --git a/debian/modules/nginx-echo/t/abort-parent.t b/debian/modules/http-echo/t/abort-parent.t similarity index 100% rename from debian/modules/nginx-echo/t/abort-parent.t rename to debian/modules/http-echo/t/abort-parent.t diff --git a/debian/modules/nginx-echo/t/blocking-sleep.t b/debian/modules/http-echo/t/blocking-sleep.t similarity index 100% rename from debian/modules/nginx-echo/t/blocking-sleep.t rename to debian/modules/http-echo/t/blocking-sleep.t diff --git a/debian/modules/nginx-echo/t/echo-after-body.t b/debian/modules/http-echo/t/echo-after-body.t similarity index 100% rename from debian/modules/nginx-echo/t/echo-after-body.t rename to debian/modules/http-echo/t/echo-after-body.t diff --git a/debian/modules/nginx-echo/t/echo-before-body.t b/debian/modules/http-echo/t/echo-before-body.t similarity index 100% rename from debian/modules/nginx-echo/t/echo-before-body.t rename to debian/modules/http-echo/t/echo-before-body.t diff --git a/debian/modules/nginx-echo/t/echo-duplicate.t b/debian/modules/http-echo/t/echo-duplicate.t similarity index 100% rename from debian/modules/nginx-echo/t/echo-duplicate.t rename to debian/modules/http-echo/t/echo-duplicate.t diff --git a/debian/modules/nginx-echo/t/echo-timer.t b/debian/modules/http-echo/t/echo-timer.t similarity index 100% rename from debian/modules/nginx-echo/t/echo-timer.t rename to debian/modules/http-echo/t/echo-timer.t diff --git a/debian/modules/nginx-echo/t/echo.t b/debian/modules/http-echo/t/echo.t similarity index 100% rename from debian/modules/nginx-echo/t/echo.t rename to debian/modules/http-echo/t/echo.t diff --git a/debian/modules/nginx-echo/t/exec.t b/debian/modules/http-echo/t/exec.t similarity index 100% rename from debian/modules/nginx-echo/t/exec.t rename to debian/modules/http-echo/t/exec.t diff --git a/debian/modules/nginx-echo/t/filter-used.t b/debian/modules/http-echo/t/filter-used.t similarity index 100% rename from debian/modules/nginx-echo/t/filter-used.t rename to debian/modules/http-echo/t/filter-used.t diff --git a/debian/modules/nginx-echo/t/foreach-split.t b/debian/modules/http-echo/t/foreach-split.t similarity index 100% rename from debian/modules/nginx-echo/t/foreach-split.t rename to debian/modules/http-echo/t/foreach-split.t diff --git a/debian/modules/nginx-echo/t/gzip.t b/debian/modules/http-echo/t/gzip.t similarity index 100% rename from debian/modules/nginx-echo/t/gzip.t rename to debian/modules/http-echo/t/gzip.t diff --git a/debian/modules/nginx-echo/t/if.t b/debian/modules/http-echo/t/if.t similarity index 100% rename from debian/modules/nginx-echo/t/if.t rename to debian/modules/http-echo/t/if.t diff --git a/debian/modules/nginx-echo/t/incr.t b/debian/modules/http-echo/t/incr.t similarity index 100% rename from debian/modules/nginx-echo/t/incr.t rename to debian/modules/http-echo/t/incr.t diff --git a/debian/modules/nginx-echo/t/location-async.t b/debian/modules/http-echo/t/location-async.t similarity index 100% rename from debian/modules/nginx-echo/t/location-async.t rename to debian/modules/http-echo/t/location-async.t diff --git a/debian/modules/nginx-echo/t/location.t b/debian/modules/http-echo/t/location.t similarity index 100% rename from debian/modules/nginx-echo/t/location.t rename to debian/modules/http-echo/t/location.t diff --git a/debian/modules/nginx-echo/t/mixed.t b/debian/modules/http-echo/t/mixed.t similarity index 100% rename from debian/modules/nginx-echo/t/mixed.t rename to debian/modules/http-echo/t/mixed.t diff --git a/debian/modules/nginx-echo/t/request-body.t b/debian/modules/http-echo/t/request-body.t similarity index 100% rename from debian/modules/nginx-echo/t/request-body.t rename to debian/modules/http-echo/t/request-body.t diff --git a/debian/modules/nginx-echo/t/request-info.t b/debian/modules/http-echo/t/request-info.t similarity index 100% rename from debian/modules/nginx-echo/t/request-info.t rename to debian/modules/http-echo/t/request-info.t diff --git a/debian/modules/nginx-echo/t/sleep.t b/debian/modules/http-echo/t/sleep.t similarity index 100% rename from debian/modules/nginx-echo/t/sleep.t rename to debian/modules/http-echo/t/sleep.t diff --git a/debian/modules/nginx-echo/t/status.t b/debian/modules/http-echo/t/status.t similarity index 100% rename from debian/modules/nginx-echo/t/status.t rename to debian/modules/http-echo/t/status.t diff --git a/debian/modules/nginx-echo/t/subrequest-async.t b/debian/modules/http-echo/t/subrequest-async.t similarity index 100% rename from debian/modules/nginx-echo/t/subrequest-async.t rename to debian/modules/http-echo/t/subrequest-async.t diff --git a/debian/modules/nginx-echo/t/subrequest.t b/debian/modules/http-echo/t/subrequest.t similarity index 100% rename from debian/modules/nginx-echo/t/subrequest.t rename to debian/modules/http-echo/t/subrequest.t diff --git a/debian/modules/nginx-echo/t/unused.t b/debian/modules/http-echo/t/unused.t similarity index 100% rename from debian/modules/nginx-echo/t/unused.t rename to debian/modules/http-echo/t/unused.t diff --git a/debian/modules/nginx-echo/util/build.sh b/debian/modules/http-echo/util/build.sh similarity index 100% rename from debian/modules/nginx-echo/util/build.sh rename to debian/modules/http-echo/util/build.sh diff --git a/debian/modules/nginx-echo/util/releng b/debian/modules/http-echo/util/releng similarity index 100% rename from debian/modules/nginx-echo/util/releng rename to debian/modules/http-echo/util/releng diff --git a/debian/modules/nginx-echo/util/wiki2pod.pl b/debian/modules/http-echo/util/wiki2pod.pl similarity index 100% rename from debian/modules/nginx-echo/util/wiki2pod.pl rename to debian/modules/http-echo/util/wiki2pod.pl diff --git a/debian/modules/nginx-echo/valgrind.suppress b/debian/modules/http-echo/valgrind.suppress similarity index 100% rename from debian/modules/nginx-echo/valgrind.suppress rename to debian/modules/http-echo/valgrind.suppress diff --git a/debian/modules/ngx-fancyindex/CHANGELOG.md b/debian/modules/http-fancyindex/CHANGELOG.md similarity index 100% rename from debian/modules/ngx-fancyindex/CHANGELOG.md rename to debian/modules/http-fancyindex/CHANGELOG.md diff --git a/debian/modules/ngx-fancyindex/HACKING.md b/debian/modules/http-fancyindex/HACKING.md similarity index 100% rename from debian/modules/ngx-fancyindex/HACKING.md rename to debian/modules/http-fancyindex/HACKING.md diff --git a/debian/modules/ngx-fancyindex/LICENSE b/debian/modules/http-fancyindex/LICENSE similarity index 100% rename from debian/modules/ngx-fancyindex/LICENSE rename to debian/modules/http-fancyindex/LICENSE diff --git a/debian/modules/ngx-fancyindex/README.rst b/debian/modules/http-fancyindex/README.rst similarity index 100% rename from debian/modules/ngx-fancyindex/README.rst rename to debian/modules/http-fancyindex/README.rst diff --git a/debian/modules/ngx-fancyindex/config b/debian/modules/http-fancyindex/config similarity index 100% rename from debian/modules/ngx-fancyindex/config rename to debian/modules/http-fancyindex/config diff --git a/debian/modules/ngx-fancyindex/nginx-0.6-support.patch b/debian/modules/http-fancyindex/nginx-0.6-support.patch similarity index 100% rename from debian/modules/ngx-fancyindex/nginx-0.6-support.patch rename to debian/modules/http-fancyindex/nginx-0.6-support.patch diff --git a/debian/modules/ngx-fancyindex/ngx_http_fancyindex_module.c b/debian/modules/http-fancyindex/ngx_http_fancyindex_module.c similarity index 100% rename from debian/modules/ngx-fancyindex/ngx_http_fancyindex_module.c rename to debian/modules/http-fancyindex/ngx_http_fancyindex_module.c diff --git a/debian/modules/ngx-fancyindex/t/00-build-artifacts.test b/debian/modules/http-fancyindex/t/00-build-artifacts.test similarity index 100% rename from debian/modules/ngx-fancyindex/t/00-build-artifacts.test rename to debian/modules/http-fancyindex/t/00-build-artifacts.test diff --git a/debian/modules/ngx-fancyindex/t/01-smoke-hasindex.test b/debian/modules/http-fancyindex/t/01-smoke-hasindex.test similarity index 100% rename from debian/modules/ngx-fancyindex/t/01-smoke-hasindex.test rename to debian/modules/http-fancyindex/t/01-smoke-hasindex.test diff --git a/debian/modules/ngx-fancyindex/t/02-smoke-indexisfancy.test b/debian/modules/http-fancyindex/t/02-smoke-indexisfancy.test similarity index 100% rename from debian/modules/ngx-fancyindex/t/02-smoke-indexisfancy.test rename to debian/modules/http-fancyindex/t/02-smoke-indexisfancy.test diff --git a/debian/modules/ngx-fancyindex/t/build-and-run b/debian/modules/http-fancyindex/t/build-and-run similarity index 100% rename from debian/modules/ngx-fancyindex/t/build-and-run rename to debian/modules/http-fancyindex/t/build-and-run diff --git a/debian/modules/ngx-fancyindex/t/has-index.test b/debian/modules/http-fancyindex/t/has-index.test similarity index 100% rename from debian/modules/ngx-fancyindex/t/has-index.test rename to debian/modules/http-fancyindex/t/has-index.test diff --git a/debian/modules/ngx-fancyindex/t/has-index/index.html b/debian/modules/http-fancyindex/t/has-index/index.html similarity index 100% rename from debian/modules/ngx-fancyindex/t/has-index/index.html rename to debian/modules/http-fancyindex/t/has-index/index.html diff --git a/debian/modules/ngx-fancyindex/t/nginx.conf b/debian/modules/http-fancyindex/t/nginx.conf similarity index 100% rename from debian/modules/ngx-fancyindex/t/nginx.conf rename to debian/modules/http-fancyindex/t/nginx.conf diff --git a/debian/modules/ngx-fancyindex/t/preamble b/debian/modules/http-fancyindex/t/preamble similarity index 100% rename from debian/modules/ngx-fancyindex/t/preamble rename to debian/modules/http-fancyindex/t/preamble diff --git a/debian/modules/ngx-fancyindex/t/run b/debian/modules/http-fancyindex/t/run similarity index 100% rename from debian/modules/ngx-fancyindex/t/run rename to debian/modules/http-fancyindex/t/run diff --git a/debian/modules/ngx-fancyindex/template.awk b/debian/modules/http-fancyindex/template.awk similarity index 100% rename from debian/modules/ngx-fancyindex/template.awk rename to debian/modules/http-fancyindex/template.awk diff --git a/debian/modules/ngx-fancyindex/template.h b/debian/modules/http-fancyindex/template.h similarity index 100% rename from debian/modules/ngx-fancyindex/template.h rename to debian/modules/http-fancyindex/template.h diff --git a/debian/modules/ngx-fancyindex/template.html b/debian/modules/http-fancyindex/template.html similarity index 100% rename from debian/modules/ngx-fancyindex/template.html rename to debian/modules/http-fancyindex/template.html diff --git a/debian/modules/headers-more-nginx-module/README.markdown b/debian/modules/http-headers-more-filter/README.markdown similarity index 100% rename from debian/modules/headers-more-nginx-module/README.markdown rename to debian/modules/http-headers-more-filter/README.markdown diff --git a/debian/modules/headers-more-nginx-module/config b/debian/modules/http-headers-more-filter/config similarity index 100% rename from debian/modules/headers-more-nginx-module/config rename to debian/modules/http-headers-more-filter/config diff --git a/debian/modules/headers-more-nginx-module/src/ddebug.h b/debian/modules/http-headers-more-filter/src/ddebug.h similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ddebug.h rename to debian/modules/http-headers-more-filter/src/ddebug.h diff --git a/debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_filter_module.c b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_filter_module.c similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_filter_module.c rename to debian/modules/http-headers-more-filter/src/ngx_http_headers_more_filter_module.c diff --git a/debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_filter_module.h b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_filter_module.h similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_filter_module.h rename to debian/modules/http-headers-more-filter/src/ngx_http_headers_more_filter_module.h diff --git a/debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_headers_in.c b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.c similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_headers_in.c rename to debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.c diff --git a/debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_headers_in.h b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.h similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_headers_in.h rename to debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.h diff --git a/debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_headers_out.c b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_out.c similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_headers_out.c rename to debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_out.c diff --git a/debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_headers_out.h b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_out.h similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_headers_out.h rename to debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_out.h diff --git a/debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_util.c b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_util.c similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_util.c rename to debian/modules/http-headers-more-filter/src/ngx_http_headers_more_util.c diff --git a/debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_util.h b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_util.h similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_util.h rename to debian/modules/http-headers-more-filter/src/ngx_http_headers_more_util.h diff --git a/debian/modules/headers-more-nginx-module/t/bug.t b/debian/modules/http-headers-more-filter/t/bug.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/bug.t rename to debian/modules/http-headers-more-filter/t/bug.t diff --git a/debian/modules/headers-more-nginx-module/t/builtin.t b/debian/modules/http-headers-more-filter/t/builtin.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/builtin.t rename to debian/modules/http-headers-more-filter/t/builtin.t diff --git a/debian/modules/headers-more-nginx-module/t/eval.t b/debian/modules/http-headers-more-filter/t/eval.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/eval.t rename to debian/modules/http-headers-more-filter/t/eval.t diff --git a/debian/modules/headers-more-nginx-module/t/input-conn.t b/debian/modules/http-headers-more-filter/t/input-conn.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/input-conn.t rename to debian/modules/http-headers-more-filter/t/input-conn.t diff --git a/debian/modules/headers-more-nginx-module/t/input-cookie.t b/debian/modules/http-headers-more-filter/t/input-cookie.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/input-cookie.t rename to debian/modules/http-headers-more-filter/t/input-cookie.t diff --git a/debian/modules/headers-more-nginx-module/t/input-ua.t b/debian/modules/http-headers-more-filter/t/input-ua.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/input-ua.t rename to debian/modules/http-headers-more-filter/t/input-ua.t diff --git a/debian/modules/headers-more-nginx-module/t/input.t b/debian/modules/http-headers-more-filter/t/input.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/input.t rename to debian/modules/http-headers-more-filter/t/input.t diff --git a/debian/modules/headers-more-nginx-module/t/phase.t b/debian/modules/http-headers-more-filter/t/phase.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/phase.t rename to debian/modules/http-headers-more-filter/t/phase.t diff --git a/debian/modules/headers-more-nginx-module/t/sanity.t b/debian/modules/http-headers-more-filter/t/sanity.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/sanity.t rename to debian/modules/http-headers-more-filter/t/sanity.t diff --git a/debian/modules/headers-more-nginx-module/t/subrequest.t b/debian/modules/http-headers-more-filter/t/subrequest.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/subrequest.t rename to debian/modules/http-headers-more-filter/t/subrequest.t diff --git a/debian/modules/headers-more-nginx-module/t/unused.t b/debian/modules/http-headers-more-filter/t/unused.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/unused.t rename to debian/modules/http-headers-more-filter/t/unused.t diff --git a/debian/modules/headers-more-nginx-module/t/vars.t b/debian/modules/http-headers-more-filter/t/vars.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/vars.t rename to debian/modules/http-headers-more-filter/t/vars.t diff --git a/debian/modules/headers-more-nginx-module/util/build.sh b/debian/modules/http-headers-more-filter/util/build.sh similarity index 100% rename from debian/modules/headers-more-nginx-module/util/build.sh rename to debian/modules/http-headers-more-filter/util/build.sh diff --git a/debian/modules/headers-more-nginx-module/valgrind.suppress b/debian/modules/http-headers-more-filter/valgrind.suppress similarity index 100% rename from debian/modules/headers-more-nginx-module/valgrind.suppress rename to debian/modules/http-headers-more-filter/valgrind.suppress diff --git a/debian/modules/nginx-lua/README.markdown b/debian/modules/http-lua/README.markdown similarity index 100% rename from debian/modules/nginx-lua/README.markdown rename to debian/modules/http-lua/README.markdown diff --git a/debian/modules/nginx-lua/config b/debian/modules/http-lua/config similarity index 100% rename from debian/modules/nginx-lua/config rename to debian/modules/http-lua/config diff --git a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki b/debian/modules/http-lua/doc/HttpLuaModule.wiki similarity index 100% rename from debian/modules/nginx-lua/doc/HttpLuaModule.wiki rename to debian/modules/http-lua/doc/HttpLuaModule.wiki diff --git a/debian/modules/nginx-lua/dtrace/ngx_lua_provider.d b/debian/modules/http-lua/dtrace/ngx_lua_provider.d similarity index 100% rename from debian/modules/nginx-lua/dtrace/ngx_lua_provider.d rename to debian/modules/http-lua/dtrace/ngx_lua_provider.d diff --git a/debian/modules/nginx-lua/misc/recv-until-pm/Makefile b/debian/modules/http-lua/misc/recv-until-pm/Makefile similarity index 100% rename from debian/modules/nginx-lua/misc/recv-until-pm/Makefile rename to debian/modules/http-lua/misc/recv-until-pm/Makefile diff --git a/debian/modules/nginx-lua/misc/recv-until-pm/lib/RecvUntil.pm b/debian/modules/http-lua/misc/recv-until-pm/lib/RecvUntil.pm similarity index 100% rename from debian/modules/nginx-lua/misc/recv-until-pm/lib/RecvUntil.pm rename to debian/modules/http-lua/misc/recv-until-pm/lib/RecvUntil.pm diff --git a/debian/modules/nginx-lua/misc/recv-until-pm/t/sanity.t b/debian/modules/http-lua/misc/recv-until-pm/t/sanity.t similarity index 100% rename from debian/modules/nginx-lua/misc/recv-until-pm/t/sanity.t rename to debian/modules/http-lua/misc/recv-until-pm/t/sanity.t diff --git a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h b/debian/modules/http-lua/src/api/ngx_http_lua_api.h similarity index 100% rename from debian/modules/nginx-lua/src/api/ngx_http_lua_api.h rename to debian/modules/http-lua/src/api/ngx_http_lua_api.h diff --git a/debian/modules/nginx-lua/src/ddebug.h b/debian/modules/http-lua/src/ddebug.h similarity index 100% rename from debian/modules/nginx-lua/src/ddebug.h rename to debian/modules/http-lua/src/ddebug.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c b/debian/modules/http-lua/src/ngx_http_lua_accessby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_accessby.c rename to debian/modules/http-lua/src/ngx_http_lua_accessby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_accessby.h b/debian/modules/http-lua/src/ngx_http_lua_accessby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_accessby.h rename to debian/modules/http-lua/src/ngx_http_lua_accessby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_api.c b/debian/modules/http-lua/src/ngx_http_lua_api.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_api.c rename to debian/modules/http-lua/src/ngx_http_lua_api.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_args.c b/debian/modules/http-lua/src/ngx_http_lua_args.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_args.c rename to debian/modules/http-lua/src/ngx_http_lua_args.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_args.h b/debian/modules/http-lua/src/ngx_http_lua_args.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_args.h rename to debian/modules/http-lua/src/ngx_http_lua_args.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c b/debian/modules/http-lua/src/ngx_http_lua_balancer.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_balancer.c rename to debian/modules/http-lua/src/ngx_http_lua_balancer.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.h b/debian/modules/http-lua/src/ngx_http_lua_balancer.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_balancer.h rename to debian/modules/http-lua/src/ngx_http_lua_balancer.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_bodyfilterby.c b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_bodyfilterby.c rename to debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_bodyfilterby.h b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_bodyfilterby.h rename to debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_cache.c b/debian/modules/http-lua/src/ngx_http_lua_cache.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_cache.c rename to debian/modules/http-lua/src/ngx_http_lua_cache.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_cache.h b/debian/modules/http-lua/src/ngx_http_lua_cache.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_cache.h rename to debian/modules/http-lua/src/ngx_http_lua_cache.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_capturefilter.c b/debian/modules/http-lua/src/ngx_http_lua_capturefilter.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_capturefilter.c rename to debian/modules/http-lua/src/ngx_http_lua_capturefilter.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_capturefilter.h b/debian/modules/http-lua/src/ngx_http_lua_capturefilter.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_capturefilter.h rename to debian/modules/http-lua/src/ngx_http_lua_capturefilter.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_clfactory.c b/debian/modules/http-lua/src/ngx_http_lua_clfactory.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_clfactory.c rename to debian/modules/http-lua/src/ngx_http_lua_clfactory.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_clfactory.h b/debian/modules/http-lua/src/ngx_http_lua_clfactory.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_clfactory.h rename to debian/modules/http-lua/src/ngx_http_lua_clfactory.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_common.h b/debian/modules/http-lua/src/ngx_http_lua_common.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_common.h rename to debian/modules/http-lua/src/ngx_http_lua_common.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_config.c b/debian/modules/http-lua/src/ngx_http_lua_config.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_config.c rename to debian/modules/http-lua/src/ngx_http_lua_config.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_config.h b/debian/modules/http-lua/src/ngx_http_lua_config.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_config.h rename to debian/modules/http-lua/src/ngx_http_lua_config.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_consts.c b/debian/modules/http-lua/src/ngx_http_lua_consts.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_consts.c rename to debian/modules/http-lua/src/ngx_http_lua_consts.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_consts.h b/debian/modules/http-lua/src/ngx_http_lua_consts.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_consts.h rename to debian/modules/http-lua/src/ngx_http_lua_consts.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c b/debian/modules/http-lua/src/ngx_http_lua_contentby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_contentby.c rename to debian/modules/http-lua/src/ngx_http_lua_contentby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_contentby.h b/debian/modules/http-lua/src/ngx_http_lua_contentby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_contentby.h rename to debian/modules/http-lua/src/ngx_http_lua_contentby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_control.c b/debian/modules/http-lua/src/ngx_http_lua_control.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_control.c rename to debian/modules/http-lua/src/ngx_http_lua_control.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_control.h b/debian/modules/http-lua/src/ngx_http_lua_control.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_control.h rename to debian/modules/http-lua/src/ngx_http_lua_control.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_coroutine.c b/debian/modules/http-lua/src/ngx_http_lua_coroutine.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_coroutine.c rename to debian/modules/http-lua/src/ngx_http_lua_coroutine.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_coroutine.h b/debian/modules/http-lua/src/ngx_http_lua_coroutine.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_coroutine.h rename to debian/modules/http-lua/src/ngx_http_lua_coroutine.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ctx.c b/debian/modules/http-lua/src/ngx_http_lua_ctx.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ctx.c rename to debian/modules/http-lua/src/ngx_http_lua_ctx.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ctx.h b/debian/modules/http-lua/src/ngx_http_lua_ctx.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ctx.h rename to debian/modules/http-lua/src/ngx_http_lua_ctx.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c b/debian/modules/http-lua/src/ngx_http_lua_directive.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_directive.c rename to debian/modules/http-lua/src/ngx_http_lua_directive.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_directive.h b/debian/modules/http-lua/src/ngx_http_lua_directive.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_directive.h rename to debian/modules/http-lua/src/ngx_http_lua_directive.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_exception.c b/debian/modules/http-lua/src/ngx_http_lua_exception.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_exception.c rename to debian/modules/http-lua/src/ngx_http_lua_exception.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_exception.h b/debian/modules/http-lua/src/ngx_http_lua_exception.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_exception.h rename to debian/modules/http-lua/src/ngx_http_lua_exception.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c b/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c rename to debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.h b/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.h rename to debian/modules/http-lua/src/ngx_http_lua_headerfilterby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers.c b/debian/modules/http-lua/src/ngx_http_lua_headers.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_headers.c rename to debian/modules/http-lua/src/ngx_http_lua_headers.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers.h b/debian/modules/http-lua/src/ngx_http_lua_headers.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_headers.h rename to debian/modules/http-lua/src/ngx_http_lua_headers.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers_in.c b/debian/modules/http-lua/src/ngx_http_lua_headers_in.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_headers_in.c rename to debian/modules/http-lua/src/ngx_http_lua_headers_in.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers_in.h b/debian/modules/http-lua/src/ngx_http_lua_headers_in.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_headers_in.h rename to debian/modules/http-lua/src/ngx_http_lua_headers_in.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c b/debian/modules/http-lua/src/ngx_http_lua_headers_out.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c rename to debian/modules/http-lua/src/ngx_http_lua_headers_out.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.h b/debian/modules/http-lua/src/ngx_http_lua_headers_out.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_headers_out.h rename to debian/modules/http-lua/src/ngx_http_lua_headers_out.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_initby.c b/debian/modules/http-lua/src/ngx_http_lua_initby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_initby.c rename to debian/modules/http-lua/src/ngx_http_lua_initby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_initby.h b/debian/modules/http-lua/src/ngx_http_lua_initby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_initby.h rename to debian/modules/http-lua/src/ngx_http_lua_initby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c b/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c rename to debian/modules/http-lua/src/ngx_http_lua_initworkerby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.h b/debian/modules/http-lua/src/ngx_http_lua_initworkerby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.h rename to debian/modules/http-lua/src/ngx_http_lua_initworkerby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_lex.c b/debian/modules/http-lua/src/ngx_http_lua_lex.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_lex.c rename to debian/modules/http-lua/src/ngx_http_lua_lex.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_lex.h b/debian/modules/http-lua/src/ngx_http_lua_lex.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_lex.h rename to debian/modules/http-lua/src/ngx_http_lua_lex.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_log.c b/debian/modules/http-lua/src/ngx_http_lua_log.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_log.c rename to debian/modules/http-lua/src/ngx_http_lua_log.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_log.h b/debian/modules/http-lua/src/ngx_http_lua_log.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_log.h rename to debian/modules/http-lua/src/ngx_http_lua_log.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.c b/debian/modules/http-lua/src/ngx_http_lua_log_ringbuf.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.c rename to debian/modules/http-lua/src/ngx_http_lua_log_ringbuf.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.h b/debian/modules/http-lua/src/ngx_http_lua_log_ringbuf.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.h rename to debian/modules/http-lua/src/ngx_http_lua_log_ringbuf.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_logby.c b/debian/modules/http-lua/src/ngx_http_lua_logby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_logby.c rename to debian/modules/http-lua/src/ngx_http_lua_logby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_logby.h b/debian/modules/http-lua/src/ngx_http_lua_logby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_logby.h rename to debian/modules/http-lua/src/ngx_http_lua_logby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_misc.c b/debian/modules/http-lua/src/ngx_http_lua_misc.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_misc.c rename to debian/modules/http-lua/src/ngx_http_lua_misc.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_misc.h b/debian/modules/http-lua/src/ngx_http_lua_misc.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_misc.h rename to debian/modules/http-lua/src/ngx_http_lua_misc.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_module.c b/debian/modules/http-lua/src/ngx_http_lua_module.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_module.c rename to debian/modules/http-lua/src/ngx_http_lua_module.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ndk.c b/debian/modules/http-lua/src/ngx_http_lua_ndk.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ndk.c rename to debian/modules/http-lua/src/ngx_http_lua_ndk.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ndk.h b/debian/modules/http-lua/src/ngx_http_lua_ndk.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ndk.h rename to debian/modules/http-lua/src/ngx_http_lua_ndk.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_output.c b/debian/modules/http-lua/src/ngx_http_lua_output.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_output.c rename to debian/modules/http-lua/src/ngx_http_lua_output.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_output.h b/debian/modules/http-lua/src/ngx_http_lua_output.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_output.h rename to debian/modules/http-lua/src/ngx_http_lua_output.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_pcrefix.c b/debian/modules/http-lua/src/ngx_http_lua_pcrefix.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_pcrefix.c rename to debian/modules/http-lua/src/ngx_http_lua_pcrefix.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_pcrefix.h b/debian/modules/http-lua/src/ngx_http_lua_pcrefix.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_pcrefix.h rename to debian/modules/http-lua/src/ngx_http_lua_pcrefix.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_phase.c b/debian/modules/http-lua/src/ngx_http_lua_phase.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_phase.c rename to debian/modules/http-lua/src/ngx_http_lua_phase.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_phase.h b/debian/modules/http-lua/src/ngx_http_lua_phase.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_phase.h rename to debian/modules/http-lua/src/ngx_http_lua_phase.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_probe.h b/debian/modules/http-lua/src/ngx_http_lua_probe.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_probe.h rename to debian/modules/http-lua/src/ngx_http_lua_probe.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c b/debian/modules/http-lua/src/ngx_http_lua_regex.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_regex.c rename to debian/modules/http-lua/src/ngx_http_lua_regex.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_regex.h b/debian/modules/http-lua/src/ngx_http_lua_regex.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_regex.h rename to debian/modules/http-lua/src/ngx_http_lua_regex.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c b/debian/modules/http-lua/src/ngx_http_lua_req_body.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_req_body.c rename to debian/modules/http-lua/src/ngx_http_lua_req_body.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_req_body.h b/debian/modules/http-lua/src/ngx_http_lua_req_body.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_req_body.h rename to debian/modules/http-lua/src/ngx_http_lua_req_body.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_req_method.c b/debian/modules/http-lua/src/ngx_http_lua_req_method.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_req_method.c rename to debian/modules/http-lua/src/ngx_http_lua_req_method.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_req_method.h b/debian/modules/http-lua/src/ngx_http_lua_req_method.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_req_method.h rename to debian/modules/http-lua/src/ngx_http_lua_req_method.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c rename to debian/modules/http-lua/src/ngx_http_lua_rewriteby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.h b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.h rename to debian/modules/http-lua/src/ngx_http_lua_rewriteby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_script.c b/debian/modules/http-lua/src/ngx_http_lua_script.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_script.c rename to debian/modules/http-lua/src/ngx_http_lua_script.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_script.h b/debian/modules/http-lua/src/ngx_http_lua_script.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_script.h rename to debian/modules/http-lua/src/ngx_http_lua_script.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c b/debian/modules/http-lua/src/ngx_http_lua_semaphore.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c rename to debian/modules/http-lua/src/ngx_http_lua_semaphore.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.h b/debian/modules/http-lua/src/ngx_http_lua_semaphore.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_semaphore.h rename to debian/modules/http-lua/src/ngx_http_lua_semaphore.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_setby.c b/debian/modules/http-lua/src/ngx_http_lua_setby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_setby.c rename to debian/modules/http-lua/src/ngx_http_lua_setby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_setby.h b/debian/modules/http-lua/src/ngx_http_lua_setby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_setby.h rename to debian/modules/http-lua/src/ngx_http_lua_setby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c b/debian/modules/http-lua/src/ngx_http_lua_shdict.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_shdict.c rename to debian/modules/http-lua/src/ngx_http_lua_shdict.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.h b/debian/modules/http-lua/src/ngx_http_lua_shdict.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_shdict.h rename to debian/modules/http-lua/src/ngx_http_lua_shdict.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c b/debian/modules/http-lua/src/ngx_http_lua_sleep.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_sleep.c rename to debian/modules/http-lua/src/ngx_http_lua_sleep.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_sleep.h b/debian/modules/http-lua/src/ngx_http_lua_sleep.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_sleep.h rename to debian/modules/http-lua/src/ngx_http_lua_sleep.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c rename to debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.h b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.h rename to debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c rename to debian/modules/http-lua/src/ngx_http_lua_socket_udp.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.h b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.h rename to debian/modules/http-lua/src/ngx_http_lua_socket_udp.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl.c b/debian/modules/http-lua/src/ngx_http_lua_ssl.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl.c rename to debian/modules/http-lua/src/ngx_http_lua_ssl.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl.h b/debian/modules/http-lua/src/ngx_http_lua_ssl.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl.h rename to debian/modules/http-lua/src/ngx_http_lua_ssl.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c rename to debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.h b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.h rename to debian/modules/http-lua/src/ngx_http_lua_ssl_certby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_ocsp.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c rename to debian/modules/http-lua/src/ngx_http_lua_ssl_ocsp.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.c rename to debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.h b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.h rename to debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.c rename to debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.h b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.h rename to debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_string.c b/debian/modules/http-lua/src/ngx_http_lua_string.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_string.c rename to debian/modules/http-lua/src/ngx_http_lua_string.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_string.h b/debian/modules/http-lua/src/ngx_http_lua_string.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_string.h rename to debian/modules/http-lua/src/ngx_http_lua_string.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_subrequest.c b/debian/modules/http-lua/src/ngx_http_lua_subrequest.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_subrequest.c rename to debian/modules/http-lua/src/ngx_http_lua_subrequest.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_subrequest.h b/debian/modules/http-lua/src/ngx_http_lua_subrequest.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_subrequest.h rename to debian/modules/http-lua/src/ngx_http_lua_subrequest.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_time.c b/debian/modules/http-lua/src/ngx_http_lua_time.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_time.c rename to debian/modules/http-lua/src/ngx_http_lua_time.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_time.h b/debian/modules/http-lua/src/ngx_http_lua_time.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_time.h rename to debian/modules/http-lua/src/ngx_http_lua_time.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c b/debian/modules/http-lua/src/ngx_http_lua_timer.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_timer.c rename to debian/modules/http-lua/src/ngx_http_lua_timer.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_timer.h b/debian/modules/http-lua/src/ngx_http_lua_timer.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_timer.h rename to debian/modules/http-lua/src/ngx_http_lua_timer.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_uri.c b/debian/modules/http-lua/src/ngx_http_lua_uri.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_uri.c rename to debian/modules/http-lua/src/ngx_http_lua_uri.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_uri.h b/debian/modules/http-lua/src/ngx_http_lua_uri.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_uri.h rename to debian/modules/http-lua/src/ngx_http_lua_uri.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_uthread.c b/debian/modules/http-lua/src/ngx_http_lua_uthread.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_uthread.c rename to debian/modules/http-lua/src/ngx_http_lua_uthread.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_uthread.h b/debian/modules/http-lua/src/ngx_http_lua_uthread.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_uthread.h rename to debian/modules/http-lua/src/ngx_http_lua_uthread.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.c b/debian/modules/http-lua/src/ngx_http_lua_util.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_util.c rename to debian/modules/http-lua/src/ngx_http_lua_util.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.h b/debian/modules/http-lua/src/ngx_http_lua_util.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_util.h rename to debian/modules/http-lua/src/ngx_http_lua_util.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_variable.c b/debian/modules/http-lua/src/ngx_http_lua_variable.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_variable.c rename to debian/modules/http-lua/src/ngx_http_lua_variable.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_variable.h b/debian/modules/http-lua/src/ngx_http_lua_variable.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_variable.h rename to debian/modules/http-lua/src/ngx_http_lua_variable.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_worker.c b/debian/modules/http-lua/src/ngx_http_lua_worker.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_worker.c rename to debian/modules/http-lua/src/ngx_http_lua_worker.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_worker.h b/debian/modules/http-lua/src/ngx_http_lua_worker.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_worker.h rename to debian/modules/http-lua/src/ngx_http_lua_worker.h diff --git a/debian/modules/nginx-lua/t/.gitignore b/debian/modules/http-lua/t/.gitignore similarity index 100% rename from debian/modules/nginx-lua/t/.gitignore rename to debian/modules/http-lua/t/.gitignore diff --git a/debian/modules/nginx-lua/t/000--init.t b/debian/modules/http-lua/t/000--init.t similarity index 100% rename from debian/modules/nginx-lua/t/000--init.t rename to debian/modules/http-lua/t/000--init.t diff --git a/debian/modules/nginx-lua/t/000-sanity.t b/debian/modules/http-lua/t/000-sanity.t similarity index 100% rename from debian/modules/nginx-lua/t/000-sanity.t rename to debian/modules/http-lua/t/000-sanity.t diff --git a/debian/modules/nginx-lua/t/001-set.t b/debian/modules/http-lua/t/001-set.t similarity index 100% rename from debian/modules/nginx-lua/t/001-set.t rename to debian/modules/http-lua/t/001-set.t diff --git a/debian/modules/nginx-lua/t/002-content.t b/debian/modules/http-lua/t/002-content.t similarity index 100% rename from debian/modules/nginx-lua/t/002-content.t rename to debian/modules/http-lua/t/002-content.t diff --git a/debian/modules/nginx-lua/t/003-errors.t b/debian/modules/http-lua/t/003-errors.t similarity index 100% rename from debian/modules/nginx-lua/t/003-errors.t rename to debian/modules/http-lua/t/003-errors.t diff --git a/debian/modules/nginx-lua/t/004-require.t b/debian/modules/http-lua/t/004-require.t similarity index 100% rename from debian/modules/nginx-lua/t/004-require.t rename to debian/modules/http-lua/t/004-require.t diff --git a/debian/modules/nginx-lua/t/005-exit.t b/debian/modules/http-lua/t/005-exit.t similarity index 100% rename from debian/modules/nginx-lua/t/005-exit.t rename to debian/modules/http-lua/t/005-exit.t diff --git a/debian/modules/nginx-lua/t/006-escape.t b/debian/modules/http-lua/t/006-escape.t similarity index 100% rename from debian/modules/nginx-lua/t/006-escape.t rename to debian/modules/http-lua/t/006-escape.t diff --git a/debian/modules/nginx-lua/t/007-md5.t b/debian/modules/http-lua/t/007-md5.t similarity index 100% rename from debian/modules/nginx-lua/t/007-md5.t rename to debian/modules/http-lua/t/007-md5.t diff --git a/debian/modules/nginx-lua/t/008-today.t b/debian/modules/http-lua/t/008-today.t similarity index 100% rename from debian/modules/nginx-lua/t/008-today.t rename to debian/modules/http-lua/t/008-today.t diff --git a/debian/modules/nginx-lua/t/009-log.t b/debian/modules/http-lua/t/009-log.t similarity index 100% rename from debian/modules/nginx-lua/t/009-log.t rename to debian/modules/http-lua/t/009-log.t diff --git a/debian/modules/nginx-lua/t/010-request_body.t b/debian/modules/http-lua/t/010-request_body.t similarity index 100% rename from debian/modules/nginx-lua/t/010-request_body.t rename to debian/modules/http-lua/t/010-request_body.t diff --git a/debian/modules/nginx-lua/t/011-md5_bin.t b/debian/modules/http-lua/t/011-md5_bin.t similarity index 100% rename from debian/modules/nginx-lua/t/011-md5_bin.t rename to debian/modules/http-lua/t/011-md5_bin.t diff --git a/debian/modules/nginx-lua/t/012-now.t b/debian/modules/http-lua/t/012-now.t similarity index 100% rename from debian/modules/nginx-lua/t/012-now.t rename to debian/modules/http-lua/t/012-now.t diff --git a/debian/modules/nginx-lua/t/013-base64.t b/debian/modules/http-lua/t/013-base64.t similarity index 100% rename from debian/modules/nginx-lua/t/013-base64.t rename to debian/modules/http-lua/t/013-base64.t diff --git a/debian/modules/nginx-lua/t/014-bugs.t b/debian/modules/http-lua/t/014-bugs.t similarity index 100% rename from debian/modules/nginx-lua/t/014-bugs.t rename to debian/modules/http-lua/t/014-bugs.t diff --git a/debian/modules/nginx-lua/t/015-status.t b/debian/modules/http-lua/t/015-status.t similarity index 100% rename from debian/modules/nginx-lua/t/015-status.t rename to debian/modules/http-lua/t/015-status.t diff --git a/debian/modules/nginx-lua/t/016-resp-header.t b/debian/modules/http-lua/t/016-resp-header.t similarity index 100% rename from debian/modules/nginx-lua/t/016-resp-header.t rename to debian/modules/http-lua/t/016-resp-header.t diff --git a/debian/modules/nginx-lua/t/017-exec.t b/debian/modules/http-lua/t/017-exec.t similarity index 100% rename from debian/modules/nginx-lua/t/017-exec.t rename to debian/modules/http-lua/t/017-exec.t diff --git a/debian/modules/nginx-lua/t/018-ndk.t b/debian/modules/http-lua/t/018-ndk.t similarity index 100% rename from debian/modules/nginx-lua/t/018-ndk.t rename to debian/modules/http-lua/t/018-ndk.t diff --git a/debian/modules/nginx-lua/t/019-const.t b/debian/modules/http-lua/t/019-const.t similarity index 100% rename from debian/modules/nginx-lua/t/019-const.t rename to debian/modules/http-lua/t/019-const.t diff --git a/debian/modules/nginx-lua/t/020-subrequest.t b/debian/modules/http-lua/t/020-subrequest.t similarity index 100% rename from debian/modules/nginx-lua/t/020-subrequest.t rename to debian/modules/http-lua/t/020-subrequest.t diff --git a/debian/modules/nginx-lua/t/021-cookie-time.t b/debian/modules/http-lua/t/021-cookie-time.t similarity index 100% rename from debian/modules/nginx-lua/t/021-cookie-time.t rename to debian/modules/http-lua/t/021-cookie-time.t diff --git a/debian/modules/nginx-lua/t/022-redirect.t b/debian/modules/http-lua/t/022-redirect.t similarity index 100% rename from debian/modules/nginx-lua/t/022-redirect.t rename to debian/modules/http-lua/t/022-redirect.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/client-abort.t b/debian/modules/http-lua/t/023-rewrite/client-abort.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/client-abort.t rename to debian/modules/http-lua/t/023-rewrite/client-abort.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/exec.t b/debian/modules/http-lua/t/023-rewrite/exec.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/exec.t rename to debian/modules/http-lua/t/023-rewrite/exec.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/exit.t b/debian/modules/http-lua/t/023-rewrite/exit.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/exit.t rename to debian/modules/http-lua/t/023-rewrite/exit.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/mixed.t b/debian/modules/http-lua/t/023-rewrite/mixed.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/mixed.t rename to debian/modules/http-lua/t/023-rewrite/mixed.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/multi-capture.t b/debian/modules/http-lua/t/023-rewrite/multi-capture.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/multi-capture.t rename to debian/modules/http-lua/t/023-rewrite/multi-capture.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/on-abort.t b/debian/modules/http-lua/t/023-rewrite/on-abort.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/on-abort.t rename to debian/modules/http-lua/t/023-rewrite/on-abort.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/redirect.t b/debian/modules/http-lua/t/023-rewrite/redirect.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/redirect.t rename to debian/modules/http-lua/t/023-rewrite/redirect.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/req-body.t b/debian/modules/http-lua/t/023-rewrite/req-body.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/req-body.t rename to debian/modules/http-lua/t/023-rewrite/req-body.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/req-socket.t b/debian/modules/http-lua/t/023-rewrite/req-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/req-socket.t rename to debian/modules/http-lua/t/023-rewrite/req-socket.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/request_body.t b/debian/modules/http-lua/t/023-rewrite/request_body.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/request_body.t rename to debian/modules/http-lua/t/023-rewrite/request_body.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/sanity.t b/debian/modules/http-lua/t/023-rewrite/sanity.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/sanity.t rename to debian/modules/http-lua/t/023-rewrite/sanity.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/sleep.t b/debian/modules/http-lua/t/023-rewrite/sleep.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/sleep.t rename to debian/modules/http-lua/t/023-rewrite/sleep.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/socket-keepalive.t b/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/socket-keepalive.t rename to debian/modules/http-lua/t/023-rewrite/socket-keepalive.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/subrequest.t b/debian/modules/http-lua/t/023-rewrite/subrequest.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/subrequest.t rename to debian/modules/http-lua/t/023-rewrite/subrequest.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket-timeout.t b/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/tcp-socket-timeout.t rename to debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t b/debian/modules/http-lua/t/023-rewrite/tcp-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t rename to debian/modules/http-lua/t/023-rewrite/tcp-socket.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/unix-socket.t b/debian/modules/http-lua/t/023-rewrite/unix-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/unix-socket.t rename to debian/modules/http-lua/t/023-rewrite/unix-socket.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-exec.t b/debian/modules/http-lua/t/023-rewrite/uthread-exec.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/uthread-exec.t rename to debian/modules/http-lua/t/023-rewrite/uthread-exec.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-exit.t b/debian/modules/http-lua/t/023-rewrite/uthread-exit.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/uthread-exit.t rename to debian/modules/http-lua/t/023-rewrite/uthread-exit.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t b/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t rename to debian/modules/http-lua/t/023-rewrite/uthread-redirect.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t b/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t rename to debian/modules/http-lua/t/023-rewrite/uthread-spawn.t diff --git a/debian/modules/nginx-lua/t/024-access/auth.t b/debian/modules/http-lua/t/024-access/auth.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/auth.t rename to debian/modules/http-lua/t/024-access/auth.t diff --git a/debian/modules/nginx-lua/t/024-access/client-abort.t b/debian/modules/http-lua/t/024-access/client-abort.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/client-abort.t rename to debian/modules/http-lua/t/024-access/client-abort.t diff --git a/debian/modules/nginx-lua/t/024-access/exec.t b/debian/modules/http-lua/t/024-access/exec.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/exec.t rename to debian/modules/http-lua/t/024-access/exec.t diff --git a/debian/modules/nginx-lua/t/024-access/exit.t b/debian/modules/http-lua/t/024-access/exit.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/exit.t rename to debian/modules/http-lua/t/024-access/exit.t diff --git a/debian/modules/nginx-lua/t/024-access/mixed.t b/debian/modules/http-lua/t/024-access/mixed.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/mixed.t rename to debian/modules/http-lua/t/024-access/mixed.t diff --git a/debian/modules/nginx-lua/t/024-access/multi-capture.t b/debian/modules/http-lua/t/024-access/multi-capture.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/multi-capture.t rename to debian/modules/http-lua/t/024-access/multi-capture.t diff --git a/debian/modules/nginx-lua/t/024-access/on-abort.t b/debian/modules/http-lua/t/024-access/on-abort.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/on-abort.t rename to debian/modules/http-lua/t/024-access/on-abort.t diff --git a/debian/modules/nginx-lua/t/024-access/redirect.t b/debian/modules/http-lua/t/024-access/redirect.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/redirect.t rename to debian/modules/http-lua/t/024-access/redirect.t diff --git a/debian/modules/nginx-lua/t/024-access/req-body.t b/debian/modules/http-lua/t/024-access/req-body.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/req-body.t rename to debian/modules/http-lua/t/024-access/req-body.t diff --git a/debian/modules/nginx-lua/t/024-access/request_body.t b/debian/modules/http-lua/t/024-access/request_body.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/request_body.t rename to debian/modules/http-lua/t/024-access/request_body.t diff --git a/debian/modules/nginx-lua/t/024-access/sanity.t b/debian/modules/http-lua/t/024-access/sanity.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/sanity.t rename to debian/modules/http-lua/t/024-access/sanity.t diff --git a/debian/modules/nginx-lua/t/024-access/satisfy.t b/debian/modules/http-lua/t/024-access/satisfy.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/satisfy.t rename to debian/modules/http-lua/t/024-access/satisfy.t diff --git a/debian/modules/nginx-lua/t/024-access/sleep.t b/debian/modules/http-lua/t/024-access/sleep.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/sleep.t rename to debian/modules/http-lua/t/024-access/sleep.t diff --git a/debian/modules/nginx-lua/t/024-access/subrequest.t b/debian/modules/http-lua/t/024-access/subrequest.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/subrequest.t rename to debian/modules/http-lua/t/024-access/subrequest.t diff --git a/debian/modules/nginx-lua/t/024-access/uthread-exec.t b/debian/modules/http-lua/t/024-access/uthread-exec.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/uthread-exec.t rename to debian/modules/http-lua/t/024-access/uthread-exec.t diff --git a/debian/modules/nginx-lua/t/024-access/uthread-exit.t b/debian/modules/http-lua/t/024-access/uthread-exit.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/uthread-exit.t rename to debian/modules/http-lua/t/024-access/uthread-exit.t diff --git a/debian/modules/nginx-lua/t/024-access/uthread-redirect.t b/debian/modules/http-lua/t/024-access/uthread-redirect.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/uthread-redirect.t rename to debian/modules/http-lua/t/024-access/uthread-redirect.t diff --git a/debian/modules/nginx-lua/t/024-access/uthread-spawn.t b/debian/modules/http-lua/t/024-access/uthread-spawn.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/uthread-spawn.t rename to debian/modules/http-lua/t/024-access/uthread-spawn.t diff --git a/debian/modules/nginx-lua/t/025-codecache.t b/debian/modules/http-lua/t/025-codecache.t similarity index 100% rename from debian/modules/nginx-lua/t/025-codecache.t rename to debian/modules/http-lua/t/025-codecache.t diff --git a/debian/modules/nginx-lua/t/026-mysql.t b/debian/modules/http-lua/t/026-mysql.t similarity index 100% rename from debian/modules/nginx-lua/t/026-mysql.t rename to debian/modules/http-lua/t/026-mysql.t diff --git a/debian/modules/nginx-lua/t/027-multi-capture.t b/debian/modules/http-lua/t/027-multi-capture.t similarity index 100% rename from debian/modules/nginx-lua/t/027-multi-capture.t rename to debian/modules/http-lua/t/027-multi-capture.t diff --git a/debian/modules/nginx-lua/t/028-req-header.t b/debian/modules/http-lua/t/028-req-header.t similarity index 100% rename from debian/modules/nginx-lua/t/028-req-header.t rename to debian/modules/http-lua/t/028-req-header.t diff --git a/debian/modules/nginx-lua/t/029-http-time.t b/debian/modules/http-lua/t/029-http-time.t similarity index 100% rename from debian/modules/nginx-lua/t/029-http-time.t rename to debian/modules/http-lua/t/029-http-time.t diff --git a/debian/modules/nginx-lua/t/030-uri-args.t b/debian/modules/http-lua/t/030-uri-args.t similarity index 100% rename from debian/modules/nginx-lua/t/030-uri-args.t rename to debian/modules/http-lua/t/030-uri-args.t diff --git a/debian/modules/nginx-lua/t/031-post-args.t b/debian/modules/http-lua/t/031-post-args.t similarity index 100% rename from debian/modules/nginx-lua/t/031-post-args.t rename to debian/modules/http-lua/t/031-post-args.t diff --git a/debian/modules/nginx-lua/t/032-iolist.t b/debian/modules/http-lua/t/032-iolist.t similarity index 100% rename from debian/modules/nginx-lua/t/032-iolist.t rename to debian/modules/http-lua/t/032-iolist.t diff --git a/debian/modules/nginx-lua/t/033-ctx.t b/debian/modules/http-lua/t/033-ctx.t similarity index 100% rename from debian/modules/nginx-lua/t/033-ctx.t rename to debian/modules/http-lua/t/033-ctx.t diff --git a/debian/modules/nginx-lua/t/034-match.t b/debian/modules/http-lua/t/034-match.t similarity index 100% rename from debian/modules/nginx-lua/t/034-match.t rename to debian/modules/http-lua/t/034-match.t diff --git a/debian/modules/nginx-lua/t/035-gmatch.t b/debian/modules/http-lua/t/035-gmatch.t similarity index 100% rename from debian/modules/nginx-lua/t/035-gmatch.t rename to debian/modules/http-lua/t/035-gmatch.t diff --git a/debian/modules/nginx-lua/t/036-sub.t b/debian/modules/http-lua/t/036-sub.t similarity index 100% rename from debian/modules/nginx-lua/t/036-sub.t rename to debian/modules/http-lua/t/036-sub.t diff --git a/debian/modules/nginx-lua/t/037-gsub.t b/debian/modules/http-lua/t/037-gsub.t similarity index 100% rename from debian/modules/nginx-lua/t/037-gsub.t rename to debian/modules/http-lua/t/037-gsub.t diff --git a/debian/modules/nginx-lua/t/038-match-o.t b/debian/modules/http-lua/t/038-match-o.t similarity index 100% rename from debian/modules/nginx-lua/t/038-match-o.t rename to debian/modules/http-lua/t/038-match-o.t diff --git a/debian/modules/nginx-lua/t/039-sub-o.t b/debian/modules/http-lua/t/039-sub-o.t similarity index 100% rename from debian/modules/nginx-lua/t/039-sub-o.t rename to debian/modules/http-lua/t/039-sub-o.t diff --git a/debian/modules/nginx-lua/t/040-gsub-o.t b/debian/modules/http-lua/t/040-gsub-o.t similarity index 100% rename from debian/modules/nginx-lua/t/040-gsub-o.t rename to debian/modules/http-lua/t/040-gsub-o.t diff --git a/debian/modules/nginx-lua/t/041-header-filter.t b/debian/modules/http-lua/t/041-header-filter.t similarity index 100% rename from debian/modules/nginx-lua/t/041-header-filter.t rename to debian/modules/http-lua/t/041-header-filter.t diff --git a/debian/modules/nginx-lua/t/042-crc32.t b/debian/modules/http-lua/t/042-crc32.t similarity index 100% rename from debian/modules/nginx-lua/t/042-crc32.t rename to debian/modules/http-lua/t/042-crc32.t diff --git a/debian/modules/nginx-lua/t/043-shdict.t b/debian/modules/http-lua/t/043-shdict.t similarity index 100% rename from debian/modules/nginx-lua/t/043-shdict.t rename to debian/modules/http-lua/t/043-shdict.t diff --git a/debian/modules/nginx-lua/t/044-req-body.t b/debian/modules/http-lua/t/044-req-body.t similarity index 100% rename from debian/modules/nginx-lua/t/044-req-body.t rename to debian/modules/http-lua/t/044-req-body.t diff --git a/debian/modules/nginx-lua/t/045-ngx-var.t b/debian/modules/http-lua/t/045-ngx-var.t similarity index 100% rename from debian/modules/nginx-lua/t/045-ngx-var.t rename to debian/modules/http-lua/t/045-ngx-var.t diff --git a/debian/modules/nginx-lua/t/046-hmac.t b/debian/modules/http-lua/t/046-hmac.t similarity index 100% rename from debian/modules/nginx-lua/t/046-hmac.t rename to debian/modules/http-lua/t/046-hmac.t diff --git a/debian/modules/nginx-lua/t/047-match-jit.t b/debian/modules/http-lua/t/047-match-jit.t similarity index 100% rename from debian/modules/nginx-lua/t/047-match-jit.t rename to debian/modules/http-lua/t/047-match-jit.t diff --git a/debian/modules/nginx-lua/t/048-match-dfa.t b/debian/modules/http-lua/t/048-match-dfa.t similarity index 100% rename from debian/modules/nginx-lua/t/048-match-dfa.t rename to debian/modules/http-lua/t/048-match-dfa.t diff --git a/debian/modules/nginx-lua/t/049-gmatch-jit.t b/debian/modules/http-lua/t/049-gmatch-jit.t similarity index 100% rename from debian/modules/nginx-lua/t/049-gmatch-jit.t rename to debian/modules/http-lua/t/049-gmatch-jit.t diff --git a/debian/modules/nginx-lua/t/050-gmatch-dfa.t b/debian/modules/http-lua/t/050-gmatch-dfa.t similarity index 100% rename from debian/modules/nginx-lua/t/050-gmatch-dfa.t rename to debian/modules/http-lua/t/050-gmatch-dfa.t diff --git a/debian/modules/nginx-lua/t/051-sub-jit.t b/debian/modules/http-lua/t/051-sub-jit.t similarity index 100% rename from debian/modules/nginx-lua/t/051-sub-jit.t rename to debian/modules/http-lua/t/051-sub-jit.t diff --git a/debian/modules/nginx-lua/t/052-sub-dfa.t b/debian/modules/http-lua/t/052-sub-dfa.t similarity index 100% rename from debian/modules/nginx-lua/t/052-sub-dfa.t rename to debian/modules/http-lua/t/052-sub-dfa.t diff --git a/debian/modules/nginx-lua/t/053-gsub-jit.t b/debian/modules/http-lua/t/053-gsub-jit.t similarity index 100% rename from debian/modules/nginx-lua/t/053-gsub-jit.t rename to debian/modules/http-lua/t/053-gsub-jit.t diff --git a/debian/modules/nginx-lua/t/054-gsub-dfa.t b/debian/modules/http-lua/t/054-gsub-dfa.t similarity index 100% rename from debian/modules/nginx-lua/t/054-gsub-dfa.t rename to debian/modules/http-lua/t/054-gsub-dfa.t diff --git a/debian/modules/nginx-lua/t/055-subreq-vars.t b/debian/modules/http-lua/t/055-subreq-vars.t similarity index 100% rename from debian/modules/nginx-lua/t/055-subreq-vars.t rename to debian/modules/http-lua/t/055-subreq-vars.t diff --git a/debian/modules/nginx-lua/t/056-flush.t b/debian/modules/http-lua/t/056-flush.t similarity index 100% rename from debian/modules/nginx-lua/t/056-flush.t rename to debian/modules/http-lua/t/056-flush.t diff --git a/debian/modules/nginx-lua/t/057-flush-timeout.t b/debian/modules/http-lua/t/057-flush-timeout.t similarity index 100% rename from debian/modules/nginx-lua/t/057-flush-timeout.t rename to debian/modules/http-lua/t/057-flush-timeout.t diff --git a/debian/modules/nginx-lua/t/058-tcp-socket.t b/debian/modules/http-lua/t/058-tcp-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/058-tcp-socket.t rename to debian/modules/http-lua/t/058-tcp-socket.t diff --git a/debian/modules/nginx-lua/t/059-unix-socket.t b/debian/modules/http-lua/t/059-unix-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/059-unix-socket.t rename to debian/modules/http-lua/t/059-unix-socket.t diff --git a/debian/modules/nginx-lua/t/060-lua-memcached.t b/debian/modules/http-lua/t/060-lua-memcached.t similarity index 100% rename from debian/modules/nginx-lua/t/060-lua-memcached.t rename to debian/modules/http-lua/t/060-lua-memcached.t diff --git a/debian/modules/nginx-lua/t/061-lua-redis.t b/debian/modules/http-lua/t/061-lua-redis.t similarity index 100% rename from debian/modules/nginx-lua/t/061-lua-redis.t rename to debian/modules/http-lua/t/061-lua-redis.t diff --git a/debian/modules/nginx-lua/t/062-count.t b/debian/modules/http-lua/t/062-count.t similarity index 100% rename from debian/modules/nginx-lua/t/062-count.t rename to debian/modules/http-lua/t/062-count.t diff --git a/debian/modules/nginx-lua/t/063-abort.t b/debian/modules/http-lua/t/063-abort.t similarity index 100% rename from debian/modules/nginx-lua/t/063-abort.t rename to debian/modules/http-lua/t/063-abort.t diff --git a/debian/modules/nginx-lua/t/064-pcall.t b/debian/modules/http-lua/t/064-pcall.t similarity index 100% rename from debian/modules/nginx-lua/t/064-pcall.t rename to debian/modules/http-lua/t/064-pcall.t diff --git a/debian/modules/nginx-lua/t/065-tcp-socket-timeout.t b/debian/modules/http-lua/t/065-tcp-socket-timeout.t similarity index 100% rename from debian/modules/nginx-lua/t/065-tcp-socket-timeout.t rename to debian/modules/http-lua/t/065-tcp-socket-timeout.t diff --git a/debian/modules/nginx-lua/t/066-socket-receiveuntil.t b/debian/modules/http-lua/t/066-socket-receiveuntil.t similarity index 100% rename from debian/modules/nginx-lua/t/066-socket-receiveuntil.t rename to debian/modules/http-lua/t/066-socket-receiveuntil.t diff --git a/debian/modules/nginx-lua/t/067-req-socket.t b/debian/modules/http-lua/t/067-req-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/067-req-socket.t rename to debian/modules/http-lua/t/067-req-socket.t diff --git a/debian/modules/nginx-lua/t/068-socket-keepalive.t b/debian/modules/http-lua/t/068-socket-keepalive.t similarity index 100% rename from debian/modules/nginx-lua/t/068-socket-keepalive.t rename to debian/modules/http-lua/t/068-socket-keepalive.t diff --git a/debian/modules/nginx-lua/t/069-null.t b/debian/modules/http-lua/t/069-null.t similarity index 100% rename from debian/modules/nginx-lua/t/069-null.t rename to debian/modules/http-lua/t/069-null.t diff --git a/debian/modules/nginx-lua/t/070-sha1.t b/debian/modules/http-lua/t/070-sha1.t similarity index 100% rename from debian/modules/nginx-lua/t/070-sha1.t rename to debian/modules/http-lua/t/070-sha1.t diff --git a/debian/modules/nginx-lua/t/071-idle-socket.t b/debian/modules/http-lua/t/071-idle-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/071-idle-socket.t rename to debian/modules/http-lua/t/071-idle-socket.t diff --git a/debian/modules/nginx-lua/t/072-conditional-get.t b/debian/modules/http-lua/t/072-conditional-get.t similarity index 100% rename from debian/modules/nginx-lua/t/072-conditional-get.t rename to debian/modules/http-lua/t/072-conditional-get.t diff --git a/debian/modules/nginx-lua/t/073-backtrace.t b/debian/modules/http-lua/t/073-backtrace.t similarity index 100% rename from debian/modules/nginx-lua/t/073-backtrace.t rename to debian/modules/http-lua/t/073-backtrace.t diff --git a/debian/modules/nginx-lua/t/074-prefix-var.t b/debian/modules/http-lua/t/074-prefix-var.t similarity index 100% rename from debian/modules/nginx-lua/t/074-prefix-var.t rename to debian/modules/http-lua/t/074-prefix-var.t diff --git a/debian/modules/nginx-lua/t/075-logby.t b/debian/modules/http-lua/t/075-logby.t similarity index 100% rename from debian/modules/nginx-lua/t/075-logby.t rename to debian/modules/http-lua/t/075-logby.t diff --git a/debian/modules/nginx-lua/t/076-no-postpone.t b/debian/modules/http-lua/t/076-no-postpone.t similarity index 100% rename from debian/modules/nginx-lua/t/076-no-postpone.t rename to debian/modules/http-lua/t/076-no-postpone.t diff --git a/debian/modules/nginx-lua/t/077-sleep.t b/debian/modules/http-lua/t/077-sleep.t similarity index 100% rename from debian/modules/nginx-lua/t/077-sleep.t rename to debian/modules/http-lua/t/077-sleep.t diff --git a/debian/modules/nginx-lua/t/078-hup-vars.t b/debian/modules/http-lua/t/078-hup-vars.t similarity index 100% rename from debian/modules/nginx-lua/t/078-hup-vars.t rename to debian/modules/http-lua/t/078-hup-vars.t diff --git a/debian/modules/nginx-lua/t/079-unused-directives.t b/debian/modules/http-lua/t/079-unused-directives.t similarity index 100% rename from debian/modules/nginx-lua/t/079-unused-directives.t rename to debian/modules/http-lua/t/079-unused-directives.t diff --git a/debian/modules/nginx-lua/t/080-hup-shdict.t b/debian/modules/http-lua/t/080-hup-shdict.t similarity index 100% rename from debian/modules/nginx-lua/t/080-hup-shdict.t rename to debian/modules/http-lua/t/080-hup-shdict.t diff --git a/debian/modules/nginx-lua/t/081-bytecode.t b/debian/modules/http-lua/t/081-bytecode.t similarity index 100% rename from debian/modules/nginx-lua/t/081-bytecode.t rename to debian/modules/http-lua/t/081-bytecode.t diff --git a/debian/modules/nginx-lua/t/082-body-filter.t b/debian/modules/http-lua/t/082-body-filter.t similarity index 100% rename from debian/modules/nginx-lua/t/082-body-filter.t rename to debian/modules/http-lua/t/082-body-filter.t diff --git a/debian/modules/nginx-lua/t/083-bad-sock-self.t b/debian/modules/http-lua/t/083-bad-sock-self.t similarity index 100% rename from debian/modules/nginx-lua/t/083-bad-sock-self.t rename to debian/modules/http-lua/t/083-bad-sock-self.t diff --git a/debian/modules/nginx-lua/t/084-inclusive-receiveuntil.t b/debian/modules/http-lua/t/084-inclusive-receiveuntil.t similarity index 100% rename from debian/modules/nginx-lua/t/084-inclusive-receiveuntil.t rename to debian/modules/http-lua/t/084-inclusive-receiveuntil.t diff --git a/debian/modules/nginx-lua/t/085-if.t b/debian/modules/http-lua/t/085-if.t similarity index 100% rename from debian/modules/nginx-lua/t/085-if.t rename to debian/modules/http-lua/t/085-if.t diff --git a/debian/modules/nginx-lua/t/086-init-by.t b/debian/modules/http-lua/t/086-init-by.t similarity index 100% rename from debian/modules/nginx-lua/t/086-init-by.t rename to debian/modules/http-lua/t/086-init-by.t diff --git a/debian/modules/nginx-lua/t/087-udp-socket.t b/debian/modules/http-lua/t/087-udp-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/087-udp-socket.t rename to debian/modules/http-lua/t/087-udp-socket.t diff --git a/debian/modules/nginx-lua/t/088-req-method.t b/debian/modules/http-lua/t/088-req-method.t similarity index 100% rename from debian/modules/nginx-lua/t/088-req-method.t rename to debian/modules/http-lua/t/088-req-method.t diff --git a/debian/modules/nginx-lua/t/089-phase.t b/debian/modules/http-lua/t/089-phase.t similarity index 100% rename from debian/modules/nginx-lua/t/089-phase.t rename to debian/modules/http-lua/t/089-phase.t diff --git a/debian/modules/nginx-lua/t/090-log-socket-errors.t b/debian/modules/http-lua/t/090-log-socket-errors.t similarity index 100% rename from debian/modules/nginx-lua/t/090-log-socket-errors.t rename to debian/modules/http-lua/t/090-log-socket-errors.t diff --git a/debian/modules/nginx-lua/t/091-coroutine.t b/debian/modules/http-lua/t/091-coroutine.t similarity index 100% rename from debian/modules/nginx-lua/t/091-coroutine.t rename to debian/modules/http-lua/t/091-coroutine.t diff --git a/debian/modules/nginx-lua/t/092-eof.t b/debian/modules/http-lua/t/092-eof.t similarity index 100% rename from debian/modules/nginx-lua/t/092-eof.t rename to debian/modules/http-lua/t/092-eof.t diff --git a/debian/modules/nginx-lua/t/093-uthread-spawn.t b/debian/modules/http-lua/t/093-uthread-spawn.t similarity index 100% rename from debian/modules/nginx-lua/t/093-uthread-spawn.t rename to debian/modules/http-lua/t/093-uthread-spawn.t diff --git a/debian/modules/nginx-lua/t/094-uthread-exit.t b/debian/modules/http-lua/t/094-uthread-exit.t similarity index 100% rename from debian/modules/nginx-lua/t/094-uthread-exit.t rename to debian/modules/http-lua/t/094-uthread-exit.t diff --git a/debian/modules/nginx-lua/t/095-uthread-exec.t b/debian/modules/http-lua/t/095-uthread-exec.t similarity index 100% rename from debian/modules/nginx-lua/t/095-uthread-exec.t rename to debian/modules/http-lua/t/095-uthread-exec.t diff --git a/debian/modules/nginx-lua/t/096-uthread-redirect.t b/debian/modules/http-lua/t/096-uthread-redirect.t similarity index 100% rename from debian/modules/nginx-lua/t/096-uthread-redirect.t rename to debian/modules/http-lua/t/096-uthread-redirect.t diff --git a/debian/modules/nginx-lua/t/097-uthread-rewrite.t b/debian/modules/http-lua/t/097-uthread-rewrite.t similarity index 100% rename from debian/modules/nginx-lua/t/097-uthread-rewrite.t rename to debian/modules/http-lua/t/097-uthread-rewrite.t diff --git a/debian/modules/nginx-lua/t/098-uthread-wait.t b/debian/modules/http-lua/t/098-uthread-wait.t similarity index 100% rename from debian/modules/nginx-lua/t/098-uthread-wait.t rename to debian/modules/http-lua/t/098-uthread-wait.t diff --git a/debian/modules/nginx-lua/t/099-c-api.t b/debian/modules/http-lua/t/099-c-api.t similarity index 100% rename from debian/modules/nginx-lua/t/099-c-api.t rename to debian/modules/http-lua/t/099-c-api.t diff --git a/debian/modules/nginx-lua/t/100-client-abort.t b/debian/modules/http-lua/t/100-client-abort.t similarity index 100% rename from debian/modules/nginx-lua/t/100-client-abort.t rename to debian/modules/http-lua/t/100-client-abort.t diff --git a/debian/modules/nginx-lua/t/101-on-abort.t b/debian/modules/http-lua/t/101-on-abort.t similarity index 100% rename from debian/modules/nginx-lua/t/101-on-abort.t rename to debian/modules/http-lua/t/101-on-abort.t diff --git a/debian/modules/nginx-lua/t/102-req-start-time.t b/debian/modules/http-lua/t/102-req-start-time.t similarity index 100% rename from debian/modules/nginx-lua/t/102-req-start-time.t rename to debian/modules/http-lua/t/102-req-start-time.t diff --git a/debian/modules/nginx-lua/t/103-req-http-ver.t b/debian/modules/http-lua/t/103-req-http-ver.t similarity index 100% rename from debian/modules/nginx-lua/t/103-req-http-ver.t rename to debian/modules/http-lua/t/103-req-http-ver.t diff --git a/debian/modules/nginx-lua/t/104-req-raw-header.t b/debian/modules/http-lua/t/104-req-raw-header.t similarity index 100% rename from debian/modules/nginx-lua/t/104-req-raw-header.t rename to debian/modules/http-lua/t/104-req-raw-header.t diff --git a/debian/modules/nginx-lua/t/105-pressure.t b/debian/modules/http-lua/t/105-pressure.t similarity index 100% rename from debian/modules/nginx-lua/t/105-pressure.t rename to debian/modules/http-lua/t/105-pressure.t diff --git a/debian/modules/nginx-lua/t/106-timer.t b/debian/modules/http-lua/t/106-timer.t similarity index 100% rename from debian/modules/nginx-lua/t/106-timer.t rename to debian/modules/http-lua/t/106-timer.t diff --git a/debian/modules/nginx-lua/t/107-timer-errors.t b/debian/modules/http-lua/t/107-timer-errors.t similarity index 100% rename from debian/modules/nginx-lua/t/107-timer-errors.t rename to debian/modules/http-lua/t/107-timer-errors.t diff --git a/debian/modules/nginx-lua/t/108-timer-safe.t b/debian/modules/http-lua/t/108-timer-safe.t similarity index 100% rename from debian/modules/nginx-lua/t/108-timer-safe.t rename to debian/modules/http-lua/t/108-timer-safe.t diff --git a/debian/modules/nginx-lua/t/109-timer-hup.t b/debian/modules/http-lua/t/109-timer-hup.t similarity index 100% rename from debian/modules/nginx-lua/t/109-timer-hup.t rename to debian/modules/http-lua/t/109-timer-hup.t diff --git a/debian/modules/nginx-lua/t/110-etag.t b/debian/modules/http-lua/t/110-etag.t similarity index 100% rename from debian/modules/nginx-lua/t/110-etag.t rename to debian/modules/http-lua/t/110-etag.t diff --git a/debian/modules/nginx-lua/t/111-req-header-ua.t b/debian/modules/http-lua/t/111-req-header-ua.t similarity index 100% rename from debian/modules/nginx-lua/t/111-req-header-ua.t rename to debian/modules/http-lua/t/111-req-header-ua.t diff --git a/debian/modules/nginx-lua/t/112-req-header-conn.t b/debian/modules/http-lua/t/112-req-header-conn.t similarity index 100% rename from debian/modules/nginx-lua/t/112-req-header-conn.t rename to debian/modules/http-lua/t/112-req-header-conn.t diff --git a/debian/modules/nginx-lua/t/113-req-header-cookie.t b/debian/modules/http-lua/t/113-req-header-cookie.t similarity index 100% rename from debian/modules/nginx-lua/t/113-req-header-cookie.t rename to debian/modules/http-lua/t/113-req-header-cookie.t diff --git a/debian/modules/nginx-lua/t/114-config.t b/debian/modules/http-lua/t/114-config.t similarity index 100% rename from debian/modules/nginx-lua/t/114-config.t rename to debian/modules/http-lua/t/114-config.t diff --git a/debian/modules/nginx-lua/t/115-quote-sql-str.t b/debian/modules/http-lua/t/115-quote-sql-str.t similarity index 100% rename from debian/modules/nginx-lua/t/115-quote-sql-str.t rename to debian/modules/http-lua/t/115-quote-sql-str.t diff --git a/debian/modules/nginx-lua/t/116-raw-req-socket.t b/debian/modules/http-lua/t/116-raw-req-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/116-raw-req-socket.t rename to debian/modules/http-lua/t/116-raw-req-socket.t diff --git a/debian/modules/nginx-lua/t/117-raw-req-socket-timeout.t b/debian/modules/http-lua/t/117-raw-req-socket-timeout.t similarity index 100% rename from debian/modules/nginx-lua/t/117-raw-req-socket-timeout.t rename to debian/modules/http-lua/t/117-raw-req-socket-timeout.t diff --git a/debian/modules/nginx-lua/t/118-use-default-type.t b/debian/modules/http-lua/t/118-use-default-type.t similarity index 100% rename from debian/modules/nginx-lua/t/118-use-default-type.t rename to debian/modules/http-lua/t/118-use-default-type.t diff --git a/debian/modules/nginx-lua/t/119-config-prefix.t b/debian/modules/http-lua/t/119-config-prefix.t similarity index 100% rename from debian/modules/nginx-lua/t/119-config-prefix.t rename to debian/modules/http-lua/t/119-config-prefix.t diff --git a/debian/modules/nginx-lua/t/120-re-find.t b/debian/modules/http-lua/t/120-re-find.t similarity index 100% rename from debian/modules/nginx-lua/t/120-re-find.t rename to debian/modules/http-lua/t/120-re-find.t diff --git a/debian/modules/nginx-lua/t/121-version.t b/debian/modules/http-lua/t/121-version.t similarity index 100% rename from debian/modules/nginx-lua/t/121-version.t rename to debian/modules/http-lua/t/121-version.t diff --git a/debian/modules/nginx-lua/t/122-worker.t b/debian/modules/http-lua/t/122-worker.t similarity index 100% rename from debian/modules/nginx-lua/t/122-worker.t rename to debian/modules/http-lua/t/122-worker.t diff --git a/debian/modules/nginx-lua/t/123-lua-path.t b/debian/modules/http-lua/t/123-lua-path.t similarity index 100% rename from debian/modules/nginx-lua/t/123-lua-path.t rename to debian/modules/http-lua/t/123-lua-path.t diff --git a/debian/modules/nginx-lua/t/124-init-worker.t b/debian/modules/http-lua/t/124-init-worker.t similarity index 100% rename from debian/modules/nginx-lua/t/124-init-worker.t rename to debian/modules/http-lua/t/124-init-worker.t diff --git a/debian/modules/nginx-lua/t/125-configure-args.t b/debian/modules/http-lua/t/125-configure-args.t similarity index 100% rename from debian/modules/nginx-lua/t/125-configure-args.t rename to debian/modules/http-lua/t/125-configure-args.t diff --git a/debian/modules/nginx-lua/t/126-shdict-frag.t b/debian/modules/http-lua/t/126-shdict-frag.t similarity index 100% rename from debian/modules/nginx-lua/t/126-shdict-frag.t rename to debian/modules/http-lua/t/126-shdict-frag.t diff --git a/debian/modules/nginx-lua/t/127-uthread-kill.t b/debian/modules/http-lua/t/127-uthread-kill.t similarity index 100% rename from debian/modules/nginx-lua/t/127-uthread-kill.t rename to debian/modules/http-lua/t/127-uthread-kill.t diff --git a/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t b/debian/modules/http-lua/t/128-duplex-tcp-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/128-duplex-tcp-socket.t rename to debian/modules/http-lua/t/128-duplex-tcp-socket.t diff --git a/debian/modules/nginx-lua/t/129-ssl-socket.t b/debian/modules/http-lua/t/129-ssl-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/129-ssl-socket.t rename to debian/modules/http-lua/t/129-ssl-socket.t diff --git a/debian/modules/nginx-lua/t/130-internal-api.t b/debian/modules/http-lua/t/130-internal-api.t similarity index 100% rename from debian/modules/nginx-lua/t/130-internal-api.t rename to debian/modules/http-lua/t/130-internal-api.t diff --git a/debian/modules/nginx-lua/t/131-duplex-req-socket.t b/debian/modules/http-lua/t/131-duplex-req-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/131-duplex-req-socket.t rename to debian/modules/http-lua/t/131-duplex-req-socket.t diff --git a/debian/modules/nginx-lua/t/132-lua-blocks.t b/debian/modules/http-lua/t/132-lua-blocks.t similarity index 100% rename from debian/modules/nginx-lua/t/132-lua-blocks.t rename to debian/modules/http-lua/t/132-lua-blocks.t diff --git a/debian/modules/nginx-lua/t/133-worker-count.t b/debian/modules/http-lua/t/133-worker-count.t similarity index 100% rename from debian/modules/nginx-lua/t/133-worker-count.t rename to debian/modules/http-lua/t/133-worker-count.t diff --git a/debian/modules/nginx-lua/t/134-worker-count-5.t b/debian/modules/http-lua/t/134-worker-count-5.t similarity index 100% rename from debian/modules/nginx-lua/t/134-worker-count-5.t rename to debian/modules/http-lua/t/134-worker-count-5.t diff --git a/debian/modules/nginx-lua/t/135-worker-id.t b/debian/modules/http-lua/t/135-worker-id.t similarity index 100% rename from debian/modules/nginx-lua/t/135-worker-id.t rename to debian/modules/http-lua/t/135-worker-id.t diff --git a/debian/modules/nginx-lua/t/136-timer-counts.t b/debian/modules/http-lua/t/136-timer-counts.t similarity index 100% rename from debian/modules/nginx-lua/t/136-timer-counts.t rename to debian/modules/http-lua/t/136-timer-counts.t diff --git a/debian/modules/nginx-lua/t/137-req-misc.t b/debian/modules/http-lua/t/137-req-misc.t similarity index 100% rename from debian/modules/nginx-lua/t/137-req-misc.t rename to debian/modules/http-lua/t/137-req-misc.t diff --git a/debian/modules/nginx-lua/t/138-balancer.t b/debian/modules/http-lua/t/138-balancer.t similarity index 100% rename from debian/modules/nginx-lua/t/138-balancer.t rename to debian/modules/http-lua/t/138-balancer.t diff --git a/debian/modules/nginx-lua/t/139-ssl-cert-by.t b/debian/modules/http-lua/t/139-ssl-cert-by.t similarity index 100% rename from debian/modules/nginx-lua/t/139-ssl-cert-by.t rename to debian/modules/http-lua/t/139-ssl-cert-by.t diff --git a/debian/modules/nginx-lua/t/140-ssl-c-api.t b/debian/modules/http-lua/t/140-ssl-c-api.t similarity index 100% rename from debian/modules/nginx-lua/t/140-ssl-c-api.t rename to debian/modules/http-lua/t/140-ssl-c-api.t diff --git a/debian/modules/nginx-lua/t/141-luajit.t b/debian/modules/http-lua/t/141-luajit.t similarity index 100% rename from debian/modules/nginx-lua/t/141-luajit.t rename to debian/modules/http-lua/t/141-luajit.t diff --git a/debian/modules/nginx-lua/t/142-ssl-session-store.t b/debian/modules/http-lua/t/142-ssl-session-store.t similarity index 100% rename from debian/modules/nginx-lua/t/142-ssl-session-store.t rename to debian/modules/http-lua/t/142-ssl-session-store.t diff --git a/debian/modules/nginx-lua/t/143-ssl-session-fetch.t b/debian/modules/http-lua/t/143-ssl-session-fetch.t similarity index 100% rename from debian/modules/nginx-lua/t/143-ssl-session-fetch.t rename to debian/modules/http-lua/t/143-ssl-session-fetch.t diff --git a/debian/modules/nginx-lua/t/144-shdict-incr-init.t b/debian/modules/http-lua/t/144-shdict-incr-init.t similarity index 100% rename from debian/modules/nginx-lua/t/144-shdict-incr-init.t rename to debian/modules/http-lua/t/144-shdict-incr-init.t diff --git a/debian/modules/nginx-lua/t/145-shdict-list.t b/debian/modules/http-lua/t/145-shdict-list.t similarity index 100% rename from debian/modules/nginx-lua/t/145-shdict-list.t rename to debian/modules/http-lua/t/145-shdict-list.t diff --git a/debian/modules/nginx-lua/t/146-malloc-trim.t b/debian/modules/http-lua/t/146-malloc-trim.t similarity index 100% rename from debian/modules/nginx-lua/t/146-malloc-trim.t rename to debian/modules/http-lua/t/146-malloc-trim.t diff --git a/debian/modules/nginx-lua/t/147-tcp-socket-timeouts.t b/debian/modules/http-lua/t/147-tcp-socket-timeouts.t similarity index 100% rename from debian/modules/nginx-lua/t/147-tcp-socket-timeouts.t rename to debian/modules/http-lua/t/147-tcp-socket-timeouts.t diff --git a/debian/modules/nginx-lua/t/148-fake-shm-zone.t b/debian/modules/http-lua/t/148-fake-shm-zone.t similarity index 100% rename from debian/modules/nginx-lua/t/148-fake-shm-zone.t rename to debian/modules/http-lua/t/148-fake-shm-zone.t diff --git a/debian/modules/nginx-lua/t/149-hup-fake-shm-zone.t b/debian/modules/http-lua/t/149-hup-fake-shm-zone.t similarity index 100% rename from debian/modules/nginx-lua/t/149-hup-fake-shm-zone.t rename to debian/modules/http-lua/t/149-hup-fake-shm-zone.t diff --git a/debian/modules/nginx-lua/t/150-fake-delayed-load.t b/debian/modules/http-lua/t/150-fake-delayed-load.t similarity index 100% rename from debian/modules/nginx-lua/t/150-fake-delayed-load.t rename to debian/modules/http-lua/t/150-fake-delayed-load.t diff --git a/debian/modules/nginx-lua/t/151-initby-hup.t b/debian/modules/http-lua/t/151-initby-hup.t similarity index 100% rename from debian/modules/nginx-lua/t/151-initby-hup.t rename to debian/modules/http-lua/t/151-initby-hup.t diff --git a/debian/modules/nginx-lua/t/152-timer-every.t b/debian/modules/http-lua/t/152-timer-every.t similarity index 100% rename from debian/modules/nginx-lua/t/152-timer-every.t rename to debian/modules/http-lua/t/152-timer-every.t diff --git a/debian/modules/nginx-lua/t/153-semaphore-hup.t b/debian/modules/http-lua/t/153-semaphore-hup.t similarity index 100% rename from debian/modules/nginx-lua/t/153-semaphore-hup.t rename to debian/modules/http-lua/t/153-semaphore-hup.t diff --git a/debian/modules/nginx-lua/t/154-semaphore.t b/debian/modules/http-lua/t/154-semaphore.t similarity index 100% rename from debian/modules/nginx-lua/t/154-semaphore.t rename to debian/modules/http-lua/t/154-semaphore.t diff --git a/debian/modules/nginx-lua/t/StapThread.pm b/debian/modules/http-lua/t/StapThread.pm similarity index 100% rename from debian/modules/nginx-lua/t/StapThread.pm rename to debian/modules/http-lua/t/StapThread.pm diff --git a/debian/modules/nginx-lua/t/cert/comodo-ca.crt b/debian/modules/http-lua/t/cert/comodo-ca.crt similarity index 100% rename from debian/modules/nginx-lua/t/cert/comodo-ca.crt rename to debian/modules/http-lua/t/cert/comodo-ca.crt diff --git a/debian/modules/nginx-lua/t/cert/equifax.crt b/debian/modules/http-lua/t/cert/equifax.crt similarity index 100% rename from debian/modules/nginx-lua/t/cert/equifax.crt rename to debian/modules/http-lua/t/cert/equifax.crt diff --git a/debian/modules/nginx-lua/t/cert/test.crl b/debian/modules/http-lua/t/cert/test.crl similarity index 100% rename from debian/modules/nginx-lua/t/cert/test.crl rename to debian/modules/http-lua/t/cert/test.crl diff --git a/debian/modules/nginx-lua/t/cert/test.crt b/debian/modules/http-lua/t/cert/test.crt similarity index 100% rename from debian/modules/nginx-lua/t/cert/test.crt rename to debian/modules/http-lua/t/cert/test.crt diff --git a/debian/modules/nginx-lua/t/cert/test.key b/debian/modules/http-lua/t/cert/test.key similarity index 100% rename from debian/modules/nginx-lua/t/cert/test.key rename to debian/modules/http-lua/t/cert/test.key diff --git a/debian/modules/nginx-lua/t/cert/test2.crt b/debian/modules/http-lua/t/cert/test2.crt similarity index 100% rename from debian/modules/nginx-lua/t/cert/test2.crt rename to debian/modules/http-lua/t/cert/test2.crt diff --git a/debian/modules/nginx-lua/t/cert/test2.key b/debian/modules/http-lua/t/cert/test2.key similarity index 100% rename from debian/modules/nginx-lua/t/cert/test2.key rename to debian/modules/http-lua/t/cert/test2.key diff --git a/debian/modules/nginx-lua/t/cert/test_ecdsa.crt b/debian/modules/http-lua/t/cert/test_ecdsa.crt similarity index 100% rename from debian/modules/nginx-lua/t/cert/test_ecdsa.crt rename to debian/modules/http-lua/t/cert/test_ecdsa.crt diff --git a/debian/modules/nginx-lua/t/cert/test_ecdsa.key b/debian/modules/http-lua/t/cert/test_ecdsa.key similarity index 100% rename from debian/modules/nginx-lua/t/cert/test_ecdsa.key rename to debian/modules/http-lua/t/cert/test_ecdsa.key diff --git a/debian/modules/nginx-lua/t/data/fake-delayed-load-module/config b/debian/modules/http-lua/t/data/fake-delayed-load-module/config similarity index 100% rename from debian/modules/nginx-lua/t/data/fake-delayed-load-module/config rename to debian/modules/http-lua/t/data/fake-delayed-load-module/config diff --git a/debian/modules/nginx-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c b/debian/modules/http-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c similarity index 100% rename from debian/modules/nginx-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c rename to debian/modules/http-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c diff --git a/debian/modules/nginx-lua/t/data/fake-module/config b/debian/modules/http-lua/t/data/fake-module/config similarity index 100% rename from debian/modules/nginx-lua/t/data/fake-module/config rename to debian/modules/http-lua/t/data/fake-module/config diff --git a/debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c b/debian/modules/http-lua/t/data/fake-module/ngx_http_fake_module.c similarity index 100% rename from debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c rename to debian/modules/http-lua/t/data/fake-module/ngx_http_fake_module.c diff --git a/debian/modules/nginx-lua/t/data/fake-shm-module/config b/debian/modules/http-lua/t/data/fake-shm-module/config similarity index 100% rename from debian/modules/nginx-lua/t/data/fake-shm-module/config rename to debian/modules/http-lua/t/data/fake-shm-module/config diff --git a/debian/modules/nginx-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c b/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c similarity index 100% rename from debian/modules/nginx-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c rename to debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c diff --git a/debian/modules/nginx-lua/t/lib/CRC32.lua b/debian/modules/http-lua/t/lib/CRC32.lua similarity index 100% rename from debian/modules/nginx-lua/t/lib/CRC32.lua rename to debian/modules/http-lua/t/lib/CRC32.lua diff --git a/debian/modules/nginx-lua/t/lib/Memcached.lua b/debian/modules/http-lua/t/lib/Memcached.lua similarity index 100% rename from debian/modules/nginx-lua/t/lib/Memcached.lua rename to debian/modules/http-lua/t/lib/Memcached.lua diff --git a/debian/modules/nginx-lua/t/lib/Redis.lua b/debian/modules/http-lua/t/lib/Redis.lua similarity index 100% rename from debian/modules/nginx-lua/t/lib/Redis.lua rename to debian/modules/http-lua/t/lib/Redis.lua diff --git a/debian/modules/nginx-lua/t/lib/ljson.lua b/debian/modules/http-lua/t/lib/ljson.lua similarity index 100% rename from debian/modules/nginx-lua/t/lib/ljson.lua rename to debian/modules/http-lua/t/lib/ljson.lua diff --git a/debian/modules/nginx-lua/tapset/ngx_lua.stp b/debian/modules/http-lua/tapset/ngx_lua.stp similarity index 100% rename from debian/modules/nginx-lua/tapset/ngx_lua.stp rename to debian/modules/http-lua/tapset/ngx_lua.stp diff --git a/debian/modules/nginx-lua/util/build.sh b/debian/modules/http-lua/util/build.sh similarity index 100% rename from debian/modules/nginx-lua/util/build.sh rename to debian/modules/http-lua/util/build.sh diff --git a/debian/modules/nginx-lua/util/fix-comments b/debian/modules/http-lua/util/fix-comments similarity index 100% rename from debian/modules/nginx-lua/util/fix-comments rename to debian/modules/http-lua/util/fix-comments diff --git a/debian/modules/nginx-lua/util/gen-lexer-c b/debian/modules/http-lua/util/gen-lexer-c similarity index 100% rename from debian/modules/nginx-lua/util/gen-lexer-c rename to debian/modules/http-lua/util/gen-lexer-c diff --git a/debian/modules/nginx-lua/util/ngx-links b/debian/modules/http-lua/util/ngx-links similarity index 100% rename from debian/modules/nginx-lua/util/ngx-links rename to debian/modules/http-lua/util/ngx-links diff --git a/debian/modules/nginx-lua/util/releng b/debian/modules/http-lua/util/releng similarity index 100% rename from debian/modules/nginx-lua/util/releng rename to debian/modules/http-lua/util/releng diff --git a/debian/modules/nginx-lua/util/retab b/debian/modules/http-lua/util/retab similarity index 100% rename from debian/modules/nginx-lua/util/retab rename to debian/modules/http-lua/util/retab diff --git a/debian/modules/nginx-lua/util/revim b/debian/modules/http-lua/util/revim similarity index 100% rename from debian/modules/nginx-lua/util/revim rename to debian/modules/http-lua/util/revim diff --git a/debian/modules/nginx-lua/util/run_test.sh b/debian/modules/http-lua/util/run_test.sh similarity index 100% rename from debian/modules/nginx-lua/util/run_test.sh rename to debian/modules/http-lua/util/run_test.sh diff --git a/debian/modules/nginx-lua/util/update-readme.sh b/debian/modules/http-lua/util/update-readme.sh similarity index 100% rename from debian/modules/nginx-lua/util/update-readme.sh rename to debian/modules/http-lua/util/update-readme.sh diff --git a/debian/modules/nginx-lua/valgrind.suppress b/debian/modules/http-lua/valgrind.suppress similarity index 100% rename from debian/modules/nginx-lua/valgrind.suppress rename to debian/modules/http-lua/valgrind.suppress diff --git a/debian/modules/nginx-development-kit/LICENSE b/debian/modules/http-ndk/LICENSE similarity index 100% rename from debian/modules/nginx-development-kit/LICENSE rename to debian/modules/http-ndk/LICENSE diff --git a/debian/modules/nginx-development-kit/README.md b/debian/modules/http-ndk/README.md similarity index 100% rename from debian/modules/nginx-development-kit/README.md rename to debian/modules/http-ndk/README.md diff --git a/debian/modules/nginx-development-kit/README_AUTO_LIB b/debian/modules/http-ndk/README_AUTO_LIB similarity index 100% rename from debian/modules/nginx-development-kit/README_AUTO_LIB rename to debian/modules/http-ndk/README_AUTO_LIB diff --git a/debian/modules/nginx-development-kit/TODO b/debian/modules/http-ndk/TODO similarity index 100% rename from debian/modules/nginx-development-kit/TODO rename to debian/modules/http-ndk/TODO diff --git a/debian/modules/nginx-development-kit/auto/actions/array b/debian/modules/http-ndk/auto/actions/array similarity index 100% rename from debian/modules/nginx-development-kit/auto/actions/array rename to debian/modules/http-ndk/auto/actions/array diff --git a/debian/modules/nginx-development-kit/auto/actions/palloc b/debian/modules/http-ndk/auto/actions/palloc similarity index 100% rename from debian/modules/nginx-development-kit/auto/actions/palloc rename to debian/modules/http-ndk/auto/actions/palloc diff --git a/debian/modules/nginx-development-kit/auto/build b/debian/modules/http-ndk/auto/build similarity index 100% rename from debian/modules/nginx-development-kit/auto/build rename to debian/modules/http-ndk/auto/build diff --git a/debian/modules/nginx-development-kit/auto/data/action_replacements b/debian/modules/http-ndk/auto/data/action_replacements similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/action_replacements rename to debian/modules/http-ndk/auto/data/action_replacements diff --git a/debian/modules/nginx-development-kit/auto/data/action_types b/debian/modules/http-ndk/auto/data/action_types similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/action_types rename to debian/modules/http-ndk/auto/data/action_types diff --git a/debian/modules/nginx-development-kit/auto/data/conf_args b/debian/modules/http-ndk/auto/data/conf_args similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/conf_args rename to debian/modules/http-ndk/auto/data/conf_args diff --git a/debian/modules/nginx-development-kit/auto/data/conf_locs b/debian/modules/http-ndk/auto/data/conf_locs similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/conf_locs rename to debian/modules/http-ndk/auto/data/conf_locs diff --git a/debian/modules/nginx-development-kit/auto/data/conf_macros b/debian/modules/http-ndk/auto/data/conf_macros similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/conf_macros rename to debian/modules/http-ndk/auto/data/conf_macros diff --git a/debian/modules/nginx-development-kit/auto/data/contexts b/debian/modules/http-ndk/auto/data/contexts similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/contexts rename to debian/modules/http-ndk/auto/data/contexts diff --git a/debian/modules/nginx-development-kit/auto/data/header_files b/debian/modules/http-ndk/auto/data/header_files similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/header_files rename to debian/modules/http-ndk/auto/data/header_files diff --git a/debian/modules/nginx-development-kit/auto/data/headers b/debian/modules/http-ndk/auto/data/headers similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/headers rename to debian/modules/http-ndk/auto/data/headers diff --git a/debian/modules/nginx-development-kit/auto/data/module_dependencies b/debian/modules/http-ndk/auto/data/module_dependencies similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/module_dependencies rename to debian/modules/http-ndk/auto/data/module_dependencies diff --git a/debian/modules/nginx-development-kit/auto/data/modules_optional b/debian/modules/http-ndk/auto/data/modules_optional similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/modules_optional rename to debian/modules/http-ndk/auto/data/modules_optional diff --git a/debian/modules/nginx-development-kit/auto/data/prefixes b/debian/modules/http-ndk/auto/data/prefixes similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/prefixes rename to debian/modules/http-ndk/auto/data/prefixes diff --git a/debian/modules/nginx-development-kit/auto/src/array.h b/debian/modules/http-ndk/auto/src/array.h similarity index 100% rename from debian/modules/nginx-development-kit/auto/src/array.h rename to debian/modules/http-ndk/auto/src/array.h diff --git a/debian/modules/nginx-development-kit/auto/src/conf_cmd_basic.h b/debian/modules/http-ndk/auto/src/conf_cmd_basic.h similarity index 100% rename from debian/modules/nginx-development-kit/auto/src/conf_cmd_basic.h rename to debian/modules/http-ndk/auto/src/conf_cmd_basic.h diff --git a/debian/modules/nginx-development-kit/auto/src/conf_merge.h b/debian/modules/http-ndk/auto/src/conf_merge.h similarity index 100% rename from debian/modules/nginx-development-kit/auto/src/conf_merge.h rename to debian/modules/http-ndk/auto/src/conf_merge.h diff --git a/debian/modules/nginx-development-kit/auto/src/palloc.h b/debian/modules/http-ndk/auto/src/palloc.h similarity index 100% rename from debian/modules/nginx-development-kit/auto/src/palloc.h rename to debian/modules/http-ndk/auto/src/palloc.h diff --git a/debian/modules/nginx-development-kit/auto/text/autogen b/debian/modules/http-ndk/auto/text/autogen similarity index 100% rename from debian/modules/nginx-development-kit/auto/text/autogen rename to debian/modules/http-ndk/auto/text/autogen diff --git a/debian/modules/nginx-development-kit/config b/debian/modules/http-ndk/config similarity index 100% rename from debian/modules/nginx-development-kit/config rename to debian/modules/http-ndk/config diff --git a/debian/modules/nginx-development-kit/docs/core/action_macros b/debian/modules/http-ndk/docs/core/action_macros similarity index 100% rename from debian/modules/nginx-development-kit/docs/core/action_macros rename to debian/modules/http-ndk/docs/core/action_macros diff --git a/debian/modules/nginx-development-kit/docs/core/conf_cmds b/debian/modules/http-ndk/docs/core/conf_cmds similarity index 100% rename from debian/modules/nginx-development-kit/docs/core/conf_cmds rename to debian/modules/http-ndk/docs/core/conf_cmds diff --git a/debian/modules/nginx-development-kit/docs/modules/set_var b/debian/modules/http-ndk/docs/modules/set_var similarity index 100% rename from debian/modules/nginx-development-kit/docs/modules/set_var rename to debian/modules/http-ndk/docs/modules/set_var diff --git a/debian/modules/nginx-development-kit/docs/patches/more_logging_info b/debian/modules/http-ndk/docs/patches/more_logging_info similarity index 100% rename from debian/modules/nginx-development-kit/docs/patches/more_logging_info rename to debian/modules/http-ndk/docs/patches/more_logging_info diff --git a/debian/modules/nginx-development-kit/docs/upstream/list b/debian/modules/http-ndk/docs/upstream/list similarity index 100% rename from debian/modules/nginx-development-kit/docs/upstream/list rename to debian/modules/http-ndk/docs/upstream/list diff --git a/debian/modules/nginx-development-kit/examples/README b/debian/modules/http-ndk/examples/README similarity index 100% rename from debian/modules/nginx-development-kit/examples/README rename to debian/modules/http-ndk/examples/README diff --git a/debian/modules/nginx-development-kit/examples/http/set_var/config b/debian/modules/http-ndk/examples/http/set_var/config similarity index 100% rename from debian/modules/nginx-development-kit/examples/http/set_var/config rename to debian/modules/http-ndk/examples/http/set_var/config diff --git a/debian/modules/nginx-development-kit/examples/http/set_var/ngx_http_set_var_examples_module.c b/debian/modules/http-ndk/examples/http/set_var/ngx_http_set_var_examples_module.c similarity index 100% rename from debian/modules/nginx-development-kit/examples/http/set_var/ngx_http_set_var_examples_module.c rename to debian/modules/http-ndk/examples/http/set_var/ngx_http_set_var_examples_module.c diff --git a/debian/modules/nginx-development-kit/ngx_auto_lib_core b/debian/modules/http-ndk/ngx_auto_lib_core similarity index 100% rename from debian/modules/nginx-development-kit/ngx_auto_lib_core rename to debian/modules/http-ndk/ngx_auto_lib_core diff --git a/debian/modules/nginx-development-kit/notes/CHANGES b/debian/modules/http-ndk/notes/CHANGES similarity index 100% rename from debian/modules/nginx-development-kit/notes/CHANGES rename to debian/modules/http-ndk/notes/CHANGES diff --git a/debian/modules/nginx-development-kit/notes/LICENSE b/debian/modules/http-ndk/notes/LICENSE similarity index 100% rename from debian/modules/nginx-development-kit/notes/LICENSE rename to debian/modules/http-ndk/notes/LICENSE diff --git a/debian/modules/nginx-development-kit/objs/ndk_array.h b/debian/modules/http-ndk/objs/ndk_array.h similarity index 100% rename from debian/modules/nginx-development-kit/objs/ndk_array.h rename to debian/modules/http-ndk/objs/ndk_array.h diff --git a/debian/modules/nginx-development-kit/objs/ndk_conf_cmd_basic.h b/debian/modules/http-ndk/objs/ndk_conf_cmd_basic.h similarity index 100% rename from debian/modules/nginx-development-kit/objs/ndk_conf_cmd_basic.h rename to debian/modules/http-ndk/objs/ndk_conf_cmd_basic.h diff --git a/debian/modules/nginx-development-kit/objs/ndk_conf_cmd_extra.h b/debian/modules/http-ndk/objs/ndk_conf_cmd_extra.h similarity index 100% rename from debian/modules/nginx-development-kit/objs/ndk_conf_cmd_extra.h rename to debian/modules/http-ndk/objs/ndk_conf_cmd_extra.h diff --git a/debian/modules/nginx-development-kit/objs/ndk_conf_merge.h b/debian/modules/http-ndk/objs/ndk_conf_merge.h similarity index 100% rename from debian/modules/nginx-development-kit/objs/ndk_conf_merge.h rename to debian/modules/http-ndk/objs/ndk_conf_merge.h diff --git a/debian/modules/nginx-development-kit/objs/ndk_config.c b/debian/modules/http-ndk/objs/ndk_config.c similarity index 100% rename from debian/modules/nginx-development-kit/objs/ndk_config.c rename to debian/modules/http-ndk/objs/ndk_config.c diff --git a/debian/modules/nginx-development-kit/objs/ndk_config.h b/debian/modules/http-ndk/objs/ndk_config.h similarity index 100% rename from debian/modules/nginx-development-kit/objs/ndk_config.h rename to debian/modules/http-ndk/objs/ndk_config.h diff --git a/debian/modules/nginx-development-kit/objs/ndk_includes.h b/debian/modules/http-ndk/objs/ndk_includes.h similarity index 100% rename from debian/modules/nginx-development-kit/objs/ndk_includes.h rename to debian/modules/http-ndk/objs/ndk_includes.h diff --git a/debian/modules/nginx-development-kit/objs/ndk_palloc.h b/debian/modules/http-ndk/objs/ndk_palloc.h similarity index 100% rename from debian/modules/nginx-development-kit/objs/ndk_palloc.h rename to debian/modules/http-ndk/objs/ndk_palloc.h diff --git a/debian/modules/nginx-development-kit/patches/auto_config b/debian/modules/http-ndk/patches/auto_config similarity index 100% rename from debian/modules/nginx-development-kit/patches/auto_config rename to debian/modules/http-ndk/patches/auto_config diff --git a/debian/modules/nginx-development-kit/patches/expose_rewrite_functions b/debian/modules/http-ndk/patches/expose_rewrite_functions similarity index 100% rename from debian/modules/nginx-development-kit/patches/expose_rewrite_functions rename to debian/modules/http-ndk/patches/expose_rewrite_functions diff --git a/debian/modules/nginx-development-kit/patches/rewrite_phase_handler b/debian/modules/http-ndk/patches/rewrite_phase_handler similarity index 100% rename from debian/modules/nginx-development-kit/patches/rewrite_phase_handler rename to debian/modules/http-ndk/patches/rewrite_phase_handler diff --git a/debian/modules/nginx-development-kit/src/hash/md5.h b/debian/modules/http-ndk/src/hash/md5.h similarity index 100% rename from debian/modules/nginx-development-kit/src/hash/md5.h rename to debian/modules/http-ndk/src/hash/md5.h diff --git a/debian/modules/nginx-development-kit/src/hash/murmurhash2.c b/debian/modules/http-ndk/src/hash/murmurhash2.c similarity index 100% rename from debian/modules/nginx-development-kit/src/hash/murmurhash2.c rename to debian/modules/http-ndk/src/hash/murmurhash2.c diff --git a/debian/modules/nginx-development-kit/src/hash/sha.h b/debian/modules/http-ndk/src/hash/sha.h similarity index 100% rename from debian/modules/nginx-development-kit/src/hash/sha.h rename to debian/modules/http-ndk/src/hash/sha.h diff --git a/debian/modules/nginx-development-kit/src/ndk.c b/debian/modules/http-ndk/src/ndk.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk.c rename to debian/modules/http-ndk/src/ndk.c diff --git a/debian/modules/nginx-development-kit/src/ndk.h b/debian/modules/http-ndk/src/ndk.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk.h rename to debian/modules/http-ndk/src/ndk.h diff --git a/debian/modules/nginx-development-kit/src/ndk_buf.c b/debian/modules/http-ndk/src/ndk_buf.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_buf.c rename to debian/modules/http-ndk/src/ndk_buf.c diff --git a/debian/modules/nginx-development-kit/src/ndk_buf.h b/debian/modules/http-ndk/src/ndk_buf.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_buf.h rename to debian/modules/http-ndk/src/ndk_buf.h diff --git a/debian/modules/nginx-development-kit/src/ndk_complex_path.c b/debian/modules/http-ndk/src/ndk_complex_path.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_complex_path.c rename to debian/modules/http-ndk/src/ndk_complex_path.c diff --git a/debian/modules/nginx-development-kit/src/ndk_complex_path.h b/debian/modules/http-ndk/src/ndk_complex_path.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_complex_path.h rename to debian/modules/http-ndk/src/ndk_complex_path.h diff --git a/debian/modules/nginx-development-kit/src/ndk_complex_value.c b/debian/modules/http-ndk/src/ndk_complex_value.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_complex_value.c rename to debian/modules/http-ndk/src/ndk_complex_value.c diff --git a/debian/modules/nginx-development-kit/src/ndk_complex_value.h b/debian/modules/http-ndk/src/ndk_complex_value.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_complex_value.h rename to debian/modules/http-ndk/src/ndk_complex_value.h diff --git a/debian/modules/nginx-development-kit/src/ndk_conf_file.c b/debian/modules/http-ndk/src/ndk_conf_file.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_conf_file.c rename to debian/modules/http-ndk/src/ndk_conf_file.c diff --git a/debian/modules/nginx-development-kit/src/ndk_conf_file.h b/debian/modules/http-ndk/src/ndk_conf_file.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_conf_file.h rename to debian/modules/http-ndk/src/ndk_conf_file.h diff --git a/debian/modules/nginx-development-kit/src/ndk_debug.c b/debian/modules/http-ndk/src/ndk_debug.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_debug.c rename to debian/modules/http-ndk/src/ndk_debug.c diff --git a/debian/modules/nginx-development-kit/src/ndk_debug.h b/debian/modules/http-ndk/src/ndk_debug.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_debug.h rename to debian/modules/http-ndk/src/ndk_debug.h diff --git a/debian/modules/nginx-development-kit/src/ndk_encoding.c b/debian/modules/http-ndk/src/ndk_encoding.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_encoding.c rename to debian/modules/http-ndk/src/ndk_encoding.c diff --git a/debian/modules/nginx-development-kit/src/ndk_encoding.h b/debian/modules/http-ndk/src/ndk_encoding.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_encoding.h rename to debian/modules/http-ndk/src/ndk_encoding.h diff --git a/debian/modules/nginx-development-kit/src/ndk_hash.c b/debian/modules/http-ndk/src/ndk_hash.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_hash.c rename to debian/modules/http-ndk/src/ndk_hash.c diff --git a/debian/modules/nginx-development-kit/src/ndk_hash.h b/debian/modules/http-ndk/src/ndk_hash.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_hash.h rename to debian/modules/http-ndk/src/ndk_hash.h diff --git a/debian/modules/nginx-development-kit/src/ndk_http.c b/debian/modules/http-ndk/src/ndk_http.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_http.c rename to debian/modules/http-ndk/src/ndk_http.c diff --git a/debian/modules/nginx-development-kit/src/ndk_http.h b/debian/modules/http-ndk/src/ndk_http.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_http.h rename to debian/modules/http-ndk/src/ndk_http.h diff --git a/debian/modules/nginx-development-kit/src/ndk_http_headers.h b/debian/modules/http-ndk/src/ndk_http_headers.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_http_headers.h rename to debian/modules/http-ndk/src/ndk_http_headers.h diff --git a/debian/modules/nginx-development-kit/src/ndk_log.c b/debian/modules/http-ndk/src/ndk_log.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_log.c rename to debian/modules/http-ndk/src/ndk_log.c diff --git a/debian/modules/nginx-development-kit/src/ndk_log.h b/debian/modules/http-ndk/src/ndk_log.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_log.h rename to debian/modules/http-ndk/src/ndk_log.h diff --git a/debian/modules/nginx-development-kit/src/ndk_parse.h b/debian/modules/http-ndk/src/ndk_parse.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_parse.h rename to debian/modules/http-ndk/src/ndk_parse.h diff --git a/debian/modules/nginx-development-kit/src/ndk_path.c b/debian/modules/http-ndk/src/ndk_path.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_path.c rename to debian/modules/http-ndk/src/ndk_path.c diff --git a/debian/modules/nginx-development-kit/src/ndk_path.h b/debian/modules/http-ndk/src/ndk_path.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_path.h rename to debian/modules/http-ndk/src/ndk_path.h diff --git a/debian/modules/nginx-development-kit/src/ndk_process.c b/debian/modules/http-ndk/src/ndk_process.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_process.c rename to debian/modules/http-ndk/src/ndk_process.c diff --git a/debian/modules/nginx-development-kit/src/ndk_process.h b/debian/modules/http-ndk/src/ndk_process.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_process.h rename to debian/modules/http-ndk/src/ndk_process.h diff --git a/debian/modules/nginx-development-kit/src/ndk_regex.c b/debian/modules/http-ndk/src/ndk_regex.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_regex.c rename to debian/modules/http-ndk/src/ndk_regex.c diff --git a/debian/modules/nginx-development-kit/src/ndk_regex.h b/debian/modules/http-ndk/src/ndk_regex.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_regex.h rename to debian/modules/http-ndk/src/ndk_regex.h diff --git a/debian/modules/nginx-development-kit/src/ndk_rewrite.c b/debian/modules/http-ndk/src/ndk_rewrite.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_rewrite.c rename to debian/modules/http-ndk/src/ndk_rewrite.c diff --git a/debian/modules/nginx-development-kit/src/ndk_rewrite.h b/debian/modules/http-ndk/src/ndk_rewrite.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_rewrite.h rename to debian/modules/http-ndk/src/ndk_rewrite.h diff --git a/debian/modules/nginx-development-kit/src/ndk_set_var.c b/debian/modules/http-ndk/src/ndk_set_var.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_set_var.c rename to debian/modules/http-ndk/src/ndk_set_var.c diff --git a/debian/modules/nginx-development-kit/src/ndk_set_var.h b/debian/modules/http-ndk/src/ndk_set_var.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_set_var.h rename to debian/modules/http-ndk/src/ndk_set_var.h diff --git a/debian/modules/nginx-development-kit/src/ndk_string.c b/debian/modules/http-ndk/src/ndk_string.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_string.c rename to debian/modules/http-ndk/src/ndk_string.c diff --git a/debian/modules/nginx-development-kit/src/ndk_string.h b/debian/modules/http-ndk/src/ndk_string.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_string.h rename to debian/modules/http-ndk/src/ndk_string.h diff --git a/debian/modules/nginx-development-kit/src/ndk_string_util.h b/debian/modules/http-ndk/src/ndk_string_util.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_string_util.h rename to debian/modules/http-ndk/src/ndk_string_util.h diff --git a/debian/modules/nginx-development-kit/src/ndk_upstream_list.c b/debian/modules/http-ndk/src/ndk_upstream_list.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_upstream_list.c rename to debian/modules/http-ndk/src/ndk_upstream_list.c diff --git a/debian/modules/nginx-development-kit/src/ndk_upstream_list.h b/debian/modules/http-ndk/src/ndk_upstream_list.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_upstream_list.h rename to debian/modules/http-ndk/src/ndk_upstream_list.h diff --git a/debian/modules/nginx-development-kit/src/ndk_uri.c b/debian/modules/http-ndk/src/ndk_uri.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_uri.c rename to debian/modules/http-ndk/src/ndk_uri.c diff --git a/debian/modules/nginx-development-kit/src/ndk_uri.h b/debian/modules/http-ndk/src/ndk_uri.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_uri.h rename to debian/modules/http-ndk/src/ndk_uri.h diff --git a/debian/modules/ngx_http_substitutions_filter_module/CHANGES b/debian/modules/http-subs-filter/CHANGES similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/CHANGES rename to debian/modules/http-subs-filter/CHANGES diff --git a/debian/modules/ngx_http_substitutions_filter_module/README b/debian/modules/http-subs-filter/README similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/README rename to debian/modules/http-subs-filter/README diff --git a/debian/modules/ngx_http_substitutions_filter_module/config b/debian/modules/http-subs-filter/config similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/config rename to debian/modules/http-subs-filter/config diff --git a/debian/modules/ngx_http_substitutions_filter_module/doc/README.google_code_home_page.wiki b/debian/modules/http-subs-filter/doc/README.google_code_home_page.wiki similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/doc/README.google_code_home_page.wiki rename to debian/modules/http-subs-filter/doc/README.google_code_home_page.wiki diff --git a/debian/modules/ngx_http_substitutions_filter_module/doc/README.html b/debian/modules/http-subs-filter/doc/README.html similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/doc/README.html rename to debian/modules/http-subs-filter/doc/README.html diff --git a/debian/modules/ngx_http_substitutions_filter_module/doc/README.wiki b/debian/modules/http-subs-filter/doc/README.wiki similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/doc/README.wiki rename to debian/modules/http-subs-filter/doc/README.wiki diff --git a/debian/modules/ngx_http_substitutions_filter_module/ngx_http_subs_filter_module.c b/debian/modules/http-subs-filter/ngx_http_subs_filter_module.c similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/ngx_http_subs_filter_module.c rename to debian/modules/http-subs-filter/ngx_http_subs_filter_module.c diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/README b/debian/modules/http-subs-filter/test/README similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/README rename to debian/modules/http-subs-filter/test/README diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/AutoInstall.pm b/debian/modules/http-subs-filter/test/inc/Module/AutoInstall.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/AutoInstall.pm rename to debian/modules/http-subs-filter/test/inc/Module/AutoInstall.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install.pm b/debian/modules/http-subs-filter/test/inc/Module/Install.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/AutoInstall.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/AutoInstall.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/AutoInstall.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/AutoInstall.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Base.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Base.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Base.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/Base.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Can.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Can.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Can.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/Can.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Fetch.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Fetch.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Fetch.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/Fetch.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Include.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Include.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Include.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/Include.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Makefile.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Makefile.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Makefile.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/Makefile.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Metadata.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Metadata.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Metadata.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/Metadata.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/TestBase.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/TestBase.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/TestBase.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/TestBase.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Win32.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Win32.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Win32.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/Win32.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/WriteAll.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/WriteAll.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/WriteAll.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/WriteAll.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Spiffy.pm b/debian/modules/http-subs-filter/test/inc/Spiffy.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Spiffy.pm rename to debian/modules/http-subs-filter/test/inc/Spiffy.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/Base.pm b/debian/modules/http-subs-filter/test/inc/Test/Base.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/Base.pm rename to debian/modules/http-subs-filter/test/inc/Test/Base.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/Base/Filter.pm b/debian/modules/http-subs-filter/test/inc/Test/Base/Filter.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/Base/Filter.pm rename to debian/modules/http-subs-filter/test/inc/Test/Base/Filter.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/Builder.pm b/debian/modules/http-subs-filter/test/inc/Test/Builder.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/Builder.pm rename to debian/modules/http-subs-filter/test/inc/Test/Builder.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/Builder/Module.pm b/debian/modules/http-subs-filter/test/inc/Test/Builder/Module.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/Builder/Module.pm rename to debian/modules/http-subs-filter/test/inc/Test/Builder/Module.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/More.pm b/debian/modules/http-subs-filter/test/inc/Test/More.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/More.pm rename to debian/modules/http-subs-filter/test/inc/Test/More.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/lib/Test/Nginx.pm b/debian/modules/http-subs-filter/test/lib/Test/Nginx.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/lib/Test/Nginx.pm rename to debian/modules/http-subs-filter/test/lib/Test/Nginx.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/lib/Test/Nginx/LWP.pm b/debian/modules/http-subs-filter/test/lib/Test/Nginx/LWP.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/lib/Test/Nginx/LWP.pm rename to debian/modules/http-subs-filter/test/lib/Test/Nginx/LWP.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/lib/Test/Nginx/Socket.pm b/debian/modules/http-subs-filter/test/lib/Test/Nginx/Socket.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/lib/Test/Nginx/Socket.pm rename to debian/modules/http-subs-filter/test/lib/Test/Nginx/Socket.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/lib/Test/Nginx/Util.pm b/debian/modules/http-subs-filter/test/lib/Test/Nginx/Util.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/lib/Test/Nginx/Util.pm rename to debian/modules/http-subs-filter/test/lib/Test/Nginx/Util.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/t/subs.t b/debian/modules/http-subs-filter/test/t/subs.t similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/t/subs.t rename to debian/modules/http-subs-filter/test/t/subs.t diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/t/subs_capture.t b/debian/modules/http-subs-filter/test/t/subs_capture.t similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/t/subs_capture.t rename to debian/modules/http-subs-filter/test/t/subs_capture.t diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/t/subs_fix_string.t b/debian/modules/http-subs-filter/test/t/subs_fix_string.t similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/t/subs_fix_string.t rename to debian/modules/http-subs-filter/test/t/subs_fix_string.t diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/t/subs_regex.t b/debian/modules/http-subs-filter/test/t/subs_regex.t similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/t/subs_regex.t rename to debian/modules/http-subs-filter/test/t/subs_regex.t diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/t/subs_types.t b/debian/modules/http-subs-filter/test/t/subs_types.t similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/t/subs_types.t rename to debian/modules/http-subs-filter/test/t/subs_types.t diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/test.sh b/debian/modules/http-subs-filter/test/test.sh similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/test.sh rename to debian/modules/http-subs-filter/test/test.sh diff --git a/debian/modules/ngx_http_substitutions_filter_module/util/update-readme.sh b/debian/modules/http-subs-filter/util/update-readme.sh similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/util/update-readme.sh rename to debian/modules/http-subs-filter/util/update-readme.sh diff --git a/debian/modules/ngx_http_substitutions_filter_module/util/wiki2google_code_homepage.pl b/debian/modules/http-subs-filter/util/wiki2google_code_homepage.pl similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/util/wiki2google_code_homepage.pl rename to debian/modules/http-subs-filter/util/wiki2google_code_homepage.pl diff --git a/debian/modules/ngx_http_substitutions_filter_module/util/wiki2pod.pl b/debian/modules/http-subs-filter/util/wiki2pod.pl similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/util/wiki2pod.pl rename to debian/modules/http-subs-filter/util/wiki2pod.pl diff --git a/debian/modules/nginx-upload-progress/CHANGES b/debian/modules/http-uploadprogress/CHANGES similarity index 100% rename from debian/modules/nginx-upload-progress/CHANGES rename to debian/modules/http-uploadprogress/CHANGES diff --git a/debian/modules/nginx-upload-progress/LICENSE b/debian/modules/http-uploadprogress/LICENSE similarity index 100% rename from debian/modules/nginx-upload-progress/LICENSE rename to debian/modules/http-uploadprogress/LICENSE diff --git a/debian/modules/nginx-upload-progress/Makefile b/debian/modules/http-uploadprogress/Makefile similarity index 100% rename from debian/modules/nginx-upload-progress/Makefile rename to debian/modules/http-uploadprogress/Makefile diff --git a/debian/modules/nginx-upload-progress/README b/debian/modules/http-uploadprogress/README similarity index 100% rename from debian/modules/nginx-upload-progress/README rename to debian/modules/http-uploadprogress/README diff --git a/debian/modules/nginx-upload-progress/config b/debian/modules/http-uploadprogress/config similarity index 100% rename from debian/modules/nginx-upload-progress/config rename to debian/modules/http-uploadprogress/config diff --git a/debian/modules/nginx-upload-progress/ngx_http_uploadprogress_module.c b/debian/modules/http-uploadprogress/ngx_http_uploadprogress_module.c similarity index 100% rename from debian/modules/nginx-upload-progress/ngx_http_uploadprogress_module.c rename to debian/modules/http-uploadprogress/ngx_http_uploadprogress_module.c diff --git a/debian/modules/nginx-upload-progress/test/client.sh b/debian/modules/http-uploadprogress/test/client.sh similarity index 100% rename from debian/modules/nginx-upload-progress/test/client.sh rename to debian/modules/http-uploadprogress/test/client.sh diff --git a/debian/modules/nginx-upload-progress/test/stress.sh b/debian/modules/http-uploadprogress/test/stress.sh similarity index 100% rename from debian/modules/nginx-upload-progress/test/stress.sh rename to debian/modules/http-uploadprogress/test/stress.sh diff --git a/debian/modules/nginx-upstream-fair/.gdbinit b/debian/modules/http-upstream-fair/.gdbinit similarity index 100% rename from debian/modules/nginx-upstream-fair/.gdbinit rename to debian/modules/http-upstream-fair/.gdbinit diff --git a/debian/modules/nginx-upstream-fair/README b/debian/modules/http-upstream-fair/README similarity index 100% rename from debian/modules/nginx-upstream-fair/README rename to debian/modules/http-upstream-fair/README diff --git a/debian/modules/nginx-upstream-fair/config b/debian/modules/http-upstream-fair/config similarity index 100% rename from debian/modules/nginx-upstream-fair/config rename to debian/modules/http-upstream-fair/config diff --git a/debian/modules/nginx-upstream-fair/ngx_http_upstream_fair_module.c b/debian/modules/http-upstream-fair/ngx_http_upstream_fair_module.c similarity index 100% rename from debian/modules/nginx-upstream-fair/ngx_http_upstream_fair_module.c rename to debian/modules/http-upstream-fair/ngx_http_upstream_fair_module.c diff --git a/debian/modules/patches/nginx-cache-purge/dynamic-module.patch b/debian/modules/patches/http-cache-purge/dynamic-module.patch similarity index 100% rename from debian/modules/patches/nginx-cache-purge/dynamic-module.patch rename to debian/modules/patches/http-cache-purge/dynamic-module.patch diff --git a/debian/modules/patches/nginx-cache-purge/segfault-1.11.6.patch b/debian/modules/patches/http-cache-purge/segfault-1.11.6.patch similarity index 100% rename from debian/modules/patches/nginx-cache-purge/segfault-1.11.6.patch rename to debian/modules/patches/http-cache-purge/segfault-1.11.6.patch diff --git a/debian/modules/patches/nginx-cache-purge/series b/debian/modules/patches/http-cache-purge/series similarity index 100% rename from debian/modules/patches/nginx-cache-purge/series rename to debian/modules/patches/http-cache-purge/series diff --git a/debian/modules/patches/nginx-dav-ext-module/dynamic-module.patch b/debian/modules/patches/http-dav-ext/dynamic-module.patch similarity index 100% rename from debian/modules/patches/nginx-dav-ext-module/dynamic-module.patch rename to debian/modules/patches/http-dav-ext/dynamic-module.patch diff --git a/debian/modules/patches/nginx-dav-ext-module/series b/debian/modules/patches/http-dav-ext/series similarity index 100% rename from debian/modules/patches/nginx-dav-ext-module/series rename to debian/modules/patches/http-dav-ext/series diff --git a/debian/modules/patches/nginx-echo/build-nginx-1.11.11.patch b/debian/modules/patches/http-echo/build-nginx-1.11.11.patch similarity index 100% rename from debian/modules/patches/nginx-echo/build-nginx-1.11.11.patch rename to debian/modules/patches/http-echo/build-nginx-1.11.11.patch diff --git a/debian/modules/patches/nginx-echo/series b/debian/modules/patches/http-echo/series similarity index 100% rename from debian/modules/patches/nginx-echo/series rename to debian/modules/patches/http-echo/series diff --git a/debian/modules/patches/nginx-lua/discover-luajit-2.1.patch b/debian/modules/patches/http-lua/discover-luajit-2.1.patch similarity index 100% rename from debian/modules/patches/nginx-lua/discover-luajit-2.1.patch rename to debian/modules/patches/http-lua/discover-luajit-2.1.patch diff --git a/debian/modules/patches/nginx-lua/openssl-1.1.0.patch b/debian/modules/patches/http-lua/openssl-1.1.0.patch similarity index 100% rename from debian/modules/patches/nginx-lua/openssl-1.1.0.patch rename to debian/modules/patches/http-lua/openssl-1.1.0.patch diff --git a/debian/modules/patches/nginx-lua/series b/debian/modules/patches/http-lua/series similarity index 100% rename from debian/modules/patches/nginx-lua/series rename to debian/modules/patches/http-lua/series diff --git a/debian/modules/patches/ngx_http_substitutions_filter_module/dynamic-module.patch b/debian/modules/patches/http-subs-filter/dynamic-module.patch similarity index 100% rename from debian/modules/patches/ngx_http_substitutions_filter_module/dynamic-module.patch rename to debian/modules/patches/http-subs-filter/dynamic-module.patch diff --git a/debian/modules/patches/ngx_http_substitutions_filter_module/series b/debian/modules/patches/http-subs-filter/series similarity index 100% rename from debian/modules/patches/ngx_http_substitutions_filter_module/series rename to debian/modules/patches/http-subs-filter/series diff --git a/debian/modules/patches/nginx-upstream-fair/drop-default-port.patch b/debian/modules/patches/http-upstream-fair/drop-default-port.patch similarity index 100% rename from debian/modules/patches/nginx-upstream-fair/drop-default-port.patch rename to debian/modules/patches/http-upstream-fair/drop-default-port.patch diff --git a/debian/modules/patches/nginx-upstream-fair/dynamic-module.patch b/debian/modules/patches/http-upstream-fair/dynamic-module.patch similarity index 100% rename from debian/modules/patches/nginx-upstream-fair/dynamic-module.patch rename to debian/modules/patches/http-upstream-fair/dynamic-module.patch diff --git a/debian/modules/patches/nginx-upstream-fair/openssl-1.1.0.patch b/debian/modules/patches/http-upstream-fair/openssl-1.1.0.patch similarity index 100% rename from debian/modules/patches/nginx-upstream-fair/openssl-1.1.0.patch rename to debian/modules/patches/http-upstream-fair/openssl-1.1.0.patch diff --git a/debian/modules/patches/nginx-upstream-fair/series b/debian/modules/patches/http-upstream-fair/series similarity index 100% rename from debian/modules/patches/nginx-upstream-fair/series rename to debian/modules/patches/http-upstream-fair/series diff --git a/debian/modules/nginx-rtmp/AUTHORS b/debian/modules/rtmp/AUTHORS similarity index 100% rename from debian/modules/nginx-rtmp/AUTHORS rename to debian/modules/rtmp/AUTHORS diff --git a/debian/modules/nginx-rtmp/LICENSE b/debian/modules/rtmp/LICENSE similarity index 100% rename from debian/modules/nginx-rtmp/LICENSE rename to debian/modules/rtmp/LICENSE diff --git a/debian/modules/nginx-rtmp/README.md b/debian/modules/rtmp/README.md similarity index 100% rename from debian/modules/nginx-rtmp/README.md rename to debian/modules/rtmp/README.md diff --git a/debian/modules/nginx-rtmp/config b/debian/modules/rtmp/config similarity index 100% rename from debian/modules/nginx-rtmp/config rename to debian/modules/rtmp/config diff --git a/debian/modules/nginx-rtmp/dash/ngx_rtmp_dash_module.c b/debian/modules/rtmp/dash/ngx_rtmp_dash_module.c similarity index 100% rename from debian/modules/nginx-rtmp/dash/ngx_rtmp_dash_module.c rename to debian/modules/rtmp/dash/ngx_rtmp_dash_module.c diff --git a/debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.c b/debian/modules/rtmp/dash/ngx_rtmp_mp4.c similarity index 100% rename from debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.c rename to debian/modules/rtmp/dash/ngx_rtmp_mp4.c diff --git a/debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.h b/debian/modules/rtmp/dash/ngx_rtmp_mp4.h similarity index 100% rename from debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.h rename to debian/modules/rtmp/dash/ngx_rtmp_mp4.h diff --git a/debian/modules/nginx-rtmp/doc/README.md b/debian/modules/rtmp/doc/README.md similarity index 100% rename from debian/modules/nginx-rtmp/doc/README.md rename to debian/modules/rtmp/doc/README.md diff --git a/debian/modules/nginx-rtmp/hls/ngx_rtmp_hls_module.c b/debian/modules/rtmp/hls/ngx_rtmp_hls_module.c similarity index 100% rename from debian/modules/nginx-rtmp/hls/ngx_rtmp_hls_module.c rename to debian/modules/rtmp/hls/ngx_rtmp_hls_module.c diff --git a/debian/modules/nginx-rtmp/hls/ngx_rtmp_mpegts.c b/debian/modules/rtmp/hls/ngx_rtmp_mpegts.c similarity index 100% rename from debian/modules/nginx-rtmp/hls/ngx_rtmp_mpegts.c rename to debian/modules/rtmp/hls/ngx_rtmp_mpegts.c diff --git a/debian/modules/nginx-rtmp/hls/ngx_rtmp_mpegts.h b/debian/modules/rtmp/hls/ngx_rtmp_mpegts.h similarity index 100% rename from debian/modules/nginx-rtmp/hls/ngx_rtmp_mpegts.h rename to debian/modules/rtmp/hls/ngx_rtmp_mpegts.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp.c b/debian/modules/rtmp/ngx_rtmp.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp.c rename to debian/modules/rtmp/ngx_rtmp.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp.h b/debian/modules/rtmp/ngx_rtmp.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp.h rename to debian/modules/rtmp/ngx_rtmp.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_access_module.c b/debian/modules/rtmp/ngx_rtmp_access_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_access_module.c rename to debian/modules/rtmp/ngx_rtmp_access_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_amf.c b/debian/modules/rtmp/ngx_rtmp_amf.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_amf.c rename to debian/modules/rtmp/ngx_rtmp_amf.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_amf.h b/debian/modules/rtmp/ngx_rtmp_amf.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_amf.h rename to debian/modules/rtmp/ngx_rtmp_amf.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_auto_push_module.c b/debian/modules/rtmp/ngx_rtmp_auto_push_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_auto_push_module.c rename to debian/modules/rtmp/ngx_rtmp_auto_push_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_bandwidth.c b/debian/modules/rtmp/ngx_rtmp_bandwidth.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_bandwidth.c rename to debian/modules/rtmp/ngx_rtmp_bandwidth.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_bandwidth.h b/debian/modules/rtmp/ngx_rtmp_bandwidth.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_bandwidth.h rename to debian/modules/rtmp/ngx_rtmp_bandwidth.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_bitop.c b/debian/modules/rtmp/ngx_rtmp_bitop.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_bitop.c rename to debian/modules/rtmp/ngx_rtmp_bitop.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_bitop.h b/debian/modules/rtmp/ngx_rtmp_bitop.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_bitop.h rename to debian/modules/rtmp/ngx_rtmp_bitop.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_cmd_module.c b/debian/modules/rtmp/ngx_rtmp_cmd_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_cmd_module.c rename to debian/modules/rtmp/ngx_rtmp_cmd_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_cmd_module.h b/debian/modules/rtmp/ngx_rtmp_cmd_module.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_cmd_module.h rename to debian/modules/rtmp/ngx_rtmp_cmd_module.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_codec_module.c b/debian/modules/rtmp/ngx_rtmp_codec_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_codec_module.c rename to debian/modules/rtmp/ngx_rtmp_codec_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_codec_module.h b/debian/modules/rtmp/ngx_rtmp_codec_module.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_codec_module.h rename to debian/modules/rtmp/ngx_rtmp_codec_module.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_control_module.c b/debian/modules/rtmp/ngx_rtmp_control_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_control_module.c rename to debian/modules/rtmp/ngx_rtmp_control_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_core_module.c b/debian/modules/rtmp/ngx_rtmp_core_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_core_module.c rename to debian/modules/rtmp/ngx_rtmp_core_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_eval.c b/debian/modules/rtmp/ngx_rtmp_eval.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_eval.c rename to debian/modules/rtmp/ngx_rtmp_eval.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_eval.h b/debian/modules/rtmp/ngx_rtmp_eval.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_eval.h rename to debian/modules/rtmp/ngx_rtmp_eval.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_exec_module.c b/debian/modules/rtmp/ngx_rtmp_exec_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_exec_module.c rename to debian/modules/rtmp/ngx_rtmp_exec_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_flv_module.c b/debian/modules/rtmp/ngx_rtmp_flv_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_flv_module.c rename to debian/modules/rtmp/ngx_rtmp_flv_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_handler.c b/debian/modules/rtmp/ngx_rtmp_handler.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_handler.c rename to debian/modules/rtmp/ngx_rtmp_handler.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_handshake.c b/debian/modules/rtmp/ngx_rtmp_handshake.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_handshake.c rename to debian/modules/rtmp/ngx_rtmp_handshake.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_init.c b/debian/modules/rtmp/ngx_rtmp_init.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_init.c rename to debian/modules/rtmp/ngx_rtmp_init.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_limit_module.c b/debian/modules/rtmp/ngx_rtmp_limit_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_limit_module.c rename to debian/modules/rtmp/ngx_rtmp_limit_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_live_module.c b/debian/modules/rtmp/ngx_rtmp_live_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_live_module.c rename to debian/modules/rtmp/ngx_rtmp_live_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_live_module.h b/debian/modules/rtmp/ngx_rtmp_live_module.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_live_module.h rename to debian/modules/rtmp/ngx_rtmp_live_module.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_log_module.c b/debian/modules/rtmp/ngx_rtmp_log_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_log_module.c rename to debian/modules/rtmp/ngx_rtmp_log_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_mp4_module.c b/debian/modules/rtmp/ngx_rtmp_mp4_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_mp4_module.c rename to debian/modules/rtmp/ngx_rtmp_mp4_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_netcall_module.c b/debian/modules/rtmp/ngx_rtmp_netcall_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_netcall_module.c rename to debian/modules/rtmp/ngx_rtmp_netcall_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_netcall_module.h b/debian/modules/rtmp/ngx_rtmp_netcall_module.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_netcall_module.h rename to debian/modules/rtmp/ngx_rtmp_netcall_module.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_notify_module.c b/debian/modules/rtmp/ngx_rtmp_notify_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_notify_module.c rename to debian/modules/rtmp/ngx_rtmp_notify_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_play_module.c b/debian/modules/rtmp/ngx_rtmp_play_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_play_module.c rename to debian/modules/rtmp/ngx_rtmp_play_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_play_module.h b/debian/modules/rtmp/ngx_rtmp_play_module.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_play_module.h rename to debian/modules/rtmp/ngx_rtmp_play_module.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_proxy_protocol.c b/debian/modules/rtmp/ngx_rtmp_proxy_protocol.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_proxy_protocol.c rename to debian/modules/rtmp/ngx_rtmp_proxy_protocol.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_proxy_protocol.h b/debian/modules/rtmp/ngx_rtmp_proxy_protocol.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_proxy_protocol.h rename to debian/modules/rtmp/ngx_rtmp_proxy_protocol.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_receive.c b/debian/modules/rtmp/ngx_rtmp_receive.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_receive.c rename to debian/modules/rtmp/ngx_rtmp_receive.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_record_module.c b/debian/modules/rtmp/ngx_rtmp_record_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_record_module.c rename to debian/modules/rtmp/ngx_rtmp_record_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_record_module.h b/debian/modules/rtmp/ngx_rtmp_record_module.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_record_module.h rename to debian/modules/rtmp/ngx_rtmp_record_module.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_relay_module.c b/debian/modules/rtmp/ngx_rtmp_relay_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_relay_module.c rename to debian/modules/rtmp/ngx_rtmp_relay_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_relay_module.h b/debian/modules/rtmp/ngx_rtmp_relay_module.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_relay_module.h rename to debian/modules/rtmp/ngx_rtmp_relay_module.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_send.c b/debian/modules/rtmp/ngx_rtmp_send.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_send.c rename to debian/modules/rtmp/ngx_rtmp_send.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_shared.c b/debian/modules/rtmp/ngx_rtmp_shared.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_shared.c rename to debian/modules/rtmp/ngx_rtmp_shared.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_stat_module.c b/debian/modules/rtmp/ngx_rtmp_stat_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_stat_module.c rename to debian/modules/rtmp/ngx_rtmp_stat_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_streams.h b/debian/modules/rtmp/ngx_rtmp_streams.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_streams.h rename to debian/modules/rtmp/ngx_rtmp_streams.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_version.h b/debian/modules/rtmp/ngx_rtmp_version.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_version.h rename to debian/modules/rtmp/ngx_rtmp_version.h diff --git a/debian/modules/nginx-rtmp/stat.xsl b/debian/modules/rtmp/stat.xsl similarity index 100% rename from debian/modules/nginx-rtmp/stat.xsl rename to debian/modules/rtmp/stat.xsl diff --git a/debian/rules b/debian/rules index a852d02..981a57e 100755 --- a/debian/rules +++ b/debian/rules @@ -82,7 +82,7 @@ light_configure_flags := \ --without-http_referer_module \ --without-http_split_clients_module \ --without-http_userid_module \ - --add-dynamic-module=$(MODULESDIR)/nginx-echo + --add-dynamic-module=$(MODULESDIR)/http-echo full_configure_flags := \ $(common_configure_flags) \ @@ -98,11 +98,11 @@ full_configure_flags := \ --with-stream_ssl_preread_module \ --with-mail=dynamic \ --with-mail_ssl_module \ - --add-dynamic-module=$(MODULESDIR)/nginx-auth-pam \ - --add-dynamic-module=$(MODULESDIR)/nginx-dav-ext-module \ - --add-dynamic-module=$(MODULESDIR)/nginx-echo \ - --add-dynamic-module=$(MODULESDIR)/nginx-upstream-fair \ - --add-dynamic-module=$(MODULESDIR)/ngx_http_substitutions_filter_module + --add-dynamic-module=$(MODULESDIR)/http-auth-pam \ + --add-dynamic-module=$(MODULESDIR)/http-dav-ext \ + --add-dynamic-module=$(MODULESDIR)/http-echo \ + --add-dynamic-module=$(MODULESDIR)/http-upstream-fair \ + --add-dynamic-module=$(MODULESDIR)/http-subs-filter extras_configure_flags := \ $(common_configure_flags) \ @@ -123,19 +123,19 @@ extras_configure_flags := \ --with-stream=dynamic \ --with-stream_ssl_module \ --with-stream_ssl_preread_module \ - --add-dynamic-module=$(MODULESDIR)/headers-more-nginx-module \ - --add-dynamic-module=$(MODULESDIR)/nginx-auth-pam \ - --add-dynamic-module=$(MODULESDIR)/nginx-cache-purge \ - --add-dynamic-module=$(MODULESDIR)/nginx-dav-ext-module \ - --add-dynamic-module=$(MODULESDIR)/nginx-development-kit \ - --add-dynamic-module=$(MODULESDIR)/nginx-echo \ - --add-dynamic-module=$(MODULESDIR)/ngx-fancyindex \ + --add-dynamic-module=$(MODULESDIR)/http-headers-more-filter \ + --add-dynamic-module=$(MODULESDIR)/http-auth-pam \ + --add-dynamic-module=$(MODULESDIR)/http-cache-purge \ + --add-dynamic-module=$(MODULESDIR)/http-dav-ext \ + --add-dynamic-module=$(MODULESDIR)/http-ndk \ + --add-dynamic-module=$(MODULESDIR)/http-echo \ + --add-dynamic-module=$(MODULESDIR)/http-fancyindex \ --add-dynamic-module=$(MODULESDIR)/nchan \ - --add-dynamic-module=$(MODULESDIR)/nginx-lua \ - --add-dynamic-module=$(MODULESDIR)/nginx-rtmp \ - --add-dynamic-module=$(MODULESDIR)/nginx-upload-progress \ - --add-dynamic-module=$(MODULESDIR)/nginx-upstream-fair \ - --add-dynamic-module=$(MODULESDIR)/ngx_http_substitutions_filter_module + --add-dynamic-module=$(MODULESDIR)/http-lua \ + --add-dynamic-module=$(MODULESDIR)/rtmp \ + --add-dynamic-module=$(MODULESDIR)/http-uploadprogress \ + --add-dynamic-module=$(MODULESDIR)/http-upstream-fair \ + --add-dynamic-module=$(MODULESDIR)/http-subs-filter %: dh $@ --without autoreconf From 0305fe8ea3e438b80a815f2ef18e6ecc77cca6b7 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 12 Oct 2017 10:37:08 +0300 Subject: [PATCH 272/651] Bump Standards-Version, no changes needed --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index e7a598a..17cfaab 100644 --- a/debian/control +++ b/debian/control @@ -24,7 +24,7 @@ Build-Depends: debhelper (>= 10), po-debconf, quilt, zlib1g-dev -Standards-Version: 4.1.0 +Standards-Version: 4.1.1 Homepage: http://nginx.net Vcs-Git: https://anonscm.debian.org/cgit/pkg-nginx/nginx.git Vcs-Browser: https://anonscm.debian.org/cgit/pkg-nginx/nginx.git From bf0c6fce6e6887b65e129f7974c3e8df69c8c627 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 12 Oct 2017 10:35:21 +0300 Subject: [PATCH 273/651] Drop dh-systemd dependency since we depend on debhelper >= 10 Fixes build-depends-on-obsolete-package in lintian. --- debian/control | 1 - 1 file changed, 1 deletion(-) diff --git a/debian/control b/debian/control index 17cfaab..b8ae948 100644 --- a/debian/control +++ b/debian/control @@ -7,7 +7,6 @@ Uploaders: Kartik Mistry , Christos Trochalakis Build-Depends: debhelper (>= 10), po-debconf, - dh-systemd (>= 1.5), dpkg-dev (>= 1.15.5), libexpat-dev, libgd-dev, From f056335a382b9ef80a0e7ea390c547ddeb61061e Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 12 Oct 2017 10:44:13 +0300 Subject: [PATCH 274/651] Release 1.13.6-1 --- debian/changelog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/debian/changelog b/debian/changelog index 396226e..8aa3e0a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +nginx (1.13.6-1) unstable; urgency=medium + + * New upstream version + * Normalize module paths in packaging repository + * Bump Standards-Version, no changes needed + * Drop dh-systemd dependency since we depend on debhelper >= 10 + + -- Christos Trochalakis Thu, 12 Oct 2017 10:37:29 +0300 + nginx (1.13.5-1) unstable; urgency=medium * New upstream version 1.13.5 From 10af9c3beff85db4b194106586a899169e734be8 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 13 Oct 2017 12:40:11 +0300 Subject: [PATCH 275/651] rtmp: Ship docs & examples Closes: #878368 --- debian/libnginx-mod-rtmp.docs | 2 +- debian/libnginx-mod-rtmp.examples | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/libnginx-mod-rtmp.docs b/debian/libnginx-mod-rtmp.docs index 8bb7d17..e5c5c00 100644 --- a/debian/libnginx-mod-rtmp.docs +++ b/debian/libnginx-mod-rtmp.docs @@ -1 +1 @@ -debian/modules/nginx-rtmp/README.md +debian/modules/rtmp/README.md diff --git a/debian/libnginx-mod-rtmp.examples b/debian/libnginx-mod-rtmp.examples index 6748d60..563f038 100644 --- a/debian/libnginx-mod-rtmp.examples +++ b/debian/libnginx-mod-rtmp.examples @@ -1 +1 @@ -debian/modules/nginx-rtmp/stat.xsl +debian/modules/rtmp/stat.xsl From 08248c9d96a3a6d83444f268219a8f8812c79f48 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 13 Oct 2017 12:59:41 +0300 Subject: [PATCH 276/651] Release 1.13.6-2 --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 8aa3e0a..5be779e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +nginx (1.13.6-2) unstable; urgency=medium + + * rtmp: Ship docs & examples (Closes: #878368) + + -- Christos Trochalakis Fri, 13 Oct 2017 12:59:28 +0300 + nginx (1.13.6-1) unstable; urgency=medium * New upstream version From dfa79bec5c13485c7be06718a713fe2793568160 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 22 Nov 2017 16:31:37 +0200 Subject: [PATCH 277/651] New upstream version 1.13.7 --- CHANGES | 24 ++++++++++++ CHANGES.ru | 24 ++++++++++++ src/core/nginx.h | 4 +- src/core/ngx_conf_file.h | 2 +- src/core/ngx_cycle.c | 24 ++++++++---- src/event/ngx_event_openssl.h | 1 + src/http/modules/ngx_http_fastcgi_module.c | 1 + .../modules/ngx_http_gzip_filter_module.c | 38 ++++++++++++++++--- src/http/modules/ngx_http_ssi_filter_module.c | 15 ++++---- .../modules/ngx_http_xslt_filter_module.c | 15 +++++++- src/http/ngx_http_postpone_filter_module.c | 9 ++++- src/http/ngx_http_request.c | 7 ++++ src/http/ngx_http_upstream.c | 12 ++++++ src/mail/ngx_mail_proxy_module.c | 7 +++- src/stream/ngx_stream_proxy_module.c | 6 +++ 15 files changed, 160 insertions(+), 29 deletions(-) diff --git a/CHANGES b/CHANGES index 6a9fdcc..d93a938 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,28 @@ +Changes with nginx 1.13.7 21 Nov 2017 + + *) Bugfix: in the $upstream_status variable. + + *) Bugfix: a segmentation fault might occur in a worker process if a + backend returned a "101 Switching Protocols" response to a + subrequest. + + *) Bugfix: a segmentation fault occurred in a master process if a shared + memory zone size was changed during a reconfiguration and the + reconfiguration failed. + + *) Bugfix: in the ngx_http_fastcgi_module. + + *) Bugfix: nginx returned the 500 error if parameters without variables + were specified in the "xslt_stylesheet" directive. + + *) Workaround: "gzip filter failed to use preallocated memory" alerts + appeared in logs when using a zlib library variant from Intel. + + *) Bugfix: the "worker_shutdown_timeout" directive did not work when + using mail proxy and when proxying WebSocket connections. + + Changes with nginx 1.13.6 10 Oct 2017 *) Bugfix: switching to the next upstream server in the stream module diff --git a/CHANGES.ru b/CHANGES.ru index 6ea87c9..e688a5c 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,28 @@ +Изменения в nginx 1.13.7 21.11.2017 + + *) Исправление: в переменной $upstream_status. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если бэкенд возвращал ответ "101 Switching Protocols" на подзапрос. + + *) Исправление: если при переконфигурации изменялся размер зоны + разделяемой памяти и переконфигурация завершалась неудачно, то в + главном процессе происходил segmentation fault. + + *) Исправление: в модуле ngx_http_fastcgi_module. + + *) Исправление: nginx возвращал ошибку 500, если в директиве + xslt_stylesheet были заданы параметры без использования переменных. + + *) Изменение: при использовании варианта библиотеки zlib от Intel в лог + писались сообщения "gzip filter failed to use preallocated memory". + + *) Исправление: директива worker_shutdown_timeout не работала при + использовании почтового прокси-сервера и при проксировании + WebSocket-соединений. + + Изменения в nginx 1.13.6 10.10.2017 *) Исправление: при использовании директивы ssl_preread в модуле stream diff --git a/src/core/nginx.h b/src/core/nginx.h index 5806837..02b51ab 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1013006 -#define NGINX_VERSION "1.13.6" +#define nginx_version 1013007 +#define NGINX_VERSION "1.13.7" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h index 213611f..9cd5806 100644 --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -128,7 +128,7 @@ struct ngx_conf_s { ngx_uint_t cmd_type; ngx_conf_handler_pt handler; - char *handler_conf; + void *handler_conf; }; diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c index 675a506..f3ac24d 100644 --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -470,8 +470,6 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) goto shm_zone_found; } - ngx_shm_free(&oshm_zone[n].shm); - break; } @@ -662,14 +660,26 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) n = 0; } - if (oshm_zone[i].shm.name.len == shm_zone[n].shm.name.len - && ngx_strncmp(oshm_zone[i].shm.name.data, - shm_zone[n].shm.name.data, - oshm_zone[i].shm.name.len) - == 0) + if (oshm_zone[i].shm.name.len != shm_zone[n].shm.name.len) { + continue; + } + + if (ngx_strncmp(oshm_zone[i].shm.name.data, + shm_zone[n].shm.name.data, + oshm_zone[i].shm.name.len) + != 0) + { + continue; + } + + if (oshm_zone[i].tag == shm_zone[n].tag + && oshm_zone[i].shm.size == shm_zone[n].shm.size + && !oshm_zone[i].noreuse) { goto live_shm_zone; } + + break; } ngx_shm_free(&oshm_zone[i].shm); diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index b9a3a96..623d851 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -22,6 +22,7 @@ #include #endif #include +#include #ifndef OPENSSL_NO_OCSP #include #endif diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index ea16eca..b4bb1d0 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -2646,6 +2646,7 @@ ngx_http_fastcgi_process_record(ngx_http_request_t *r, } } + f->pos = p; f->state = state; return NGX_AGAIN; diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index 73b6d89..e4c343c 100644 --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -57,6 +57,7 @@ typedef struct { unsigned nomem:1; unsigned gzheader:1; unsigned buffering:1; + unsigned intel:1; size_t zin; size_t zout; @@ -233,6 +234,8 @@ static ngx_str_t ngx_http_gzip_ratio = ngx_string("gzip_ratio"); static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static ngx_http_output_body_filter_pt ngx_http_next_body_filter; +static ngx_uint_t ngx_http_gzip_assume_intel; + static ngx_int_t ngx_http_gzip_header_filter(ngx_http_request_t *r) @@ -527,7 +530,27 @@ ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) * *) 5920 bytes on amd64 and sparc64 */ - ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9)); + if (!ngx_http_gzip_assume_intel) { + ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9)); + + } else { + /* + * A zlib variant from Intel, https://github.com/jtkukunas/zlib. + * It can force window bits to 13 for fast compression level, + * on processors with SSE 4.2 it uses 64K hash instead of scaling + * it from the specified memory level, and also introduces + * 16-byte padding in one out of the two window-sized buffers. + */ + + if (conf->level == 1) { + wbits = ngx_max(wbits, 13); + } + + ctx->allocated = 8192 + 16 + (1 << (wbits + 2)) + + (1 << (ngx_max(memlevel, 8) + 8)) + + (1 << (memlevel + 8)); + ctx->intel = 1; + } } @@ -1003,7 +1026,7 @@ ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size) alloc = items * size; - if (alloc % 512 != 0 && alloc < 8192) { + if (items == 1 && alloc % 512 != 0 && alloc < 8192) { /* * The zlib deflate_state allocation, it takes about 6K, @@ -1025,9 +1048,14 @@ ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size) return p; } - ngx_log_error(NGX_LOG_ALERT, ctx->request->connection->log, 0, - "gzip filter failed to use preallocated memory: %ud of %ui", - items * size, ctx->allocated); + if (ctx->intel) { + ngx_log_error(NGX_LOG_ALERT, ctx->request->connection->log, 0, + "gzip filter failed to use preallocated memory: " + "%ud of %ui", items * size, ctx->allocated); + + } else { + ngx_http_gzip_assume_intel = 1; + } p = ngx_palloc(ctx->request->pool, items * size); diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index e29e173..c799b2f 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -1630,8 +1630,7 @@ ngx_http_ssi_evaluate_string(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, u_char ch, *p, **value, *data, *part_data; size_t *size, len, prefix, part_len; ngx_str_t var, *val; - ngx_int_t key; - ngx_uint_t i, n, bracket, quoted; + ngx_uint_t i, n, bracket, quoted, key; ngx_array_t lengths, values; ngx_http_variable_value_t *vv; @@ -1883,9 +1882,8 @@ ngx_http_ssi_regex_match(ngx_http_request_t *r, ngx_str_t *pattern, int rc, *captures; u_char *p, errstr[NGX_MAX_CONF_ERRSTR]; size_t size; - ngx_int_t key; ngx_str_t *vv, name, value; - ngx_uint_t i, n; + ngx_uint_t i, n, key; ngx_http_ssi_ctx_t *ctx; ngx_http_ssi_var_t *var; ngx_regex_compile_t rgc; @@ -1988,10 +1986,10 @@ static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params) { - ngx_int_t rc, key; + ngx_int_t rc; ngx_str_t *uri, *file, *wait, *set, *stub, args; ngx_buf_t *b; - ngx_uint_t flags, i; + ngx_uint_t flags, i, key; ngx_chain_t *cl, *tl, **ll, *out; ngx_http_request_t *sr; ngx_http_ssi_var_t *var; @@ -2248,9 +2246,9 @@ ngx_http_ssi_echo(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, { u_char *p; uintptr_t len; - ngx_int_t key; ngx_buf_t *b; ngx_str_t *var, *value, *enc, text; + ngx_uint_t key; ngx_chain_t *cl; ngx_http_variable_value_t *vv; @@ -2410,8 +2408,9 @@ static ngx_int_t ngx_http_ssi_set(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params) { - ngx_int_t key, rc; + ngx_int_t rc; ngx_str_t *name, *value, *vv; + ngx_uint_t key; ngx_http_ssi_var_t *var; ngx_http_ssi_ctx_t *mctx; diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c index fae5895..ea7ce2a 100644 --- a/src/http/modules/ngx_http_xslt_filter_module.c +++ b/src/http/modules/ngx_http_xslt_filter_module.c @@ -686,8 +686,19 @@ ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, * specified in xslt_stylesheet directives */ - p = string.data; - last = string.data + string.len; + if (param[i].value.lengths) { + p = string.data; + + } else { + p = ngx_pnalloc(r->pool, string.len + 1); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, string.data, string.len + 1); + } + + last = p + string.len; while (p && *p) { diff --git a/src/http/ngx_http_postpone_filter_module.c b/src/http/ngx_http_postpone_filter_module.c index e893b83..55f2698 100644 --- a/src/http/ngx_http_postpone_filter_module.c +++ b/src/http/ngx_http_postpone_filter_module.c @@ -63,7 +63,10 @@ ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in) if (r != c->data) { if (in) { - ngx_http_postpone_filter_add(r, in); + if (ngx_http_postpone_filter_add(r, in) != NGX_OK) { + return NGX_ERROR; + } + return NGX_OK; } @@ -86,7 +89,9 @@ ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in) } if (in) { - ngx_http_postpone_filter_add(r, in); + if (ngx_http_postpone_filter_add(r, in) != NGX_OK) { + return NGX_ERROR; + } } do { diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index de1b202..5668bf4 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -2225,6 +2225,13 @@ ngx_http_request_handler(ngx_event_t *ev) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http run request: \"%V?%V\"", &r->uri, &r->args); + if (c->close) { + r->main->count++; + ngx_http_terminate_request(r, 0); + ngx_http_run_posted_requests(c); + return; + } + if (ev->delayed && ev->timedout) { ev->delayed = 0; ev->timedout = 0; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 2ea521b..75f463b 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -3206,6 +3206,13 @@ ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u) /* TODO: prevent upgrade if not requested or not possible */ + if (r != r->main) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "connection upgrade in subrequest"); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); + return; + } + r->keepalive = 0; c->log->action = "proxying upgraded connection"; @@ -4111,6 +4118,7 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, switch (ft_type) { case NGX_HTTP_UPSTREAM_FT_TIMEOUT: + case NGX_HTTP_UPSTREAM_FT_HTTP_504: status = NGX_HTTP_GATEWAY_TIME_OUT; break; @@ -4118,6 +4126,10 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, status = NGX_HTTP_INTERNAL_SERVER_ERROR; break; + case NGX_HTTP_UPSTREAM_FT_HTTP_503: + status = NGX_HTTP_SERVICE_UNAVAILABLE; + break; + case NGX_HTTP_UPSTREAM_FT_HTTP_403: status = NGX_HTTP_FORBIDDEN; break; diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c index 007284b..1c86e54 100644 --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -882,10 +882,13 @@ ngx_mail_proxy_handler(ngx_event_t *ev) c = ev->data; s = c->data; - if (ev->timedout) { + if (ev->timedout || c->close) { c->log->action = "proxying"; - if (c == s->connection) { + if (c->close) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, "shutdown timeout"); + + } else if (c == s->connection) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); c->timedout = 1; diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 9d4b075..ad81cc8 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -1290,6 +1290,12 @@ ngx_stream_proxy_process_connection(ngx_event_t *ev, ngx_uint_t from_upstream) s = c->data; u = s->upstream; + if (c->close) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, "shutdown timeout"); + ngx_stream_proxy_finalize(s, NGX_STREAM_OK); + return; + } + c = s->connection; pc = u->peer.connection; From 9f10b314887ff633e1ef28419538980904938425 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 13 Dec 2017 10:51:58 +0200 Subject: [PATCH 278/651] Bump Standards-Version, no changes needed --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index b8ae948..38cd027 100644 --- a/debian/control +++ b/debian/control @@ -23,7 +23,7 @@ Build-Depends: debhelper (>= 10), po-debconf, quilt, zlib1g-dev -Standards-Version: 4.1.1 +Standards-Version: 4.1.2 Homepage: http://nginx.net Vcs-Git: https://anonscm.debian.org/cgit/pkg-nginx/nginx.git Vcs-Browser: https://anonscm.debian.org/cgit/pkg-nginx/nginx.git From 08d6a8fe7a78a1d008a1e566d7bd96b317c51a93 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 14 Dec 2017 10:53:44 +0200 Subject: [PATCH 279/651] debian/watch: switch to HTTPS for the upstream check Fixes lintian `source: debian-watch-uses-insecure-uri` info. --- debian/watch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/watch b/debian/watch index 6fa2f3e..0a39b11 100644 --- a/debian/watch +++ b/debian/watch @@ -1,3 +1,3 @@ version=3 opts=pgpsigurlmangle=s/$/.asc/ \ -http://nginx.org/download/nginx-(1\.13\.\d+)\.tar\.gz +https://nginx.org/download/nginx-(1\.13\.\d+)\.tar\.gz From 794cca0ebffcebe24c4d52eac33a961da1b79acd Mon Sep 17 00:00:00 2001 From: Mpampis Kostas Date: Sat, 22 Jul 2017 16:26:21 +0300 Subject: [PATCH 280/651] Automate modules watch & upgrade process This patch introduces the debian/ngxmod script and some helper files which can be used to automate the modules watch & upgrade process. The only subcommand for now is `uscan` and can be called as: $ debian/ngxmod uscan The uscan subcommand runs uscan for each nginx module listed in the newly deb822 formatted debian/modules/control using the watchfiles in debian/modules/watch. If a new version is available, it will ask you if you want to upgrade. If you agree, it will download the tarball, place it in the nginx source's parent directory and upgrade the module's source. After the upgrade, it will remove the files listed in the Files-Excluded module field and finally it will commit the changes. Closes: #869499 --- debian/modules/README.Modules-versions | 69 -------- debian/modules/control | 71 ++++++++ debian/modules/uupdate | 10 ++ debian/modules/watch/http-auth-pam | 4 + debian/modules/watch/http-cache-purge | 4 + debian/modules/watch/http-dav-ext | 4 + debian/modules/watch/http-echo | 4 + debian/modules/watch/http-fancyindex | 4 + debian/modules/watch/http-headers-more-filter | 4 + debian/modules/watch/http-lua | 4 + debian/modules/watch/http-ndk | 4 + debian/modules/watch/http-subs-filter | 4 + debian/modules/watch/http-uploadprogress | 4 + debian/modules/watch/nchan | 4 + debian/modules/watch/rtmp | 4 + debian/ngxmod | 156 ++++++++++++++++++ 16 files changed, 285 insertions(+), 69 deletions(-) delete mode 100644 debian/modules/README.Modules-versions create mode 100644 debian/modules/control create mode 100755 debian/modules/uupdate create mode 100644 debian/modules/watch/http-auth-pam create mode 100644 debian/modules/watch/http-cache-purge create mode 100644 debian/modules/watch/http-dav-ext create mode 100644 debian/modules/watch/http-echo create mode 100644 debian/modules/watch/http-fancyindex create mode 100644 debian/modules/watch/http-headers-more-filter create mode 100644 debian/modules/watch/http-lua create mode 100644 debian/modules/watch/http-ndk create mode 100644 debian/modules/watch/http-subs-filter create mode 100644 debian/modules/watch/http-uploadprogress create mode 100644 debian/modules/watch/nchan create mode 100644 debian/modules/watch/rtmp create mode 100755 debian/ngxmod diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions deleted file mode 100644 index ff5f63b..0000000 --- a/debian/modules/README.Modules-versions +++ /dev/null @@ -1,69 +0,0 @@ -README for Modules versions ---------------------------- - - This file lists third party modules built with nginx in Debian, homepage and - version. - - headers-more-nginx-module - Homepage: https://github.com/agentzh/headers-more-nginx-module - Version: v0.32 - - nginx-development-kit - Homepage: https://github.com/simpl/ngx_devel_kit/ - Version: v0.3.0 - - nginx-auth-pam - Homepage: https://github.com/stogh/ngx_http_auth_pam_module - Version: 1.5.1 - - nginx-echo - Homepage: https://github.com/agentzh/echo-nginx-module - Version: v0.60 - Patch: build-nginx-1.11.11.patch - - nginx-lua - Homepage: https://github.com/openresty/lua-nginx-module - Version: v0.10.10 - Patch: openssl-1.1.0.patch - Patch: discover-luajit-2.1.patch - - nginx-upstream-fair - Homepage: https://github.com/gnosek/nginx-upstream-fair - Version: a18b409 - Patch: dynamic-module.patch - Patch: openssl-1.1.0.patch - Patch: drop-default-port.patch - - nchan - Homepage: https://github.com/slact/nchan - Version: 1.0.8 - - nginx-upload-progress - Homepage: https://github.com/masterzen/nginx-upload-progress-module - rm -r debian/nginx-upload-progress/test - Version: v0.9.2 - - nginx-cache-purge - Homepage: https://github.com/FRiCKLE/ngx_cache_purge/ - Version: 2.3 - Patch: dynamic-module.patch - Patch: segfault-1.11.6.patch - - nginx-dav-ext-module - Homepage: https://github.com/arut/nginx-dav-ext-module - Version: v0.0.3 - Patch: dynamic-module.patch - - ngx-fancyindex - Homepage: https://github.com/aperezdc/ngx-fancyindex - Version: v0.4.1 - - ngx_http_substitutions_filter_module - Homepage: https://github.com/yaoweibin/ngx_http_substitutions_filter_module - Version: v0.6.4 - Patch: dynamic-module.patch - - nginx-rtmp - Homepage: https://github.com/arut/nginx-rtmp-module - rm -r debian/modules/nginx-rtmp-module/test - Version: v1.1.11 diff --git a/debian/modules/control b/debian/modules/control new file mode 100644 index 0000000..5f67e38 --- /dev/null +++ b/debian/modules/control @@ -0,0 +1,71 @@ +Module: http-headers-more-filter +Homepage: https://github.com/agentzh/headers-more-nginx-module +Version: v0.32 +Files-Excluded: .gitignore .gitattributes .travis.yml + +Module: http-ndk +Homepage: https://github.com/simpl/ngx_devel_kit/ +Version: v0.3.0 + +Module: http-auth-pam +Homepage: https://github.com/stogh/ngx_http_auth_pam_module +Version: v1.5.1 + +Module: http-echo +Homepage: https://github.com/agentzh/echo-nginx-module +Version: v0.60 +Files-Excluded: .gitignore .gitattributes .travis.yml +Patch: build-nginx-1.11.11.patch + +Module: http-lua +Homepage: https://github.com/openresty/lua-nginx-module +Version: v0.10.10 +Patch: + openssl-1.1.0.patch + discover-luajit-2.1.patch +Files-Excluded: .gitignore .gitattributes .travis.yml .github + +Module: http-upstream-fair +Homepage: https://github.com/gnosek/nginx-upstream-fair +Version: a18b409 +Patch: + dynamic-module.patch + openssl-1.1.0.patch + drop-default-port.patch + +Module: nchan +Homepage: https://github.com/slact/nchan +Version: v1.0.8 + +Module: http-uploadprogress +Homepage: https://github.com/masterzen/nginx-upload-progress-module +Files-Excluded: test +Version: v0.9.2 + +Module: http-cache-purge +Homepage: https://github.com/FRiCKLE/ngx_cache_purge/ +Version: 2.3 +Patch: + dynamic-module.patch + segfault-1.11.6.patch + +Module: http-dav-ext +Homepage: https://github.com/arut/nginx-dav-ext-module +Version: v0.0.3 +Patch: dynamic-module.patch + +Module: http-fancyindex +Homepage: https://github.com/aperezdc/ngx-fancyindex +Version: v0.4.1 +Files-Excluded: .gitignore .travis.yml + +Module: http-subs-filter +Homepage: https://github.com/yaoweibin/ngx_http_substitutions_filter_module +Version: v0.6.4 +Patch: dynamic-module.patch + +Module: rtmp +Homepage: https://github.com/arut/nginx-rtmp-module +Files-Excluded: test +Version: v1.1.11 + diff --git a/debian/modules/uupdate b/debian/modules/uupdate new file mode 100755 index 0000000..98a5f8b --- /dev/null +++ b/debian/modules/uupdate @@ -0,0 +1,10 @@ +#!/bin/bash + +# debian/modules/uupdate - simple tar wrapper used by uscan to upgrade modules source + +MOD_TAR_NAME=$2 +MOD_TAR_VER=$4 +DESTDIR=debian/modules/$1 + +tar --strip-components=1 -xf ../$MOD_TAR_NAME-$MOD_TAR_VER.tar.gz -C $DESTDIR +echo $MOD_TAR_VER > /tmp/ngx_uupdate_version_$1 diff --git a/debian/modules/watch/http-auth-pam b/debian/modules/watch/http-auth-pam new file mode 100644 index 0000000..eac2f73 --- /dev/null +++ b/debian/modules/watch/http-auth-pam @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-http-auth-pam-$1.tar.gz%" \ + https://github.com/stogh/ngx_http_auth_pam_module/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-auth-pam ngx-mod-http-auth-pam diff --git a/debian/modules/watch/http-cache-purge b/debian/modules/watch/http-cache-purge new file mode 100644 index 0000000..2566801 --- /dev/null +++ b/debian/modules/watch/http-cache-purge @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-cache-purge-$1.tar.gz%" \ + https://github.com/FRiCKLE/ngx_cache_purge/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-cache-purge ngx-mod-cache-purge diff --git a/debian/modules/watch/http-dav-ext b/debian/modules/watch/http-dav-ext new file mode 100644 index 0000000..d704cfc --- /dev/null +++ b/debian/modules/watch/http-dav-ext @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-dav-ext-$1.tar.gz%" \ + https://github.com/arut/nginx-dav-ext-module/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-dav-ext ngx-mod-dav-ext diff --git a/debian/modules/watch/http-echo b/debian/modules/watch/http-echo new file mode 100644 index 0000000..615532b --- /dev/null +++ b/debian/modules/watch/http-echo @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-echo-$1.tar.gz%" \ + https://github.com/agentzh/echo-nginx-module/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-echo ngx-mod-echo diff --git a/debian/modules/watch/http-fancyindex b/debian/modules/watch/http-fancyindex new file mode 100644 index 0000000..72435fd --- /dev/null +++ b/debian/modules/watch/http-fancyindex @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-fancyindex-$1.tar.gz%" \ + https://github.com/aperezdc/ngx-fancyindex/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-fancyindex ngx-mod-fancyindex diff --git a/debian/modules/watch/http-headers-more-filter b/debian/modules/watch/http-headers-more-filter new file mode 100644 index 0000000..cfe5fc9 --- /dev/null +++ b/debian/modules/watch/http-headers-more-filter @@ -0,0 +1,4 @@ +version=4 +opts="uversionmangle=s/0.261/0.26.1/,dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-headers-more-$1.tar.gz%" \ + https://github.com/agentzh/headers-more-nginx-module/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-headers-more-filter ngx-mod-headers-more diff --git a/debian/modules/watch/http-lua b/debian/modules/watch/http-lua new file mode 100644 index 0000000..7f1718f --- /dev/null +++ b/debian/modules/watch/http-lua @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%lua-nginx-module-$1.tar.gz%" \ + https://github.com/openresty/lua-nginx-module/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-lua lua-nginx-module diff --git a/debian/modules/watch/http-ndk b/debian/modules/watch/http-ndk new file mode 100644 index 0000000..43f0cbd --- /dev/null +++ b/debian/modules/watch/http-ndk @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-devel-kit-$1.tar.gz%" \ + https://github.com/simpl/ngx_devel_kit/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-ndk ngx-mod-devel-kit diff --git a/debian/modules/watch/http-subs-filter b/debian/modules/watch/http-subs-filter new file mode 100644 index 0000000..cca3e05 --- /dev/null +++ b/debian/modules/watch/http-subs-filter @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-http-substitutions-filter-$1.tar.gz%" \ + https://github.com/yaoweibin/ngx_http_substitutions_filter_module/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-subs-filter ngx-mod-http-substitutions-filter diff --git a/debian/modules/watch/http-uploadprogress b/debian/modules/watch/http-uploadprogress new file mode 100644 index 0000000..7c0b7cf --- /dev/null +++ b/debian/modules/watch/http-uploadprogress @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-upload-progress-$1.tar.gz%" \ + https://github.com/masterzen/nginx-upload-progress-module/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-uploadprogress ngx-mod-upload-progress diff --git a/debian/modules/watch/nchan b/debian/modules/watch/nchan new file mode 100644 index 0000000..6b95884 --- /dev/null +++ b/debian/modules/watch/nchan @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-nchan-$1.tar.gz%" \ + https://github.com/slact/nchan/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate nchan ngx-mod-nchan diff --git a/debian/modules/watch/rtmp b/debian/modules/watch/rtmp new file mode 100644 index 0000000..f8137a2 --- /dev/null +++ b/debian/modules/watch/rtmp @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-rtmp-$1.tar.gz%" \ + https://github.com/arut/nginx-rtmp-module/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate rtmp ngx-mod-rtmp diff --git a/debian/ngxmod b/debian/ngxmod new file mode 100755 index 0000000..f8180d1 --- /dev/null +++ b/debian/ngxmod @@ -0,0 +1,156 @@ +#!/usr/bin/env python +''' +ngxmod - nginx modules management helper script + +Usage: + ngxmod + +Subcommands: + + uscan - scan/watch upstream nginx module sources for new releases + + It runs uscan for each nginx module listed in debian/modules/control. + + If a new version is available, it will ask you if you want to upgrade. + If you agree it will use uscan to download the tarball, place it in the nginx + source's parent directory and unpack it using modules/uupdate to upgrade + the module's source. + + After the upgrade, it will remove the files listed in the Files-Excluded + field and finally it will commit the changes. +''' + +import deb822 +import os +import sys +import re +from subprocess import call + +MODULES_PATH = 'modules/' +MODULES_CTRL = os.path.join(MODULES_PATH, 'control') + +def prompt(query): + ''' + Ask the given query and wait for an y/N answer. + + :query: The query + :returns: The yes (True) or no (False) answer + ''' + sys.stdout.write('%s [y/N]: ' % query) + choice = raw_input().lower() + + return choice == 'y' + + +def upgrade_module(mi, watchfile): + ''' + Upgrade the given module using uscan and the custom modules/uupdate. + After the upgrade, remove the Files-Excluded. + + :param mi: modules/control info for the module + :param watchfile: The watchfile of the module + :returns: The new module version + ''' + uscan_upgrade_cmd = [ + 'uscan', '--upstream-version', mi['Version'], + '--watchfile', 'debian/%s' % watchfile, '--no-symlink' + ] + upgrade_ret = call(uscan_upgrade_cmd, stdout=open(os.devnull, 'w')) + + if 'Files-Excluded' in mi and upgrade_ret == 0: + print 'Removing Files-Excluded: %s' % mi['Files-Excluded'] + + files = re.split('\s+', mi['Files-Excluded']) + files = filter(None, files) + abs_files = ['%s%s/%s' % (MODULES_PATH, mi['Module'], f) for f in files] + + rm_cmd = ['rm', '-r'] + rm_cmd.extend(abs_files) + + call(rm_cmd) + + return open('/tmp/ngx_uupdate_version_%s' % mi['Module']).read().rstrip() + + +def update_module_version(mi, new_ver): + ''' + Update the given module's version in modules/control. + + :param mi: modules/control info for the module + :param new_ver: The new module version + ''' + modules_info = deb822.Deb822.iter_paragraphs(file(MODULES_CTRL)) + modules_ctrl_new = '%s%s' % (MODULES_CTRL, '.new') + with open(modules_ctrl_new, 'w') as c: + for m in modules_info: + if mi['Module'] == m['Module']: + m['Version'] = re.sub('[^v]+', new_ver, m['Version']) + + c.write(m.dump() + '\n') + c.closed + os.rename(modules_ctrl_new, MODULES_CTRL) + + +def commit_module(mi, new_ver): + ''' + Git-commit the given module's upgraded source. + + :param mi: modules/control info for the module + :param new_ver: The new module version + ''' + module_name = mi['Module'] + module_path = os.path.join(MODULES_PATH, module_name) + + git_add_cmd = ['git', 'add', module_path, MODULES_CTRL] + call(git_add_cmd) + + commit_msg = 'Update %s to v%s' % (module_name, new_ver) + git_commit_cmd = ['git', 'commit', '-m', commit_msg] + call(git_commit_cmd) + + +def usage(): + print(""" +Usage: + ngxmod + +Subcommands: + + uscan - scan/watch upstream nginx module sources for new releases +""") + + +def main(): + modules_info = deb822.Deb822.iter_paragraphs(file(MODULES_CTRL)) + + for mi in modules_info: + sys.stdout.write('Uscanning %s...' % mi['Module']) + sys.stdout.flush() + + watchfile = os.path.join(MODULES_PATH, 'watch', mi['Module']) + + if not os.path.isfile(watchfile): + print 'no watchfile available.' + continue + + uscan_check_cmd = [ + 'uscan', '--upstream-version', mi['Version'], + '--watchfile', watchfile, '--package', + mi['Module'] + ] + check_ret = call(uscan_check_cmd) + + if check_ret == 0: + if prompt('Do you want to upgrade %s?' % mi['Module']): + new_module_ver = upgrade_module(mi, watchfile) + update_module_version(mi, new_module_ver) + commit_module(mi, new_module_ver) + else: + print 'up-to-date.' + + +if __name__ == '__main__': + if len(sys.argv) == 2 and sys.argv[1] == 'uscan': + main() + else: + usage() From 7f899937abcb400b8fc8e5d014ca16af9705eeab Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 11 Dec 2017 11:46:58 +0200 Subject: [PATCH 281/651] Bits & pieces for ngxmod o Drop d/m/uupdate in favor of ngxmod uupdate subcommand. While at it, take advantage of the canonical module names and drop the last argument. o Move unpacking & commit to uupdate subcommand, that way we don't to have to communicate the upstream version with ngxmod uscan. o Move around a few things, and switch to argparse. --- debian/modules/uupdate | 10 - debian/modules/watch/http-auth-pam | 4 +- debian/modules/watch/http-cache-purge | 4 +- debian/modules/watch/http-dav-ext | 4 +- debian/modules/watch/http-echo | 4 +- debian/modules/watch/http-fancyindex | 4 +- debian/modules/watch/http-headers-more-filter | 4 +- debian/modules/watch/http-lua | 4 +- debian/modules/watch/http-ndk | 4 +- debian/modules/watch/http-subs-filter | 4 +- debian/modules/watch/http-uploadprogress | 4 +- debian/modules/watch/nchan | 4 +- debian/modules/watch/rtmp | 4 +- debian/ngxmod | 278 +++++++++++------- 14 files changed, 194 insertions(+), 142 deletions(-) delete mode 100755 debian/modules/uupdate diff --git a/debian/modules/uupdate b/debian/modules/uupdate deleted file mode 100755 index 98a5f8b..0000000 --- a/debian/modules/uupdate +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -# debian/modules/uupdate - simple tar wrapper used by uscan to upgrade modules source - -MOD_TAR_NAME=$2 -MOD_TAR_VER=$4 -DESTDIR=debian/modules/$1 - -tar --strip-components=1 -xf ../$MOD_TAR_NAME-$MOD_TAR_VER.tar.gz -C $DESTDIR -echo $MOD_TAR_VER > /tmp/ngx_uupdate_version_$1 diff --git a/debian/modules/watch/http-auth-pam b/debian/modules/watch/http-auth-pam index eac2f73..3fb5a27 100644 --- a/debian/modules/watch/http-auth-pam +++ b/debian/modules/watch/http-auth-pam @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-http-auth-pam-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-auth-pam-$1.tar.gz%" \ https://github.com/stogh/ngx_http_auth_pam_module/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-auth-pam ngx-mod-http-auth-pam + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-auth-pam diff --git a/debian/modules/watch/http-cache-purge b/debian/modules/watch/http-cache-purge index 2566801..e2458f2 100644 --- a/debian/modules/watch/http-cache-purge +++ b/debian/modules/watch/http-cache-purge @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-cache-purge-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-cache-purge-$1.tar.gz%" \ https://github.com/FRiCKLE/ngx_cache_purge/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-cache-purge ngx-mod-cache-purge + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-cache-purge diff --git a/debian/modules/watch/http-dav-ext b/debian/modules/watch/http-dav-ext index d704cfc..064766a 100644 --- a/debian/modules/watch/http-dav-ext +++ b/debian/modules/watch/http-dav-ext @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-dav-ext-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-dav-ext-$1.tar.gz%" \ https://github.com/arut/nginx-dav-ext-module/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-dav-ext ngx-mod-dav-ext + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-dav-ext diff --git a/debian/modules/watch/http-echo b/debian/modules/watch/http-echo index 615532b..3d44f5d 100644 --- a/debian/modules/watch/http-echo +++ b/debian/modules/watch/http-echo @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-echo-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-echo-$1.tar.gz%" \ https://github.com/agentzh/echo-nginx-module/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-echo ngx-mod-echo + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-echo diff --git a/debian/modules/watch/http-fancyindex b/debian/modules/watch/http-fancyindex index 72435fd..5833ccd 100644 --- a/debian/modules/watch/http-fancyindex +++ b/debian/modules/watch/http-fancyindex @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-fancyindex-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-fancyindex-$1.tar.gz%" \ https://github.com/aperezdc/ngx-fancyindex/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-fancyindex ngx-mod-fancyindex + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-fancyindex diff --git a/debian/modules/watch/http-headers-more-filter b/debian/modules/watch/http-headers-more-filter index cfe5fc9..b0cae5c 100644 --- a/debian/modules/watch/http-headers-more-filter +++ b/debian/modules/watch/http-headers-more-filter @@ -1,4 +1,4 @@ version=4 -opts="uversionmangle=s/0.261/0.26.1/,dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-headers-more-$1.tar.gz%" \ +opts="uversionmangle=s/0.261/0.26.1/,dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-headers-more-filter-$1.tar.gz%" \ https://github.com/agentzh/headers-more-nginx-module/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-headers-more-filter ngx-mod-headers-more + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-headers-more-filter diff --git a/debian/modules/watch/http-lua b/debian/modules/watch/http-lua index 7f1718f..193d824 100644 --- a/debian/modules/watch/http-lua +++ b/debian/modules/watch/http-lua @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%lua-nginx-module-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-lua-$1.tar.gz%" \ https://github.com/openresty/lua-nginx-module/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-lua lua-nginx-module + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-lua diff --git a/debian/modules/watch/http-ndk b/debian/modules/watch/http-ndk index 43f0cbd..f359136 100644 --- a/debian/modules/watch/http-ndk +++ b/debian/modules/watch/http-ndk @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-devel-kit-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-ndk-$1.tar.gz%" \ https://github.com/simpl/ngx_devel_kit/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-ndk ngx-mod-devel-kit + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-ndk diff --git a/debian/modules/watch/http-subs-filter b/debian/modules/watch/http-subs-filter index cca3e05..2d37540 100644 --- a/debian/modules/watch/http-subs-filter +++ b/debian/modules/watch/http-subs-filter @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-http-substitutions-filter-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-subs-filter-$1.tar.gz%" \ https://github.com/yaoweibin/ngx_http_substitutions_filter_module/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-subs-filter ngx-mod-http-substitutions-filter + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-subs-filter diff --git a/debian/modules/watch/http-uploadprogress b/debian/modules/watch/http-uploadprogress index 7c0b7cf..cccba98 100644 --- a/debian/modules/watch/http-uploadprogress +++ b/debian/modules/watch/http-uploadprogress @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-upload-progress-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-uploadprogress-$1.tar.gz%" \ https://github.com/masterzen/nginx-upload-progress-module/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-uploadprogress ngx-mod-upload-progress + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-uploadprogress diff --git a/debian/modules/watch/nchan b/debian/modules/watch/nchan index 6b95884..199ab19 100644 --- a/debian/modules/watch/nchan +++ b/debian/modules/watch/nchan @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-nchan-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-nchan-$1.tar.gz%" \ https://github.com/slact/nchan/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate nchan ngx-mod-nchan + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate nchan diff --git a/debian/modules/watch/rtmp b/debian/modules/watch/rtmp index f8137a2..2a95f4c 100644 --- a/debian/modules/watch/rtmp +++ b/debian/modules/watch/rtmp @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-rtmp-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-rtmp-$1.tar.gz%" \ https://github.com/arut/nginx-rtmp-module/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate rtmp ngx-mod-rtmp + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate rtmp diff --git a/debian/ngxmod b/debian/ngxmod index f8180d1..7eacaa5 100755 --- a/debian/ngxmod +++ b/debian/ngxmod @@ -1,130 +1,156 @@ #!/usr/bin/env python -''' -ngxmod - nginx modules management helper script +""" +Handy Debian nginx module management helper +""" -Usage: - ngxmod - -Subcommands: - - uscan - scan/watch upstream nginx module sources for new releases - - It runs uscan for each nginx module listed in debian/modules/control. - - If a new version is available, it will ask you if you want to upgrade. - If you agree it will use uscan to download the tarball, place it in the nginx - source's parent directory and unpack it using modules/uupdate to upgrade - the module's source. - - After the upgrade, it will remove the files listed in the Files-Excluded - field and finally it will commit the changes. -''' - -import deb822 +import argparse import os -import sys import re +import shutil +import sys +import tarfile +import tempfile + from subprocess import call -MODULES_PATH = 'modules/' -MODULES_CTRL = os.path.join(MODULES_PATH, 'control') +import deb822 + +DEBIAN_PATH = os.path.dirname(os.path.realpath(__file__)) +MODULES_PATH = os.path.join(DEBIAN_PATH, 'modules') +CTRL_PATH = os.path.join(MODULES_PATH, 'control') +CTRL = [p for p in deb822.Deb822.iter_paragraphs(file(CTRL_PATH))] + + +def ctrl(name): + "Return deb822 paragraph for the selected module" + global CTRL + + for m in CTRL: + if m['Module'] == name: + return m + + +def update_ctrl(): + "Save current control to disk" + global CTRL + + new_ctrl = CTRL_PATH + '.new' + with open(new_ctrl, 'w') as c: + for m in CTRL: + c.write(m.dump() + '\n') + + os.rename(new_ctrl, CTRL_PATH) + def prompt(query): - ''' + """ Ask the given query and wait for an y/N answer. :query: The query :returns: The yes (True) or no (False) answer - ''' + """ sys.stdout.write('%s [y/N]: ' % query) choice = raw_input().lower() return choice == 'y' -def upgrade_module(mi, watchfile): - ''' - Upgrade the given module using uscan and the custom modules/uupdate. - After the upgrade, remove the Files-Excluded. - - :param mi: modules/control info for the module - :param watchfile: The watchfile of the module - :returns: The new module version - ''' - uscan_upgrade_cmd = [ - 'uscan', '--upstream-version', mi['Version'], - '--watchfile', 'debian/%s' % watchfile, '--no-symlink' - ] - upgrade_ret = call(uscan_upgrade_cmd, stdout=open(os.devnull, 'w')) - - if 'Files-Excluded' in mi and upgrade_ret == 0: - print 'Removing Files-Excluded: %s' % mi['Files-Excluded'] - - files = re.split('\s+', mi['Files-Excluded']) - files = filter(None, files) - abs_files = ['%s%s/%s' % (MODULES_PATH, mi['Module'], f) for f in files] - - rm_cmd = ['rm', '-r'] - rm_cmd.extend(abs_files) - - call(rm_cmd) - - return open('/tmp/ngx_uupdate_version_%s' % mi['Module']).read().rstrip() - - -def update_module_version(mi, new_ver): - ''' - Update the given module's version in modules/control. - - :param mi: modules/control info for the module - :param new_ver: The new module version - ''' - modules_info = deb822.Deb822.iter_paragraphs(file(MODULES_CTRL)) - modules_ctrl_new = '%s%s' % (MODULES_CTRL, '.new') - with open(modules_ctrl_new, 'w') as c: - for m in modules_info: - if mi['Module'] == m['Module']: - m['Version'] = re.sub('[^v]+', new_ver, m['Version']) - - c.write(m.dump() + '\n') - c.closed - os.rename(modules_ctrl_new, MODULES_CTRL) - - -def commit_module(mi, new_ver): - ''' +def commit(module, version): + """ Git-commit the given module's upgraded source. - :param mi: modules/control info for the module - :param new_ver: The new module version - ''' - module_name = mi['Module'] - module_path = os.path.join(MODULES_PATH, module_name) + :param module: module name + :param version: The updated module version + """ + module_path = os.path.join(MODULES_PATH, module) - git_add_cmd = ['git', 'add', module_path, MODULES_CTRL] + git_add_cmd = ['git', 'add', '--all', module_path, CTRL_PATH] call(git_add_cmd) - commit_msg = 'Update %s to v%s' % (module_name, new_ver) - git_commit_cmd = ['git', 'commit', '-m', commit_msg] + commit_msg = '%s: Upgrade to v%s' % (module, version) + git_commit_cmd = [ + 'git', 'commit', '-m', commit_msg, + '--', module_path, CTRL_PATH] call(git_commit_cmd) -def usage(): - print(""" -Usage: - ngxmod +def unpack(module, version, exclude): + "Unpack upstream tar file into module path" -Subcommands: + tar_gz = os.path.join( + "..", "libnginx-mod-%s-%s.tar.gz" % (module, version)) + if not os.path.exists(tar_gz): + print "%s doesn't exist!" % tar_gz + exit(1) - uscan - scan/watch upstream nginx module sources for new releases -""") + module_path = os.path.join(MODULES_PATH, module) + tmpdir = tempfile.mkdtemp(prefix="libnginx-mod-%s-%s." % (module, version)) + with tarfile.open(tar_gz) as tar: + members = tar.getmembers() + + # stip top-level directory from tar + topdir = members[0] + if not topdir or not topdir.isdir(): + print "No top directory found!" + exit(1) + + topdir = members[0].path + if any(topdir not in ti.path for ti in members): + print "Not all files are under the top directory '%s'" % topdir + exit(1) + + def remove_topdir_prefix(tarinfo): + "Strip top directory" + tarinfo.path = os.path.relpath(tarinfo.path, topdir) + return tarinfo + members = [remove_topdir_prefix(tarinfo) for tarinfo in members] + tar.extractall(path=tmpdir, members=members) + + shutil.rmtree(module_path) + shutil.move(tmpdir, module_path) + + for e in exclude: + print "Removing %s..." % e + abspath = os.path.join(module_path, e) + if os.path.isdir(abspath): + shutil.rmtree(abspath) + else: + os.remove(abspath) -def main(): - modules_info = deb822.Deb822.iter_paragraphs(file(MODULES_CTRL)) +def cmd_uupdate(args): + "Internal uupdate helper, upgrades & commits the given module" + c = ctrl(args.module) - for mi in modules_info: - sys.stdout.write('Uscanning %s...' % mi['Module']) + exclude = [] + if 'Files-Excluded' in c: + exclude = c['Files-Excluded'].split() + + unpack(args.module, args.upstream_version, exclude) + + # change ctrl version + c['Version'] = re.sub('[^v]+', args.upstream_version, c['Version']) + update_ctrl() + + commit(args.module, args.upstream_version) + + +def cmd_uscan(args): + """ + Run uscan for each nginx module listed in debian/modules/control. + + If a new version is found, it will be downloaded & unpacked to the proper + debian/modules/MODULE path. + + After the upgrade, all files listed in the Files-Excluded: control field + will be removed, debian/modules/control version will be updated and all + changes will be commited to git. + """ + global CTRL + + # For every module that has watchfile... + for mi in CTRL: + sys.stdout.write('Uscanning %s: ' % mi['Module']) sys.stdout.flush() watchfile = os.path.join(MODULES_PATH, 'watch', mi['Module']) @@ -133,24 +159,60 @@ def main(): print 'no watchfile available.' continue + # Check uscan_check_cmd = [ 'uscan', '--upstream-version', mi['Version'], '--watchfile', watchfile, '--package', mi['Module'] ] - check_ret = call(uscan_check_cmd) + if call(uscan_check_cmd) != 0: + print 'up-to-date' + continue - if check_ret == 0: - if prompt('Do you want to upgrade %s?' % mi['Module']): - new_module_ver = upgrade_module(mi, watchfile) - update_module_version(mi, new_module_ver) - commit_module(mi, new_module_ver) - else: - print 'up-to-date.' + # Ask + if not prompt('Do you want to upgrade %s?' % mi['Module']): + continue + + # Upgrade + uscan_upgrade_cmd = [ + 'uscan', '--upstream-version', mi['Version'], + '--watchfile', watchfile, '--no-symlink' + ] + if call(uscan_upgrade_cmd, stdout=open(os.devnull, 'w')) != 0: + print "Uscan for %s failed!" % mi['Module'] + exit(1) + + +def main(): + """ngxmod main""" + + parser = argparse.ArgumentParser( + description=__doc__) + cmds = parser.add_subparsers(title="Commands") + + import textwrap + uscan_cmd = cmds.add_parser( + "uscan", + help="scan/watch upstream nginx module sources for new releases", + description=textwrap.dedent(cmd_uscan.__doc__), + formatter_class=argparse.RawDescriptionHelpFormatter) + uscan_cmd.set_defaults(func=cmd_uscan) + + uupdate_cmd = cmds.add_parser( + "uupdate", + help=cmd_uupdate.__doc__, + description=cmd_uupdate.__doc__) + uupdate_cmd.add_argument("module", metavar="MODULE", help="Module name") + uupdate_cmd.add_argument( + "--upstream-version", + required=True, + metavar="VERSION", + help="Upstream version") + uupdate_cmd.set_defaults(func=cmd_uupdate) + + args = parser.parse_args() + args.func(args) if __name__ == '__main__': - if len(sys.argv) == 2 and sys.argv[1] == 'uscan': - main() - else: - usage() + main() From 33799993fc8fbe4d3aca32b6518cc3a01d4729b7 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 13 Dec 2017 11:22:21 +0200 Subject: [PATCH 282/651] http-headers-more-filter: Upgrade to 0.33 --- debian/modules/control | 2 +- .../http-headers-more-filter/README.markdown | 40 ++++-- .../src/ngx_http_headers_more_headers_in.c | 63 +++++---- .../http-headers-more-filter/t/builtin.t | 1 - .../http-headers-more-filter/t/input-conn.t | 1 - .../http-headers-more-filter/t/input-ua.t | 1 - .../http-headers-more-filter/t/input.t | 42 +++++- .../http-headers-more-filter/t/phase.t | 1 - .../http-headers-more-filter/t/sanity.t | 1 - .../http-headers-more-filter/t/subrequest.t | 1 - .../http-headers-more-filter/t/unused.t | 1 - .../modules/http-headers-more-filter/t/vars.t | 1 - .../valgrind.suppress | 126 ++++-------------- 13 files changed, 134 insertions(+), 147 deletions(-) diff --git a/debian/modules/control b/debian/modules/control index 5f67e38..71c63eb 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -1,6 +1,6 @@ Module: http-headers-more-filter Homepage: https://github.com/agentzh/headers-more-nginx-module -Version: v0.32 +Version: v0.33 Files-Excluded: .gitignore .gitattributes .travis.yml Module: http-ndk diff --git a/debian/modules/http-headers-more-filter/README.markdown b/debian/modules/http-headers-more-filter/README.markdown index d584461..452ef1f 100644 --- a/debian/modules/http-headers-more-filter/README.markdown +++ b/debian/modules/http-headers-more-filter/README.markdown @@ -36,7 +36,7 @@ Table of Contents Version ======= -This document describes headers-more-nginx-module [v0.32](https://github.com/openresty/headers-more-nginx-module/tags) released on 4 November 2016. +This document describes headers-more-nginx-module [v0.33](https://github.com/openresty/headers-more-nginx-module/tags) released on 3 November 2017. Synopsis ======== @@ -248,7 +248,8 @@ or See [more_set_headers](#more_set_headers) for more details. -Wildcard `*` can also be used to specify a header name pattern. For example, the following directive effectively clears *any* output headers starting by "`X-Hidden-`": +The wildcard character, `*`, can also be used at the end of the header name to specify a pattern. For example, the following directive +effectively clears *any* output headers starting by "`X-Hidden-`": ```nginx @@ -298,25 +299,40 @@ In fact, ```nginx - more_clear_input_headers -s 404 -t 'text/plain' Foo Baz; + more_clear_input_headers -t 'text/plain' Foo Baz; ``` is exactly equivalent to ```nginx - more_set_input_headers -s 404 -t 'text/plain' "Foo: " "Baz: "; + more_set_input_headers -t 'text/plain' "Foo: " "Baz: "; ``` or ```nginx - more_set_input_headers -s 404 -t 'text/plain' Foo Baz + more_set_input_headers -t 'text/plain' Foo Baz +``` + +To remove request headers "Foo" and "Baz" for all incoming requests regardless of the content type, we can write + +```nginx + + more_clear_input_headers "Foo" "Baz"; ``` See [more_set_input_headers](#more_set_input_headers) for more details. +The wildcard character, `*`, can also be used at the end of the header name to specify a pattern. For example, the following directive +effectively clears *any* input headers starting by "`X-Hidden-`": + +```nginx + + more_clear_input_headers 'X-Hidden-*'; +``` + [Back to TOC](#table-of-contents) Limitations @@ -331,13 +347,13 @@ Installation ============ Grab the nginx source code from [nginx.org](http://nginx.org/), for example, -the version 1.11.2 (see [nginx compatibility](#compatibility)), and then build the source with this module: +the version 1.13.6 (see [nginx compatibility](#compatibility)), and then build the source with this module: ```bash - wget 'http://nginx.org/download/nginx-1.11.2.tar.gz' - tar -xzvf nginx-1.11.2.tar.gz - cd nginx-1.11.2/ + wget 'http://nginx.org/download/nginx-1.13.6.tar.gz' + tar -xzvf nginx-1.13.6.tar.gz + cd nginx-1.13.6/ # Here we assume you would install you nginx under /opt/nginx/. ./configure --prefix=/opt/nginx \ @@ -366,6 +382,8 @@ Compatibility The following versions of Nginx should work with this module: +* **1.13.x** (last tested: 1.13.6) +* **1.12.x** * **1.11.x** (last tested: 1.11.2) * **1.10.x** * **1.9.x** (last tested: 1.9.15) @@ -479,7 +497,7 @@ You'll be very welcomed to submit patches to the [author](#author) or just ask f Authors ======= -* Yichun "agentzh" Zhang (章亦春) *<agentzh@gmail.com>*, CloudFlare Inc. +* Yichun "agentzh" Zhang (章亦春) *<agentzh@gmail.com>*, OpenResty Inc. * Bernd Dorn ( ) This wiki page is also maintained by the author himself, and everybody is encouraged to improve this page as well. @@ -491,7 +509,7 @@ Copyright & License The code base is borrowed directly from the standard [headers](http://nginx.org/en/docs/http/ngx_http_headers_module.html) module in Nginx 0.8.24. This part of code is copyrighted by Igor Sysoev. -Copyright (c) 2009-2014, Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +Copyright (c) 2009-2017, Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. Copyright (c) 2010-2013, Bernd Dorn. diff --git a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.c b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.c index bdea8de..c3eb8f7 100644 --- a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.c +++ b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.c @@ -243,42 +243,59 @@ retry: i = 0; } - if (h[i].key.len == hv->key.len + if (!hv->wildcard + && h[i].key.len == hv->key.len && ngx_strncasecmp(h[i].key.data, hv->key.data, h[i].key.len) == 0) { - if (value->len == 0 || (matched && matched != &h[i])) { - h[i].hash = 0; + goto matched; + } - rc = ngx_http_headers_more_rm_header_helper( - &r->headers_in.headers, part, i); + if (hv->wildcard + && value->len == 0 + && h[i].key.len >= hv->key.len - 1 + && ngx_strncasecmp(h[i].key.data, hv->key.data, + hv->key.len - 1) == 0) + { + goto matched; + } - ngx_http_headers_more_assert( - !(r->headers_in.headers.part.next == NULL - && r->headers_in.headers.last - != &r->headers_in.headers.part)); + /* not matched */ + continue; - if (rc == NGX_OK) { - if (output_header) { - *output_header = NULL; - } +matched: - goto retry; + if (value->len == 0 || (matched && matched != &h[i])) { + h[i].hash = 0; + + rc = ngx_http_headers_more_rm_header_helper( + &r->headers_in.headers, part, i); + + ngx_http_headers_more_assert( + !(r->headers_in.headers.part.next == NULL + && r->headers_in.headers.last + != &r->headers_in.headers.part)); + + if (rc == NGX_OK) { + if (output_header) { + *output_header = NULL; } - return NGX_ERROR; + goto retry; } - h[i].value = *value; + return NGX_ERROR; + } - if (output_header) { - *output_header = &h[i]; - dd("setting existing builtin input header"); - } + h[i].value = *value; - if (matched == NULL) { - matched = &h[i]; - } + if (output_header) { + *output_header = &h[i]; + dd("setting existing builtin input header"); + } + + if (matched == NULL) { + matched = &h[i]; } } diff --git a/debian/modules/http-headers-more-filter/t/builtin.t b/debian/modules/http-headers-more-filter/t/builtin.t index f2b5c34..27b20af 100644 --- a/debian/modules/http-headers-more-filter/t/builtin.t +++ b/debian/modules/http-headers-more-filter/t/builtin.t @@ -336,4 +336,3 @@ hello Vary: hello --- response_body hello - diff --git a/debian/modules/http-headers-more-filter/t/input-conn.t b/debian/modules/http-headers-more-filter/t/input-conn.t index a32d4e1..f53e80f 100644 --- a/debian/modules/http-headers-more-filter/t/input-conn.t +++ b/debian/modules/http-headers-more-filter/t/input-conn.t @@ -135,4 +135,3 @@ content: conn type: 0 connection: bad --- no_error_log [error] - diff --git a/debian/modules/http-headers-more-filter/t/input-ua.t b/debian/modules/http-headers-more-filter/t/input-ua.t index 56d2222..da9a60d 100644 --- a/debian/modules/http-headers-more-filter/t/input-ua.t +++ b/debian/modules/http-headers-more-filter/t/input-ua.t @@ -626,4 +626,3 @@ content: konqueror: 1 User-Agent: Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.10 (like Gecko) (Kubuntu) --- no_error_log [error] - diff --git a/debian/modules/http-headers-more-filter/t/input.t b/debian/modules/http-headers-more-filter/t/input.t index 0b8989f..01ae73f 100644 --- a/debian/modules/http-headers-more-filter/t/input.t +++ b/debian/modules/http-headers-more-filter/t/input.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket; # 'no_plan'; repeat_each(2); -plan tests => repeat_each() * 124; +plan tests => repeat_each() * 128; no_long_string(); #no_diff; @@ -1289,3 +1289,43 @@ X-Forwarded-For: 8.8.8.8 Foo: 127.0.0.1 --- no_error_log [error] + + + +=== TEST 50: clear input headers with wildcard +--- config + location /hello { + more_clear_input_headers 'X-Hidden-*'; + content_by_lua ' + ngx.say("X-Hidden-One: ", ngx.var.http_x_hidden_one) + ngx.say("X-Hidden-Two: ", ngx.var.http_x_hidden_two) + '; + } +--- request + GET /hello +--- more_headers +X-Hidden-One: i am hidden +X-Hidden-Two: me 2 +--- response_body +X-Hidden-One: nil +X-Hidden-Two: nil + + + +=== TEST 51: make sure wildcard doesn't affect more_set_input_headers +--- config + location /hello { + more_set_input_headers 'X-Hidden-*: lol'; + content_by_lua ' + ngx.say("X-Hidden-One: ", ngx.var.http_x_hidden_one) + ngx.say("X-Hidden-Two: ", ngx.var.http_x_hidden_two) + '; + } +--- request + GET /hello +--- more_headers +X-Hidden-One: i am hidden +X-Hidden-Two: me 2 +--- response_body +X-Hidden-One: i am hidden +X-Hidden-Two: me 2 diff --git a/debian/modules/http-headers-more-filter/t/phase.t b/debian/modules/http-headers-more-filter/t/phase.t index 343d2e5..11183db 100644 --- a/debian/modules/http-headers-more-filter/t/phase.t +++ b/debian/modules/http-headers-more-filter/t/phase.t @@ -23,4 +23,3 @@ __DATA__ X-Foo: Blah --- response_body_like: 403 Forbidden --- error_code: 403 - diff --git a/debian/modules/http-headers-more-filter/t/sanity.t b/debian/modules/http-headers-more-filter/t/sanity.t index e316cac..d06f5dc 100644 --- a/debian/modules/http-headers-more-filter/t/sanity.t +++ b/debian/modules/http-headers-more-filter/t/sanity.t @@ -565,4 +565,3 @@ hi --- response_body ok --- http09 - diff --git a/debian/modules/http-headers-more-filter/t/subrequest.t b/debian/modules/http-headers-more-filter/t/subrequest.t index 34e84c9..9443eca 100644 --- a/debian/modules/http-headers-more-filter/t/subrequest.t +++ b/debian/modules/http-headers-more-filter/t/subrequest.t @@ -66,4 +66,3 @@ main: dog --- response_headers ! Host --- skip_nginx: 3: < 0.7.46 - diff --git a/debian/modules/http-headers-more-filter/t/unused.t b/debian/modules/http-headers-more-filter/t/unused.t index 1f35adc..c51f91c 100644 --- a/debian/modules/http-headers-more-filter/t/unused.t +++ b/debian/modules/http-headers-more-filter/t/unused.t @@ -172,4 +172,3 @@ bar headers more header handler [error] --- log_level: debug - diff --git a/debian/modules/http-headers-more-filter/t/vars.t b/debian/modules/http-headers-more-filter/t/vars.t index 426c68c..04c75c3 100644 --- a/debian/modules/http-headers-more-filter/t/vars.t +++ b/debian/modules/http-headers-more-filter/t/vars.t @@ -56,4 +56,3 @@ hi dog --- response_headers Host: - diff --git a/debian/modules/http-headers-more-filter/valgrind.suppress b/debian/modules/http-headers-more-filter/valgrind.suppress index bba7217..d51de70 100644 --- a/debian/modules/http-headers-more-filter/valgrind.suppress +++ b/debian/modules/http-headers-more-filter/valgrind.suppress @@ -1,40 +1,9 @@ -{ - -Memcheck:Cond -fun:lj_str_new -} { - Memcheck:Cond - fun:lj_str_new - fun:lua_pushlstring -} -{ - - Memcheck:Addr4 - fun:lj_str_new - fun:lua_pushlstring -} -{ - -Memcheck:Leak -fun:malloc -fun:ngx_alloc -obj:* -} -{ - -Memcheck:Leak -fun:malloc -fun:ngx_alloc -} -{ - -Memcheck:Leak -fun:malloc -fun:ngx_alloc -fun:ngx_palloc_large -fun:ngx_palloc + Memcheck:Leak + fun:malloc + fun:ngx_alloc + obj:* } { @@ -44,27 +13,6 @@ fun:ngx_palloc fun:ngx_calloc fun:ngx_event_process_init } -{ - -Memcheck:Addr4 -fun:lj_str_new -fun:lua_pushlstring -fun:ngx_http_lua_get_output_header -} -{ - - Memcheck:Addr4 - fun:lj_str_new - fun:lua_getfield - fun:ngx_http_lua_cache_load_code -} -{ - - Memcheck:Addr4 - fun:lj_str_new - fun:lua_setfield - fun:ngx_http_lua_cache_store_code -} { Memcheck:Leak @@ -72,34 +20,12 @@ fun:ngx_http_lua_get_output_header fun:ngx_alloc fun:ngx_event_process_init } -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:(below main) -} { Memcheck:Param epoll_ctl(event) fun:epoll_ctl } -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_create_pool -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_malloc - fun:ngx_palloc_large -} { Memcheck:Cond @@ -108,22 +34,6 @@ fun:ngx_http_lua_get_output_header fun:ngx_log_error_core fun:ngx_http_charset_header_filter } -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_malloc - fun:ngx_pnalloc -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_malloc - fun:ngx_palloc -} { nginx-core-process-init Memcheck:Leak @@ -185,15 +95,6 @@ fun:ngx_http_lua_get_output_header fun:ngx_epoll_process_events fun:ngx_process_events_and_timers } -{ - - Memcheck:Leak - fun:memalign - fun:posix_memalign - fun:ngx_memalign - fun:ngx_palloc_block - fun:ngx_palloc -} { Memcheck:Addr8 @@ -213,3 +114,22 @@ fun:ngx_http_lua_get_output_header fun:do_preload fun:dl_main } +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_single_process_cycle +} +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_worker_process_init + fun:ngx_worker_process_cycle +} From 8acbe3fbc400848abfa345e8db5ffe1bebc9c0bb Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 13 Dec 2017 11:22:39 +0200 Subject: [PATCH 283/651] http-echo: Upgrade to 0.61 Drop build-nginx-1.11.11 patch now included upstream --- debian/modules/control | 3 +- debian/modules/http-echo/README.markdown | 24 +- .../http-echo/src/ngx_http_echo_module.c | 13 ++ .../http-echo/src/ngx_http_echo_module.h | 4 + .../src/ngx_http_echo_request_info.c | 62 +++++ .../src/ngx_http_echo_request_info.h | 3 + debian/modules/http-echo/valgrind.suppress | 10 + .../http-echo/build-nginx-1.11.11.patch | 212 ------------------ debian/modules/patches/http-echo/series | 1 - 9 files changed, 107 insertions(+), 225 deletions(-) delete mode 100644 debian/modules/patches/http-echo/build-nginx-1.11.11.patch delete mode 100644 debian/modules/patches/http-echo/series diff --git a/debian/modules/control b/debian/modules/control index 71c63eb..b779595 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -13,9 +13,8 @@ Version: v1.5.1 Module: http-echo Homepage: https://github.com/agentzh/echo-nginx-module -Version: v0.60 +Version: v0.61 Files-Excluded: .gitignore .gitattributes .travis.yml -Patch: build-nginx-1.11.11.patch Module: http-lua Homepage: https://github.com/openresty/lua-nginx-module diff --git a/debian/modules/http-echo/README.markdown b/debian/modules/http-echo/README.markdown index 9de2c0b..71ac080 100644 --- a/debian/modules/http-echo/README.markdown +++ b/debian/modules/http-echo/README.markdown @@ -68,7 +68,7 @@ This module is production ready. Version ======= -This document describes ngx_echo [v0.59](https://github.com/openresty/echo-nginx-module/tags) released on 15 May 2016. +This document describes ngx_echo [v0.61](https://github.com/openresty/echo-nginx-module/tags) released on 8 August 2017. Synopsis ======== @@ -284,9 +284,9 @@ People will also find it useful in real-world applications that need to This is a special dual-role module that can *lazily* serve as a content handler or register itself as an output filter only upon demand. By default, this module does not do anything at all. -Technially, this module has also demonstrated the following techniques that might be helpful for module writers: +Technically, this module has also demonstrated the following techniques that might be helpful for module writers: -1. Issue parallel subreqeusts directly from content handler. +1. Issue parallel subrequests directly from content handler. 1. Issue chained subrequests directly from content handler, by passing continuation along the subrequest chain. 1. Issue subrequests with all HTTP 1.1 methods and even an optional faked HTTP request body. 1. Interact with the Nginx event model directly from content handler using custom events and timers, and resume the content handler back if necessary. @@ -395,7 +395,7 @@ The output on the client side looks like this world ``` -Special characters like newlines (`\n`) and tabs (`\t`) can be escaped using C-style escaping sequences. But a notable exception is the dollar sign (`$`). As of Nginx 0.8.20, there's still no clean way to esacpe this characters. (A work-around might be to use a `$echo_dollor` variable that is always evaluated to the constant `$` character. This feature will possibly be introduced in a future version of this module.) +Special characters like newlines (`\n`) and tabs (`\t`) can be escaped using C-style escaping sequences. But a notable exception is the dollar sign (`$`). As of Nginx 0.8.20, there's still no clean way to escape this character. (A work-around might be to use a `$echo_dollor` variable that is always evaluated to the constant `$` character. This feature will possibly be introduced in a future version of this module.) As of the echo [v0.28](#v028) release, one can suppress the trailing newline character in the output by using the `-n` option, as in @@ -1493,6 +1493,8 @@ Accessing `/echoback` yields Behind the scene, it recovers `r->main->header_in` (or the large header buffers, if any) on the C level and does not construct the headers itself by traversing parsed results in the request object. +This varible is always evaluated to an empty value in HTTP/2 requests for now due to the current implementation. + This variable was first introduced in [version 0.15](#v015). [Back to TOC](#table-of-contents) @@ -1569,13 +1571,13 @@ You're recommended to install this module (as well as the Nginx core and many ot Alternatively, you can install this module manually with the Nginx source: Grab the nginx source code from [nginx.org](http://nginx.org/), for example, -the version 1.9.15 (see [nginx compatibility](#compatibility)), and then build the source with this module: +the version 1.11.2 (see [nginx compatibility](#compatibility)), and then build the source with this module: ```bash - $ wget 'http://nginx.org/download/nginx-1.9.15.tar.gz' - $ tar -xzvf nginx-1.9.15.tar.gz - $ cd nginx-1.9.15/ + $ wget 'http://nginx.org/download/nginx-1.11.2.tar.gz' + $ tar -xzvf nginx-1.11.2.tar.gz + $ cd nginx-1.11.2/ # Here we assume you would install you nginx under /opt/nginx/. $ ./configure --prefix=/opt/nginx \ @@ -1604,6 +1606,8 @@ Compatibility The following versions of Nginx should work with this module: +* **1.11.x** (last tested: 1.11.2) +* **1.10.x** * **1.9.x** (last tested: 1.9.15) * **1.8.x** * **1.7.x** (last tested: 1.7.10) @@ -1796,7 +1800,7 @@ You'll be very welcomed to submit patches to the [author](#author) or just ask f Author ====== -Yichun "agentzh" Zhang (章亦春) *<agentzh@gmail.com>*, CloudFlare Inc. +Yichun "agentzh" Zhang (章亦春) *<agentzh@gmail.com>*, OpenResty Inc. This wiki page is also maintained by the author himself, and everybody is encouraged to improve this page as well. @@ -1805,7 +1809,7 @@ This wiki page is also maintained by the author himself, and everybody is encour Copyright & License =================== -Copyright (c) 2009-2016, Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +Copyright (c) 2009-2017, Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. This module is licensed under the terms of the BSD license. diff --git a/debian/modules/http-echo/src/ngx_http_echo_module.c b/debian/modules/http-echo/src/ngx_http_echo_module.c index ae70479..8d736d7 100644 --- a/debian/modules/http-echo/src/ngx_http_echo_module.c +++ b/debian/modules/http-echo/src/ngx_http_echo_module.c @@ -632,6 +632,9 @@ ngx_http_echo_echo_exec(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) static void * ngx_http_echo_create_main_conf(ngx_conf_t *cf) { +#if nginx_version >= 1011011 + ngx_pool_cleanup_t *cln; +#endif ngx_http_echo_main_conf_t *emcf; emcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_echo_main_conf_t)); @@ -643,6 +646,16 @@ ngx_http_echo_create_main_conf(ngx_conf_t *cf) * hmcf->requires_filter = 0; */ +#if nginx_version >= 1011011 + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NULL; + } + + cln->data = emcf; + cln->handler = ngx_http_echo_request_headers_cleanup; +#endif + return emcf; } diff --git a/debian/modules/http-echo/src/ngx_http_echo_module.h b/debian/modules/http-echo/src/ngx_http_echo_module.h index 2d212c3..ce0a305 100644 --- a/debian/modules/http-echo/src/ngx_http_echo_module.h +++ b/debian/modules/http-echo/src/ngx_http_echo_module.h @@ -92,6 +92,10 @@ typedef struct { typedef struct { ngx_int_t requires_filter; +#if nginx_version >= 1011011 + ngx_buf_t **busy_buf_ptrs; + ngx_int_t busy_buf_ptr_count; +#endif } ngx_http_echo_main_conf_t; diff --git a/debian/modules/http-echo/src/ngx_http_echo_request_info.c b/debian/modules/http-echo/src/ngx_http_echo_request_info.c index d28ec4d..7dd3683 100644 --- a/debian/modules/http-echo/src/ngx_http_echo_request_info.c +++ b/debian/modules/http-echo/src/ngx_http_echo_request_info.c @@ -17,6 +17,9 @@ static void ngx_http_echo_post_read_request_body(ngx_http_request_t *r); +#if nginx_version >= 1011011 +void ngx_http_echo_request_headers_cleanup(void *data); +#endif ngx_int_t @@ -179,6 +182,11 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, ngx_int_t i, j; ngx_buf_t *b, *first = NULL; unsigned found; +#if nginx_version >= 1011011 + ngx_buf_t **bb; + ngx_chain_t *cl; + ngx_http_echo_main_conf_t *emcf; +#endif ngx_connection_t *c; ngx_http_request_t *mr; ngx_http_connection_t *hc; @@ -195,6 +203,10 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, } #endif +#if nginx_version >= 1011011 + emcf = ngx_http_get_module_main_conf(r, ngx_http_echo_module); +#endif + size = 0; b = c->buffer; @@ -215,8 +227,35 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, if (hc->nbusy) { b = NULL; + +#if nginx_version >= 1011011 + if (hc->nbusy > emcf->busy_buf_ptr_count) { + if (emcf->busy_buf_ptrs) { + ngx_free(emcf->busy_buf_ptrs); + } + + emcf->busy_buf_ptrs = ngx_alloc(hc->nbusy * sizeof(ngx_buf_t *), + r->connection->log); + + if (emcf->busy_buf_ptrs == NULL) { + return NGX_ERROR; + } + + emcf->busy_buf_ptr_count = hc->nbusy; + } + + bb = emcf->busy_buf_ptrs; + for (cl = hc->busy; cl; cl = cl->next) { + *bb++ = cl->buf; + } + + bb = emcf->busy_buf_ptrs; + for (i = hc->nbusy; i > 0; i--) { + b = bb[i - 1]; +#else for (i = 0; i < hc->nbusy; i++) { b = hc->busy[i]; +#endif if (first == NULL) { if (mr->request_line.data >= b->pos @@ -280,8 +319,15 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, } if (hc->nbusy) { + +#if nginx_version >= 1011011 + bb = emcf->busy_buf_ptrs; + for (i = hc->nbusy; i > 0; i--) { + b = bb[i - 1]; +#else for (i = 0; i < hc->nbusy; i++) { b = hc->busy[i]; +#endif if (!found) { if (b != first) { @@ -457,4 +503,20 @@ ngx_http_echo_response_status_variable(ngx_http_request_t *r, return NGX_OK; } + +#if nginx_version >= 1011011 +void +ngx_http_echo_request_headers_cleanup(void *data) +{ + ngx_http_echo_main_conf_t *emcf; + + emcf = (ngx_http_echo_main_conf_t *) data; + + if (emcf->busy_buf_ptrs) { + ngx_free(emcf->busy_buf_ptrs); + emcf->busy_buf_ptrs = NULL; + } +} +#endif + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-echo/src/ngx_http_echo_request_info.h b/debian/modules/http-echo/src/ngx_http_echo_request_info.h index 3b3713b..aa5730b 100644 --- a/debian/modules/http-echo/src/ngx_http_echo_request_info.h +++ b/debian/modules/http-echo/src/ngx_http_echo_request_info.h @@ -29,5 +29,8 @@ ngx_int_t ngx_http_echo_request_uri_variable(ngx_http_request_t *r, ngx_int_t ngx_http_echo_response_status_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +#if nginx_version >= 1011011 +void ngx_http_echo_request_headers_cleanup(void *data); +#endif #endif /* ECHO_REQUEST_INFO_H */ diff --git a/debian/modules/http-echo/valgrind.suppress b/debian/modules/http-echo/valgrind.suppress index 0f8e871..d4bfe63 100644 --- a/debian/modules/http-echo/valgrind.suppress +++ b/debian/modules/http-echo/valgrind.suppress @@ -36,3 +36,13 @@ fun:do_preload fun:dl_main } +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_single_process_cycle + fun:main +} diff --git a/debian/modules/patches/http-echo/build-nginx-1.11.11.patch b/debian/modules/patches/http-echo/build-nginx-1.11.11.patch deleted file mode 100644 index dbb9ce7..0000000 --- a/debian/modules/patches/http-echo/build-nginx-1.11.11.patch +++ /dev/null @@ -1,212 +0,0 @@ -From 7740e11558b530b66b469c657576f5280b7cdb1b Mon Sep 17 00:00:00 2001 -From: Andrei Belov -Date: Wed, 22 Mar 2017 08:43:30 +0300 -Subject: [PATCH] feature: nginx 1.11.11+ can now build with this module. - -Note: nginx 1.11.11+ are still not an officially supported target yet. -More work needed. - -Closes openresty/echo-nginx-module#64 - -See also: -http://hg.nginx.org/nginx/rev/e662cbf1b932 - -Signed-off-by: Yichun Zhang (agentzh) ---- - src/ngx_http_echo_module.c | 13 +++++++++ - src/ngx_http_echo_module.h | 4 +++ - src/ngx_http_echo_request_info.c | 62 ++++++++++++++++++++++++++++++++++++++++ - src/ngx_http_echo_request_info.h | 3 ++ - valgrind.suppress | 10 +++++++ - 5 files changed, 92 insertions(+) - -diff --git a/src/ngx_http_echo_module.c b/src/ngx_http_echo_module.c -index ae70479..8d736d7 100644 ---- a/src/ngx_http_echo_module.c -+++ b/src/ngx_http_echo_module.c -@@ -632,6 +632,9 @@ ngx_http_echo_echo_exec(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) - static void * - ngx_http_echo_create_main_conf(ngx_conf_t *cf) - { -+#if nginx_version >= 1011011 -+ ngx_pool_cleanup_t *cln; -+#endif - ngx_http_echo_main_conf_t *emcf; - - emcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_echo_main_conf_t)); -@@ -643,6 +646,16 @@ ngx_http_echo_create_main_conf(ngx_conf_t *cf) - * hmcf->requires_filter = 0; - */ - -+#if nginx_version >= 1011011 -+ cln = ngx_pool_cleanup_add(cf->pool, 0); -+ if (cln == NULL) { -+ return NULL; -+ } -+ -+ cln->data = emcf; -+ cln->handler = ngx_http_echo_request_headers_cleanup; -+#endif -+ - return emcf; - } - -diff --git a/src/ngx_http_echo_module.h b/src/ngx_http_echo_module.h -index 2d212c3..ce0a305 100644 ---- a/src/ngx_http_echo_module.h -+++ b/src/ngx_http_echo_module.h -@@ -92,6 +92,10 @@ typedef struct { - - typedef struct { - ngx_int_t requires_filter; -+#if nginx_version >= 1011011 -+ ngx_buf_t **busy_buf_ptrs; -+ ngx_int_t busy_buf_ptr_count; -+#endif - } ngx_http_echo_main_conf_t; - - -diff --git a/src/ngx_http_echo_request_info.c b/src/ngx_http_echo_request_info.c -index d28ec4d..7dd3683 100644 ---- a/src/ngx_http_echo_request_info.c -+++ b/src/ngx_http_echo_request_info.c -@@ -17,6 +17,9 @@ - - - static void ngx_http_echo_post_read_request_body(ngx_http_request_t *r); -+#if nginx_version >= 1011011 -+void ngx_http_echo_request_headers_cleanup(void *data); -+#endif - - - ngx_int_t -@@ -179,6 +182,11 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, - ngx_int_t i, j; - ngx_buf_t *b, *first = NULL; - unsigned found; -+#if nginx_version >= 1011011 -+ ngx_buf_t **bb; -+ ngx_chain_t *cl; -+ ngx_http_echo_main_conf_t *emcf; -+#endif - ngx_connection_t *c; - ngx_http_request_t *mr; - ngx_http_connection_t *hc; -@@ -195,6 +203,10 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, - } - #endif - -+#if nginx_version >= 1011011 -+ emcf = ngx_http_get_module_main_conf(r, ngx_http_echo_module); -+#endif -+ - size = 0; - b = c->buffer; - -@@ -215,8 +227,35 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, - - if (hc->nbusy) { - b = NULL; -+ -+#if nginx_version >= 1011011 -+ if (hc->nbusy > emcf->busy_buf_ptr_count) { -+ if (emcf->busy_buf_ptrs) { -+ ngx_free(emcf->busy_buf_ptrs); -+ } -+ -+ emcf->busy_buf_ptrs = ngx_alloc(hc->nbusy * sizeof(ngx_buf_t *), -+ r->connection->log); -+ -+ if (emcf->busy_buf_ptrs == NULL) { -+ return NGX_ERROR; -+ } -+ -+ emcf->busy_buf_ptr_count = hc->nbusy; -+ } -+ -+ bb = emcf->busy_buf_ptrs; -+ for (cl = hc->busy; cl; cl = cl->next) { -+ *bb++ = cl->buf; -+ } -+ -+ bb = emcf->busy_buf_ptrs; -+ for (i = hc->nbusy; i > 0; i--) { -+ b = bb[i - 1]; -+#else - for (i = 0; i < hc->nbusy; i++) { - b = hc->busy[i]; -+#endif - - if (first == NULL) { - if (mr->request_line.data >= b->pos -@@ -280,8 +319,15 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, - } - - if (hc->nbusy) { -+ -+#if nginx_version >= 1011011 -+ bb = emcf->busy_buf_ptrs; -+ for (i = hc->nbusy; i > 0; i--) { -+ b = bb[i - 1]; -+#else - for (i = 0; i < hc->nbusy; i++) { - b = hc->busy[i]; -+#endif - - if (!found) { - if (b != first) { -@@ -457,4 +503,20 @@ ngx_http_echo_response_status_variable(ngx_http_request_t *r, - return NGX_OK; - } - -+ -+#if nginx_version >= 1011011 -+void -+ngx_http_echo_request_headers_cleanup(void *data) -+{ -+ ngx_http_echo_main_conf_t *emcf; -+ -+ emcf = (ngx_http_echo_main_conf_t *) data; -+ -+ if (emcf->busy_buf_ptrs) { -+ ngx_free(emcf->busy_buf_ptrs); -+ emcf->busy_buf_ptrs = NULL; -+ } -+} -+#endif -+ - /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ -diff --git a/src/ngx_http_echo_request_info.h b/src/ngx_http_echo_request_info.h -index 3b3713b..aa5730b 100644 ---- a/src/ngx_http_echo_request_info.h -+++ b/src/ngx_http_echo_request_info.h -@@ -29,5 +29,8 @@ ngx_int_t ngx_http_echo_request_uri_variable(ngx_http_request_t *r, - ngx_int_t ngx_http_echo_response_status_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); - -+#if nginx_version >= 1011011 -+void ngx_http_echo_request_headers_cleanup(void *data); -+#endif - - #endif /* ECHO_REQUEST_INFO_H */ -diff --git a/valgrind.suppress b/valgrind.suppress -index 0f8e871..d4bfe63 100644 ---- a/valgrind.suppress -+++ b/valgrind.suppress -@@ -36,3 +36,13 @@ - fun:do_preload - fun:dl_main - } -+{ -+ -+ Memcheck:Leak -+ match-leak-kinds: definite -+ fun:malloc -+ fun:ngx_alloc -+ fun:ngx_set_environment -+ fun:ngx_single_process_cycle -+ fun:main -+} --- -2.11.0 - diff --git a/debian/modules/patches/http-echo/series b/debian/modules/patches/http-echo/series deleted file mode 100644 index 7e5c302..0000000 --- a/debian/modules/patches/http-echo/series +++ /dev/null @@ -1 +0,0 @@ -build-nginx-1.11.11.patch From 5fb0700fb278a7a8217233755c6e688ffc8e5e94 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 13 Dec 2017 11:22:50 +0200 Subject: [PATCH 284/651] http-lua: Upgrade to 0.10.11 Rebase openssl-1.1.0 patch --- debian/modules/control | 2 +- debian/modules/http-lua/README.markdown | 182 +++++++++++++++++- .../modules/http-lua/doc/HttpLuaModule.wiki | 162 +++++++++++++++- .../http-lua/src/api/ngx_http_lua_api.h | 2 +- .../http-lua/src/ngx_http_lua_accessby.c | 10 +- .../http-lua/src/ngx_http_lua_directive.c | 2 +- .../http-lua/src/ngx_http_lua_output.c | 7 +- .../http-lua/src/ngx_http_lua_req_body.c | 6 +- .../http-lua/src/ngx_http_lua_rewriteby.c | 10 +- .../http-lua/src/ngx_http_lua_semaphore.c | 6 +- .../http-lua/src/ngx_http_lua_shdict.c | 167 ++++++++++++++++ .../modules/http-lua/src/ngx_http_lua_sleep.c | 6 +- .../http-lua/src/ngx_http_lua_socket_tcp.c | 25 ++- .../http-lua/src/ngx_http_lua_socket_udp.c | 6 +- .../http-lua/src/ngx_http_lua_ssl_certby.c | 5 +- .../src/ngx_http_lua_ssl_session_fetchby.c | 5 +- .../src/ngx_http_lua_ssl_session_storeby.c | 3 +- .../http-lua/src/ngx_http_lua_subrequest.c | 6 +- .../modules/http-lua/src/ngx_http_lua_util.c | 10 +- .../modules/http-lua/src/ngx_http_lua_util.h | 2 +- debian/modules/http-lua/t/000--init.t | 73 ++++--- debian/modules/http-lua/t/002-content.t | 8 +- debian/modules/http-lua/t/004-require.t | 1 + debian/modules/http-lua/t/017-exec.t | 24 ++- debian/modules/http-lua/t/023-rewrite/exec.t | 24 ++- .../t/023-rewrite/tcp-socket-timeout.t | 44 ++--- debian/modules/http-lua/t/024-access/exec.t | 24 ++- debian/modules/http-lua/t/035-gmatch.t | 1 + debian/modules/http-lua/t/058-tcp-socket.t | 39 +++- .../http-lua/t/065-tcp-socket-timeout.t | 68 ++++--- .../modules/http-lua/t/097-uthread-rewrite.t | 1 + debian/modules/http-lua/t/106-timer.t | 6 +- debian/modules/http-lua/t/129-ssl-socket.t | 6 +- debian/modules/http-lua/t/139-ssl-cert-by.t | 8 +- .../http-lua/t/142-ssl-session-store.t | 7 +- .../http-lua/t/143-ssl-session-fetch.t | 19 +- .../http-lua/t/147-tcp-socket-timeouts.t | 93 +++++++++ debian/modules/http-lua/t/154-semaphore.t | 2 + debian/modules/http-lua/util/build.sh | 4 + debian/modules/http-lua/valgrind.suppress | 68 +++++-- .../patches/http-lua/openssl-1.1.0.patch | 86 ++++----- 41 files changed, 1007 insertions(+), 223 deletions(-) diff --git a/debian/modules/control b/debian/modules/control index b779595..bd7cc0a 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -18,7 +18,7 @@ Files-Excluded: .gitignore .gitattributes .travis.yml Module: http-lua Homepage: https://github.com/openresty/lua-nginx-module -Version: v0.10.10 +Version: v0.10.11 Patch: openssl-1.1.0.patch discover-luajit-2.1.patch diff --git a/debian/modules/http-lua/README.markdown b/debian/modules/http-lua/README.markdown index fac3a0d..c42bd3e 100644 --- a/debian/modules/http-lua/README.markdown +++ b/debian/modules/http-lua/README.markdown @@ -62,7 +62,7 @@ Production ready. Version ======= -This document describes ngx_lua [v0.10.10](https://github.com/openresty/lua-nginx-module/tags) released on 8 August 2017. +This document describes ngx_lua [v0.10.11](https://github.com/openresty/lua-nginx-module/tags) released on 3 November 2017. Synopsis ======== @@ -249,6 +249,7 @@ Nginx Compatibility The latest version of this module is compatible with the following versions of Nginx: +* 1.13.x (last tested: 1.13.6) * 1.11.x (last tested: 1.11.2) * 1.10.x * 1.9.x (last tested: 1.9.15) @@ -276,9 +277,9 @@ Build the source with this module: ```bash - wget 'http://nginx.org/download/nginx-1.11.2.tar.gz' - tar -xzvf nginx-1.11.2.tar.gz - cd nginx-1.11.2/ + wget 'http://nginx.org/download/nginx-1.13.6.tar.gz' + tar -xzvf nginx-1.13.6.tar.gz + cd nginx-1.13.6/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib @@ -871,6 +872,7 @@ Nginx may terminate a request early with (at least): * 400 (Bad Request) * 405 (Not Allowed) * 408 (Request Timeout) +* 413 (Request Entity Too Large) * 414 (Request URI Too Large) * 494 (Request Headers Too Large) * 499 (Client Closed Request) @@ -1335,16 +1337,19 @@ Runs the Lua code specified by the argument `` on the global Lua When Nginx receives the `HUP` signal and starts reloading the config file, the Lua VM will also be re-created and `init_by_lua` will run again on the new Lua VM. In case that the [lua_code_cache](#lua_code_cache) directive is turned off (default on), the `init_by_lua` handler will run upon every request because in this special mode a standalone Lua VM is always created for each request. -Usually you can register (true) Lua global variables or pre-load Lua modules at server start-up by means of this hook. Here is an example for pre-loading Lua modules: +Usually you can pre-load Lua modules at server start-up by means of this hook and take advantage of modern operating systems' copy-on-write (COW) optimization. Here is an example for pre-loading Lua modules: ```nginx - init_by_lua 'cjson = require "cjson"'; + # this runs before forking out nginx worker processes: + init_by_lua_block { require "cjson" } server { location = /api { content_by_lua_block { - ngx.say(cjson.encode({dog = 5, cat = 6})) + -- the following require() will just return + -- the alrady loaded module from package.loaded: + ngx.say(require "cjson".encode{dog = 5, cat = 6}) } } } @@ -1356,10 +1361,10 @@ You can also initialize the [lua_shared_dict](#lua_shared_dict) shm storage at t lua_shared_dict dogs 1m; - init_by_lua ' + init_by_lua_block { local dogs = ngx.shared.dogs; dogs:set("Tom", 56) - '; + } server { location = /api { @@ -2691,7 +2696,7 @@ ssl_session_store_by_lua_file **context:** *http* -**phase:** *right-before-SSL-handshake* +**phase:** *right-after-SSL-handshake* Equivalent to [ssl_session_store_by_lua_block](#ssl_session_store_by_lua_block), except that the file specified by `` contains the Lua code, or rather, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. @@ -3188,9 +3193,13 @@ Nginx API for Lua * [ngx.shared.DICT.lpop](#ngxshareddictlpop) * [ngx.shared.DICT.rpop](#ngxshareddictrpop) * [ngx.shared.DICT.llen](#ngxshareddictllen) +* [ngx.shared.DICT.ttl](#ngxshareddictttl) +* [ngx.shared.DICT.expire](#ngxshareddictexpire) * [ngx.shared.DICT.flush_all](#ngxshareddictflush_all) * [ngx.shared.DICT.flush_expired](#ngxshareddictflush_expired) * [ngx.shared.DICT.get_keys](#ngxshareddictget_keys) +* [ngx.shared.DICT.capacity](#ngxshareddictcapacity) +* [ngx.shared.DICT.free_space](#ngxshareddictfree_space) * [ngx.socket.udp](#ngxsocketudp) * [udpsock:setpeername](#udpsocksetpeername) * [udpsock:send](#udpsocksend) @@ -6195,9 +6204,13 @@ The resulting object `dict` has the following methods: * [lpop](#ngxshareddictlpop) * [rpop](#ngxshareddictrpop) * [llen](#ngxshareddictllen) +* [ttl](#ngxshareddictttl) +* [expire](#ngxshareddictexpire) * [flush_all](#ngxshareddictflush_all) * [flush_expired](#ngxshareddictflush_expired) * [get_keys](#ngxshareddictget_keys) +* [capacity](#ngxshareddictcapacity) +* [free_space](#ngxshareddictfree_space) All these methods are *atomic* operations, that is, safe from concurrent accesses from multiple nginx worker processes for the same `lua_shared_dict` zone. @@ -6540,6 +6553,82 @@ See also [ngx.shared.DICT](#ngxshareddict). [Back to TOC](#nginx-api-for-lua) +ngx.shared.DICT.ttl +------------------- +**syntax:** *ttl, err = ngx.shared.DICT:ttl(key)* + +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** + +**requires:** `resty.core.shdict` or `resty.core` + +Retrieves the remaining TTL (time-to-live in seconds) of a key-value pair in the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). Returns the TTL as a number if the operation is successfully completed or `nil` and an error message otherwise. + +If the key does not exist (or has already expired), this method will return `nil` and the error string `"not found"`. + +The TTL is originally determined by the `exptime` argument of the [set](#ngxshareddictset), [add](#ngxshareddictadd), [replace](#ngxshareddictreplace) (and the likes) methods. It has a time resolution of `0.001` seconds. A value of `0` means that the item will never expire. + +Example: + +```lua + + require "resty.core" + + local cats = ngx.shared.cats + local succ, err = cats:set("Marry", "a nice cat", 0.5) + + ngx.sleep(0.2) + + local ttl, err = cats:ttl("Marry") + ngx.say(ttl) -- 0.3 +``` + +This feature was first introduced in the `v0.10.11` release. + +**Note:** This method requires the `resty.core.shdict` or `resty.core` modules from the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. + +See also [ngx.shared.DICT](#ngxshareddict). + +[Back to TOC](#nginx-api-for-lua) + +ngx.shared.DICT.expire +---------------------- +**syntax:** *success, err = ngx.shared.DICT:expire(key, exptime)* + +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** + +**requires:** `resty.core.shdict` or `resty.core` + +Updates the `exptime` (in second) of a key-value pair in the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). Returns a boolean indicating success if the operation completes or `nil` and an error message otherwise. + +If the key does not exist, this method will return `nil` and the error string `"not found"`. + +The `exptime` argument has a resolution of `0.001` seconds. If `exptime` is `0`, then the item will never expire. + +Example: + +```lua + + require "resty.core" + + local cats = ngx.shared.cats + local succ, err = cats:set("Marry", "a nice cat", 0.1) + + succ, err = cats:expire("Marry", 0.5) + + ngx.sleep(0.2) + + local val, err = cats:get("Marry") + ngx.say(val) -- "a nice cat" +``` + +This feature was first introduced in the `v0.10.11` release. + +**Note:** This method requires the `resty.core.shdict` or `resty.core` modules from the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. + +See also [ngx.shared.DICT](#ngxshareddict). + +[Back to TOC](#nginx-api-for-lua) + ngx.shared.DICT.flush_all ------------------------- **syntax:** *ngx.shared.DICT:flush_all()* @@ -6586,6 +6675,79 @@ This feature was first introduced in the `v0.7.3` release. [Back to TOC](#nginx-api-for-lua) +ngx.shared.DICT.capacity +------------------------ +**syntax:** *capacity_bytes = ngx.shared.DICT:capacity()* + +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** + +**requires:** `resty.core.shdict` or `resty.core` + +Retrieves the capacity in bytes for the shm-based dictionary [ngx.shared.DICT](#ngxshareddict) declared with +the [lua_shared_dict](#lua_shared_dict) directive. + +Example: + +```lua + + require "resty.core.shdict" + + local cats = ngx.shared.cats + local capacity_bytes = cats:capacity() +``` + +This feature was first introduced in the `v0.10.11` release. + +**Note:** This method requires the `resty.core.shdict` or `resty.core` modules from the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. + +This feature requires at least nginx core version `0.7.3`. + +See also [ngx.shared.DICT](#ngxshareddict). + +[Back to TOC](#nginx-api-for-lua) + +ngx.shared.DICT.free_space +-------------------------- +**syntax:** *free_page_bytes = ngx.shared.DICT:free_space()* + +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** + +**requires:** `resty.core.shdict` or `resty.core` + +Retrieves the free page size in bytes for the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). + +**Note:** The memory for ngx.shared.DICT is allocated via the nginx slab allocator which has each slot for +data size ranges like \~8, 9\~16, 17\~32, ..., 1025\~2048, 2048\~ bytes. And pages are assigned to a slot if there +is no room in already assigned pages for the slot. + +So even if the return value of the `free_space` method is zero, there may be room in already assigned pages, so +you may successfully set a new key value pair to the shared dict without getting `true` for `forcible` or +non nil `err` from the `ngx.shared.DICT.set`. + +On the other hand, if already assigned pages for a slot are full and a new key value pair is added to the +slot and there is no free page, you may get `true` for `forcible` or non nil `err` from the +`ngx.shared.DICT.set` method. + +Example: + +```lua + + require "resty.core.shdict" + + local cats = ngx.shared.cats + local free_page_bytes = cats:free_space() +``` + +This feature was first introduced in the `v0.10.11` release. + +**Note:** This method requires the `resty.core.shdict` or `resty.core` modules from the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. + +This feature requires at least nginx core version `1.11.7`. + +See also [ngx.shared.DICT](#ngxshareddict). + +[Back to TOC](#nginx-api-for-lua) + ngx.socket.udp -------------- **syntax:** *udpsock = ngx.socket.udp()* diff --git a/debian/modules/http-lua/doc/HttpLuaModule.wiki b/debian/modules/http-lua/doc/HttpLuaModule.wiki index 8393056..2424d39 100644 --- a/debian/modules/http-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/http-lua/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.10] released on 8 August 2017. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.11] released on 3 November 2017. = Synopsis = @@ -186,6 +186,7 @@ The Lua state (Lua VM instance) is shared across all the requests handled by a s The latest version of this module is compatible with the following versions of Nginx: +* 1.13.x (last tested: 1.13.6) * 1.11.x (last tested: 1.11.2) * 1.10.x * 1.9.x (last tested: 1.9.15) @@ -209,9 +210,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.11.2.tar.gz' - tar -xzvf nginx-1.11.2.tar.gz - cd nginx-1.11.2/ + wget 'http://nginx.org/download/nginx-1.13.6.tar.gz' + tar -xzvf nginx-1.13.6.tar.gz + cd nginx-1.13.6/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib @@ -706,6 +707,7 @@ Nginx may terminate a request early with (at least): * 400 (Bad Request) * 405 (Not Allowed) * 408 (Request Timeout) +* 413 (Request Entity Too Large) * 414 (Request URI Too Large) * 494 (Request Headers Too Large) * 499 (Client Closed Request) @@ -1057,15 +1059,18 @@ Runs the Lua code specified by the argument on the When Nginx receives the HUP signal and starts reloading the config file, the Lua VM will also be re-created and init_by_lua will run again on the new Lua VM. In case that the [[#lua_code_cache|lua_code_cache]] directive is turned off (default on), the init_by_lua handler will run upon every request because in this special mode a standalone Lua VM is always created for each request. -Usually you can register (true) Lua global variables or pre-load Lua modules at server start-up by means of this hook. Here is an example for pre-loading Lua modules: +Usually you can pre-load Lua modules at server start-up by means of this hook and take advantage of modern operating systems' copy-on-write (COW) optimization. Here is an example for pre-loading Lua modules: - init_by_lua 'cjson = require "cjson"'; + # this runs before forking out nginx worker processes: + init_by_lua_block { require "cjson" } server { location = /api { content_by_lua_block { - ngx.say(cjson.encode({dog = 5, cat = 6})) + -- the following require() will just return + -- the alrady loaded module from package.loaded: + ngx.say(require "cjson".encode{dog = 5, cat = 6}) } } } @@ -1076,10 +1081,10 @@ You can also initialize the [[#lua_shared_dict|lua_shared_dict]] shm storage at lua_shared_dict dogs 1m; - init_by_lua ' + init_by_lua_block { local dogs = ngx.shared.dogs; dogs:set("Tom", 56) - '; + } server { location = /api { @@ -2276,7 +2281,7 @@ Note that: this directive is only allowed to used in '''http context''' from the '''context:''' ''http'' -'''phase:''' ''right-before-SSL-handshake'' +'''phase:''' ''right-after-SSL-handshake'' Equivalent to [[#ssl_session_store_by_lua_block|ssl_session_store_by_lua_block]], except that the file specified by contains the Lua code, or rather, the [[#Lua/LuaJIT bytecode support|Lua/LuaJIT bytecode]] to be executed. @@ -5193,9 +5198,13 @@ The resulting object dict has the following methods: * [[#ngx.shared.DICT.lpop|lpop]] * [[#ngx.shared.DICT.rpop|rpop]] * [[#ngx.shared.DICT.llen|llen]] +* [[#ngx.shared.DICT.ttl|ttl]] +* [[#ngx.shared.DICT.expire|expire]] * [[#ngx.shared.DICT.flush_all|flush_all]] * [[#ngx.shared.DICT.flush_expired|flush_expired]] * [[#ngx.shared.DICT.get_keys|get_keys]] +* [[#ngx.shared.DICT.capacity|capacity]] +* [[#ngx.shared.DICT.free_space|free_space]] All these methods are ''atomic'' operations, that is, safe from concurrent accesses from multiple nginx worker processes for the same lua_shared_dict zone. @@ -5488,6 +5497,74 @@ This feature was first introduced in the v0.10.6 release. See also [[#ngx.shared.DICT|ngx.shared.DICT]]. +== ngx.shared.DICT.ttl == +'''syntax:''' ''ttl, err = ngx.shared.DICT:ttl(key)'' + +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' + +'''requires:''' resty.core.shdict or resty.core + +Retrieves the remaining TTL (time-to-live in seconds) of a key-value pair in the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. Returns the TTL as a number if the operation is successfully completed or nil and an error message otherwise. + +If the key does not exist (or has already expired), this method will return nil and the error string "not found". + +The TTL is originally determined by the exptime argument of the [[#ngx.shared.DICT.set|set]], [[#ngx.shared.DICT.add|add]], [[#ngx.shared.DICT.replace|replace]] (and the likes) methods. It has a time resolution of 0.001 seconds. A value of 0 means that the item will never expire. + +Example: + + + require "resty.core" + + local cats = ngx.shared.cats + local succ, err = cats:set("Marry", "a nice cat", 0.5) + + ngx.sleep(0.2) + + local ttl, err = cats:ttl("Marry") + ngx.say(ttl) -- 0.3 + + +This feature was first introduced in the v0.10.11 release. + +'''Note:''' This method requires the resty.core.shdict or resty.core modules from the [https://github.com/openresty/lua-resty-core lua-resty-core] library. + +See also [[#ngx.shared.DICT|ngx.shared.DICT]]. + +== ngx.shared.DICT.expire == +'''syntax:''' ''success, err = ngx.shared.DICT:expire(key, exptime)'' + +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' + +'''requires:''' resty.core.shdict or resty.core + +Updates the exptime (in second) of a key-value pair in the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. Returns a boolean indicating success if the operation completes or nil and an error message otherwise. + +If the key does not exist, this method will return nil and the error string "not found". + +The exptime argument has a resolution of 0.001 seconds. If exptime is 0, then the item will never expire. + +Example: + + + require "resty.core" + + local cats = ngx.shared.cats + local succ, err = cats:set("Marry", "a nice cat", 0.1) + + succ, err = cats:expire("Marry", 0.5) + + ngx.sleep(0.2) + + local val, err = cats:get("Marry") + ngx.say(val) -- "a nice cat" + + +This feature was first introduced in the v0.10.11 release. + +'''Note:''' This method requires the resty.core.shdict or resty.core modules from the [https://github.com/openresty/lua-resty-core lua-resty-core] library. + +See also [[#ngx.shared.DICT|ngx.shared.DICT]]. + == ngx.shared.DICT.flush_all == '''syntax:''' ''ngx.shared.DICT:flush_all()'' @@ -5525,6 +5602,71 @@ By default, only the first 1024 keys (if any) are returned. When the v0.7.3 release. +== ngx.shared.DICT.capacity == +'''syntax:''' ''capacity_bytes = ngx.shared.DICT:capacity()'' + +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' + +'''requires:''' resty.core.shdict or resty.core + +Retrieves the capacity in bytes for the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] declared with +the [[#lua_shared_dict|lua_shared_dict]] directive. + +Example: + + + require "resty.core.shdict" + + local cats = ngx.shared.cats + local capacity_bytes = cats:capacity() + + +This feature was first introduced in the v0.10.11 release. + +'''Note:''' This method requires the resty.core.shdict or resty.core modules from the [https://github.com/openresty/lua-resty-core lua-resty-core] library. + +This feature requires at least nginx core version 0.7.3. + +See also [[#ngx.shared.DICT|ngx.shared.DICT]]. + +== ngx.shared.DICT.free_space == +'''syntax:''' ''free_page_bytes = ngx.shared.DICT:free_space()'' + +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' + +'''requires:''' resty.core.shdict or resty.core + +Retrieves the free page size in bytes for the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. + +'''Note:''' The memory for ngx.shared.DICT is allocated via the nginx slab allocator which has each slot for +data size ranges like \~8, 9\~16, 17\~32, ..., 1025\~2048, 2048\~ bytes. And pages are assigned to a slot if there +is no room in already assigned pages for the slot. + +So even if the return value of the free_space method is zero, there may be room in already assigned pages, so +you may successfully set a new key value pair to the shared dict without getting true for forcible or +non nil err from the ngx.shared.DICT.set. + +On the other hand, if already assigned pages for a slot are full and a new key value pair is added to the +slot and there is no free page, you may get true for forcible or non nil err from the +ngx.shared.DICT.set method. + +Example: + + + require "resty.core.shdict" + + local cats = ngx.shared.cats + local free_page_bytes = cats:free_space() + + +This feature was first introduced in the v0.10.11 release. + +'''Note:''' This method requires the resty.core.shdict or resty.core modules from the [https://github.com/openresty/lua-resty-core lua-resty-core] library. + +This feature requires at least nginx core version 1.11.7. + +See also [[#ngx.shared.DICT|ngx.shared.DICT]]. + == ngx.socket.udp == '''syntax:''' ''udpsock = ngx.socket.udp()'' diff --git a/debian/modules/http-lua/src/api/ngx_http_lua_api.h b/debian/modules/http-lua/src/api/ngx_http_lua_api.h index cd64fc8..1e07b71 100644 --- a/debian/modules/http-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/http-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10010 +#define ngx_http_lua_version 10011 typedef struct { diff --git a/debian/modules/http-lua/src/ngx_http_lua_accessby.c b/debian/modules/http-lua/src/ngx_http_lua_accessby.c index 1a4ba6d..56bf0fa 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_accessby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_accessby.c @@ -238,6 +238,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) { int co_ref; ngx_int_t rc; + ngx_uint_t nreqs; lua_State *co; ngx_event_t *rev; ngx_connection_t *c; @@ -329,6 +330,9 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) r->read_event_handler = ngx_http_block_reading; } + c = r->connection; + nreqs = c->requests; + rc = ngx_http_lua_run_thread(L, r, ctx, 0); dd("returned %d", (int) rc); @@ -337,10 +341,8 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) return rc; } - c = r->connection; - if (rc == NGX_AGAIN) { - rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); + rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs); if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) { return rc; @@ -353,7 +355,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) } else if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); + rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs); if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) { return rc; diff --git a/debian/modules/http-lua/src/ngx_http_lua_directive.c b/debian/modules/http-lua/src/ngx_http_lua_directive.c index 6a562f4..014a472 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_directive.c +++ b/debian/modules/http-lua/src/ngx_http_lua_directive.c @@ -1542,7 +1542,7 @@ ngx_http_lua_conf_read_lua_token(ngx_conf_t *cf, #if nginx_version >= 1009002 if (dump) { - dump->last = ngx_cpymem(dump->last, b->pos, size); + dump->last = ngx_cpymem(dump->last, b->start + len, size); } #endif } diff --git a/debian/modules/http-lua/src/ngx_http_lua_output.c b/debian/modules/http-lua/src/ngx_http_lua_output.c index b410ba4..0fe8840 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_output.c +++ b/debian/modules/http-lua/src/ngx_http_lua_output.c @@ -724,6 +724,7 @@ ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) int n; lua_State *vm; ngx_int_t rc; + ngx_uint_t nreqs; ngx_connection_t *c; c = r->connection; @@ -748,18 +749,20 @@ ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) } vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; + rc = ngx_http_lua_run_thread(vm, r, ctx, n); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } /* rc == NGX_ERROR || rc >= NGX_OK */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_req_body.c b/debian/modules/http-lua/src/ngx_http_lua_req_body.c index 6f2ae38..e6bf3c1 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_req_body.c +++ b/debian/modules/http-lua/src/ngx_http_lua_req_body.c @@ -1125,6 +1125,7 @@ ngx_http_lua_read_body_resume(ngx_http_request_t *r) { lua_State *vm; ngx_int_t rc; + ngx_uint_t nreqs; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; @@ -1134,6 +1135,7 @@ ngx_http_lua_read_body_resume(ngx_http_request_t *r) c = r->connection; vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; rc = ngx_http_lua_run_thread(vm, r, ctx, 0); @@ -1141,12 +1143,12 @@ ngx_http_lua_read_body_resume(ngx_http_request_t *r) "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (ctx->entered_content_phase) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c index 44d8941..077c2d3 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c @@ -235,6 +235,7 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) int co_ref; lua_State *co; ngx_int_t rc; + ngx_uint_t nreqs; ngx_event_t *rev; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; @@ -324,20 +325,21 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) r->read_event_handler = ngx_http_block_reading; } + c = r->connection; + nreqs = c->requests; + rc = ngx_http_lua_run_thread(L, r, ctx, 0); if (rc == NGX_ERROR || rc > NGX_OK) { return rc; } - c = r->connection; - if (rc == NGX_AGAIN) { - rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); + rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs); } else if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); + rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs); } if (rc == NGX_OK || rc == NGX_DECLINED) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_semaphore.c b/debian/modules/http-lua/src/ngx_http_lua_semaphore.c index eda0141..0b70aea 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_semaphore.c +++ b/debian/modules/http-lua/src/ngx_http_lua_semaphore.c @@ -258,6 +258,7 @@ ngx_http_lua_sema_resume(ngx_http_request_t *r) lua_State *vm; ngx_connection_t *c; ngx_int_t rc; + ngx_uint_t nreqs; ngx_http_lua_ctx_t *ctx; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -269,6 +270,7 @@ ngx_http_lua_sema_resume(ngx_http_request_t *r) c = r->connection; vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; if (ctx->cur_co_ctx->sem_resume_status == SEMAPHORE_WAIT_SUCC) { lua_pushboolean(ctx->cur_co_ctx->co, 1); @@ -285,12 +287,12 @@ ngx_http_lua_sema_resume(ngx_http_request_t *r) "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } /* rc == NGX_ERROR || rc >= NGX_OK */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_shdict.c b/debian/modules/http-lua/src/ngx_http_lua_shdict.c index d6cad7e..5b48eb4 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_shdict.c +++ b/debian/modules/http-lua/src/ngx_http_lua_shdict.c @@ -2843,6 +2843,173 @@ ngx_http_lua_ffi_shdict_flush_all(ngx_shm_zone_t *zone) return NGX_OK; } + + +static ngx_int_t +ngx_http_lua_shdict_peek(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, + u_char *kdata, size_t klen, ngx_http_lua_shdict_node_t **sdp) +{ + ngx_int_t rc; + ngx_rbtree_node_t *node, *sentinel; + ngx_http_lua_shdict_ctx_t *ctx; + ngx_http_lua_shdict_node_t *sd; + + ctx = shm_zone->data; + + node = ctx->sh->rbtree.root; + sentinel = ctx->sh->rbtree.sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + sd = (ngx_http_lua_shdict_node_t *) &node->color; + + rc = ngx_memn2cmp(kdata, sd->data, klen, (size_t) sd->key_len); + + if (rc == 0) { + *sdp = sd; + + return NGX_OK; + } + + node = (rc < 0) ? node->left : node->right; + } + + *sdp = NULL; + + return NGX_DECLINED; +} + + +int +ngx_http_lua_ffi_shdict_get_ttl(ngx_shm_zone_t *zone, u_char *key, + size_t key_len) +{ + uint32_t hash; + uint64_t now; + uint64_t expires; + ngx_int_t rc; + ngx_time_t *tp; + ngx_http_lua_shdict_ctx_t *ctx; + ngx_http_lua_shdict_node_t *sd; + + if (zone == NULL) { + return NGX_ERROR; + } + + ctx = zone->data; + hash = ngx_crc32_short(key, key_len); + + ngx_shmtx_lock(&ctx->shpool->mutex); + + rc = ngx_http_lua_shdict_peek(zone, hash, key, key_len, &sd); + + if (rc == NGX_DECLINED) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return NGX_DECLINED; + } + + /* rc == NGX_OK */ + + expires = sd->expires; + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + if (expires == 0) { + return 0; + } + + tp = ngx_timeofday(); + now = (uint64_t) tp->sec * 1000 + tp->msec; + + return expires - now; +} + + +int +ngx_http_lua_ffi_shdict_set_expire(ngx_shm_zone_t *zone, u_char *key, + size_t key_len, int exptime) +{ + uint32_t hash; + ngx_int_t rc; + ngx_time_t *tp = NULL; + ngx_http_lua_shdict_ctx_t *ctx; + ngx_http_lua_shdict_node_t *sd; + + if (zone == NULL) { + return NGX_ERROR; + } + + if (exptime > 0) { + tp = ngx_timeofday(); + } + + ctx = zone->data; + hash = ngx_crc32_short(key, key_len); + + ngx_shmtx_lock(&ctx->shpool->mutex); + + rc = ngx_http_lua_shdict_peek(zone, hash, key, key_len, &sd); + + if (rc == NGX_DECLINED) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return NGX_DECLINED; + } + + /* rc == NGX_OK */ + + if (exptime > 0) { + sd->expires = (uint64_t) tp->sec * 1000 + tp->msec + + (uint64_t) exptime; + + } else { + sd->expires = 0; + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return NGX_OK; +} + + +size_t +ngx_http_lua_ffi_shdict_capacity(ngx_shm_zone_t *zone) +{ + return zone->shm.size; +} + + +# if nginx_version >= 1011007 +size_t +ngx_http_lua_ffi_shdict_free_space(ngx_shm_zone_t *zone) +{ + size_t bytes; + ngx_http_lua_shdict_ctx_t *ctx; + + ctx = zone->data; + + ngx_shmtx_lock(&ctx->shpool->mutex); + bytes = ctx->shpool->pfree * ngx_pagesize; + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return bytes; +} +# endif /* nginx_version >= 1011007 */ + + #endif /* NGX_LUA_NO_FFI_API */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_sleep.c b/debian/modules/http-lua/src/ngx_http_lua_sleep.c index ffee97f..09ea0f6 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_sleep.c +++ b/debian/modules/http-lua/src/ngx_http_lua_sleep.c @@ -180,6 +180,7 @@ ngx_http_lua_sleep_resume(ngx_http_request_t *r) lua_State *vm; ngx_connection_t *c; ngx_int_t rc; + ngx_uint_t nreqs; ngx_http_lua_ctx_t *ctx; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -191,6 +192,7 @@ ngx_http_lua_sleep_resume(ngx_http_request_t *r) c = r->connection; vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; rc = ngx_http_lua_run_thread(vm, r, ctx, 0); @@ -198,12 +200,12 @@ ngx_http_lua_sleep_resume(ngx_http_request_t *r) "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (ctx->entered_content_phase) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c index 382a94d..f0988bc 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c @@ -474,6 +474,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) switch (lua_type(L, -1)) { case LUA_TNUMBER: lua_tostring(L, -1); + /* FALLTHROUGH */ case LUA_TSTRING: custom_pool = 1; @@ -743,6 +744,9 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; + coctx->cleanup = NULL; + coctx->data = NULL; + u->resolved->ctx = NULL; lua_pushnil(L); lua_pushfstring(L, "%s could not be resolved", host.data); @@ -2708,6 +2712,10 @@ ngx_http_lua_socket_tcp_settimeout(lua_State *L) } timeout = (ngx_int_t) lua_tonumber(L, 2); + if (timeout >> 31) { + return luaL_error(L, "bad timeout value"); + } + lua_pushinteger(L, timeout); lua_pushinteger(L, timeout); @@ -2751,8 +2759,19 @@ ngx_http_lua_socket_tcp_settimeouts(lua_State *L) } connect_timeout = (ngx_int_t) lua_tonumber(L, 2); + if (connect_timeout >> 31) { + return luaL_error(L, "bad timeout value"); + } + send_timeout = (ngx_int_t) lua_tonumber(L, 3); + if (send_timeout >> 31) { + return luaL_error(L, "bad timeout value"); + } + read_timeout = (ngx_int_t) lua_tonumber(L, 4); + if (read_timeout >> 31) { + return luaL_error(L, "bad timeout value"); + } lua_rawseti(L, 1, SOCKET_READ_TIMEOUT_INDEX); lua_rawseti(L, 1, SOCKET_SEND_TIMEOUT_INDEX); @@ -5234,6 +5253,7 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) int nret; lua_State *vm; ngx_int_t rc; + ngx_uint_t nreqs; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; @@ -5284,6 +5304,7 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) c = r->connection; vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; rc = ngx_http_lua_run_thread(vm, r, ctx, nret); @@ -5291,12 +5312,12 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (ctx->entered_content_phase) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c index 1ec0c00..08ba1cc 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c @@ -1514,6 +1514,7 @@ ngx_http_lua_socket_udp_resume(ngx_http_request_t *r) int nret; lua_State *vm; ngx_int_t rc; + ngx_uint_t nreqs; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; @@ -1549,6 +1550,7 @@ ngx_http_lua_socket_udp_resume(ngx_http_request_t *r) c = r->connection; vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; rc = ngx_http_lua_run_thread(vm, r, ctx, nret); @@ -1556,12 +1558,12 @@ ngx_http_lua_socket_udp_resume(ngx_http_request_t *r) "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (ctx->entered_content_phase) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c index c3591d1..95be47f 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c @@ -197,7 +197,8 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) c = ngx_ssl_get_connection(ssl_conn); - dd("c = %p", c); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl cert: connection reusable: %ud", c->reusable); cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); @@ -220,6 +221,8 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) dd("first time"); + ngx_reusable_connection(c, 0); + hc = c->data; fc = ngx_http_lua_create_fake_connection(NULL); diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c index 556b732..3a3c1f5 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c @@ -191,7 +191,8 @@ ngx_http_lua_ssl_sess_fetch_handler(ngx_ssl_conn_t *ssl_conn, u_char *id, c = ngx_ssl_get_connection(ssl_conn); - dd("c = %p", c); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl session fetch: connection reusable: %ud", c->reusable); cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); @@ -224,6 +225,8 @@ ngx_http_lua_ssl_sess_fetch_handler(ngx_ssl_conn_t *ssl_conn, u_char *id, dd("first time"); + ngx_reusable_connection(c, 0); + hc = c->data; fc = ngx_http_lua_create_fake_connection(NULL); diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c index bae8273..f83e85d 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c @@ -183,7 +183,8 @@ ngx_http_lua_ssl_sess_store_handler(ngx_ssl_conn_t *ssl_conn, c = ngx_ssl_get_connection(ssl_conn); - dd("c = %p", c); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl session store: connection reusable: %ud", c->reusable); cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); diff --git a/debian/modules/http-lua/src/ngx_http_lua_subrequest.c b/debian/modules/http-lua/src/ngx_http_lua_subrequest.c index 6f7aa97..47096e9 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_subrequest.c +++ b/debian/modules/http-lua/src/ngx_http_lua_subrequest.c @@ -1587,6 +1587,7 @@ ngx_http_lua_subrequest_resume(ngx_http_request_t *r) { lua_State *vm; ngx_int_t rc; + ngx_uint_t nreqs; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; @@ -1620,6 +1621,7 @@ ngx_http_lua_subrequest_resume(ngx_http_request_t *r) c = r->connection; vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; rc = ngx_http_lua_run_thread(vm, r, ctx, coctx->nsubreqs); @@ -1627,12 +1629,12 @@ ngx_http_lua_subrequest_resume(ngx_http_request_t *r) "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } /* rc == NGX_ERROR || rc >= NGX_OK */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_util.c b/debian/modules/http-lua/src/ngx_http_lua_util.c index c7bee3e..df0aae8 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_util.c +++ b/debian/modules/http-lua/src/ngx_http_lua_util.c @@ -3055,13 +3055,13 @@ ngx_http_lua_create_co_ctx(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) /* this is for callers other than the content handler */ ngx_int_t ngx_http_lua_run_posted_threads(ngx_connection_t *c, lua_State *L, - ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) + ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_uint_t nreqs) { ngx_int_t rc; ngx_http_lua_posted_thread_t *pt; for ( ;; ) { - if (c->destroyed) { + if (c->destroyed || c->requests != nreqs) { return NGX_DONE; } @@ -3461,6 +3461,7 @@ ngx_http_lua_on_abort_resume(ngx_http_request_t *r) { lua_State *vm; ngx_int_t rc; + ngx_uint_t nreqs; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; @@ -3480,6 +3481,7 @@ ngx_http_lua_on_abort_resume(ngx_http_request_t *r) c = r->connection; vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; rc = ngx_http_lua_run_thread(vm, r, ctx, 0); @@ -3487,12 +3489,12 @@ ngx_http_lua_on_abort_resume(ngx_http_request_t *r) "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (ctx->entered_content_phase) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_util.h b/debian/modules/http-lua/src/ngx_http_lua_util.h index a37852f..2f995e0 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_util.h +++ b/debian/modules/http-lua/src/ngx_http_lua_util.h @@ -205,7 +205,7 @@ ngx_http_lua_co_ctx_t *ngx_http_lua_create_co_ctx(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); ngx_int_t ngx_http_lua_run_posted_threads(ngx_connection_t *c, lua_State *L, - ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); + ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_uint_t nreqs); ngx_int_t ngx_http_lua_post_thread(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx); diff --git a/debian/modules/http-lua/t/000--init.t b/debian/modules/http-lua/t/000--init.t index ad2d70e..dbe2c33 100644 --- a/debian/modules/http-lua/t/000--init.t +++ b/debian/modules/http-lua/t/000--init.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 1); +plan tests => repeat_each() * (blocks() * 3); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; @@ -14,9 +14,13 @@ our $http_config = <<'_EOC_'; drizzle_server 127.0.0.1:$TEST_NGINX_MYSQL_PORT protocol=mysql dbname=ngx_test user=ngx_test password=ngx_test; } + + lua_package_path "../lua-resty-mysql/lib/?.lua;;"; _EOC_ no_shuffle(); +no_long_string(); + run_tests(); __DATA__ @@ -25,51 +29,46 @@ __DATA__ --- http_config eval: $::http_config --- config location = /init { - drizzle_pass database; - drizzle_query "DROP TABLE IF EXISTS conv_uid"; + content_by_lua_block { + local mysql = require "resty.mysql" + local db = assert(mysql:new()) + local ok, err, errcode, sqlstate = db:connect{ + host = "127.0.0.1", + port = $TEST_NGINX_MYSQL_PORT, + database = "ngx_test", + user = "ngx_test", + password = "ngx_test", + charset = "utf8", + } + + local queries = { + "DROP TABLE IF EXISTS conv_uid", + "CREATE TABLE conv_uid(id serial primary key, new_uid integer, old_uid integer)", + "INSERT INTO conv_uid(old_uid,new_uid) VALUES(32,56),(35,78)", + } + + for _, query in ipairs(queries) do + local ok, err = db:query(query) + if not ok then + ngx.say("failed to run mysql query \"", query, "\": ", err) + return + end + end + + ngx.say("done!") + } } --- request GET /init ---- error_code: 200 +--- response_body +done! --- timeout: 10 --- no_error_log [error] -=== TEST 2: conv_uid - create table ---- http_config eval: $::http_config ---- config - location = /init { - drizzle_pass database; - drizzle_query "CREATE TABLE conv_uid(id serial primary key, new_uid integer, old_uid integer)"; - } ---- request -GET /init ---- error_code: 200 ---- timeout: 10 ---- no_error_log -[error] - - - -=== TEST 3: conv_uid - insert value ---- http_config eval: $::http_config ---- config - location = /init { - drizzle_pass database; - drizzle_query "INSERT INTO conv_uid(old_uid,new_uid) VALUES(32,56),(35,78)"; - } ---- request -GET /init ---- error_code: 200 ---- timeout: 10 ---- no_error_log -[error] - - - -=== TEST 4: flush data from memcached +=== TEST 2: flush data from memcached --- config location /flush { set $memc_cmd flush_all; diff --git a/debian/modules/http-lua/t/002-content.t b/debian/modules/http-lua/t/002-content.t index 3f2460e..cc92d6f 100644 --- a/debian/modules/http-lua/t/002-content.t +++ b/debian/modules/http-lua/t/002-content.t @@ -10,7 +10,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 19); +plan tests => repeat_each() * (blocks() * 2 + 23); #no_diff(); #no_long_string(); @@ -539,6 +539,9 @@ GET /main Content-Length: 12 --- response_body chop hello, world +--- no_error_log +[error] +[alert] @@ -761,6 +764,9 @@ Content-Length: 13 hello, world --- timeout: 5 +--- no_error_log +[error] +[alert] diff --git a/debian/modules/http-lua/t/004-require.t b/debian/modules/http-lua/t/004-require.t index ec74116..35e04db 100644 --- a/debian/modules/http-lua/t/004-require.t +++ b/debian/modules/http-lua/t/004-require.t @@ -35,6 +35,7 @@ __DATA__ location /load { content_by_lua ' package.loaded.foo = nil; + collectgarbage() local foo = require "foo"; foo.hi() '; diff --git a/debian/modules/http-lua/t/017-exec.t b/debian/modules/http-lua/t/017-exec.t index 535c4ab..544b8bb 100644 --- a/debian/modules/http-lua/t/017-exec.t +++ b/debian/modules/http-lua/t/017-exec.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 4); +plan tests => repeat_each() * (blocks() * 2 + 8); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; @@ -572,3 +572,25 @@ hello, bah ["dummy", "dummy"] --- no_error_log [error] + + + +=== TEST 25: pipelined requests +--- config + location /t { + content_by_lua_block { + ngx.exec("@foo") + } + } + + location @foo { + return 200; + } +--- pipelined_requests eval +["GET /t", "GET /t"] +--- error_code eval +[200, 200] +--- response_body eval +["", ""] +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/023-rewrite/exec.t b/debian/modules/http-lua/t/023-rewrite/exec.t index bd97968..edd4607 100644 --- a/debian/modules/http-lua/t/023-rewrite/exec.t +++ b/debian/modules/http-lua/t/023-rewrite/exec.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); #repeat_each(1); -plan tests => blocks() * repeat_each() * 2; +plan tests => repeat_each() * (blocks() * 2 + 4); #no_diff(); #no_long_string(); @@ -376,3 +376,25 @@ ngx.exec("@proxy") GET /main --- response_body hello, bah + + + +=== TEST 17: pipelined requests +--- config + location /t { + rewrite_by_lua_block { + ngx.exec("@foo") + } + } + + location @foo { + return 200; + } +--- pipelined_requests eval +["GET /t", "GET /t"] +--- error_code eval +[200, 200] +--- response_body eval +["", ""] +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t b/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t index 15bec7f..a32ed7b 100644 --- a/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t +++ b/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t @@ -24,7 +24,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 14); +plan tests => repeat_each() * (blocks() * 4 + 8); our $HtmlDir = html_dir; @@ -174,7 +174,7 @@ lua tcp socket connect timeout: 102 -=== TEST 5: sock:settimeout(-1) does not override lua_socket_connect_timeout +=== TEST 5: -1 is bad timeout value --- config server_tokens off; lua_socket_connect_timeout 102ms; @@ -198,14 +198,12 @@ lua tcp socket connect timeout: 102 } --- request GET /t5 ---- response_body -failed to connect: timeout +--- response_body_like chomp +500 Internal Server Error --- error_log -lua tcp socket connect timeout: 102 ---- no_error_log -[error] -[alert] +bad timeout value --- timeout: 10 +--- error_code: 500 @@ -371,7 +369,7 @@ lua tcp socket read timed out -=== TEST 10: sock:settimeout(-1) does not override lua_socket_read_timeout +=== TEST 10: -1 is bad timeout value --- config server_tokens off; lua_socket_read_timeout 102ms; @@ -385,8 +383,6 @@ lua tcp socket read timed out return end - ngx.say("connected: ", ok) - sock:settimeout(-1) local line @@ -402,13 +398,12 @@ lua tcp socket read timed out } --- request GET /t ---- response_body -connected: 1 -failed to receive: timeout +--- response_body_like chomp +500 Internal Server Error --- error_log -lua tcp socket read timeout: 102 -lua tcp socket connect timeout: 60000 -lua tcp socket read timed out +bad timeout value +--- timeout: 10 +--- error_code: 500 @@ -574,7 +569,7 @@ lua tcp socket write timed out -=== TEST 15: sock:settimeout(-1) does not override lua_socket_send_timeout +=== TEST 15: -1 is bad timeout value --- config server_tokens off; lua_socket_send_timeout 102ms; @@ -588,8 +583,6 @@ lua tcp socket write timed out return end - ngx.say("connected: ", ok) - sock:settimeout(-1) local bytes @@ -605,10 +598,9 @@ lua tcp socket write timed out } --- request GET /t ---- response_body -connected: 1 -failed to send: timeout +--- response_body_like chomp +500 Internal Server Error --- error_log -lua tcp socket send timeout: 102 -lua tcp socket connect timeout: 60000 -lua tcp socket write timed out +bad timeout value +--- timeout: 10 +--- error_code: 500 diff --git a/debian/modules/http-lua/t/024-access/exec.t b/debian/modules/http-lua/t/024-access/exec.t index 3fb87be..43c1a77 100644 --- a/debian/modules/http-lua/t/024-access/exec.t +++ b/debian/modules/http-lua/t/024-access/exec.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 2); +plan tests => repeat_each() * (blocks() * 2 + 6); #no_diff(); #no_long_string(); @@ -369,3 +369,25 @@ GET /read 'unsafe URI "/hi/../" was detected', qr/runtime error: access_by_lua\(nginx.conf:\d+\):2: unsafe uri/, ] + + + +=== TEST 17: pipelined requests +--- config + location /t { + access_by_lua_block { + ngx.exec("@foo") + } + } + + location @foo { + return 200; + } +--- pipelined_requests eval +["GET /t", "GET /t"] +--- error_code eval +[200, 200] +--- response_body eval +["", ""] +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/035-gmatch.t b/debian/modules/http-lua/t/035-gmatch.t index 5b63ae4..0426997 100644 --- a/debian/modules/http-lua/t/035-gmatch.t +++ b/debian/modules/http-lua/t/035-gmatch.t @@ -440,6 +440,7 @@ done location /main { content_by_lua ' package.loaded.foo = nil + collectgarbage() local res = ngx.location.capture("/t") if res.status == 200 then diff --git a/debian/modules/http-lua/t/058-tcp-socket.t b/debian/modules/http-lua/t/058-tcp-socket.t index 1ee113b..0743dd7 100644 --- a/debian/modules/http-lua/t/058-tcp-socket.t +++ b/debian/modules/http-lua/t/058-tcp-socket.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 190; +plan tests => repeat_each() * 193; our $HtmlDir = html_dir; @@ -3690,3 +3690,40 @@ received: OK close: 1 nil --- no_error_log [error] + + + +=== TEST 61: resolver send query failing immediately in connect() +this case did not clear coctx->cleanup properly and would lead to memory invalid accesses. + +this test case requires the following iptables rule to work properly: + +sudo iptables -I OUTPUT 1 -p udp --dport 10086 -j REJECT + +--- config + location /t { + resolver 127.0.0.1:10086 ipv6=off; + resolver_timeout 10ms; + + content_by_lua_block { + local sock = ngx.socket.tcp() + + for i = 1, 3 do -- retry + local ok, err = sock:connect("www.google.com", 80) + if not ok then + ngx.say("failed to connect: ", err) + end + end + + ngx.say("hello!") + } + } +--- request +GET /t +--- response_body +failed to connect: www.google.com could not be resolved +failed to connect: www.google.com could not be resolved +failed to connect: www.google.com could not be resolved +hello! +--- error_log eval +qr{\[alert\] .*? send\(\) failed \(\d+: Operation not permitted\) while resolving} diff --git a/debian/modules/http-lua/t/065-tcp-socket-timeout.t b/debian/modules/http-lua/t/065-tcp-socket-timeout.t index 212766e..9e5460e 100644 --- a/debian/modules/http-lua/t/065-tcp-socket-timeout.t +++ b/debian/modules/http-lua/t/065-tcp-socket-timeout.t @@ -28,7 +28,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 12); +plan tests => repeat_each() * (blocks() * 4 + 6); our $HtmlDir = html_dir; @@ -159,7 +159,7 @@ lua tcp socket connect timed out -=== TEST 5: sock:settimeout(-1) does not override lua_socket_connect_timeout +=== TEST 5: -1 is bad timeout value --- config server_tokens off; lua_socket_connect_timeout 102ms; @@ -179,11 +179,11 @@ lua tcp socket connect timed out } --- request GET /t ---- response_body -failed to connect: timeout +--- response_body_like chomp +500 Internal Server Error --- error_log -lua tcp socket connect timeout: 102 -lua tcp socket connect timed out +bad timeout value +--- error_code: 500 @@ -342,7 +342,7 @@ lua tcp socket read timed out -=== TEST 10: sock:settimeout(-1) does not override lua_socket_read_timeout +=== TEST 10: -1 is bad timeout value --- config server_tokens off; lua_socket_read_timeout 102ms; @@ -356,8 +356,6 @@ lua tcp socket read timed out return end - ngx.say("connected: ", ok) - sock:settimeout(-1) local line @@ -371,13 +369,11 @@ lua tcp socket read timed out } --- request GET /t ---- response_body -connected: 1 -failed to receive: timeout +--- response_body_like chomp +500 Internal Server Error +--- error_code: 500 --- error_log -lua tcp socket read timeout: 102 -lua tcp socket connect timeout: 60000 -lua tcp socket read timed out +bad timeout value @@ -563,8 +559,6 @@ lua tcp socket write timed out return end - ngx.say("connected: ", ok) - sock:settimeout(-1) local bytes @@ -578,13 +572,11 @@ lua tcp socket write timed out } --- request GET /t ---- response_body -connected: 1 -failed to send: timeout +--- response_body_like chomp +500 Internal Server Error --- error_log -lua tcp socket send timeout: 102 -lua tcp socket connect timeout: 60000 -lua tcp socket write timed out +bad timeout value +--- error_code: 500 @@ -994,3 +986,33 @@ close: 1 nil --- no_error_log [error] + + + +=== TEST 23: timeout overflow detection +--- config + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + local ok, err = pcall(sock.settimeout, sock, (2 ^ 31) - 1) + if not ok then + ngx.say("failed to set timeout: ", err) + else + ngx.say("settimeout: ok") + end + + ok, err = pcall(sock.settimeout, sock, 2 ^ 31) + if not ok then + ngx.say("failed to set timeout: ", err) + else + ngx.say("settimeout: ok") + end + } + } +--- request +GET /t +--- response_body_like +settimeout: ok +failed to set timeout: bad timeout value +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/097-uthread-rewrite.t b/debian/modules/http-lua/t/097-uthread-rewrite.t index a93adc8..2f0c06f 100644 --- a/debian/modules/http-lua/t/097-uthread-rewrite.t +++ b/debian/modules/http-lua/t/097-uthread-rewrite.t @@ -258,6 +258,7 @@ free request hello foo --- no_error_log [error] +--- wait: 0.1 diff --git a/debian/modules/http-lua/t/106-timer.t b/debian/modules/http-lua/t/106-timer.t index 04a532e..3e4741e 100644 --- a/debian/modules/http-lua/t/106-timer.t +++ b/debian/modules/http-lua/t/106-timer.t @@ -174,7 +174,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:4[4-9]|5[0-6]) local begin = ngx.now() local function f() print("my lua timer handler") - ngx.sleep(0.02) + ngx.sleep(0.2) print("elapsed: ", ngx.now() - begin) end local ok, err = ngx.timer.at(0.05, f) @@ -199,7 +199,7 @@ delete thread 2 --- response_body registered timer ---- wait: 0.12 +--- wait: 0.3 --- no_error_log [error] [alert] @@ -208,7 +208,7 @@ registered timer --- error_log eval [ qr/\[lua\] .*? my lua timer handler/, -qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.(?:1[4-9]|2[0-6]?)/, "lua ngx.timer expired", "http lua close fake http connection" ] diff --git a/debian/modules/http-lua/t/129-ssl-socket.t b/debian/modules/http-lua/t/129-ssl-socket.t index 1c3f7cd..e7447a7 100644 --- a/debian/modules/http-lua/t/129-ssl-socket.t +++ b/debian/modules/http-lua/t/129-ssl-socket.t @@ -1181,7 +1181,7 @@ lua ssl free session: ([0-9A-F]+):1 $/ --- error_log lua ssl server name: "openresty.org" -SSL: TLSv1.2, cipher: "ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 +SSL: TLSv1.2, cipher: "ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 --- no_error_log SSL reused session [error] @@ -1261,7 +1261,7 @@ lua ssl free session: ([0-9A-F]+):1 $/ --- error_log lua ssl server name: "openresty.org" -SSL: TLSv1.2, cipher: "ECDHE-RSA-AES256-SHA +SSL: TLSv1.2, cipher: "ECDHE-RSA-AES256-SHA SSLv3 --- no_error_log SSL reused session [error] @@ -1341,7 +1341,7 @@ lua ssl free session: ([0-9A-F]+):1 $/ --- error_log lua ssl server name: "openresty.org" -SSL: TLSv1, cipher: "ECDHE-RSA-AES256-SHA +SSL: TLSv1, cipher: "ECDHE-RSA-AES128-SHA SSLv3 --- no_error_log SSL reused session [error] diff --git a/debian/modules/http-lua/t/139-ssl-cert-by.t b/debian/modules/http-lua/t/139-ssl-cert-by.t index c13044f..b521e9e 100644 --- a/debian/modules/http-lua/t/139-ssl-cert-by.t +++ b/debian/modules/http-lua/t/139-ssl-cert-by.t @@ -113,11 +113,17 @@ close: 1 nil --- error_log lua ssl server name: "test.com" -ssl_certificate_by_lua:1: ssl cert by lua is running! --- no_error_log [error] [alert] +--- grep_error_log eval: qr/ssl_certificate_by_lua:.*?,|\bssl cert: connection reusable: \d+|\breusable connection: \d+/ +--- grep_error_log_out eval +qr/reusable connection: 1 +ssl cert: connection reusable: 1 +reusable connection: 0 +ssl_certificate_by_lua:1: ssl cert by lua is running!, +/ diff --git a/debian/modules/http-lua/t/142-ssl-session-store.t b/debian/modules/http-lua/t/142-ssl-session-store.t index 73b6e19..825d016 100644 --- a/debian/modules/http-lua/t/142-ssl-session-store.t +++ b/debian/modules/http-lua/t/142-ssl-session-store.t @@ -82,11 +82,16 @@ close: 1 nil --- error_log lua ssl server name: "test.com" -ssl_session_store_by_lua_block:1: ssl session store by lua is running! --- no_error_log [error] [alert] +--- grep_error_log eval: qr/ssl_session_store_by_lua_block:.*?,|\bssl session store: connection reusable: \d+|\breusable connection: \d+/ +--- grep_error_log_out eval +qr/^reusable connection: 0 +ssl session store: connection reusable: 0 +ssl_session_store_by_lua_block:1: ssl session store by lua is running!, +/m, diff --git a/debian/modules/http-lua/t/143-ssl-session-fetch.t b/debian/modules/http-lua/t/143-ssl-session-fetch.t index 701ead7..7be180f 100644 --- a/debian/modules/http-lua/t/143-ssl-session-fetch.t +++ b/debian/modules/http-lua/t/143-ssl-session-fetch.t @@ -83,16 +83,21 @@ connected: 1 ssl handshake: userdata close: 1 nil ---- grep_error_log eval -qr/ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!/s +--- grep_error_log eval: qr/ssl_session_fetch_by_lua_block:.*?,|\bssl session fetch: connection reusable: \d+|\breusable connection: \d+/ --- grep_error_log_out eval [ -'', -'ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running! -', -'ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running! -', +qr/\A(?:reusable connection: [01]\n)+\z/s, +qr/^reusable connection: 1 +ssl session fetch: connection reusable: 1 +reusable connection: 0 +ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!, +/m, +qr/^reusable connection: 1 +ssl session fetch: connection reusable: 1 +reusable connection: 0 +ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!, +/m, ] --- no_error_log diff --git a/debian/modules/http-lua/t/147-tcp-socket-timeouts.t b/debian/modules/http-lua/t/147-tcp-socket-timeouts.t index 0689a9b..8199e84 100644 --- a/debian/modules/http-lua/t/147-tcp-socket-timeouts.t +++ b/debian/modules/http-lua/t/147-tcp-socket-timeouts.t @@ -532,3 +532,96 @@ received: ok failed to receive a line: closed [] --- no_error_log [error] + + + +=== TEST 8: connection timeout overflow detection +--- config + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + local ok, err = pcall(sock.settimeouts, sock, + (2 ^ 31) - 1, 500, 500) + if not ok then + ngx.say("failed to set timeouts: ", err) + else + ngx.say("settimeouts: ok") + end + + ok, err = pcall(sock.settimeouts, sock, 2 ^ 31, 500, 500) + if not ok then + ngx.say("failed to set timeouts: ", err) + else + ngx.say("settimeouts: ok") + end + } + } +--- request +GET /t +--- response_body_like +settimeouts: ok +failed to set timeouts: bad timeout value +--- no_error_log +[error] + + + +=== TEST 9: send timeout overflow detection +--- config + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + local ok, err = pcall(sock.settimeouts, sock, + 500, (2 ^ 31) - 1, 500) + if not ok then + ngx.say("failed to set timeouts: ", err) + else + ngx.say("settimeouts: ok") + end + + ok, err = pcall(sock.settimeouts, sock, 500, 2 ^ 31, 500) + if not ok then + ngx.say("failed to set timeouts: ", err) + else + ngx.say("settimeouts: ok") + end + } + } +--- request +GET /t +--- response_body_like +settimeouts: ok +failed to set timeouts: bad timeout value +--- no_error_log +[error] + + + +=== TEST 10: read timeout overflow detection +--- config + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + local ok, err = pcall(sock.settimeouts, sock, + 500, 500, (2 ^ 31) - 1) + if not ok then + ngx.say("failed to set timeouts: ", err) + else + ngx.say("settimeouts: ok") + end + + ok, err = pcall(sock.settimeouts, sock, 500, 500, 2 ^ 31) + if not ok then + ngx.say("failed to set timeouts: ", err) + else + ngx.say("settimeouts: ok") + end + } + } +--- request +GET /t +--- response_body_like +settimeouts: ok +failed to set timeouts: bad timeout value +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/154-semaphore.t b/debian/modules/http-lua/t/154-semaphore.t index 3c1f004..875f181 100644 --- a/debian/modules/http-lua/t/154-semaphore.t +++ b/debian/modules/http-lua/t/154-semaphore.t @@ -75,6 +75,7 @@ semaphore gc wait queue is not empty === TEST 2: timer + shutdown error log (lua code cache off) +FIXME: this test case leaks memory. --- http_config lua_code_cache off; --- config @@ -116,3 +117,4 @@ hello, world --- shutdown_error_log --- no_shutdown_error_log semaphore gc wait queue is not empty +--- SKIP diff --git a/debian/modules/http-lua/util/build.sh b/debian/modules/http-lua/util/build.sh index e45c00a..164bf9f 100755 --- a/debian/modules/http-lua/util/build.sh +++ b/debian/modules/http-lua/util/build.sh @@ -23,6 +23,7 @@ force=$2 #--with-http_spdy_module \ time ngx-build $force $version \ + --with-pcre-jit \ --with-ipv6 \ --with-cc-opt="-I$PCRE_INC -I$OPENSSL_INC" \ --with-http_v2_module \ @@ -35,6 +36,8 @@ time ngx-build $force $version \ --without-mail_imap_module \ --with-http_image_filter_module \ --without-mail_smtp_module \ + --with-stream \ + --with-stream_ssl_module \ --without-http_upstream_ip_hash_module \ --without-http_memcached_module \ --without-http_auth_basic_module \ @@ -50,6 +53,7 @@ time ngx-build $force $version \ --add-module=$root/../rds-json-nginx-module \ --add-module=$root/../coolkit-nginx-module \ --add-module=$root/../redis2-nginx-module \ + --add-module=$root/../stream-lua-nginx-module \ --add-module=$root/t/data/fake-module \ --add-module=$root/t/data/fake-shm-module \ --add-module=$root/t/data/fake-delayed-load-module \ diff --git a/debian/modules/http-lua/valgrind.suppress b/debian/modules/http-lua/valgrind.suppress index d0bcc56..7273986 100644 --- a/debian/modules/http-lua/valgrind.suppress +++ b/debian/modules/http-lua/valgrind.suppress @@ -1,16 +1,16 @@ { - -Memcheck:Addr1 -fun:ngx_init_cycle -fun:ngx_master_process_cycle -fun:main + + Memcheck:Addr1 + fun:ngx_init_cycle + fun:ngx_master_process_cycle + fun:main } { - -Memcheck:Addr4 -fun:ngx_init_cycle -fun:ngx_master_process_cycle -fun:main + + Memcheck:Addr4 + fun:ngx_init_cycle + fun:ngx_master_process_cycle + fun:main } { @@ -104,11 +104,11 @@ fun:main fun:ngx_event_process_init } { - - Memcheck:Param - sendmsg(mmsg[0].msg_hdr) - fun:sendmmsg - fun:__libc_res_nsend + + Memcheck:Param + sendmsg(mmsg[0].msg_hdr) + fun:sendmmsg + fun:__libc_res_nsend } { @@ -120,11 +120,11 @@ fun:main fun:ngx_start_cache_manager_processes } { - - Memcheck:Cond - fun:ngx_init_cycle - fun:ngx_master_process_cycle - fun:main + + Memcheck:Cond + fun:ngx_init_cycle + fun:ngx_master_process_cycle + fun:main } { @@ -157,10 +157,36 @@ fun:main fun:ngx_alloc fun:ngx_set_environment fun:ngx_single_process_cycle - fun:main } { Memcheck:Cond obj:* } +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_worker_process_init +} +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_create_pool + fun:main +} +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_single_process_cycle +} diff --git a/debian/modules/patches/http-lua/openssl-1.1.0.patch b/debian/modules/patches/http-lua/openssl-1.1.0.patch index 431031b..4dafce2 100644 --- a/debian/modules/patches/http-lua/openssl-1.1.0.patch +++ b/debian/modules/patches/http-lua/openssl-1.1.0.patch @@ -1,4 +1,4 @@ -From 525d5a550f5f256af01de1264358086a4cd1ac4a Mon Sep 17 00:00:00 2001 +From 47ab0d4eca3fa62403c798d7dfad50a5f9f7215a Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Tue, 13 Sep 2016 22:31:32 +0100 Subject: [PATCH 1/4] bugfix: ssl: don't use SSLv3 in tests. @@ -11,7 +11,7 @@ tickets set ssl_session_tickets to off instead. 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/t/142-ssl-session-store.t b/t/142-ssl-session-store.t -index 73b6e197..260fe490 100644 +index 825d0163..cc3a664c 100644 --- a/t/142-ssl-session-store.t +++ b/t/142-ssl-session-store.t @@ -32,7 +32,7 @@ __DATA__ @@ -23,7 +23,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -102,7 +102,7 @@ ssl_session_store_by_lua_block:1: ssl session store by lua is running! +@@ -107,7 +107,7 @@ ssl_session_store_by_lua_block:1: ssl session store by lua is running!, server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -32,7 +32,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -177,7 +177,7 @@ API disabled in the context of ssl_session_store_by_lua* +@@ -182,7 +182,7 @@ API disabled in the context of ssl_session_store_by_lua* server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -41,7 +41,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -267,9 +267,9 @@ my timer run! +@@ -272,9 +272,9 @@ my timer run! listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -52,7 +52,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -335,9 +335,9 @@ API disabled in the context of ssl_session_store_by_lua* +@@ -340,9 +340,9 @@ API disabled in the context of ssl_session_store_by_lua* server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -63,7 +63,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -407,9 +407,9 @@ ngx.exit does not yield and the error code is eaten. +@@ -412,9 +412,9 @@ ngx.exit does not yield and the error code is eaten. server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -74,7 +74,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -480,9 +480,9 @@ ssl_session_store_by_lua*: handler return value: 0, sess new cb exit code: 0 +@@ -485,9 +485,9 @@ ssl_session_store_by_lua*: handler return value: 0, sess new cb exit code: 0 server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -85,7 +85,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -548,9 +548,9 @@ should never reached here +@@ -553,9 +553,9 @@ should never reached here server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -96,7 +96,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -621,7 +621,7 @@ get_phase: ssl_session_store +@@ -626,7 +626,7 @@ get_phase: ssl_session_store } ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -105,7 +105,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -690,7 +690,7 @@ qr/elapsed in ssl cert by lua: 0.(?:09|1[01])\d+,/, +@@ -695,7 +695,7 @@ qr/elapsed in ssl cert by lua: 0.(?:09|1[01])\d+,/, server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -114,7 +114,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -760,7 +760,6 @@ a.lua:1: ssl store session by lua is running! +@@ -765,7 +765,6 @@ a.lua:1: ssl store session by lua is running! ssl_session_store_by_lua_block { print("handler in test.com") } @@ -122,7 +122,7 @@ index 73b6e197..260fe490 100644 ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; -@@ -770,7 +769,6 @@ a.lua:1: ssl store session by lua is running! +@@ -775,7 +774,6 @@ a.lua:1: ssl store session by lua is running! server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -130,7 +130,7 @@ index 73b6e197..260fe490 100644 ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; -@@ -836,7 +834,7 @@ qr/\[emerg\] .*? "ssl_session_store_by_lua_block" directive is not allowed here +@@ -841,7 +839,7 @@ qr/\[emerg\] .*? "ssl_session_store_by_lua_block" directive is not allowed here server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -140,7 +140,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } diff --git a/t/143-ssl-session-fetch.t b/t/143-ssl-session-fetch.t -index 701ead72..3626f0fb 100644 +index 7be180f8..4dc992d3 100644 --- a/t/143-ssl-session-fetch.t +++ b/t/143-ssl-session-fetch.t @@ -33,7 +33,7 @@ __DATA__ @@ -152,7 +152,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -114,7 +114,7 @@ qr/ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!/s +@@ -119,7 +119,7 @@ ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!, server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -161,7 +161,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -198,7 +198,7 @@ qr/elapsed in ssl fetch session by lua: 0.(?:09|1[01])\d+,/, +@@ -203,7 +203,7 @@ qr/elapsed in ssl fetch session by lua: 0.(?:09|1[01])\d+,/, server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -170,7 +170,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -297,9 +297,9 @@ qr/my timer run!/s +@@ -302,9 +302,9 @@ qr/my timer run!/s server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -181,7 +181,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -377,9 +377,9 @@ qr/received memc reply: OK/s +@@ -382,9 +382,9 @@ qr/received memc reply: OK/s server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -192,7 +192,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -458,9 +458,9 @@ should never reached here +@@ -463,9 +463,9 @@ should never reached here server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -203,7 +203,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -540,9 +540,9 @@ should never reached here +@@ -545,9 +545,9 @@ should never reached here server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -214,7 +214,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -621,9 +621,9 @@ should never reached here +@@ -626,9 +626,9 @@ should never reached here server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -225,7 +225,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -704,9 +704,9 @@ should never reached here +@@ -709,9 +709,9 @@ should never reached here server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -236,7 +236,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -787,7 +787,7 @@ should never reached here +@@ -792,7 +792,7 @@ should never reached here server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -245,7 +245,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -872,7 +872,7 @@ qr/get_phase: ssl_session_fetch/s +@@ -877,7 +877,7 @@ qr/get_phase: ssl_session_fetch/s } ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -254,7 +254,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -956,7 +956,7 @@ ssl store session by lua is running! +@@ -961,7 +961,7 @@ ssl store session by lua is running! server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -263,7 +263,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -1036,7 +1036,7 @@ qr/\S+:\d+: ssl fetch sess by lua is running!/s +@@ -1041,7 +1041,7 @@ qr/\S+:\d+: ssl fetch sess by lua is running!/s server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -273,10 +273,10 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -- -2.14.1 +2.15.1 -From d308b44b3daf7702d9218e2a5620a89a5eca8389 Mon Sep 17 00:00:00 2001 +From 5cb24ce5eccd580d1bd6a2c44d7ea3cef5ad7740 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Thu, 12 May 2016 13:12:23 +0100 Subject: [PATCH 2/4] bugfix: ssl: do not access SSL_SESSION struct directly. @@ -288,10 +288,10 @@ In OpenSSL 1.1.0 it was made opaque. 2 files changed, 80 insertions(+), 83 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c -index 382a94de..07164746 100644 +index f0988bc5..17d3db2e 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c -@@ -1316,9 +1316,8 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) +@@ -1320,9 +1320,8 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) return 2; } @@ -303,7 +303,7 @@ index 382a94de..07164746 100644 } } -@@ -1583,9 +1582,8 @@ ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, +@@ -1587,9 +1586,8 @@ ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, } else { *ud = ssl_session; @@ -315,7 +315,7 @@ index 382a94de..07164746 100644 /* set up the __gc metamethod */ lua_pushlightuserdata(L, &ngx_http_lua_ssl_session_metatable_key); -@@ -5365,9 +5363,8 @@ ngx_http_lua_ssl_free_session(lua_State *L) +@@ -5386,9 +5384,8 @@ ngx_http_lua_ssl_free_session(lua_State *L) psession = lua_touserdata(L, 1); if (psession && *psession != NULL) { @@ -328,7 +328,7 @@ index 382a94de..07164746 100644 ngx_ssl_free_session(*psession); } diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t -index 1c3f7cd0..0cd1f52f 100644 +index e7447a7c..c4bce9e0 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -108,10 +108,10 @@ sent http request: 59 bytes. @@ -714,10 +714,10 @@ index 1c3f7cd0..0cd1f52f 100644 --- error_log lua ssl certificate verify error: (18: self signed certificate) -- -2.14.1 +2.15.1 -From 473c121668c658140dffdbeb70aa7df1fc48d2a7 Mon Sep 17 00:00:00 2001 +From 567bca126f4b9e71fbf9d473e85b975f190dcd3c Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Fri, 10 Jun 2016 13:23:21 +0100 Subject: [PATCH 3/4] bugfix: ssl: do not access SSL struct directly for @@ -745,10 +745,10 @@ index 31b4f243..9ec8b509 100644 return NGX_DECLINED; } -- -2.14.1 +2.15.1 -From 44988918835b8b41e51e75c1618250a560bc11ca Mon Sep 17 00:00:00 2001 +From 840ad10b8447f9ea1f0ddede344916d423029e67 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Tue, 13 Sep 2016 22:19:10 +0100 Subject: [PATCH 4/4] bugfix: ssl: make SSL session callback build with OpenSSL @@ -761,7 +761,7 @@ Subject: [PATCH 4/4] bugfix: ssl: make SSL session callback build with OpenSSL 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/ngx_http_lua_ssl_session_fetchby.c b/src/ngx_http_lua_ssl_session_fetchby.c -index 556b7320..5289cb92 100644 +index 3a3c1f54..2c75f6a9 100644 --- a/src/ngx_http_lua_ssl_session_fetchby.c +++ b/src/ngx_http_lua_ssl_session_fetchby.c @@ -171,8 +171,11 @@ ngx_http_lua_ssl_sess_fetch_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, @@ -778,7 +778,7 @@ index 556b7320..5289cb92 100644 { lua_State *L; ngx_int_t rc; -@@ -284,7 +287,7 @@ ngx_http_lua_ssl_sess_fetch_handler(ngx_ssl_conn_t *ssl_conn, u_char *id, +@@ -287,7 +290,7 @@ ngx_http_lua_ssl_sess_fetch_handler(ngx_ssl_conn_t *ssl_conn, u_char *id, cctx->exit_code = 1; /* successful by default */ cctx->connection = c; cctx->request = r; @@ -805,7 +805,7 @@ index 5a6f96f5..50c6616d 100644 diff --git a/src/ngx_http_lua_ssl_session_storeby.c b/src/ngx_http_lua_ssl_session_storeby.c -index bae8273d..dc1fad9b 100644 +index f83e85d9..ce832ea1 100644 --- a/src/ngx_http_lua_ssl_session_storeby.c +++ b/src/ngx_http_lua_ssl_session_storeby.c @@ -172,6 +172,8 @@ int @@ -817,7 +817,7 @@ index bae8273d..dc1fad9b 100644 lua_State *L; ngx_int_t rc; ngx_connection_t *c, *fc = NULL; -@@ -246,11 +248,13 @@ ngx_http_lua_ssl_sess_store_handler(ngx_ssl_conn_t *ssl_conn, +@@ -247,11 +249,13 @@ ngx_http_lua_ssl_sess_store_handler(ngx_ssl_conn_t *ssl_conn, } } @@ -834,5 +834,5 @@ index bae8273d..dc1fad9b 100644 dd("setting cctx"); -- -2.14.1 +2.15.1 From 72b4f71671c9f87f63be9db63f7f821c41aead92 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 13 Dec 2017 11:23:07 +0200 Subject: [PATCH 285/651] http-dav-ext: Upgrade to 0.1.0 Closes: #878611 --- debian/modules/control | 3 +- debian/modules/http-dav-ext/LICENSE | 22 ++++++++++ debian/modules/http-dav-ext/README | 29 ------------- debian/modules/http-dav-ext/README.rst | 41 +++++++++++++++++++ debian/modules/http-dav-ext/config | 19 ++++++--- .../http-dav-ext/ngx_http_dav_ext_module.c | 9 ++-- .../patches/http-dav-ext/dynamic-module.patch | 41 ------------------- debian/modules/patches/http-dav-ext/series | 1 - 8 files changed, 83 insertions(+), 82 deletions(-) create mode 100644 debian/modules/http-dav-ext/LICENSE delete mode 100644 debian/modules/http-dav-ext/README create mode 100644 debian/modules/http-dav-ext/README.rst delete mode 100644 debian/modules/patches/http-dav-ext/dynamic-module.patch delete mode 100644 debian/modules/patches/http-dav-ext/series diff --git a/debian/modules/control b/debian/modules/control index bd7cc0a..6552957 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -50,8 +50,7 @@ Patch: Module: http-dav-ext Homepage: https://github.com/arut/nginx-dav-ext-module -Version: v0.0.3 -Patch: dynamic-module.patch +Version: v0.1.0 Module: http-fancyindex Homepage: https://github.com/aperezdc/ngx-fancyindex diff --git a/debian/modules/http-dav-ext/LICENSE b/debian/modules/http-dav-ext/LICENSE new file mode 100644 index 0000000..7be3135 --- /dev/null +++ b/debian/modules/http-dav-ext/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2012-2017, Roman Arutyunyan +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. 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. + +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. diff --git a/debian/modules/http-dav-ext/README b/debian/modules/http-dav-ext/README deleted file mode 100644 index bc727ff..0000000 --- a/debian/modules/http-dav-ext/README +++ /dev/null @@ -1,29 +0,0 @@ -== nginx-dav-ext-module == - -NGINX WebDAV missing commands support (PROPFIND & OPTIONS) - -(c) 2012 Arutyunyan Roman (arut@qip.ru) - - -For full WebDAV support in NGINX you need to turn on standard NGINX -WebDAV module (providing partial WebDAV implementation) as well as -this module for missing methods - -./configure --with-http_dav_module --add-module= - - - -Requirements: - - libexpat-dev - - -Example config: - - location / { - - dav_methods PUT DELETE MKCOL COPY MOVE; - dav_ext_methods PROPFIND OPTIONS; - - root /var/root/; - } diff --git a/debian/modules/http-dav-ext/README.rst b/debian/modules/http-dav-ext/README.rst new file mode 100644 index 0000000..91c10e3 --- /dev/null +++ b/debian/modules/http-dav-ext/README.rst @@ -0,0 +1,41 @@ +******************** +nginx-dav-ext-module +******************** + +NGINX WebDAV missing commands support (PROPFIND & OPTIONS) + +Copyright |copy| 2012-2017 Arutyunyan Roman (arutyunyan.roman@gmail.com) + +.. |copy| unicode:: U+000A9 .. COPYRIGHT SIGN + +For full WebDAV support in NGINX you need to enable the standard NGINX +WebDAV module (providing partial WebDAV implementation) as well as +this module for missing methods: + +.. code-block:: bash + + $ ./configure --with-http_dav_module --add-module=/path/to/this-module + +The module can be built dynamically: + +.. code-block:: bash + + $ ./configure --with-http_dav_module --add-dynamic-module=/path/to/this-module + +Requirements +============ + +``libexpat-dev`` + + +Example config +============== + +.. code-block:: + + location / { + dav_methods PUT DELETE MKCOL COPY MOVE; + dav_ext_methods PROPFIND OPTIONS; + + root /var/root/; + } diff --git a/debian/modules/http-dav-ext/config b/debian/modules/http-dav-ext/config index 98b2b7a..372620b 100644 --- a/debian/modules/http-dav-ext/config +++ b/debian/modules/http-dav-ext/config @@ -1,9 +1,16 @@ -ngx_addon_name="ngx_http_dav_ext_module" +ngx_addon_name=ngx_http_dav_ext_module -HTTP_MODULES="$HTTP_MODULES \ - ngx_http_dav_ext_module" +if [ -f auto/module ] ; then -NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ - $ngx_addon_dir/ngx_http_dav_ext_module.c" + ngx_module_type=HTTP + ngx_module_name=ngx_http_dav_ext_module + ngx_module_libs=-lexpat + ngx_module_srcs="$ngx_addon_dir/ngx_http_dav_ext_module.c" -CORE_LIBS="$CORE_LIBS -lexpat" + . auto/module + +else + HTTP_MODULES="$HTTP_MODULES ngx_http_dav_ext_module" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_dav_ext_module.c" + CORE_LIBS="$CORE_LIBS -lexpat" +fi diff --git a/debian/modules/http-dav-ext/ngx_http_dav_ext_module.c b/debian/modules/http-dav-ext/ngx_http_dav_ext_module.c index 73d86de..ae75fc3 100644 --- a/debian/modules/http-dav-ext/ngx_http_dav_ext_module.c +++ b/debian/modules/http-dav-ext/ngx_http_dav_ext_module.c @@ -1,5 +1,5 @@ /****************************************************************************** - Copyright (c) 2012, Roman Arutyunyan (arut@qip.ru) + Copyright (c) 2012-2017, Roman Arutyunyan (arutyunyan.roman@gmail.com) All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -535,9 +535,12 @@ ngx_http_dav_ext_send_propfind(ngx_http_request_t *r) u_char *p, *uc; if (ngx_http_variable_unknown_header(&vv, &depth_name, - &r->headers_in.headers.part, 0) == NGX_OK - && vv.valid) + &r->headers_in.headers.part, 0) != NGX_OK) { + return NGX_ERROR; + } + + if (!vv.not_found) { if (vv.len == sizeof("infinity") -1 && !ngx_strncasecmp(vv.data, (u_char*)"infinity", vv.len)) { diff --git a/debian/modules/patches/http-dav-ext/dynamic-module.patch b/debian/modules/patches/http-dav-ext/dynamic-module.patch deleted file mode 100644 index c865460..0000000 --- a/debian/modules/patches/http-dav-ext/dynamic-module.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0473d8d1bb63a14afe608ecf46bfc933234e3048 Mon Sep 17 00:00:00 2001 -From: Florian Kinder -Date: Fri, 28 Oct 2016 13:34:21 +0200 -Subject: [PATCH] Added dynamic module support -Origin: other, https://github.com/Fank/nginx-dav-ext-module/pull/1 - ---- - config | 22 +++++++++++++++++----- - 1 file changed, 17 insertions(+), 5 deletions(-) - -diff --git a/config b/config -index 98b2b7a..b6b65de 100644 ---- a/config -+++ b/config -@@ -1,9 +1,21 @@ - ngx_addon_name="ngx_http_dav_ext_module" - --HTTP_MODULES="$HTTP_MODULES \ -- ngx_http_dav_ext_module" - --NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ -- $ngx_addon_dir/ngx_http_dav_ext_module.c" -+if test -n "$ngx_module_link"; then -+ ngx_module_type=HTTP -+ ngx_module_name=ngx_http_dav_ext_module -+ ngx_module_incs= -+ ngx_module_deps= -+ ngx_module_srcs="$ngx_addon_dir/ngx_http_dav_ext_module.c" -+ ngx_module_libs="-lexpat" -+ -+ . auto/module -+else -+ CORE_LIBS="$CORE_LIBS -lexpat" - --CORE_LIBS="$CORE_LIBS -lexpat" -+ HTTP_MODULES="$HTTP_MODULES \ -+ ngx_http_dav_ext_module" -+ -+ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ -+ $ngx_addon_dir/ngx_http_dav_ext_module.c" -+fi diff --git a/debian/modules/patches/http-dav-ext/series b/debian/modules/patches/http-dav-ext/series deleted file mode 100644 index f9b9360..0000000 --- a/debian/modules/patches/http-dav-ext/series +++ /dev/null @@ -1 +0,0 @@ -dynamic-module.patch From ee4b10edd7fc48819c2c5debcbd422af70bcd406 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 13 Dec 2017 11:23:19 +0200 Subject: [PATCH 286/651] http-fancyindex: Upgrade to 0.4.2 --- debian/modules/control | 2 +- debian/modules/http-fancyindex/CHANGELOG.md | 21 ++++++- debian/modules/http-fancyindex/README.rst | 32 ++++++++-- .../ngx_http_fancyindex_module.c | 60 +++++++------------ .../http-fancyindex/t/03-exact_size_off.test | 8 +++ .../t/bug61-empty-file-segfault.test | 16 +++++ debian/modules/http-fancyindex/t/run | 2 +- debian/modules/http-fancyindex/template.h | 25 +++----- debian/modules/http-fancyindex/template.html | 25 +++----- 9 files changed, 110 insertions(+), 81 deletions(-) create mode 100644 debian/modules/http-fancyindex/t/03-exact_size_off.test create mode 100644 debian/modules/http-fancyindex/t/bug61-empty-file-segfault.test diff --git a/debian/modules/control b/debian/modules/control index 6552957..a0aa9ba 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -54,7 +54,7 @@ Version: v0.1.0 Module: http-fancyindex Homepage: https://github.com/aperezdc/ngx-fancyindex -Version: v0.4.1 +Version: v0.4.2 Files-Excluded: .gitignore .travis.yml Module: http-subs-filter diff --git a/debian/modules/http-fancyindex/CHANGELOG.md b/debian/modules/http-fancyindex/CHANGELOG.md index 9d76ae0..6acc50f 100644 --- a/debian/modules/http-fancyindex/CHANGELOG.md +++ b/debian/modules/http-fancyindex/CHANGELOG.md @@ -3,6 +3,24 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +## [0.4.2] - 2017-08-19 +### Changed +- Generated HTML from the default template is now proper HTML5, and it should + pass validation (#52). +- File sizes now have decimal positions when using `fancyindex_exact_size off`. + (Patch by Anders Trier <>.) +- Multiple updates to `README.rst` (Patches by Danila Vershinin + <>, Iulian Onofrei, Lilian Besson, and Nick Geoghegan + <>.) + +### Fixed +- Sorting by file size now also works correctly for directories which contain + files of sizes bigger than `INT_MAX`. (#74, fix suggestion by Chris Young.) +- Custom headers which fail to declare an UTF-8 encoding no longer cause table + header arrows to be rendered incorrectly by browsers (#50). +- Fix segmentation fault when opening directories with empty files (#61, patch + by Catgirl <>.) + ## [0.4.1] - 2016-08-18 ### Added - New `fancyindex_directories_first` configuration directive (enabled by @@ -100,7 +118,8 @@ All notable changes to this project will be documented in this file. - `NEWS.rst` file, to act as change log. -[Unreleased]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.4.1...HEAD +[Unreleased]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.4.2...HEAD +[0.4.2]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.4.1...v0.4.2 [0.4.1]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.4.0...v0.4.1 [0.4.0]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.3.6...v0.4.0 [0.3.6]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.3.5...v0.3.6 diff --git a/debian/modules/http-fancyindex/README.rst b/debian/modules/http-fancyindex/README.rst index 93a8206..0e3273c 100644 --- a/debian/modules/http-fancyindex/README.rst +++ b/debian/modules/http-fancyindex/README.rst @@ -26,7 +26,27 @@ server written by `Igor Sysoev `__. Requirements ============ -You will need the sources for Nginx_. Any version starting from the 0.7 +CentOS 7 +~~~~~~~~ + +For users of the `official stable `__ Nginx repository, `extra packages repository with dynamic modules `__ is available and fancyindex is included. + +Install directly:: + + yum install https://extras.getpagespeed.com/redhat/7/x86_64/RPMS/nginx-module-fancyindex-1.12.0.0.4.1-1.el7.gps.x86_64.rpm + +Alternatively, add extras repository first (for future updates) and install the module:: + + yum install nginx-module-fancyindex + +Then load the module in `/etc/nginx/nginx.conf` using + + load_module "modules/ngx_http_fancyindex_module.so"; + +Other platforms +~~~~~~~~~~~~~~~ + +In most other cases you will need the sources for Nginx_. Any version starting from the 0.7 series onwards will work. Note that the modules *might* compile with versions in the 0.6 series by applying ``nginx-0.6-support.patch``, but this is unsupported (YMMV). @@ -58,7 +78,8 @@ Building Since version 0.4.0, the module can also be built as a `dynamic module `_, - using ``--add-dynamic-module=…`` instead. + using ``--add-dynamic-module=…`` instead and ``load_module "modules/ngx_http_fancyindex_module.so";` + in the configuration file 4. Build and install the software:: @@ -92,10 +113,9 @@ achieved using the module: * `Theme `__ by `@TheInsomniac `__. Uses custom header and footer. -* `Theme `__ by - nwrd `__. Uses custom header and footer, the - header includes search field to filter by filename using JavaScript - (`demo `__). +* `Theme `__ by + `Naereen `__. Uses custom header and footer, the + header includes search field to filter by filename using JavaScript. Directives diff --git a/debian/modules/http-fancyindex/ngx_http_fancyindex_module.c b/debian/modules/http-fancyindex/ngx_http_fancyindex_module.c index 170167d..10331a5 100644 --- a/debian/modules/http-fancyindex/ngx_http_fancyindex_module.c +++ b/debian/modules/http-fancyindex/ngx_http_fancyindex_module.c @@ -190,6 +190,10 @@ static ngx_conf_enum_t ngx_http_fancyindex_sort_criteria[] = { */ #define ngx_sizeof_ssz(_s) (sizeof(_s) - 1) +/** + * Compute the length of a statically allocated array + */ +#define DIM(x) (sizeof(x)/sizeof(*(x))) /** * Copy a static zero-terminated string. Useful to output template @@ -552,16 +556,20 @@ make_content_buf( off_t length; size_t len, root, copy, allocated; - u_char *filename, *last, scale; + int64_t multiplier; + u_char *filename, *last; ngx_tm_t tm; ngx_array_t entries; ngx_time_t *tp; - ngx_uint_t i; - ngx_int_t size; + ngx_uint_t i, j; ngx_str_t path; ngx_dir_t dir; ngx_buf_t *b; + static const char *sizes[] = { "EiB", "PiB", "TiB", "GiB", "MiB", "KiB", "B" }; + static const int64_t exbibyte = 1024LL * 1024LL * 1024LL * + 1024LL * 1024LL * 1024LL; + /* * NGX_DIR_MASK_LEN is lesser than NGX_HTTP_FANCYINDEX_PREALLOCATE */ @@ -982,41 +990,17 @@ make_content_buf( *b->last++ = '-'; } else { length = entry[i].size; + multiplier = exbibyte; - if (length > 1024 * 1024 * 1024 - 1) { - size = (ngx_int_t) (length / (1024 * 1024 * 1024)); - if ((length % (1024 * 1024 * 1024)) - > (1024 * 1024 * 1024 / 2 - 1)) - { - size++; - } - scale = 'G'; + for (j = 0; j < DIM(sizes) - 1 && length < multiplier; j++) + multiplier /= 1024; - } else if (length > 1024 * 1024 - 1) { - size = (ngx_int_t) (length / (1024 * 1024)); - if ((length % (1024 * 1024)) > (1024 * 1024 / 2 - 1)) { - size++; - } - scale = 'M'; - - } else if (length > 9999) { - size = (ngx_int_t) (length / 1024); - if (length % 1024 > 511) { - size++; - } - scale = 'K'; - - } else { - size = (ngx_int_t) length; - scale = '\0'; - } - - if (scale) { - b->last = ngx_sprintf(b->last, "%6i%c", size, scale); - - } else { - b->last = ngx_sprintf(b->last, " %6i", size); - } + /* If we are showing the filesize in bytes, do not show a decimal */ + if (j == DIM(sizes) - 1) + b->last = ngx_sprintf(b->last, "%O %s", length, sizes[j]); + else + b->last = ngx_sprintf(b->last, "%.1f %s", + (float) length / multiplier, sizes[j]); } } @@ -1245,7 +1229,7 @@ ngx_http_fancyindex_cmp_entries_size_desc(const void *one, const void *two) ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; - return (int) (second->size - first->size); + return (first->size > second->size) - (first->size < second->size); } @@ -1275,7 +1259,7 @@ ngx_http_fancyindex_cmp_entries_size_asc(const void *one, const void *two) ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; - return (int) (first->size - second->size); + return (first->size > second->size) - (first->size < second->size); } diff --git a/debian/modules/http-fancyindex/t/03-exact_size_off.test b/debian/modules/http-fancyindex/t/03-exact_size_off.test new file mode 100644 index 0000000..cdc61ec --- /dev/null +++ b/debian/modules/http-fancyindex/t/03-exact_size_off.test @@ -0,0 +1,8 @@ +#! /bin/bash +cat <<--- +We test if the output from using "fancyindex_exact_size off" looks sane +-- +nginx_start 'fancyindex_exact_size off;' +content=$(fetch) +grep -e '[1-9]\.[0-9] KiB' <<< "${content}" +grep -E '[0-9]+ B' <<< "${content}" diff --git a/debian/modules/http-fancyindex/t/bug61-empty-file-segfault.test b/debian/modules/http-fancyindex/t/bug61-empty-file-segfault.test new file mode 100644 index 0000000..d9c5a40 --- /dev/null +++ b/debian/modules/http-fancyindex/t/bug61-empty-file-segfault.test @@ -0,0 +1,16 @@ +#! /bin/bash +cat <<--- +Bug #61: Listing a directory with an empty file crashes Nginx +https://github.com/aperezdc/ngx-fancyindex/issues/61 +-- + +# Prepare an empty directory with an empty file +mkdir -p "${TESTDIR}/bug61" +touch "${TESTDIR}/bug61/bug61.txt" + +nginx_start 'fancyindex_exact_size off;' +content=$(fetch /bug61/) +test -n "${content}" || fail "Empty response" +echo "Response:" +echo "${content}" +nginx_is_running || fail "Nginx died" diff --git a/debian/modules/http-fancyindex/t/run b/debian/modules/http-fancyindex/t/run index 2001bff..dda4c59 100755 --- a/debian/modules/http-fancyindex/t/run +++ b/debian/modules/http-fancyindex/t/run @@ -26,7 +26,7 @@ readonly dynamic declare -a t_pass=( ) declare -a t_fail=( ) -for t in "$T"/*.test ; do +for t in `ls "$T"/*.test | sort -R` ; do name="t/${t##*/}" name=${name%.test} printf "${name} ... " diff --git a/debian/modules/http-fancyindex/template.h b/debian/modules/http-fancyindex/template.h index 4881ac7..e08ba01 100644 --- a/debian/modules/http-fancyindex/template.h +++ b/debian/modules/http-fancyindex/template.h @@ -1,12 +1,10 @@ /* Automagically generated, do not edit! */ static const u_char t01_head1[] = "" -"" -"\n" -"" -"\n" +"" +"" "" -"" -"" +"" +"" " diff --git a/html/index.html b/html/index.html index 2ca3b95..e8f5622 100644 --- a/html/index.html +++ b/html/index.html @@ -3,11 +3,9 @@ Welcome to nginx! diff --git a/src/core/nginx.h b/src/core/nginx.h index 7b873a1..329b603 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1020002 -#define NGINX_VERSION "1.20.2" +#define nginx_version 1022000 +#define NGINX_VERSION "1.22.0" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h index 4b66562..fdcd0cd 100644 --- a/src/core/ngx_buf.h +++ b/src/core/ngx_buf.h @@ -90,9 +90,6 @@ struct ngx_output_chain_ctx_s { #if (NGX_HAVE_FILE_AIO || NGX_COMPAT) ngx_output_chain_aio_pt aio_handler; -#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) - ssize_t (*aio_preload)(ngx_buf_t *file); -#endif #endif #if (NGX_THREADS || NGX_COMPAT) diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 8339e2b..fe729a7 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -495,21 +495,24 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) return NGX_ERROR; } - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, - (const void *) &reuseaddr, sizeof(int)) - == -1) - { - ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - "setsockopt(SO_REUSEADDR) %V failed", - &ls[i].addr_text); + if (ls[i].type != SOCK_DGRAM || !ngx_test_config) { - if (ngx_close_socket(s) == -1) { + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (const void *) &reuseaddr, sizeof(int)) + == -1) + { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - ngx_close_socket_n " %V failed", + "setsockopt(SO_REUSEADDR) %V failed", &ls[i].addr_text); - } - return NGX_ERROR; + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_close_socket_n " %V failed", + &ls[i].addr_text); + } + + return NGX_ERROR; + } } #if (NGX_HAVE_REUSEPORT) diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index 4716da4..8cc1475 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -185,7 +185,7 @@ struct ngx_connection_s { unsigned need_last_buf:1; -#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) +#if (NGX_HAVE_SENDFILE_NODISKIO || NGX_COMPAT) unsigned busy_count:2; #endif diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c index d9c157c..8215c27 100644 --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -274,6 +274,10 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) } for (n = 0; n < nelts; n++) { + if (names[n].key.data == NULL) { + continue; + } + if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *)) { ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, diff --git a/src/core/ngx_module.h b/src/core/ngx_module.h index 8cf3210..6fb4554 100644 --- a/src/core/ngx_module.h +++ b/src/core/ngx_module.h @@ -41,7 +41,7 @@ #define NGX_MODULE_SIGNATURE_3 "0" #endif -#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) +#if (NGX_HAVE_SENDFILE_NODISKIO || NGX_COMPAT) #define NGX_MODULE_SIGNATURE_4 "1" #else #define NGX_MODULE_SIGNATURE_4 "0" diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c index 5c3dbe8..8570742 100644 --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -29,10 +29,6 @@ static ngx_inline ngx_int_t ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf); -#if (NGX_HAVE_AIO_SENDFILE) -static ngx_int_t ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx, - ngx_file_t *file); -#endif static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in); static ngx_int_t ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, @@ -260,10 +256,6 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) } #endif - if (buf->in_file && buf->file->directio) { - return 0; - } - sendfile = ctx->sendfile; #if (NGX_SENDFILE_LIMIT) @@ -272,6 +264,19 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) sendfile = 0; } +#endif + +#if !(NGX_HAVE_SENDFILE_NODISKIO) + + /* + * With DIRECTIO, disable sendfile() unless sendfile(SF_NOCACHE) + * is available. + */ + + if (buf->in_file && buf->file->directio) { + sendfile = 0; + } + #endif if (!sendfile) { @@ -283,12 +288,6 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) buf->in_file = 0; } -#if (NGX_HAVE_AIO_SENDFILE) - if (ctx->aio_preload && buf->in_file) { - (void) ngx_output_chain_aio_setup(ctx, buf->file); - } -#endif - if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) { return 0; } @@ -301,28 +300,6 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) } -#if (NGX_HAVE_AIO_SENDFILE) - -static ngx_int_t -ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx, ngx_file_t *file) -{ - ngx_event_aio_t *aio; - - if (file->aio == NULL && ngx_file_aio_init(file, ctx->pool) != NGX_OK) { - return NGX_ERROR; - } - - aio = file->aio; - - aio->data = ctx->filter_ctx; - aio->preload_handler = ctx->aio_preload; - - return NGX_OK; -} - -#endif - - static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in) @@ -803,6 +780,10 @@ ngx_chain_writer(void *data, ngx_chain_t *in) return NGX_ERROR; } + if (chain && c->write->ready) { + ngx_post_event(c->write, &ngx_posted_next_events); + } + for (cl = ctx->out; cl && cl != chain; /* void */) { ln = cl; cl = cl->next; diff --git a/src/core/ngx_rbtree.h b/src/core/ngx_rbtree.h index 97f0e3e..e8c3582 100644 --- a/src/core/ngx_rbtree.h +++ b/src/core/ngx_rbtree.h @@ -47,6 +47,9 @@ struct ngx_rbtree_s { (tree)->sentinel = s; \ (tree)->insert = i +#define ngx_rbtree_data(node, type, link) \ + (type *) ((u_char *) (node) - offsetof(type, link)) + void ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node); void ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node); diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c index 52169f6..bebf3b6 100644 --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -10,15 +10,22 @@ typedef struct { - ngx_flag_t pcre_jit; + ngx_flag_t pcre_jit; + ngx_list_t *studies; } ngx_regex_conf_t; +static ngx_inline void ngx_regex_malloc_init(ngx_pool_t *pool); +static ngx_inline void ngx_regex_malloc_done(void); + +#if (NGX_PCRE2) +static void * ngx_libc_cdecl ngx_regex_malloc(size_t size, void *data); +static void ngx_libc_cdecl ngx_regex_free(void *p, void *data); +#else 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 void ngx_regex_cleanup(void *data); static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle); @@ -65,32 +72,197 @@ ngx_module_t ngx_regex_module = { }; -static ngx_pool_t *ngx_pcre_pool; -static ngx_list_t *ngx_pcre_studies; +static ngx_pool_t *ngx_regex_pool; +static ngx_list_t *ngx_regex_studies; +static ngx_uint_t ngx_regex_direct_alloc; + +#if (NGX_PCRE2) +static pcre2_compile_context *ngx_regex_compile_context; +static pcre2_match_data *ngx_regex_match_data; +static ngx_uint_t ngx_regex_match_data_size; +#endif void ngx_regex_init(void) { +#if !(NGX_PCRE2) pcre_malloc = ngx_regex_malloc; pcre_free = ngx_regex_free; +#endif } static ngx_inline void ngx_regex_malloc_init(ngx_pool_t *pool) { - ngx_pcre_pool = pool; + ngx_regex_pool = pool; + ngx_regex_direct_alloc = (pool == NULL) ? 1 : 0; } static ngx_inline void ngx_regex_malloc_done(void) { - ngx_pcre_pool = NULL; + ngx_regex_pool = NULL; + ngx_regex_direct_alloc = 0; } +#if (NGX_PCRE2) + +ngx_int_t +ngx_regex_compile(ngx_regex_compile_t *rc) +{ + int n, errcode; + char *p; + u_char errstr[128]; + size_t erroff; + uint32_t options; + pcre2_code *re; + ngx_regex_elt_t *elt; + pcre2_general_context *gctx; + pcre2_compile_context *cctx; + + if (ngx_regex_compile_context == NULL) { + /* + * Allocate a compile context if not yet allocated. This uses + * direct allocations from heap, so the result can be cached + * even at runtime. + */ + + ngx_regex_malloc_init(NULL); + + gctx = pcre2_general_context_create(ngx_regex_malloc, ngx_regex_free, + NULL); + if (gctx == NULL) { + ngx_regex_malloc_done(); + goto nomem; + } + + cctx = pcre2_compile_context_create(gctx); + if (cctx == NULL) { + pcre2_general_context_free(gctx); + ngx_regex_malloc_done(); + goto nomem; + } + + ngx_regex_compile_context = cctx; + + pcre2_general_context_free(gctx); + ngx_regex_malloc_done(); + } + + options = 0; + + if (rc->options & NGX_REGEX_CASELESS) { + options |= PCRE2_CASELESS; + } + + if (rc->options & NGX_REGEX_MULTILINE) { + options |= PCRE2_MULTILINE; + } + + if (rc->options & ~(NGX_REGEX_CASELESS|NGX_REGEX_MULTILINE)) { + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "regex \"%V\" compilation failed: invalid options", + &rc->pattern) + - rc->err.data; + return NGX_ERROR; + } + + ngx_regex_malloc_init(rc->pool); + + re = pcre2_compile(rc->pattern.data, rc->pattern.len, options, + &errcode, &erroff, ngx_regex_compile_context); + + /* ensure that there is no current pool */ + ngx_regex_malloc_done(); + + if (re == NULL) { + pcre2_get_error_message(errcode, errstr, 128); + + if ((size_t) erroff == rc->pattern.len) { + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "pcre2_compile() failed: %s in \"%V\"", + errstr, &rc->pattern) + - rc->err.data; + + } else { + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "pcre2_compile() failed: %s in \"%V\" at \"%s\"", + errstr, &rc->pattern, rc->pattern.data + erroff) + - rc->err.data; + } + + return NGX_ERROR; + } + + rc->regex = re; + + /* do not study at runtime */ + + if (ngx_regex_studies != NULL) { + elt = ngx_list_push(ngx_regex_studies); + if (elt == NULL) { + goto nomem; + } + + elt->regex = rc->regex; + elt->name = rc->pattern.data; + } + + n = pcre2_pattern_info(re, PCRE2_INFO_CAPTURECOUNT, &rc->captures); + if (n < 0) { + p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_CAPTURECOUNT) failed: %d"; + goto failed; + } + + if (rc->captures == 0) { + return NGX_OK; + } + + n = pcre2_pattern_info(re, PCRE2_INFO_NAMECOUNT, &rc->named_captures); + if (n < 0) { + p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMECOUNT) failed: %d"; + goto failed; + } + + if (rc->named_captures == 0) { + return NGX_OK; + } + + n = pcre2_pattern_info(re, PCRE2_INFO_NAMEENTRYSIZE, &rc->name_size); + if (n < 0) { + p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMEENTRYSIZE) failed: %d"; + goto failed; + } + + n = pcre2_pattern_info(re, PCRE2_INFO_NAMETABLE, &rc->names); + if (n < 0) { + p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMETABLE) failed: %d"; + goto failed; + } + + return NGX_OK; + +failed: + + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n) + - rc->err.data; + return NGX_ERROR; + +nomem: + + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "regex \"%V\" compilation failed: no memory", + &rc->pattern) + - rc->err.data; + return NGX_ERROR; +} + +#else + ngx_int_t ngx_regex_compile(ngx_regex_compile_t *rc) { @@ -98,11 +270,30 @@ ngx_regex_compile(ngx_regex_compile_t *rc) char *p; pcre *re; const char *errstr; + ngx_uint_t options; ngx_regex_elt_t *elt; + options = 0; + + if (rc->options & NGX_REGEX_CASELESS) { + options |= PCRE_CASELESS; + } + + if (rc->options & NGX_REGEX_MULTILINE) { + options |= PCRE_MULTILINE; + } + + if (rc->options & ~(NGX_REGEX_CASELESS|NGX_REGEX_MULTILINE)) { + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "regex \"%V\" compilation failed: invalid options", + &rc->pattern) + - rc->err.data; + return NGX_ERROR; + } + ngx_regex_malloc_init(rc->pool); - re = pcre_compile((const char *) rc->pattern.data, (int) rc->options, + re = pcre_compile((const char *) rc->pattern.data, (int) options, &errstr, &erroff, NULL); /* ensure that there is no current pool */ @@ -113,13 +304,13 @@ ngx_regex_compile(ngx_regex_compile_t *rc) rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, "pcre_compile() failed: %s in \"%V\"", errstr, &rc->pattern) - - rc->err.data; + - rc->err.data; } else { rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, "pcre_compile() failed: %s in \"%V\" at \"%s\"", errstr, &rc->pattern, rc->pattern.data + erroff) - - rc->err.data; + - rc->err.data; } return NGX_ERROR; @@ -134,8 +325,8 @@ ngx_regex_compile(ngx_regex_compile_t *rc) /* do not study at runtime */ - if (ngx_pcre_studies != NULL) { - elt = ngx_list_push(ngx_pcre_studies); + if (ngx_regex_studies != NULL) { + elt = ngx_list_push(ngx_regex_studies); if (elt == NULL) { goto nomem; } @@ -193,6 +384,83 @@ nomem: return NGX_ERROR; } +#endif + + +#if (NGX_PCRE2) + +ngx_int_t +ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_uint_t size) +{ + size_t *ov; + ngx_int_t rc; + ngx_uint_t n, i; + + /* + * The pcre2_match() function might allocate memory for backtracking + * frames, typical allocations are from 40k and above. So the allocator + * is configured to do direct allocations from heap during matching. + */ + + ngx_regex_malloc_init(NULL); + + if (ngx_regex_match_data == NULL + || size > ngx_regex_match_data_size) + { + /* + * Allocate a match data if not yet allocated or smaller than + * needed. + */ + + if (ngx_regex_match_data) { + pcre2_match_data_free(ngx_regex_match_data); + } + + ngx_regex_match_data_size = size; + ngx_regex_match_data = pcre2_match_data_create(size / 3, NULL); + + if (ngx_regex_match_data == NULL) { + rc = PCRE2_ERROR_NOMEMORY; + goto failed; + } + } + + rc = pcre2_match(re, s->data, s->len, 0, 0, ngx_regex_match_data, NULL); + + if (rc < 0) { + goto failed; + } + + n = pcre2_get_ovector_count(ngx_regex_match_data); + ov = pcre2_get_ovector_pointer(ngx_regex_match_data); + + if (n > size / 3) { + n = size / 3; + } + + for (i = 0; i < n; i++) { + captures[i * 2] = ov[i * 2]; + captures[i * 2 + 1] = ov[i * 2 + 1]; + } + +failed: + + ngx_regex_malloc_done(); + + return rc; +} + +#else + +ngx_int_t +ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_uint_t size) +{ + return pcre_exec(re->code, re->extra, (const char *) s->data, s->len, + 0, 0, captures, size); +} + +#endif + ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log) @@ -227,14 +495,40 @@ ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log) } +#if (NGX_PCRE2) + +static void * ngx_libc_cdecl +ngx_regex_malloc(size_t size, void *data) +{ + if (ngx_regex_pool) { + return ngx_palloc(ngx_regex_pool, size); + } + + if (ngx_regex_direct_alloc) { + return ngx_alloc(size, ngx_cycle->log); + } + + return NULL; +} + + +static void ngx_libc_cdecl +ngx_regex_free(void *p, void *data) +{ + if (ngx_regex_direct_alloc) { + ngx_free(p); + } + + return; +} + +#else + static void * ngx_libc_cdecl ngx_regex_malloc(size_t size) { - ngx_pool_t *pool; - pool = ngx_pcre_pool; - - if (pool) { - return ngx_palloc(pool, size); + if (ngx_regex_pool) { + return ngx_palloc(ngx_regex_pool, size); } return NULL; @@ -247,19 +541,20 @@ ngx_regex_free(void *p) return; } +#endif -#if (NGX_HAVE_PCRE_JIT) static void -ngx_pcre_free_studies(void *data) +ngx_regex_cleanup(void *data) { - ngx_list_t *studies = data; +#if (NGX_PCRE2 || NGX_HAVE_PCRE_JIT) + ngx_regex_conf_t *rcf = data; ngx_uint_t i; ngx_list_part_t *part; ngx_regex_elt_t *elts; - part = &studies->part; + part = &rcf->studies->part; elts = part->elts; for (i = 0; /* void */ ; i++) { @@ -274,56 +569,83 @@ ngx_pcre_free_studies(void *data) i = 0; } + /* + * 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. In PCRE2, we call the pcre2_code_free() function + * for the same reason. + */ + +#if (NGX_PCRE2) + pcre2_code_free(elts[i].regex); +#else if (elts[i].regex->extra != NULL) { pcre_free_study(elts[i].regex->extra); } +#endif + } +#endif + + /* + * On configuration parsing errors ngx_regex_module_init() will not + * be called. Make sure ngx_regex_studies is properly cleared anyway. + */ + + ngx_regex_studies = NULL; + +#if (NGX_PCRE2) + + /* + * Free compile context and match data. If needed at runtime by + * the new cycle, these will be re-allocated. + */ + + if (ngx_regex_compile_context) { + pcre2_compile_context_free(ngx_regex_compile_context); + ngx_regex_compile_context = NULL; + } + + if (ngx_regex_match_data) { + pcre2_match_data_free(ngx_regex_match_data); + ngx_regex_match_data = NULL; + ngx_regex_match_data_size = 0; } -} #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; + int opt; +#if !(NGX_PCRE2) + const char *errstr; +#endif + ngx_uint_t i; + ngx_list_part_t *part; + ngx_regex_elt_t *elts; + ngx_regex_conf_t *rcf; 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 (NGX_PCRE2 || NGX_HAVE_PCRE_JIT) + if (rcf->pcre_jit) { +#if (NGX_PCRE2) + opt = 1; +#else 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 } + #endif ngx_regex_malloc_init(cycle->pool); - part = &ngx_pcre_studies->part; + part = &rcf->studies->part; elts = part->elts; for (i = 0; /* void */ ; i++) { @@ -338,6 +660,23 @@ ngx_regex_module_init(ngx_cycle_t *cycle) i = 0; } +#if (NGX_PCRE2) + + if (opt) { + int n; + + n = pcre2_jit_compile(elts[i].regex, PCRE2_JIT_COMPLETE); + + if (n != 0) { + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, + "pcre2_jit_compile() failed: %d in \"%s\", " + "ignored", + n, elts[i].name); + } + } + +#else + elts[i].regex->extra = pcre_study(elts[i].regex->code, opt, &errstr); if (errstr != NULL) { @@ -360,12 +699,16 @@ ngx_regex_module_init(ngx_cycle_t *cycle) elts[i].name); } } +#endif #endif } ngx_regex_malloc_done(); - ngx_pcre_studies = NULL; + ngx_regex_studies = NULL; +#if (NGX_PCRE2) + ngx_regex_compile_context = NULL; +#endif return NGX_OK; } @@ -374,7 +717,8 @@ ngx_regex_module_init(ngx_cycle_t *cycle) static void * ngx_regex_create_conf(ngx_cycle_t *cycle) { - ngx_regex_conf_t *rcf; + ngx_regex_conf_t *rcf; + ngx_pool_cleanup_t *cln; rcf = ngx_pcalloc(cycle->pool, sizeof(ngx_regex_conf_t)); if (rcf == NULL) { @@ -383,11 +727,21 @@ ngx_regex_create_conf(ngx_cycle_t *cycle) 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) { + cln = ngx_pool_cleanup_add(cycle->pool, 0); + if (cln == NULL) { return NULL; } + cln->handler = ngx_regex_cleanup; + cln->data = rcf; + + rcf->studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t)); + if (rcf->studies == NULL) { + return NULL; + } + + ngx_regex_studies = rcf->studies; + return rcf; } @@ -412,7 +766,21 @@ ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data) return NGX_CONF_OK; } -#if (NGX_HAVE_PCRE_JIT) +#if (NGX_PCRE2) + { + int r; + uint32_t jit; + + jit = 0; + r = pcre2_config(PCRE2_CONFIG_JIT, &jit); + + if (r != 0 || jit != 1) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "PCRE2 library does not support JIT"); + *fp = 0; + } + } +#elif (NGX_HAVE_PCRE_JIT) { int jit, r; diff --git a/src/core/ngx_regex.h b/src/core/ngx_regex.h index 680486c..182373a 100644 --- a/src/core/ngx_regex.h +++ b/src/core/ngx_regex.h @@ -12,24 +12,38 @@ #include #include + +#if (NGX_PCRE2) + +#define PCRE2_CODE_UNIT_WIDTH 8 +#include + +#define NGX_REGEX_NO_MATCHED PCRE2_ERROR_NOMATCH /* -1 */ + +typedef pcre2_code ngx_regex_t; + +#else + #include - -#define NGX_REGEX_NO_MATCHED PCRE_ERROR_NOMATCH /* -1 */ - -#define NGX_REGEX_CASELESS PCRE_CASELESS - +#define NGX_REGEX_NO_MATCHED PCRE_ERROR_NOMATCH /* -1 */ typedef struct { pcre *code; pcre_extra *extra; } ngx_regex_t; +#endif + + +#define NGX_REGEX_CASELESS 0x00000001 +#define NGX_REGEX_MULTILINE 0x00000002 + typedef struct { ngx_str_t pattern; ngx_pool_t *pool; - ngx_int_t options; + ngx_uint_t options; ngx_regex_t *regex; int captures; @@ -49,10 +63,14 @@ typedef struct { 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->code, re->extra, (const char *) (s)->data, (s)->len, 0, 0, \ - captures, size) -#define ngx_regex_exec_n "pcre_exec()" +ngx_int_t ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, + ngx_uint_t size); + +#if (NGX_PCRE2) +#define ngx_regex_exec_n "pcre2_match()" +#else +#define ngx_regex_exec_n "pcre_exec()" +#endif ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log); diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index 58d5f3e..6d129e5 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -51,9 +51,7 @@ typedef struct { } ngx_resolver_an_t; -#define ngx_resolver_node(n) \ - (ngx_resolver_node_t *) \ - ((u_char *) (n) - offsetof(ngx_resolver_node_t, node)) +#define ngx_resolver_node(n) ngx_rbtree_data(n, ngx_resolver_node_t, node) static ngx_int_t ngx_udp_connect(ngx_resolver_connection_t *rec); diff --git a/src/core/ngx_rwlock.c b/src/core/ngx_rwlock.c index ed2b0f8..e7da8a8 100644 --- a/src/core/ngx_rwlock.c +++ b/src/core/ngx_rwlock.c @@ -89,22 +89,10 @@ ngx_rwlock_rlock(ngx_atomic_t *lock) void ngx_rwlock_unlock(ngx_atomic_t *lock) { - ngx_atomic_uint_t readers; - - readers = *lock; - - if (readers == NGX_RWLOCK_WLOCK) { + if (*lock == NGX_RWLOCK_WLOCK) { (void) ngx_atomic_cmp_set(lock, NGX_RWLOCK_WLOCK, 0); - return; - } - - for ( ;; ) { - - if (ngx_atomic_cmp_set(lock, readers, readers - 1)) { - return; - } - - readers = *lock; + } else { + (void) ngx_atomic_fetch_add(lock, -1); } } diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index 93f32ea..98f270a 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -1493,19 +1493,32 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) uint32_t *escape; static u_char hex[] = "0123456789ABCDEF"; - /* " ", "#", "%", "?", %00-%1F, %7F-%FF */ + /* + * Per RFC 3986 only the following chars are allowed in URIs unescaped: + * + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" + * + * And "%" can appear as a part of escaping itself. The following + * characters are not allowed and need to be escaped: %00-%1F, %7F-%FF, + * " ", """, "<", ">", "\", "^", "`", "{", "|", "}". + */ + + /* " ", "#", "%", "?", not allowed */ static uint32_t uri[] = { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0x80000029, /* 1000 0000 0000 0000 0000 0000 0010 1001 */ + 0xd000002d, /* 1101 0000 0000 0000 0000 0000 0010 1101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -1513,19 +1526,19 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ }; - /* " ", "#", "%", "&", "+", "?", %00-%1F, %7F-%FF */ + /* " ", "#", "%", "&", "+", ";", "?", not allowed */ static uint32_t args[] = { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0x88000869, /* 1000 1000 0000 0000 0000 1000 0110 1001 */ + 0xd800086d, /* 1101 1000 0000 0000 0000 1000 0110 1101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -1553,19 +1566,19 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ }; - /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */ + /* " ", "#", """, "%", "'", not allowed */ static uint32_t html[] = { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0x000000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */ + 0x500000ad, /* 0101 0000 0000 0000 0000 0000 1010 1101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -1573,19 +1586,19 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ }; - /* " ", """, "%", "'", %00-%1F, %7F-%FF */ + /* " ", """, "'", not allowed */ static uint32_t refresh[] = { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */ + 0x50000085, /* 0101 0000 0000 0000 0000 0000 1000 0101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xd8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c index 7964b00..16788c9 100644 --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -200,10 +200,6 @@ ngx_monotonic_time(time_t sec, ngx_uint_t msec) #if defined(CLOCK_MONOTONIC_FAST) clock_gettime(CLOCK_MONOTONIC_FAST, &ts); - -#elif defined(CLOCK_MONOTONIC_COARSE) - clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); - #else clock_gettime(CLOCK_MONOTONIC, &ts); #endif diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index 7777d04..47229b5 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -55,6 +55,7 @@ ngx_uint_t ngx_accept_events; ngx_uint_t ngx_accept_mutex_held; ngx_msec_t ngx_accept_mutex_delay; ngx_int_t ngx_accept_disabled; +ngx_uint_t ngx_use_exclusive_accept; #if (NGX_STAT_STUB) @@ -441,20 +442,23 @@ ngx_event_init_conf(ngx_cycle_t *cycle, void *conf) #if (NGX_HAVE_REUSEPORT) - ls = cycle->listening.elts; - for (i = 0; i < cycle->listening.nelts; i++) { - - if (!ls[i].reuseport || ls[i].worker != 0) { - continue; - } - - if (ngx_clone_listening(cycle, &ls[i]) != NGX_OK) { - return NGX_CONF_ERROR; - } - - /* cloning may change cycle->listening.elts */ + if (!ngx_test_config) { ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + + if (!ls[i].reuseport || ls[i].worker != 0) { + continue; + } + + if (ngx_clone_listening(cycle, &ls[i]) != NGX_OK) { + return NGX_CONF_ERROR; + } + + /* cloning may change cycle->listening.elts */ + + ls = cycle->listening.elts; + } } #endif @@ -641,6 +645,8 @@ ngx_event_process_init(ngx_cycle_t *cycle) #endif + ngx_use_exclusive_accept = 0; + ngx_queue_init(&ngx_posted_accept_events); ngx_queue_init(&ngx_posted_next_events); ngx_queue_init(&ngx_posted_events); @@ -886,6 +892,8 @@ ngx_event_process_init(ngx_cycle_t *cycle) if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ccf->worker_processes > 1) { + ngx_use_exclusive_accept = 1; + if (ngx_add_event(rev, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT) == NGX_ERROR) { diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index 97f9673..548c906 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -147,10 +147,6 @@ struct ngx_event_aio_s { ngx_fd_t fd; -#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) - ssize_t (*preload_handler)(ngx_buf_t *file); -#endif - #if (NGX_HAVE_EVENTFD) int64_t res; #endif @@ -466,6 +462,7 @@ extern ngx_uint_t ngx_accept_events; extern ngx_uint_t ngx_accept_mutex_held; extern ngx_msec_t ngx_accept_mutex_delay; extern ngx_int_t ngx_accept_disabled; +extern ngx_uint_t ngx_use_exclusive_accept; #if (NGX_STAT_STUB) diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index b05666c..2703879 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -11,6 +11,9 @@ static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all); +#if (NGX_HAVE_EPOLLEXCLUSIVE) +static void ngx_reorder_accept_events(ngx_listening_t *ls); +#endif static void ngx_close_accepted_connection(ngx_connection_t *c); @@ -314,6 +317,10 @@ ngx_event_accept(ngx_event_t *ev) } } while (ev->available); + +#if (NGX_HAVE_EPOLLEXCLUSIVE) + ngx_reorder_accept_events(ls); +#endif } @@ -420,6 +427,57 @@ ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all) } +#if (NGX_HAVE_EPOLLEXCLUSIVE) + +static void +ngx_reorder_accept_events(ngx_listening_t *ls) +{ + ngx_connection_t *c; + + /* + * Linux with EPOLLEXCLUSIVE usually notifies only the process which + * was first to add the listening socket to the epoll instance. As + * a result most of the connections are handled by the first worker + * process. To fix this, we re-add the socket periodically, so other + * workers will get a chance to accept connections. + */ + + if (!ngx_use_exclusive_accept) { + return; + } + +#if (NGX_HAVE_REUSEPORT) + + if (ls->reuseport) { + return; + } + +#endif + + c = ls->connection; + + if (c->requests++ % 16 != 0 + && ngx_accept_disabled <= 0) + { + return; + } + + if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT) + == NGX_ERROR) + { + return; + } + + if (ngx_add_event(c->read, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT) + == NGX_ERROR) + { + return; + } +} + +#endif + + static void ngx_close_accepted_connection(ngx_connection_t *c) { diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index ce2a566..1e6fc96 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -47,6 +47,8 @@ static void ngx_ssl_write_handler(ngx_event_t *wev); static ssize_t ngx_ssl_write_early(ngx_connection_t *c, u_char *data, size_t size); #endif +static ssize_t ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, + size_t size); static void ngx_ssl_read_handler(ngx_event_t *rev); static void ngx_ssl_shutdown_handler(ngx_event_t *ev); static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, @@ -299,11 +301,6 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER); #endif -#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING - /* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */ - SSL_CTX_set_options(ssl->ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING); -#endif - #ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG); #endif @@ -863,11 +860,6 @@ ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers, SSL_CTX_set_options(ssl->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } -#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) - /* a temporary 512-bit RSA key is required for export versions of MSIE */ - SSL_CTX_set_tmp_rsa_callback(ssl->ctx, ngx_ssl_rsa512_key_callback); -#endif - return NGX_OK; } @@ -1120,32 +1112,6 @@ ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret) } -#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) - -RSA * -ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, - int key_length) -{ - static RSA *key; - - if (key_length != 512) { - return NULL; - } - -#ifndef OPENSSL_NO_DEPRECATED - - if (key == NULL) { - key = RSA_generate_key(512, RSA_F4, NULL, NULL); - } - -#endif - - return key; -} - -#endif - - ngx_array_t * ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file) { @@ -1417,6 +1383,9 @@ ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) if (SSL_CTX_set0_tmp_dh_pkey(ssl->ctx, dh) != 1) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_set0_tmp_dh_pkey(\%s\") failed", file->data); +#if (OPENSSL_VERSION_NUMBER >= 0x3000001fL) + EVP_PKEY_free(dh); +#endif BIO_free(bio); return NGX_ERROR; } @@ -1798,6 +1767,16 @@ ngx_ssl_handshake(ngx_connection_t *c) #endif #endif +#endif + +#ifdef BIO_get_ktls_send + + if (BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection)) == 1) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "BIO_get_ktls_send(): 1"); + c->ssl->sendfile = 1; + } + #endif rc = ngx_ssl_ocsp_validate(c); @@ -1935,6 +1914,16 @@ ngx_ssl_try_early_data(ngx_connection_t *c) c->read->ready = 1; c->write->ready = 1; +#ifdef BIO_get_ktls_send + + if (BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection)) == 1) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "BIO_get_ktls_send(): 1"); + c->ssl->sendfile = 1; + } + +#endif + rc = ngx_ssl_ocsp_validate(c); if (rc == NGX_ERROR) { @@ -2538,10 +2527,11 @@ ngx_ssl_write_handler(ngx_event_t *wev) ngx_chain_t * ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { - int n; - ngx_uint_t flush; - ssize_t send, size; - ngx_buf_t *buf; + int n; + ngx_uint_t flush; + ssize_t send, size, file_size; + ngx_buf_t *buf; + ngx_chain_t *cl; if (!c->ssl->buffer) { @@ -2615,6 +2605,11 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) continue; } + if (in->buf->in_file && c->ssl->sendfile) { + flush = 1; + break; + } + size = in->buf->last - in->buf->pos; if (size > buf->end - buf->last) { @@ -2646,8 +2641,35 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) size = buf->last - buf->pos; if (size == 0) { + + if (in && in->buf->in_file && send < limit) { + + /* coalesce the neighbouring file bufs */ + + cl = in; + file_size = (size_t) ngx_chain_coalesce_file(&cl, limit - send); + + n = ngx_ssl_sendfile(c, in->buf, file_size); + + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + if (n == NGX_AGAIN) { + break; + } + + in = ngx_chain_update_sent(in, n); + + send += n; + flush = 0; + + continue; + } + buf->flush = 0; c->buffered &= ~NGX_SSL_BUFFERED; + return in; } @@ -2672,7 +2694,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) buf->pos = buf->start; buf->last = buf->start; - if (in == NULL || send == limit) { + if (in == NULL || send >= limit) { break; } } @@ -2803,7 +2825,7 @@ ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size) #ifdef SSL_READ_EARLY_DATA_SUCCESS -ssize_t +static ssize_t ngx_ssl_write_early(ngx_connection_t *c, u_char *data, size_t size) { int n, sslerr; @@ -2918,6 +2940,183 @@ ngx_ssl_write_early(ngx_connection_t *c, u_char *data, size_t size) #endif +static ssize_t +ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size) +{ +#ifdef BIO_get_ktls_send + + int sslerr, flags; + ssize_t n; + ngx_err_t err; + + ngx_ssl_clear_error(c->log); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL to sendfile: @%O %uz", + file->file_pos, size); + + ngx_set_errno(0); + +#if (NGX_HAVE_SENDFILE_NODISKIO) + + flags = (c->busy_count <= 2) ? SF_NODISKIO : 0; + + if (file->file->directio) { + flags |= SF_NOCACHE; + } + +#else + flags = 0; +#endif + + n = SSL_sendfile(c->ssl->connection, file->file->fd, file->file_pos, + size, flags); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_sendfile: %d", n); + + if (n > 0) { + + if (c->ssl->saved_read_handler) { + + c->read->handler = c->ssl->saved_read_handler; + c->ssl->saved_read_handler = NULL; + c->read->ready = 1; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + ngx_post_event(c->read, &ngx_posted_events); + } + +#if (NGX_HAVE_SENDFILE_NODISKIO) + c->busy_count = 0; +#endif + + c->sent += n; + + return n; + } + + if (n == 0) { + + /* + * if sendfile returns zero, then someone has truncated the file, + * so the offset became beyond the end of the file + */ + + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "SSL_sendfile() reported that \"%s\" was truncated at %O", + file->file->name.data, file->file_pos); + + return NGX_ERROR; + } + + sslerr = SSL_get_error(c->ssl->connection, n); + + if (sslerr == SSL_ERROR_ZERO_RETURN) { + + /* + * OpenSSL fails to return SSL_ERROR_SYSCALL if an error + * happens during writing after close_notify alert from the + * peer, and returns SSL_ERROR_ZERO_RETURN instead + */ + + sslerr = SSL_ERROR_SYSCALL; + } + + if (sslerr == SSL_ERROR_SSL + && ERR_GET_REASON(ERR_peek_error()) == SSL_R_UNINITIALIZED + && ngx_errno != 0) + { + /* + * OpenSSL fails to return SSL_ERROR_SYSCALL if an error + * happens in sendfile(), and returns SSL_ERROR_SSL with + * SSL_R_UNINITIALIZED reason instead + */ + + sslerr = SSL_ERROR_SYSCALL; + } + + err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); + + if (sslerr == SSL_ERROR_WANT_WRITE) { + + if (c->ssl->saved_read_handler) { + + c->read->handler = c->ssl->saved_read_handler; + c->ssl->saved_read_handler = NULL; + c->read->ready = 1; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + ngx_post_event(c->read, &ngx_posted_events); + } + +#if (NGX_HAVE_SENDFILE_NODISKIO) + + if (ngx_errno == EBUSY) { + c->busy_count++; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL_sendfile() busy, count:%d", c->busy_count); + + if (c->write->posted) { + ngx_delete_posted_event(c->write); + } + + ngx_post_event(c->write, &ngx_posted_next_events); + } + +#endif + + c->write->ready = 0; + return NGX_AGAIN; + } + + if (sslerr == SSL_ERROR_WANT_READ) { + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL_sendfile: want read"); + + c->read->ready = 0; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + /* + * we do not set the timer because there is already + * the write event timer + */ + + if (c->ssl->saved_read_handler == NULL) { + c->ssl->saved_read_handler = c->read->handler; + c->read->handler = ngx_ssl_read_handler; + } + + return NGX_AGAIN; + } + + c->ssl->no_wait_shutdown = 1; + c->ssl->no_send_shutdown = 1; + c->write->error = 1; + + ngx_ssl_connection_error(c, sslerr, err, "SSL_sendfile() failed"); + +#else + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "SSL_sendfile() not available"); +#endif + + return NGX_ERROR; +} + + static void ngx_ssl_read_handler(ngx_event_t *rev) { @@ -3169,6 +3368,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #endif #ifdef SSL_R_CALLBACK_FAILED || n == SSL_R_CALLBACK_FAILED /* 234 */ +#endif +#ifdef SSL_R_NO_APPLICATION_PROTOCOL + || n == SSL_R_NO_APPLICATION_PROTOCOL /* 235 */ #endif || n == SSL_R_UNEXPECTED_MESSAGE /* 244 */ || n == SSL_R_UNEXPECTED_RECORD /* 245 */ @@ -4249,7 +4451,21 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, return -1; } - return (i == 0) ? 1 : 2 /* renew */; + /* renew if TLSv1.3 */ + +#ifdef TLS1_3_VERSION + if (SSL_version(ssl_conn) == TLS1_3_VERSION) { + return 2; + } +#endif + + /* renew if non-default key */ + + if (i != 0) { + return 2; + } + + return 1; } } @@ -4567,6 +4783,42 @@ ngx_ssl_get_ciphers(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } +ngx_int_t +ngx_ssl_get_curve(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ +#ifdef SSL_get_negotiated_group + + int nid; + + nid = SSL_get_negotiated_group(c->ssl->connection); + + if (nid != NID_undef) { + + if ((nid & TLSEXT_nid_unknown) == 0) { + s->len = ngx_strlen(OBJ_nid2sn(nid)); + s->data = (u_char *) OBJ_nid2sn(nid); + return NGX_OK; + } + + s->len = sizeof("0x0000") - 1; + + s->data = ngx_pnalloc(pool, s->len); + if (s->data == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(s->data, "0x%04xd", nid & 0xffff); + + return NGX_OK; + } + +#endif + + s->len = 0; + return NGX_OK; +} + + ngx_int_t ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { @@ -4734,6 +4986,36 @@ ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } +ngx_int_t +ngx_ssl_get_alpn_protocol(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + + unsigned int len; + const unsigned char *data; + + SSL_get0_alpn_selected(c->ssl->connection, &data, &len); + + if (len > 0) { + + s->data = ngx_pnalloc(pool, len); + if (s->data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(s->data, data, len); + s->len = len; + + return NGX_OK; + } + +#endif + + s->len = 0; + return NGX_OK; +} + + ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 81b87d7..c9e86d9 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -29,7 +29,6 @@ #include #endif #include -#include #include #include @@ -110,6 +109,7 @@ struct ngx_ssl_connection_s { unsigned handshake_rejected:1; unsigned renegotiation:1; unsigned buffer:1; + unsigned sendfile:1; unsigned no_wait_shutdown:1; unsigned no_send_shutdown:1; unsigned shutdown_without_free:1; @@ -208,10 +208,6 @@ ngx_int_t ngx_ssl_ocsp_validate(ngx_connection_t *c); ngx_int_t ngx_ssl_ocsp_get_status(ngx_connection_t *c, const char **s); void ngx_ssl_ocsp_cleanup(ngx_connection_t *c); ngx_int_t ngx_ssl_ocsp_cache_init(ngx_shm_zone_t *shm_zone, void *data); -#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) -RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, - int key_length); -#endif ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file); ngx_array_t *ngx_ssl_preserve_passwords(ngx_conf_t *cf, ngx_array_t *passwords); @@ -260,6 +256,8 @@ ngx_int_t ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_ciphers(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_curve(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, @@ -270,6 +268,8 @@ ngx_int_t ngx_ssl_get_early_data(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_alpn_protocol(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, diff --git a/src/event/ngx_event_timer.c b/src/event/ngx_event_timer.c index 698b88f..35052bc 100644 --- a/src/event/ngx_event_timer.c +++ b/src/event/ngx_event_timer.c @@ -73,7 +73,7 @@ ngx_event_expire_timers(void) return; } - ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer)); + ev = ngx_rbtree_data(node, ngx_event_t, timer); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, "event timer del: %d: %M", @@ -113,7 +113,7 @@ ngx_event_no_timers_left(void) node; node = ngx_rbtree_next(&ngx_event_timer_rbtree, node)) { - ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer)); + ev = ngx_rbtree_data(node, ngx_event_t, timer); if (!ev->cancelable) { return NGX_AGAIN; diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c index ed9df34..0693319 100644 --- a/src/http/modules/ngx_http_auth_basic_module.c +++ b/src/http/modules/ngx_http_auth_basic_module.c @@ -16,7 +16,7 @@ typedef struct { ngx_http_complex_value_t *realm; - ngx_http_complex_value_t user_file; + ngx_http_complex_value_t *user_file; } ngx_http_auth_basic_loc_conf_t; @@ -107,7 +107,7 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r) alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_basic_module); - if (alcf->realm == NULL || alcf->user_file.value.data == NULL) { + if (alcf->realm == NULL || alcf->user_file == NULL) { return NGX_DECLINED; } @@ -133,7 +133,7 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (ngx_http_complex_value(r, &alcf->user_file, &user_file) != NGX_OK) { + if (ngx_http_complex_value(r, alcf->user_file, &user_file) != NGX_OK) { return NGX_ERROR; } @@ -357,6 +357,9 @@ ngx_http_auth_basic_create_loc_conf(ngx_conf_t *cf) return NULL; } + conf->realm = NGX_CONF_UNSET_PTR; + conf->user_file = NGX_CONF_UNSET_PTR; + return conf; } @@ -367,13 +370,8 @@ ngx_http_auth_basic_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_auth_basic_loc_conf_t *prev = parent; ngx_http_auth_basic_loc_conf_t *conf = child; - if (conf->realm == NULL) { - conf->realm = prev->realm; - } - - if (conf->user_file.value.data == NULL) { - conf->user_file = prev->user_file; - } + ngx_conf_merge_ptr_value(conf->realm, prev->realm, NULL); + ngx_conf_merge_ptr_value(conf->user_file, prev->user_file, NULL); return NGX_CONF_OK; } @@ -406,17 +404,22 @@ ngx_http_auth_basic_user_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; ngx_http_compile_complex_value_t ccv; - if (alcf->user_file.value.data) { + if (alcf->user_file != NGX_CONF_UNSET_PTR) { return "is duplicate"; } + alcf->user_file = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); + if (alcf->user_file == NULL) { + return NGX_CONF_ERROR; + } + value = cf->args->elts; ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); ccv.cf = cf; ccv.value = &value[1]; - ccv.complex_value = &alcf->user_file; + ccv.complex_value = alcf->user_file; ccv.zero = 1; ccv.conf_prefix = 1; diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c index 8b69e6f..0cc9ae1 100644 --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -1072,6 +1072,10 @@ ngx_http_dav_error(ngx_log_t *log, ngx_err_t err, ngx_int_t not_found, static ngx_int_t ngx_http_dav_location(ngx_http_request_t *r) { + u_char *p; + size_t len; + uintptr_t escape; + r->headers_out.location = ngx_list_push(&r->headers_out.headers); if (r->headers_out.location == NULL) { return NGX_ERROR; @@ -1079,7 +1083,26 @@ ngx_http_dav_location(ngx_http_request_t *r) r->headers_out.location->hash = 1; ngx_str_set(&r->headers_out.location->key, "Location"); - r->headers_out.location->value = r->uri; + + escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, NGX_ESCAPE_URI); + + if (escape) { + len = r->uri.len + escape; + + p = ngx_pnalloc(r->pool, len); + if (p == NULL) { + ngx_http_clear_location(r); + return NGX_ERROR; + } + + r->headers_out.location->value.len = len; + r->headers_out.location->value.data = p; + + ngx_escape_uri(p, r->uri.data, r->uri.len, NGX_ESCAPE_URI); + + } else { + r->headers_out.location->value = r->uri; + } return NGX_OK; } diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 5191880..4a8dc33 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -2019,10 +2019,12 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) break; } - /* there was error while a header line parsing */ + /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent invalid header"); + "upstream sent invalid header: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c index 27a36e8..864fc4f 100644 --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -37,9 +37,6 @@ typedef struct { ngx_uint_t ssl_verify_depth; ngx_str_t ssl_trusted_certificate; ngx_str_t ssl_crl; - ngx_str_t ssl_certificate; - ngx_str_t ssl_certificate_key; - ngx_array_t *ssl_passwords; ngx_array_t *ssl_conf_commands; #endif } ngx_http_grpc_loc_conf_t; @@ -426,16 +423,16 @@ static ngx_command_t ngx_http_grpc_commands[] = { { ngx_string("grpc_ssl_certificate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_grpc_loc_conf_t, ssl_certificate), + offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_certificate), NULL }, { ngx_string("grpc_ssl_certificate_key"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_grpc_loc_conf_t, ssl_certificate_key), + offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_certificate_key), NULL }, { ngx_string("grpc_ssl_password_file"), @@ -2180,6 +2177,8 @@ ngx_http_grpc_filter(void *data, ssize_t bytes) } ctx->rst = 1; + + continue; } if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) { @@ -3181,10 +3180,10 @@ ngx_http_grpc_parse_fragment(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, ctx->field_rest -= size; if (ctx->field_huffman) { - if (ngx_http_v2_huff_decode(&ctx->field_state, p, size, - &ctx->field_end, - ctx->field_rest == 0, - r->connection->log) + if (ngx_http_huff_decode(&ctx->field_state, p, size, + &ctx->field_end, + ctx->field_rest == 0, + r->connection->log) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, @@ -3290,10 +3289,10 @@ ngx_http_grpc_parse_fragment(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, ctx->field_rest -= size; if (ctx->field_huffman) { - if (ngx_http_v2_huff_decode(&ctx->field_state, p, size, - &ctx->field_end, - ctx->field_rest == 0, - r->connection->log) + if (ngx_http_huff_decode(&ctx->field_state, p, size, + &ctx->field_end, + ctx->field_rest == 0, + r->connection->log) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, @@ -3385,7 +3384,7 @@ ngx_http_grpc_validate_header_name(ngx_http_request_t *r, ngx_str_t *s) return NGX_ERROR; } - if (ch == '\0' || ch == CR || ch == LF) { + if (ch <= 0x20 || ch == 0x7f) { return NGX_ERROR; } } @@ -3487,6 +3486,8 @@ ngx_http_grpc_parse_rst_stream(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, return NGX_AGAIN; } + ctx->state = ngx_http_grpc_st_start; + return NGX_OK; } @@ -4340,7 +4341,6 @@ ngx_http_grpc_create_loc_conf(ngx_conf_t *cf) * conf->upstream.ignore_headers = 0; * conf->upstream.next_upstream = 0; * conf->upstream.hide_headers_hash = { NULL, 0 }; - * conf->upstream.ssl_name = NULL; * * conf->headers.lengths = NULL; * conf->headers.values = NULL; @@ -4352,8 +4352,6 @@ ngx_http_grpc_create_loc_conf(ngx_conf_t *cf) * conf->ssl_ciphers = { 0, NULL }; * conf->ssl_trusted_certificate = { 0, NULL }; * conf->ssl_crl = { 0, NULL }; - * conf->ssl_certificate = { 0, NULL }; - * conf->ssl_certificate_key = { 0, NULL }; */ conf->upstream.local = NGX_CONF_UNSET_PTR; @@ -4373,10 +4371,13 @@ ngx_http_grpc_create_loc_conf(ngx_conf_t *cf) #if (NGX_HTTP_SSL) conf->upstream.ssl_session_reuse = NGX_CONF_UNSET; + conf->upstream.ssl_name = NGX_CONF_UNSET_PTR; conf->upstream.ssl_server_name = NGX_CONF_UNSET; conf->upstream.ssl_verify = NGX_CONF_UNSET; conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; - conf->ssl_passwords = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_certificate = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_certificate_key = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_passwords = NGX_CONF_UNSET_PTR; conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif @@ -4468,10 +4469,8 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); - if (conf->upstream.ssl_name == NULL) { - conf->upstream.ssl_name = prev->upstream.ssl_name; - } - + ngx_conf_merge_ptr_value(conf->upstream.ssl_name, + prev->upstream.ssl_name, NULL); ngx_conf_merge_value(conf->upstream.ssl_server_name, prev->upstream.ssl_server_name, 0); ngx_conf_merge_value(conf->upstream.ssl_verify, @@ -4482,11 +4481,12 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->ssl_trusted_certificate, ""); ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); - ngx_conf_merge_str_value(conf->ssl_certificate, - prev->ssl_certificate, ""); - ngx_conf_merge_str_value(conf->ssl_certificate_key, - prev->ssl_certificate_key, ""); - ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate, + prev->upstream.ssl_certificate, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key, + prev->upstream.ssl_certificate_key, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords, + prev->upstream.ssl_passwords, NULL); ngx_conf_merge_ptr_value(conf->ssl_conf_commands, prev->ssl_conf_commands, NULL); @@ -4842,15 +4842,15 @@ ngx_http_grpc_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; - if (glcf->ssl_passwords != NGX_CONF_UNSET_PTR) { + if (glcf->upstream.ssl_passwords != NGX_CONF_UNSET_PTR) { return "is duplicate"; } value = cf->args->elts; - glcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); + glcf->upstream.ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); - if (glcf->ssl_passwords == NULL) { + if (glcf->upstream.ssl_passwords == NULL) { return NGX_CONF_ERROR; } @@ -4896,29 +4896,43 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf) cln->handler = ngx_ssl_cleanup_ctx; cln->data = glcf->upstream.ssl; - if (glcf->ssl_certificate.len) { - - if (glcf->ssl_certificate_key.len == 0) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"grpc_ssl_certificate_key\" is defined " - "for certificate \"%V\"", &glcf->ssl_certificate); - return NGX_ERROR; - } - - if (ngx_ssl_certificate(cf, glcf->upstream.ssl, &glcf->ssl_certificate, - &glcf->ssl_certificate_key, glcf->ssl_passwords) - != NGX_OK) - { - return NGX_ERROR; - } - } - if (ngx_ssl_ciphers(cf, glcf->upstream.ssl, &glcf->ssl_ciphers, 0) != NGX_OK) { return NGX_ERROR; } + if (glcf->upstream.ssl_certificate) { + + if (glcf->upstream.ssl_certificate_key == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"grpc_ssl_certificate_key\" is defined " + "for certificate \"%V\"", + &glcf->upstream.ssl_certificate->value); + return NGX_ERROR; + } + + if (glcf->upstream.ssl_certificate->lengths + || glcf->upstream.ssl_certificate_key->lengths) + { + glcf->upstream.ssl_passwords = + ngx_ssl_preserve_passwords(cf, glcf->upstream.ssl_passwords); + if (glcf->upstream.ssl_passwords == NULL) { + return NGX_ERROR; + } + + } else { + if (ngx_ssl_certificate(cf, glcf->upstream.ssl, + &glcf->upstream.ssl_certificate->value, + &glcf->upstream.ssl_certificate_key->value, + glcf->upstream.ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + } + } + if (glcf->upstream.ssl_verify) { if (glcf->ssl_trusted_certificate.len == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index 0e93fbd..9c3f627 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -11,31 +11,33 @@ #define NGX_HTTP_MP4_TRAK_ATOM 0 #define NGX_HTTP_MP4_TKHD_ATOM 1 -#define NGX_HTTP_MP4_MDIA_ATOM 2 -#define NGX_HTTP_MP4_MDHD_ATOM 3 -#define NGX_HTTP_MP4_HDLR_ATOM 4 -#define NGX_HTTP_MP4_MINF_ATOM 5 -#define NGX_HTTP_MP4_VMHD_ATOM 6 -#define NGX_HTTP_MP4_SMHD_ATOM 7 -#define NGX_HTTP_MP4_DINF_ATOM 8 -#define NGX_HTTP_MP4_STBL_ATOM 9 -#define NGX_HTTP_MP4_STSD_ATOM 10 -#define NGX_HTTP_MP4_STTS_ATOM 11 -#define NGX_HTTP_MP4_STTS_DATA 12 -#define NGX_HTTP_MP4_STSS_ATOM 13 -#define NGX_HTTP_MP4_STSS_DATA 14 -#define NGX_HTTP_MP4_CTTS_ATOM 15 -#define NGX_HTTP_MP4_CTTS_DATA 16 -#define NGX_HTTP_MP4_STSC_ATOM 17 -#define NGX_HTTP_MP4_STSC_START 18 -#define NGX_HTTP_MP4_STSC_DATA 19 -#define NGX_HTTP_MP4_STSC_END 20 -#define NGX_HTTP_MP4_STSZ_ATOM 21 -#define NGX_HTTP_MP4_STSZ_DATA 22 -#define NGX_HTTP_MP4_STCO_ATOM 23 -#define NGX_HTTP_MP4_STCO_DATA 24 -#define NGX_HTTP_MP4_CO64_ATOM 25 -#define NGX_HTTP_MP4_CO64_DATA 26 +#define NGX_HTTP_MP4_EDTS_ATOM 2 +#define NGX_HTTP_MP4_ELST_ATOM 3 +#define NGX_HTTP_MP4_MDIA_ATOM 4 +#define NGX_HTTP_MP4_MDHD_ATOM 5 +#define NGX_HTTP_MP4_HDLR_ATOM 6 +#define NGX_HTTP_MP4_MINF_ATOM 7 +#define NGX_HTTP_MP4_VMHD_ATOM 8 +#define NGX_HTTP_MP4_SMHD_ATOM 9 +#define NGX_HTTP_MP4_DINF_ATOM 10 +#define NGX_HTTP_MP4_STBL_ATOM 11 +#define NGX_HTTP_MP4_STSD_ATOM 12 +#define NGX_HTTP_MP4_STTS_ATOM 13 +#define NGX_HTTP_MP4_STTS_DATA 14 +#define NGX_HTTP_MP4_STSS_ATOM 15 +#define NGX_HTTP_MP4_STSS_DATA 16 +#define NGX_HTTP_MP4_CTTS_ATOM 17 +#define NGX_HTTP_MP4_CTTS_DATA 18 +#define NGX_HTTP_MP4_STSC_ATOM 19 +#define NGX_HTTP_MP4_STSC_START 20 +#define NGX_HTTP_MP4_STSC_DATA 21 +#define NGX_HTTP_MP4_STSC_END 22 +#define NGX_HTTP_MP4_STSZ_ATOM 23 +#define NGX_HTTP_MP4_STSZ_DATA 24 +#define NGX_HTTP_MP4_STCO_ATOM 25 +#define NGX_HTTP_MP4_STCO_DATA 26 +#define NGX_HTTP_MP4_CO64_ATOM 27 +#define NGX_HTTP_MP4_CO64_DATA 28 #define NGX_HTTP_MP4_LAST_ATOM NGX_HTTP_MP4_CO64_DATA @@ -43,6 +45,7 @@ typedef struct { size_t buffer_size; size_t max_buffer_size; + ngx_flag_t start_key_frame; } ngx_http_mp4_conf_t; @@ -53,6 +56,25 @@ typedef struct { } ngx_mp4_stsc_entry_t; +typedef struct { + u_char size[4]; + u_char name[4]; +} ngx_mp4_edts_atom_t; + + +typedef struct { + u_char size[4]; + u_char name[4]; + u_char version[1]; + u_char flags[3]; + u_char entries[4]; + u_char duration[8]; + u_char media_time[8]; + u_char media_rate[2]; + u_char reserved[2]; +} ngx_mp4_elst_atom_t; + + typedef struct { uint32_t timescale; uint32_t time_to_sample_entries; @@ -70,6 +92,9 @@ typedef struct { ngx_uint_t end_chunk_samples; uint64_t start_chunk_samples_size; uint64_t end_chunk_samples_size; + uint64_t duration; + uint64_t prefix; + uint64_t movie_duration; off_t start_offset; off_t end_offset; @@ -85,6 +110,8 @@ typedef struct { ngx_buf_t trak_atom_buf; ngx_buf_t tkhd_atom_buf; + ngx_buf_t edts_atom_buf; + ngx_buf_t elst_atom_buf; ngx_buf_t mdia_atom_buf; ngx_buf_t mdhd_atom_buf; ngx_buf_t hdlr_atom_buf; @@ -111,6 +138,8 @@ typedef struct { ngx_buf_t co64_atom_buf; ngx_buf_t co64_data_buf; + ngx_mp4_edts_atom_t edts_atom; + ngx_mp4_elst_atom_t elst_atom; ngx_mp4_stsc_entry_t stsc_start_chunk_entry; ngx_mp4_stsc_entry_t stsc_end_chunk_entry; } ngx_http_mp4_trak_t; @@ -186,6 +215,14 @@ typedef struct { ((u_char *) (p))[6] = n3; \ ((u_char *) (p))[7] = n4 +#define ngx_mp4_get_16value(p) \ + ( ((uint16_t) ((u_char *) (p))[0] << 8) \ + + ( ((u_char *) (p))[1]) ) + +#define ngx_mp4_set_16value(p, n) \ + ((u_char *) (p))[0] = (u_char) ((n) >> 8); \ + ((u_char *) (p))[1] = (u_char) (n) + #define ngx_mp4_get_32value(p) \ ( ((uint32_t) ((u_char *) (p))[0] << 24) \ + ( ((u_char *) (p))[1] << 16) \ @@ -253,6 +290,8 @@ static void ngx_http_mp4_update_mdia_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); +static void ngx_http_mp4_update_mdhd_atom(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_read_hdlr_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_read_minf_atom(ngx_http_mp4_file_t *mp4, @@ -267,6 +306,8 @@ static ngx_int_t ngx_http_mp4_read_smhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_read_stbl_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); +static void ngx_http_mp4_update_edts_atom(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak); static void ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_read_stsd_atom(ngx_http_mp4_file_t *mp4, @@ -277,6 +318,8 @@ static ngx_int_t ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak, ngx_uint_t start); +static uint32_t ngx_http_mp4_seek_key_frame(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak, uint32_t start_sample); static ngx_int_t ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4, @@ -340,6 +383,13 @@ static ngx_command_t ngx_http_mp4_commands[] = { offsetof(ngx_http_mp4_conf_t, max_buffer_size), NULL }, + { ngx_string("mp4_start_key_frame"), + 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_mp4_conf_t, start_key_frame), + NULL }, + ngx_null_command }; @@ -822,10 +872,11 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) ngx_http_mp4_update_stbl_atom(mp4, &trak[i]); ngx_http_mp4_update_minf_atom(mp4, &trak[i]); - trak[i].size += trak[i].mdhd_size; + ngx_http_mp4_update_mdhd_atom(mp4, &trak[i]); trak[i].size += trak[i].hdlr_size; ngx_http_mp4_update_mdia_atom(mp4, &trak[i]); trak[i].size += trak[i].tkhd_size; + ngx_http_mp4_update_edts_atom(mp4, &trak[i]); ngx_http_mp4_update_trak_atom(mp4, &trak[i]); mp4->moov_size += trak[i].size; @@ -1587,6 +1638,7 @@ ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) trak = ngx_mp4_last_trak(mp4); trak->tkhd_size = atom_size; + trak->movie_duration = duration; ngx_mp4_set_32value(tkhd_atom->size, atom_size); @@ -1749,16 +1801,10 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) trak = ngx_mp4_last_trak(mp4); trak->mdhd_size = atom_size; trak->timescale = timescale; + trak->duration = duration; ngx_mp4_set_32value(mdhd_atom->size, atom_size); - if (mdhd_atom->version[0] == 0) { - ngx_mp4_set_32value(mdhd_atom->duration, duration); - - } else { - ngx_mp4_set_64value(mdhd64_atom->duration, duration); - } - atom = &trak->mdhd_atom_buf; atom->temporary = 1; atom->pos = atom_header; @@ -1772,6 +1818,33 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) } +static void +ngx_http_mp4_update_mdhd_atom(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak) +{ + ngx_buf_t *atom; + ngx_mp4_mdhd_atom_t *mdhd_atom; + ngx_mp4_mdhd64_atom_t *mdhd64_atom; + + atom = trak->out[NGX_HTTP_MP4_MDHD_ATOM].buf; + if (atom == NULL) { + return; + } + + mdhd_atom = (ngx_mp4_mdhd_atom_t *) atom->pos; + mdhd64_atom = (ngx_mp4_mdhd64_atom_t *) atom->pos; + + if (mdhd_atom->version[0] == 0) { + ngx_mp4_set_32value(mdhd_atom->duration, trak->duration); + + } else { + ngx_mp4_set_64value(mdhd64_atom->duration, trak->duration); + } + + trak->size += trak->mdhd_size; +} + + static ngx_int_t ngx_http_mp4_read_hdlr_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) { @@ -1961,6 +2034,59 @@ ngx_http_mp4_read_stbl_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) } +static void +ngx_http_mp4_update_edts_atom(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak) +{ + ngx_buf_t *atom; + ngx_mp4_elst_atom_t *elst_atom; + ngx_mp4_edts_atom_t *edts_atom; + + if (trak->prefix == 0) { + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 edts atom update prefix:%uL", trak->prefix); + + edts_atom = &trak->edts_atom; + ngx_mp4_set_32value(edts_atom->size, sizeof(ngx_mp4_edts_atom_t) + + sizeof(ngx_mp4_elst_atom_t)); + ngx_mp4_set_atom_name(edts_atom, 'e', 'd', 't', 's'); + + atom = &trak->edts_atom_buf; + atom->temporary = 1; + atom->pos = (u_char *) edts_atom; + atom->last = (u_char *) edts_atom + sizeof(ngx_mp4_edts_atom_t); + + trak->out[NGX_HTTP_MP4_EDTS_ATOM].buf = atom; + + elst_atom = &trak->elst_atom; + ngx_mp4_set_32value(elst_atom->size, sizeof(ngx_mp4_elst_atom_t)); + ngx_mp4_set_atom_name(elst_atom, 'e', 'l', 's', 't'); + + elst_atom->version[0] = 1; + elst_atom->flags[0] = 0; + elst_atom->flags[1] = 0; + elst_atom->flags[2] = 0; + + ngx_mp4_set_32value(elst_atom->entries, 1); + ngx_mp4_set_64value(elst_atom->duration, trak->movie_duration); + ngx_mp4_set_64value(elst_atom->media_time, trak->prefix); + ngx_mp4_set_16value(elst_atom->media_rate, 1); + ngx_mp4_set_16value(elst_atom->reserved, 0); + + atom = &trak->elst_atom_buf; + atom->temporary = 1; + atom->pos = (u_char *) elst_atom; + atom->last = (u_char *) elst_atom + sizeof(ngx_mp4_elst_atom_t); + + trak->out[NGX_HTTP_MP4_ELST_ATOM].buf = atom; + + trak->size += sizeof(ngx_mp4_edts_atom_t) + sizeof(ngx_mp4_elst_atom_t); +} + + static void ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak) @@ -2159,7 +2285,7 @@ static ngx_int_t ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak, ngx_uint_t start) { - uint32_t count, duration, rest; + uint32_t count, duration, rest, key_prefix; uint64_t start_time; ngx_buf_t *data; ngx_uint_t start_sample, entries, start_sec; @@ -2183,7 +2309,7 @@ ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf; - start_time = (uint64_t) start_sec * trak->timescale / 1000; + start_time = (uint64_t) start_sec * trak->timescale / 1000 + trak->prefix; entries = trak->time_to_sample_entries; start_sample = 0; @@ -2229,6 +2355,26 @@ ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, found: if (start) { + key_prefix = ngx_http_mp4_seek_key_frame(mp4, trak, start_sample); + + start_sample -= key_prefix; + + while (rest < key_prefix) { + trak->prefix += rest * duration; + key_prefix -= rest; + + entry--; + entries++; + + count = ngx_mp4_get_32value(entry->count); + duration = ngx_mp4_get_32value(entry->duration); + rest = count; + } + + trak->prefix += key_prefix * duration; + trak->duration += trak->prefix; + rest -= key_prefix; + ngx_mp4_set_32value(entry->count, count - rest); data->pos = (u_char *) entry; trak->time_to_sample_entries = entries; @@ -2253,6 +2399,49 @@ found: } +static uint32_t +ngx_http_mp4_seek_key_frame(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak, + uint32_t start_sample) +{ + uint32_t key_prefix, sample, *entry, *end; + ngx_buf_t *data; + ngx_http_mp4_conf_t *conf; + + conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module); + if (!conf->start_key_frame) { + return 0; + } + + data = trak->out[NGX_HTTP_MP4_STSS_DATA].buf; + if (data == NULL) { + return 0; + } + + entry = (uint32_t *) data->pos; + end = (uint32_t *) data->last; + + /* sync samples starts from 1 */ + start_sample++; + + key_prefix = 0; + + while (entry < end) { + sample = ngx_mp4_get_32value(entry); + if (sample > start_sample) { + break; + } + + key_prefix = start_sample - sample; + entry++; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 key frame prefix:%uD", key_prefix); + + return key_prefix; +} + + typedef struct { u_char size[4]; u_char name[4]; @@ -3590,6 +3779,7 @@ ngx_http_mp4_create_conf(ngx_conf_t *cf) conf->buffer_size = NGX_CONF_UNSET_SIZE; conf->max_buffer_size = NGX_CONF_UNSET_SIZE; + conf->start_key_frame = NGX_CONF_UNSET; return conf; } @@ -3604,6 +3794,7 @@ ngx_http_mp4_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 512 * 1024); ngx_conf_merge_size_value(conf->max_buffer_size, prev->max_buffer_size, 10 * 1024 * 1024); + ngx_conf_merge_value(conf->start_key_frame, prev->start_key_frame, 0); return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index a63c3ed..7c4061c 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -124,9 +124,6 @@ typedef struct { ngx_uint_t ssl_verify_depth; ngx_str_t ssl_trusted_certificate; ngx_str_t ssl_crl; - ngx_str_t ssl_certificate; - ngx_str_t ssl_certificate_key; - ngx_array_t *ssl_passwords; ngx_array_t *ssl_conf_commands; #endif } ngx_http_proxy_loc_conf_t; @@ -753,16 +750,16 @@ static ngx_command_t ngx_http_proxy_commands[] = { { ngx_string("proxy_ssl_certificate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate), + offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_certificate), NULL }, { ngx_string("proxy_ssl_certificate_key"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate_key), + offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_certificate_key), NULL }, { ngx_string("proxy_ssl_password_file"), @@ -1189,7 +1186,7 @@ ngx_http_proxy_create_key(ngx_http_request_t *r) loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0; - if (r->quoted_uri || r->space_in_uri || r->internal) { + if (r->quoted_uri || r->internal) { escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, r->uri.len - loc_len, NGX_ESCAPE_URI); } else { @@ -1302,7 +1299,7 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0; - if (r->quoted_uri || r->space_in_uri || r->internal) { + if (r->quoted_uri || r->internal) { escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, r->uri.len - loc_len, NGX_ESCAPE_URI); } @@ -2022,10 +2019,12 @@ ngx_http_proxy_process_header(ngx_http_request_t *r) return NGX_AGAIN; } - /* there was error while a header line parsing */ + /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent invalid header"); + "upstream sent invalid header: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } @@ -2338,6 +2337,7 @@ ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes) ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "upstream sent more data than specified in " "\"Content-Length\" header"); + u->keepalive = 0; return NGX_OK; } @@ -3327,9 +3327,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) * conf->upstream.hide_headers_hash = { NULL, 0 }; * conf->upstream.store_lengths = NULL; * conf->upstream.store_values = NULL; - * conf->upstream.ssl_name = NULL; * - * conf->method = NULL; * conf->location = NULL; * conf->url = { 0, NULL }; * conf->headers.lengths = NULL; @@ -3347,8 +3345,6 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) * conf->ssl_ciphers = { 0, NULL }; * conf->ssl_trusted_certificate = { 0, NULL }; * conf->ssl_crl = { 0, NULL }; - * conf->ssl_certificate = { 0, NULL }; - * conf->ssl_certificate_key = { 0, NULL }; */ conf->upstream.store = NGX_CONF_UNSET; @@ -3400,20 +3396,26 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) #if (NGX_HTTP_SSL) conf->upstream.ssl_session_reuse = NGX_CONF_UNSET; + conf->upstream.ssl_name = NGX_CONF_UNSET_PTR; conf->upstream.ssl_server_name = NGX_CONF_UNSET; conf->upstream.ssl_verify = NGX_CONF_UNSET; + conf->upstream.ssl_certificate = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_certificate_key = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_passwords = NGX_CONF_UNSET_PTR; conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; - conf->ssl_passwords = NGX_CONF_UNSET_PTR; conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif /* "proxy_cyclic_temp_file" is disabled */ conf->upstream.cyclic_temp_file = 0; + conf->upstream.change_buffering = 1; + conf->headers_source = NGX_CONF_UNSET_PTR; + conf->method = NGX_CONF_UNSET_PTR; + conf->redirect = NGX_CONF_UNSET; - conf->upstream.change_buffering = 1; conf->cookie_domains = NGX_CONF_UNSET_PTR; conf->cookie_paths = NGX_CONF_UNSET_PTR; @@ -3708,10 +3710,6 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #endif - if (conf->method == NULL) { - conf->method = prev->method; - } - ngx_conf_merge_value(conf->upstream.pass_request_headers, prev->upstream.pass_request_headers, 1); ngx_conf_merge_value(conf->upstream.pass_request_body, @@ -3732,10 +3730,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); - if (conf->upstream.ssl_name == NULL) { - conf->upstream.ssl_name = prev->upstream.ssl_name; - } - + ngx_conf_merge_ptr_value(conf->upstream.ssl_name, + prev->upstream.ssl_name, NULL); ngx_conf_merge_value(conf->upstream.ssl_server_name, prev->upstream.ssl_server_name, 0); ngx_conf_merge_value(conf->upstream.ssl_verify, @@ -3746,11 +3742,12 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->ssl_trusted_certificate, ""); ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); - ngx_conf_merge_str_value(conf->ssl_certificate, - prev->ssl_certificate, ""); - ngx_conf_merge_str_value(conf->ssl_certificate_key, - prev->ssl_certificate_key, ""); - ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate, + prev->upstream.ssl_certificate, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key, + prev->upstream.ssl_certificate_key, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords, + prev->upstream.ssl_passwords, NULL); ngx_conf_merge_ptr_value(conf->ssl_conf_commands, prev->ssl_conf_commands, NULL); @@ -3761,6 +3758,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #endif + ngx_conf_merge_ptr_value(conf->method, prev->method, NULL); + ngx_conf_merge_value(conf->redirect, prev->redirect, 1); if (conf->redirect) { @@ -4859,15 +4858,15 @@ ngx_http_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; - if (plcf->ssl_passwords != NGX_CONF_UNSET_PTR) { + if (plcf->upstream.ssl_passwords != NGX_CONF_UNSET_PTR) { return "is duplicate"; } value = cf->args->elts; - plcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); + plcf->upstream.ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); - if (plcf->ssl_passwords == NULL) { + if (plcf->upstream.ssl_passwords == NULL) { return NGX_CONF_ERROR; } @@ -4946,29 +4945,43 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) cln->handler = ngx_ssl_cleanup_ctx; cln->data = plcf->upstream.ssl; - if (plcf->ssl_certificate.len) { - - if (plcf->ssl_certificate_key.len == 0) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"proxy_ssl_certificate_key\" is defined " - "for certificate \"%V\"", &plcf->ssl_certificate); - return NGX_ERROR; - } - - if (ngx_ssl_certificate(cf, plcf->upstream.ssl, &plcf->ssl_certificate, - &plcf->ssl_certificate_key, plcf->ssl_passwords) - != NGX_OK) - { - return NGX_ERROR; - } - } - if (ngx_ssl_ciphers(cf, plcf->upstream.ssl, &plcf->ssl_ciphers, 0) != NGX_OK) { return NGX_ERROR; } + if (plcf->upstream.ssl_certificate) { + + if (plcf->upstream.ssl_certificate_key == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"proxy_ssl_certificate_key\" is defined " + "for certificate \"%V\"", + &plcf->upstream.ssl_certificate->value); + return NGX_ERROR; + } + + if (plcf->upstream.ssl_certificate->lengths + || plcf->upstream.ssl_certificate_key->lengths) + { + plcf->upstream.ssl_passwords = + ngx_ssl_preserve_passwords(cf, plcf->upstream.ssl_passwords); + if (plcf->upstream.ssl_passwords == NULL) { + return NGX_ERROR; + } + + } else { + if (ngx_ssl_certificate(cf, plcf->upstream.ssl, + &plcf->upstream.ssl_certificate->value, + &plcf->upstream.ssl_certificate_key->value, + plcf->upstream.ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + } + } + if (plcf->upstream.ssl_verify) { if (plcf->ssl_trusted_certificate.len == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index 600999c..e5d31ae 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -1140,10 +1140,12 @@ ngx_http_scgi_process_header(ngx_http_request_t *r) return NGX_AGAIN; } - /* there was error while a header line parsing */ + /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent invalid header"); + "upstream sent invalid header: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } diff --git a/src/http/modules/ngx_http_secure_link_module.c b/src/http/modules/ngx_http_secure_link_module.c index 536e09a..4d4ce6a 100644 --- a/src/http/modules/ngx_http_secure_link_module.c +++ b/src/http/modules/ngx_http_secure_link_module.c @@ -302,11 +302,12 @@ ngx_http_secure_link_create_conf(ngx_conf_t *cf) /* * set by ngx_pcalloc(): * - * conf->variable = NULL; - * conf->md5 = NULL; * conf->secret = { 0, NULL }; */ + conf->variable = NGX_CONF_UNSET_PTR; + conf->md5 = NGX_CONF_UNSET_PTR; + return conf; } @@ -318,6 +319,9 @@ ngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_secure_link_conf_t *conf = child; if (conf->secret.data) { + ngx_conf_init_ptr_value(conf->variable, NULL); + ngx_conf_init_ptr_value(conf->md5, NULL); + if (conf->variable || conf->md5) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"secure_link_secret\" cannot be mixed with " @@ -328,13 +332,8 @@ ngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_OK; } - if (conf->variable == NULL) { - conf->variable = prev->variable; - } - - if (conf->md5 == NULL) { - conf->md5 = prev->md5; - } + ngx_conf_merge_ptr_value(conf->variable, prev->variable, NULL); + ngx_conf_merge_ptr_value(conf->md5, prev->md5, NULL); if (conf->variable == NULL && conf->md5 == NULL) { conf->secret = prev->secret; diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index a47d696..d74d460 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -17,7 +17,7 @@ typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c, #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" #define NGX_DEFAULT_ECDH_CURVE "auto" -#define NGX_HTTP_NPN_ADVERTISE "\x08http/1.1" +#define NGX_HTTP_ALPN_PROTOS "\x08http/1.1\x08http/1.0\x08http/0.9" #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation @@ -26,11 +26,6 @@ static int ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char *in, unsigned int inlen, void *arg); #endif -#ifdef TLSEXT_TYPE_next_proto_neg -static int ngx_http_ssl_npn_advertised(ngx_ssl_conn_t *ssl_conn, - const unsigned char **out, unsigned int *outlen, void *arg); -#endif - static ngx_int_t ngx_http_ssl_static_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_ssl_variable(ngx_http_request_t *r, @@ -347,6 +342,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_ciphers"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_ciphers, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_curve"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_curve, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_curves"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_curves, NGX_HTTP_VAR_CHANGEABLE, 0 }, @@ -363,6 +361,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_server_name"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_server_name, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_alpn_protocol"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_alpn_protocol, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_cert"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 }, @@ -444,22 +445,20 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, hc = c->data; if (hc->addr_conf->http2) { - srv = - (unsigned char *) NGX_HTTP_V2_ALPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE; - srvlen = sizeof(NGX_HTTP_V2_ALPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1; - + srv = (unsigned char *) NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS; + srvlen = sizeof(NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS) - 1; } else #endif { - srv = (unsigned char *) NGX_HTTP_NPN_ADVERTISE; - srvlen = sizeof(NGX_HTTP_NPN_ADVERTISE) - 1; + srv = (unsigned char *) NGX_HTTP_ALPN_PROTOS; + srvlen = sizeof(NGX_HTTP_ALPN_PROTOS) - 1; } if (SSL_select_next_proto((unsigned char **) out, outlen, srv, srvlen, in, inlen) != OPENSSL_NPN_NEGOTIATED) { - return SSL_TLSEXT_ERR_NOACK; + return SSL_TLSEXT_ERR_ALERT_FATAL; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, @@ -471,44 +470,6 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, #endif -#ifdef TLSEXT_TYPE_next_proto_neg - -static int -ngx_http_ssl_npn_advertised(ngx_ssl_conn_t *ssl_conn, - const unsigned char **out, unsigned int *outlen, void *arg) -{ -#if (NGX_HTTP_V2 || NGX_DEBUG) - ngx_connection_t *c; - - c = ngx_ssl_get_connection(ssl_conn); - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "SSL NPN advertised"); -#endif - -#if (NGX_HTTP_V2) - { - ngx_http_connection_t *hc; - - hc = c->data; - - if (hc->addr_conf->http2) { - *out = - (unsigned char *) NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE; - *outlen = sizeof(NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1; - - return SSL_TLSEXT_ERR_OK; - } - } -#endif - - *out = (unsigned char *) NGX_HTTP_NPN_ADVERTISE; - *outlen = sizeof(NGX_HTTP_NPN_ADVERTISE) - 1; - - return SSL_TLSEXT_ERR_OK; -} - -#endif - - static ngx_int_t ngx_http_ssl_static_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) @@ -792,10 +753,12 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_http_ssl_alpn_select, NULL); #endif -#ifdef TLSEXT_TYPE_next_proto_neg - SSL_CTX_set_next_protos_advertised_cb(conf->ssl.ctx, - ngx_http_ssl_npn_advertised, NULL); -#endif + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, + conf->prefer_server_ciphers) + != NGX_OK) + { + return NGX_CONF_ERROR; + } if (ngx_http_ssl_compile_certificates(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; @@ -829,13 +792,6 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) } } - if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, - conf->prefer_server_ciphers) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - conf->ssl.buffer_size = conf->buffer_size; if (conf->verify) { diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c index 282d6ee..cf29d5a 100644 --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -50,6 +50,7 @@ ngx_http_static_handler(ngx_http_request_t *r) { u_char *last, *location; size_t root, len; + uintptr_t escape; ngx_str_t path; ngx_int_t rc; ngx_uint_t level; @@ -155,14 +156,18 @@ ngx_http_static_handler(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - len = r->uri.len + 1; + escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, + NGX_ESCAPE_URI); - if (!clcf->alias && r->args.len == 0) { + if (!clcf->alias && r->args.len == 0 && escape == 0) { + len = r->uri.len + 1; location = path.data + root; *last = '/'; } else { + len = r->uri.len + escape + 1; + if (r->args.len) { len += r->args.len + 1; } @@ -173,7 +178,13 @@ ngx_http_static_handler(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - last = ngx_copy(location, r->uri.data, r->uri.len); + if (escape) { + last = (u_char *) ngx_escape_uri(location, r->uri.data, + r->uri.len, NGX_ESCAPE_URI); + + } else { + last = ngx_copy(location, r->uri.data, r->uri.len); + } *last = '/'; diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index 1334f44..d46741a 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -54,9 +54,6 @@ typedef struct { ngx_uint_t ssl_verify_depth; ngx_str_t ssl_trusted_certificate; ngx_str_t ssl_crl; - ngx_str_t ssl_certificate; - ngx_str_t ssl_certificate_key; - ngx_array_t *ssl_passwords; ngx_array_t *ssl_conf_commands; #endif } ngx_http_uwsgi_loc_conf_t; @@ -548,16 +545,16 @@ static ngx_command_t ngx_http_uwsgi_commands[] = { { ngx_string("uwsgi_ssl_certificate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate), + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_certificate), NULL }, { ngx_string("uwsgi_ssl_certificate_key"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate_key), + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_certificate_key), NULL }, { ngx_string("uwsgi_ssl_password_file"), @@ -1364,10 +1361,12 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r) return NGX_AGAIN; } - /* there was error while a header line parsing */ + /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent invalid header"); + "upstream sent invalid header: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } @@ -1509,10 +1508,13 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf) #if (NGX_HTTP_SSL) conf->upstream.ssl_session_reuse = NGX_CONF_UNSET; + conf->upstream.ssl_name = NGX_CONF_UNSET_PTR; conf->upstream.ssl_server_name = NGX_CONF_UNSET; conf->upstream.ssl_verify = NGX_CONF_UNSET; conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; - conf->ssl_passwords = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_certificate = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_certificate_key = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_passwords = NGX_CONF_UNSET_PTR; conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif @@ -1824,10 +1826,8 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); - if (conf->upstream.ssl_name == NULL) { - conf->upstream.ssl_name = prev->upstream.ssl_name; - } - + ngx_conf_merge_ptr_value(conf->upstream.ssl_name, + prev->upstream.ssl_name, NULL); ngx_conf_merge_value(conf->upstream.ssl_server_name, prev->upstream.ssl_server_name, 0); ngx_conf_merge_value(conf->upstream.ssl_verify, @@ -1838,11 +1838,12 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->ssl_trusted_certificate, ""); ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); - ngx_conf_merge_str_value(conf->ssl_certificate, - prev->ssl_certificate, ""); - ngx_conf_merge_str_value(conf->ssl_certificate_key, - prev->ssl_certificate_key, ""); - ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate, + prev->upstream.ssl_certificate, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key, + prev->upstream.ssl_certificate_key, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords, + prev->upstream.ssl_passwords, NULL); ngx_conf_merge_ptr_value(conf->ssl_conf_commands, prev->ssl_conf_commands, NULL); @@ -2377,15 +2378,15 @@ ngx_http_uwsgi_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; - if (uwcf->ssl_passwords != NGX_CONF_UNSET_PTR) { + if (uwcf->upstream.ssl_passwords != NGX_CONF_UNSET_PTR) { return "is duplicate"; } value = cf->args->elts; - uwcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); + uwcf->upstream.ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); - if (uwcf->ssl_passwords == NULL) { + if (uwcf->upstream.ssl_passwords == NULL) { return NGX_CONF_ERROR; } @@ -2431,29 +2432,43 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf) cln->handler = ngx_ssl_cleanup_ctx; cln->data = uwcf->upstream.ssl; - if (uwcf->ssl_certificate.len) { - - if (uwcf->ssl_certificate_key.len == 0) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"uwsgi_ssl_certificate_key\" is defined " - "for certificate \"%V\"", &uwcf->ssl_certificate); - return NGX_ERROR; - } - - if (ngx_ssl_certificate(cf, uwcf->upstream.ssl, &uwcf->ssl_certificate, - &uwcf->ssl_certificate_key, uwcf->ssl_passwords) - != NGX_OK) - { - return NGX_ERROR; - } - } - if (ngx_ssl_ciphers(cf, uwcf->upstream.ssl, &uwcf->ssl_ciphers, 0) != NGX_OK) { return NGX_ERROR; } + if (uwcf->upstream.ssl_certificate) { + + if (uwcf->upstream.ssl_certificate_key == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"uwsgi_ssl_certificate_key\" is defined " + "for certificate \"%V\"", + &uwcf->upstream.ssl_certificate->value); + return NGX_ERROR; + } + + if (uwcf->upstream.ssl_certificate->lengths + || uwcf->upstream.ssl_certificate_key->lengths) + { + uwcf->upstream.ssl_passwords = + ngx_ssl_preserve_passwords(cf, uwcf->upstream.ssl_passwords); + if (uwcf->upstream.ssl_passwords == NULL) { + return NGX_ERROR; + } + + } else { + if (ngx_ssl_certificate(cf, uwcf->upstream.ssl, + &uwcf->upstream.ssl_certificate->value, + &uwcf->upstream.ssl_certificate_key->value, + uwcf->upstream.ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + } + } + if (uwcf->upstream.ssl_verify) { if (uwcf->ssl_trusted_certificate.len == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index e1d3d00..73c08d5 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -37,6 +37,8 @@ static ngx_int_t ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, ngx_http_core_loc_conf_t *pclcf); static ngx_int_t ngx_http_init_static_location_trees(ngx_conf_t *cf, ngx_http_core_loc_conf_t *pclcf); +static ngx_int_t ngx_http_escape_location_name(ngx_conf_t *cf, + ngx_http_core_loc_conf_t *clcf); static ngx_int_t ngx_http_cmp_locations(const ngx_queue_t *one, const ngx_queue_t *two); static ngx_int_t ngx_http_join_exact_locations(ngx_conf_t *cf, @@ -882,6 +884,41 @@ ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations, ngx_queue_insert_tail(*locations, &lq->queue); + if (ngx_http_escape_location_name(cf, clcf) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_escape_location_name(ngx_conf_t *cf, ngx_http_core_loc_conf_t *clcf) +{ + u_char *p; + size_t len; + uintptr_t escape; + + escape = 2 * ngx_escape_uri(NULL, clcf->name.data, clcf->name.len, + NGX_ESCAPE_URI); + + if (escape) { + len = clcf->name.len + escape; + + p = ngx_pnalloc(cf->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + clcf->escaped_name.len = len; + clcf->escaped_name.data = p; + + ngx_escape_uri(p, clcf->name.data, clcf->name.len, NGX_ESCAPE_URI); + + } else { + clcf->escaped_name = clcf->name; + } + return NGX_OK; } @@ -1301,13 +1338,12 @@ ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, } #if (NGX_HTTP_V2 && NGX_HTTP_SSL \ - && !defined TLSEXT_TYPE_application_layer_protocol_negotiation \ - && !defined TLSEXT_TYPE_next_proto_neg) + && !defined TLSEXT_TYPE_application_layer_protocol_negotiation) if (lsopt->http2 && lsopt->ssl) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "nginx was built with OpenSSL that lacks ALPN " - "and NPN support, HTTP/2 is not enabled for %V", + "support, HTTP/2 is not enabled for %V", &lsopt->addr_text); } diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index 8b43857..be8b7cd 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -167,6 +167,14 @@ ngx_uint_t ngx_http_degraded(ngx_http_request_t *); #endif +#if (NGX_HTTP_V2) +ngx_int_t ngx_http_huff_decode(u_char *state, u_char *src, size_t len, + u_char **dst, ngx_uint_t last, ngx_log_t *log); +size_t ngx_http_huff_encode(u_char *src, size_t len, u_char *dst, + ngx_uint_t lower); +#endif + + extern ngx_module_t ngx_http_module; extern ngx_str_t ngx_http_html_default_types[]; diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c index c8ad5da..bd3028b 100644 --- a/src/http/ngx_http_copy_filter_module.c +++ b/src/http/ngx_http_copy_filter_module.c @@ -19,10 +19,6 @@ typedef struct { static void ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx, ngx_file_t *file); static void ngx_http_copy_aio_event_handler(ngx_event_t *ev); -#if (NGX_HAVE_AIO_SENDFILE) -static ssize_t ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file); -static void ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev); -#endif #endif #if (NGX_THREADS) static ngx_int_t ngx_http_copy_thread_handler(ngx_thread_task_t *task, @@ -128,9 +124,6 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) #if (NGX_HAVE_FILE_AIO) if (ngx_file_aio && clcf->aio == NGX_HTTP_AIO_ON) { ctx->aio_handler = ngx_http_copy_aio_handler; -#if (NGX_HAVE_AIO_SENDFILE) - ctx->aio_preload = ngx_http_copy_aio_sendfile_preload; -#endif } #endif @@ -207,53 +200,6 @@ ngx_http_copy_aio_event_handler(ngx_event_t *ev) ngx_http_run_posted_requests(c); } - -#if (NGX_HAVE_AIO_SENDFILE) - -static ssize_t -ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file) -{ - ssize_t n; - static u_char buf[1]; - ngx_event_aio_t *aio; - ngx_http_request_t *r; - ngx_output_chain_ctx_t *ctx; - - n = ngx_file_aio_read(file->file, buf, 1, file->file_pos, NULL); - - if (n == NGX_AGAIN) { - aio = file->file->aio; - aio->handler = ngx_http_copy_aio_sendfile_event_handler; - - r = aio->data; - r->main->blocked++; - r->aio = 1; - - ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); - ctx->aio = 1; - } - - return n; -} - - -static void -ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev) -{ - ngx_event_aio_t *aio; - ngx_http_request_t *r; - - aio = ev->data; - r = aio->data; - - r->main->blocked--; - r->aio = 0; - ev->complete = 0; - - r->connection->write->handler(r->connection->write); -} - -#endif #endif @@ -263,6 +209,7 @@ static ngx_int_t ngx_http_copy_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) { ngx_str_t name; + ngx_connection_t *c; ngx_thread_pool_t *tp; ngx_http_request_t *r; ngx_output_chain_ctx_t *ctx; @@ -270,6 +217,27 @@ ngx_http_copy_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) r = file->thread_ctx; + if (r->aio) { + /* + * tolerate sendfile() calls if another operation is already + * running; this can happen due to subrequests, multiple calls + * of the next body filter from a filter, or in HTTP/2 due to + * a write event on the main connection + */ + + c = r->connection; + +#if (NGX_HTTP_V2) + if (r->stream) { + c = r->stream->connection->connection; + } +#endif + + if (task == c->sendfile_task) { + return NGX_OK; + } + } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); tp = clcf->thread_pool; @@ -323,6 +291,20 @@ ngx_http_copy_thread_event_handler(ngx_event_t *ev) r->main->blocked--; r->aio = 0; +#if (NGX_HTTP_V2) + + if (r->stream) { + /* + * for HTTP/2, update write event to make sure processing will + * reach the main connection to handle sendfile() in threads + */ + + c->write->ready = 1; + c->write->active = 0; + } + +#endif + if (r->done) { /* * trigger connection event handler if the subrequest was diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 6664fa6..c7463dc 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -1010,10 +1010,10 @@ ngx_http_core_find_config_phase(ngx_http_request_t *r, ngx_str_set(&r->headers_out.location->key, "Location"); if (r->args.len == 0) { - r->headers_out.location->value = clcf->name; + r->headers_out.location->value = clcf->escaped_name; } else { - len = clcf->name.len + 1 + r->args.len; + len = clcf->escaped_name.len + 1 + r->args.len; p = ngx_pnalloc(r->pool, len); if (p == NULL) { @@ -1025,7 +1025,7 @@ ngx_http_core_find_config_phase(ngx_http_request_t *r, r->headers_out.location->value.len = len; r->headers_out.location->value.data = p; - p = ngx_cpymem(p, clcf->name.data, clcf->name.len); + p = ngx_cpymem(p, clcf->escaped_name.data, clcf->escaped_name.len); *p++ = '?'; ngx_memcpy(p, r->args.data, r->args.len); } @@ -3467,6 +3467,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf) /* * set by ngx_pcalloc(): * + * clcf->escaped_name = { 0, NULL }; * clcf->root = { 0, NULL }; * clcf->limit_except = 0; * clcf->post_action = { 0, NULL }; @@ -3479,8 +3480,6 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf) * clcf->exact_match = 0; * clcf->auto_redirect = 0; * clcf->alias = 0; - * clcf->limit_rate = NULL; - * clcf->limit_rate_after = NULL; * clcf->gzip_proxied = 0; * clcf->keepalive_disable = 0; */ @@ -3512,6 +3511,8 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf) clcf->send_timeout = NGX_CONF_UNSET_MSEC; clcf->send_lowat = NGX_CONF_UNSET_SIZE; clcf->postpone_output = NGX_CONF_UNSET_SIZE; + clcf->limit_rate = NGX_CONF_UNSET_PTR; + clcf->limit_rate_after = NGX_CONF_UNSET_PTR; clcf->keepalive_time = NGX_CONF_UNSET_MSEC; clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC; clcf->keepalive_header = NGX_CONF_UNSET; @@ -3719,7 +3720,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->internal, prev->internal, 0); ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0); ngx_conf_merge_size_value(conf->sendfile_max_chunk, - prev->sendfile_max_chunk, 0); + prev->sendfile_max_chunk, 2 * 1024 * 1024); ngx_conf_merge_size_value(conf->subrequest_output_buffer_size, prev->subrequest_output_buffer_size, (size_t) ngx_pagesize); @@ -3743,13 +3744,9 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output, 1460); - if (conf->limit_rate == NULL) { - conf->limit_rate = prev->limit_rate; - } - - if (conf->limit_rate_after == NULL) { - conf->limit_rate_after = prev->limit_rate_after; - } + ngx_conf_merge_ptr_value(conf->limit_rate, prev->limit_rate, NULL); + ngx_conf_merge_ptr_value(conf->limit_rate_after, + prev->limit_rate_after, NULL); ngx_conf_merge_msec_value(conf->keepalive_time, prev->keepalive_time, 3600000); @@ -4571,19 +4568,6 @@ ngx_http_core_set_aio(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } -#if (NGX_HAVE_AIO_SENDFILE) - - if (ngx_strcmp(value[1].data, "sendfile") == 0) { - clcf->aio = NGX_HTTP_AIO_ON; - - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "the \"sendfile\" parameter of " - "the \"aio\" directive is deprecated"); - return NGX_CONF_OK; - } - -#endif - if (ngx_strncmp(value[1].data, "threads", 7) == 0 && (value[1].len == 7 || value[1].data[7] == '=')) { diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 2341fd4..004a98e 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -299,6 +299,7 @@ typedef struct { struct ngx_http_core_loc_conf_s { ngx_str_t name; /* location name */ + ngx_str_t escaped_name; #if (NGX_PCRE) ngx_http_regex_t *regex; @@ -501,8 +502,8 @@ ngx_int_t ngx_http_gzip_ok(ngx_http_request_t *r); ngx_int_t ngx_http_subrequest(ngx_http_request_t *r, - ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **sr, - ngx_http_post_subrequest_t *psr, ngx_uint_t flags); + ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr, + ngx_http_post_subrequest_t *ps, ngx_uint_t flags); ngx_int_t ngx_http_internal_redirect(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args); ngx_int_t ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name); diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c index 9b89405..76f6e96 100644 --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -197,6 +197,10 @@ ngx_http_header_filter(ngx_http_request_t *r) } } + if (r->keepalive && (ngx_terminate || ngx_exiting)) { + r->keepalive = 0; + } + len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1 /* the end of the header */ + sizeof(CRLF) - 1; diff --git a/src/http/v2/ngx_http_v2_huff_decode.c b/src/http/ngx_http_huff_decode.c similarity index 99% rename from src/http/v2/ngx_http_v2_huff_decode.c rename to src/http/ngx_http_huff_decode.c index 49ca576..14b7b78 100644 --- a/src/http/v2/ngx_http_v2_huff_decode.c +++ b/src/http/ngx_http_huff_decode.c @@ -15,14 +15,14 @@ typedef struct { u_char emit; u_char sym; u_char ending; -} ngx_http_v2_huff_decode_code_t; +} ngx_http_huff_decode_code_t; -static ngx_inline ngx_int_t ngx_http_v2_huff_decode_bits(u_char *state, +static ngx_inline ngx_int_t ngx_http_huff_decode_bits(u_char *state, u_char *ending, ngx_uint_t bits, u_char **dst); -static ngx_http_v2_huff_decode_code_t ngx_http_v2_huff_decode_codes[256][16] = +static ngx_http_huff_decode_code_t ngx_http_huff_decode_codes[256][16] = { /* 0 */ { @@ -2640,7 +2640,7 @@ static ngx_http_v2_huff_decode_code_t ngx_http_v2_huff_decode_codes[256][16] = ngx_int_t -ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, +ngx_http_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, ngx_uint_t last, ngx_log_t *log) { u_char *end, ch, ending; @@ -2653,7 +2653,7 @@ ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, while (src != end) { ch = *src++; - if (ngx_http_v2_huff_decode_bits(state, &ending, ch >> 4, dst) + if (ngx_http_huff_decode_bits(state, &ending, ch >> 4, dst) != NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, @@ -2663,7 +2663,7 @@ ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, return NGX_ERROR; } - if (ngx_http_v2_huff_decode_bits(state, &ending, ch & 0xf, dst) + if (ngx_http_huff_decode_bits(state, &ending, ch & 0xf, dst) != NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, @@ -2692,12 +2692,12 @@ ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, static ngx_inline ngx_int_t -ngx_http_v2_huff_decode_bits(u_char *state, u_char *ending, ngx_uint_t bits, +ngx_http_huff_decode_bits(u_char *state, u_char *ending, ngx_uint_t bits, u_char **dst) { - ngx_http_v2_huff_decode_code_t code; + ngx_http_huff_decode_code_t code; - code = ngx_http_v2_huff_decode_codes[*state][bits]; + code = ngx_http_huff_decode_codes[*state][bits]; if (code.next == *state) { return NGX_ERROR; diff --git a/src/http/v2/ngx_http_v2_huff_encode.c b/src/http/ngx_http_huff_encode.c similarity index 93% rename from src/http/v2/ngx_http_v2_huff_encode.c rename to src/http/ngx_http_huff_encode.c index 3f822cd..c03b153 100644 --- a/src/http/v2/ngx_http_v2_huff_encode.c +++ b/src/http/ngx_http_huff_encode.c @@ -14,10 +14,10 @@ typedef struct { uint32_t code; uint32_t len; -} ngx_http_v2_huff_encode_code_t; +} ngx_http_huff_encode_code_t; -static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table[256] = +static ngx_http_huff_encode_code_t ngx_http_huff_encode_table[256] = { {0x00001ff8, 13}, {0x007fffd8, 23}, {0x0fffffe2, 28}, {0x0fffffe3, 28}, {0x0fffffe4, 28}, {0x0fffffe5, 28}, {0x0fffffe6, 28}, {0x0fffffe7, 28}, @@ -87,7 +87,7 @@ static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table[256] = /* same as above, but embeds lowercase transformation */ -static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table_lc[256] = +static ngx_http_huff_encode_code_t ngx_http_huff_encode_table_lc[256] = { {0x00001ff8, 13}, {0x007fffd8, 23}, {0x0fffffe2, 28}, {0x0fffffe3, 28}, {0x0fffffe4, 28}, {0x0fffffe5, 28}, {0x0fffffe6, 28}, {0x0fffffe7, 28}, @@ -161,10 +161,10 @@ static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table_lc[256] = #if (NGX_HAVE_LITTLE_ENDIAN) #if (NGX_HAVE_GCC_BSWAP64) -#define ngx_http_v2_huff_encode_buf(dst, buf) \ +#define ngx_http_huff_encode_buf(dst, buf) \ (*(uint64_t *) (dst) = __builtin_bswap64(buf)) #else -#define ngx_http_v2_huff_encode_buf(dst, buf) \ +#define ngx_http_huff_encode_buf(dst, buf) \ ((dst)[0] = (u_char) ((buf) >> 56), \ (dst)[1] = (u_char) ((buf) >> 48), \ (dst)[2] = (u_char) ((buf) >> 40), \ @@ -176,28 +176,28 @@ static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table_lc[256] = #endif #else /* !NGX_HAVE_LITTLE_ENDIAN */ -#define ngx_http_v2_huff_encode_buf(dst, buf) \ +#define ngx_http_huff_encode_buf(dst, buf) \ (*(uint64_t *) (dst) = (buf)) #endif #else /* NGX_PTR_SIZE == 4 */ -#define ngx_http_v2_huff_encode_buf(dst, buf) \ +#define ngx_http_huff_encode_buf(dst, buf) \ (*(uint32_t *) (dst) = htonl(buf)) #endif size_t -ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst, ngx_uint_t lower) +ngx_http_huff_encode(u_char *src, size_t len, u_char *dst, ngx_uint_t lower) { - u_char *end; - size_t hlen; - ngx_uint_t buf, pending, code; - ngx_http_v2_huff_encode_code_t *table, *next; + u_char *end; + size_t hlen; + ngx_uint_t buf, pending, code; + ngx_http_huff_encode_code_t *table, *next; - table = lower ? ngx_http_v2_huff_encode_table_lc - : ngx_http_v2_huff_encode_table; + table = lower ? ngx_http_huff_encode_table_lc + : ngx_http_huff_encode_table; hlen = 0; buf = 0; pending = 0; @@ -224,7 +224,7 @@ ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst, ngx_uint_t lower) buf |= code >> pending; - ngx_http_v2_huff_encode_buf(&dst[hlen], buf); + ngx_http_huff_encode_buf(&dst[hlen], buf); hlen += sizeof(buf); diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index 20ad89a..6460da2 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -11,7 +11,7 @@ static uint32_t usual[] = { - 0xffffdbfe, /* 1111 1111 1111 1111 1101 1011 1111 1110 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ 0x7fff37d6, /* 0111 1111 1111 1111 0011 0111 1101 0110 */ @@ -24,7 +24,7 @@ static uint32_t usual[] = { #endif /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0x7fffffff, /* 0111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -116,10 +116,8 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) sw_host_end, sw_host_ip_literal, sw_port, - sw_host_http_09, sw_after_slash_in_uri, sw_check_uri, - sw_check_uri_http_09, sw_uri, sw_http_09, sw_http_H, @@ -246,6 +244,11 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) r->method = NGX_HTTP_OPTIONS; } + if (ngx_str7_cmp(m, 'C', 'O', 'N', 'N', 'E', 'C', 'T', ' ')) + { + r->method = NGX_HTTP_CONNECT; + } + break; case 8: @@ -393,7 +396,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) */ r->uri_start = r->schema_end + 1; r->uri_end = r->schema_end + 2; - state = sw_host_http_09; + state = sw_http_09; break; default: return NGX_HTTP_PARSE_INVALID_REQUEST; @@ -467,35 +470,13 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) */ r->uri_start = r->schema_end + 1; r->uri_end = r->schema_end + 2; - state = sw_host_http_09; + state = sw_http_09; break; default: return NGX_HTTP_PARSE_INVALID_REQUEST; } break; - /* space+ after "http://host[:port] " */ - case sw_host_http_09: - switch (ch) { - case ' ': - break; - case CR: - r->http_minor = 9; - state = sw_almost_done; - break; - case LF: - r->http_minor = 9; - goto done; - case 'H': - r->http_protocol.data = p; - state = sw_http_H; - break; - default: - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - /* check "/.", "//", "%", and "\" (Win32) in URI */ case sw_after_slash_in_uri: @@ -507,7 +488,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) switch (ch) { case ' ': r->uri_end = p; - state = sw_check_uri_http_09; + state = sw_http_09; break; case CR: r->uri_end = p; @@ -547,9 +528,10 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case '+': r->plus_in_uri = 1; break; - case '\0': - return NGX_HTTP_PARSE_INVALID_REQUEST; default: + if (ch < 0x20 || ch == 0x7f) { + return NGX_HTTP_PARSE_INVALID_REQUEST; + } state = sw_check_uri; break; } @@ -579,7 +561,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) break; case ' ': r->uri_end = p; - state = sw_check_uri_http_09; + state = sw_http_09; break; case CR: r->uri_end = p; @@ -611,36 +593,14 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case '+': r->plus_in_uri = 1; break; - case '\0': - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - /* space+ after URI */ - case sw_check_uri_http_09: - switch (ch) { - case ' ': - break; - case CR: - r->http_minor = 9; - state = sw_almost_done; - break; - case LF: - r->http_minor = 9; - goto done; - case 'H': - r->http_protocol.data = p; - state = sw_http_H; - break; default: - r->space_in_uri = 1; - state = sw_check_uri; - p--; + if (ch < 0x20 || ch == 0x7f) { + return NGX_HTTP_PARSE_INVALID_REQUEST; + } break; } break; - /* URI */ case sw_uri: @@ -665,8 +625,11 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case '#': r->complex_uri = 1; break; - case '\0': - return NGX_HTTP_PARSE_INVALID_REQUEST; + default: + if (ch < 0x20 || ch == 0x7f) { + return NGX_HTTP_PARSE_INVALID_REQUEST; + } + break; } break; @@ -687,10 +650,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) state = sw_http_H; break; default: - r->space_in_uri = 1; - state = sw_uri; - p--; - break; + return NGX_HTTP_PARSE_INVALID_REQUEST; } break; @@ -933,7 +893,8 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, break; } - if (ch == '\0') { + if (ch <= 0x20 || ch == 0x7f || ch == ':') { + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -1001,7 +962,8 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, break; } - if (ch == '\0') { + if (ch <= 0x20 || ch == 0x7f) { + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -1024,6 +986,7 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, r->header_end = p; goto done; case '\0': + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; default: r->header_start = p; @@ -1047,6 +1010,7 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, r->header_end = p; goto done; case '\0': + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; } break; @@ -1062,6 +1026,7 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, case LF: goto done; case '\0': + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; default: state = sw_value; @@ -1165,10 +1130,6 @@ ngx_http_parse_uri(ngx_http_request_t *r) } switch (ch) { - case ' ': - r->space_in_uri = 1; - state = sw_check_uri; - break; case '.': r->complex_uri = 1; state = sw_uri; @@ -1199,6 +1160,9 @@ ngx_http_parse_uri(ngx_http_request_t *r) r->plus_in_uri = 1; break; default: + if (ch <= 0x20 || ch == 0x7f) { + return NGX_ERROR; + } state = sw_check_uri; break; } @@ -1226,9 +1190,6 @@ ngx_http_parse_uri(ngx_http_request_t *r) case '.': r->uri_ext = p + 1; break; - case ' ': - r->space_in_uri = 1; - break; #if (NGX_WIN32) case '\\': r->complex_uri = 1; @@ -1250,6 +1211,11 @@ ngx_http_parse_uri(ngx_http_request_t *r) case '+': r->plus_in_uri = 1; break; + default: + if (ch <= 0x20 || ch == 0x7f) { + return NGX_ERROR; + } + break; } break; @@ -1261,12 +1227,14 @@ ngx_http_parse_uri(ngx_http_request_t *r) } switch (ch) { - case ' ': - r->space_in_uri = 1; - break; case '#': r->complex_uri = 1; break; + default: + if (ch <= 0x20 || ch == 0x7f) { + return NGX_ERROR; + } + break; } break; } diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 136c461..013b715 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -607,7 +607,7 @@ ngx_http_alloc_request(ngx_connection_t *c) } #if (NGX_HTTP_SSL) - if (c->ssl) { + if (c->ssl && !c->ssl->sendfile) { r->main_filter_need_in_memory = 1; } #endif @@ -806,8 +806,7 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c) c->ssl->no_wait_shutdown = 1; #if (NGX_HTTP_V2 \ - && (defined TLSEXT_TYPE_application_layer_protocol_negotiation \ - || defined TLSEXT_TYPE_next_proto_neg)) + && defined TLSEXT_TYPE_application_layer_protocol_negotiation) { unsigned int len; const unsigned char *data; @@ -817,19 +816,8 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c) if (hc->addr_conf->http2) { -#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation SSL_get0_alpn_selected(c->ssl->connection, &data, &len); -#ifdef TLSEXT_TYPE_next_proto_neg - if (len == 0) { - SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len); - } -#endif - -#else /* TLSEXT_TYPE_next_proto_neg */ - SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len); -#endif - if (len == 2 && data[0] == 'h' && data[1] == '2') { ngx_http_v2_init(c->read); return; @@ -1043,12 +1031,14 @@ ngx_http_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) } ngx_http_free_request(r, 0); + c->log->action = "SSL handshaking"; c->destroyed = 0; return 1; failed: ngx_http_free_request(r, 0); + c->log->action = "SSL handshaking"; c->destroyed = 0; return 0; } @@ -1262,7 +1252,7 @@ ngx_http_process_request_uri(ngx_http_request_t *r) r->unparsed_uri.len = r->uri_end - r->uri_start; r->unparsed_uri.data = r->uri_start; - r->valid_unparsed_uri = (r->space_in_uri || r->empty_path_in_uri) ? 0 : 1; + r->valid_unparsed_uri = r->empty_path_in_uri ? 0 : 1; if (r->uri_ext) { if (r->args_start) { @@ -1520,7 +1510,9 @@ ngx_http_process_request_headers(ngx_event_t *rev) /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent invalid header line"); + "client sent invalid header line: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); break; @@ -1978,20 +1970,28 @@ ngx_http_process_request_header(ngx_http_request_t *r) } } - if (r->method == NGX_HTTP_TRACE) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent TRACE method"); - ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); - return NGX_ERROR; - } - if (r->headers_in.transfer_encoding) { + if (r->http_version < NGX_HTTP_VERSION_11) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent HTTP/1.0 request with " + "\"Transfer-Encoding\" header"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; + } + if (r->headers_in.transfer_encoding->value.len == 7 && ngx_strncasecmp(r->headers_in.transfer_encoding->value.data, (u_char *) "chunked", 7) == 0) { - r->headers_in.content_length = NULL; - r->headers_in.content_length_n = -1; + if (r->headers_in.content_length) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent \"Content-Length\" and " + "\"Transfer-Encoding\" headers " + "at the same time"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; + } + r->headers_in.chunked = 1; } else { @@ -2011,6 +2011,20 @@ ngx_http_process_request_header(ngx_http_request_t *r) } } + if (r->method == NGX_HTTP_CONNECT) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent CONNECT method"); + ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); + return NGX_ERROR; + } + + if (r->method == NGX_HTTP_TRACE) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent TRACE method"); + ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); + return NGX_ERROR; + } + return NGX_OK; } @@ -2158,15 +2172,16 @@ ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc) } break; - case '\0': - return NGX_DECLINED; - default: if (ngx_path_separator(ch)) { return NGX_DECLINED; } + if (ch <= 0x20 || ch == 0x7f) { + return NGX_DECLINED; + } + if (ch >= 'A' && ch <= 'Z') { alloc = 1; } diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 6dfb4a4..b1269d2 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -25,22 +25,23 @@ #define NGX_HTTP_VERSION_11 1001 #define NGX_HTTP_VERSION_20 2000 -#define NGX_HTTP_UNKNOWN 0x0001 -#define NGX_HTTP_GET 0x0002 -#define NGX_HTTP_HEAD 0x0004 -#define NGX_HTTP_POST 0x0008 -#define NGX_HTTP_PUT 0x0010 -#define NGX_HTTP_DELETE 0x0020 -#define NGX_HTTP_MKCOL 0x0040 -#define NGX_HTTP_COPY 0x0080 -#define NGX_HTTP_MOVE 0x0100 -#define NGX_HTTP_OPTIONS 0x0200 -#define NGX_HTTP_PROPFIND 0x0400 -#define NGX_HTTP_PROPPATCH 0x0800 -#define NGX_HTTP_LOCK 0x1000 -#define NGX_HTTP_UNLOCK 0x2000 -#define NGX_HTTP_PATCH 0x4000 -#define NGX_HTTP_TRACE 0x8000 +#define NGX_HTTP_UNKNOWN 0x00000001 +#define NGX_HTTP_GET 0x00000002 +#define NGX_HTTP_HEAD 0x00000004 +#define NGX_HTTP_POST 0x00000008 +#define NGX_HTTP_PUT 0x00000010 +#define NGX_HTTP_DELETE 0x00000020 +#define NGX_HTTP_MKCOL 0x00000040 +#define NGX_HTTP_COPY 0x00000080 +#define NGX_HTTP_MOVE 0x00000100 +#define NGX_HTTP_OPTIONS 0x00000200 +#define NGX_HTTP_PROPFIND 0x00000400 +#define NGX_HTTP_PROPPATCH 0x00000800 +#define NGX_HTTP_LOCK 0x00001000 +#define NGX_HTTP_UNLOCK 0x00002000 +#define NGX_HTTP_PATCH 0x00004000 +#define NGX_HTTP_TRACE 0x00008000 +#define NGX_HTTP_CONNECT 0x00010000 #define NGX_HTTP_CONNECTION_CLOSE 1 #define NGX_HTTP_CONNECTION_KEEP_ALIVE 2 @@ -301,6 +302,9 @@ typedef struct { ngx_chain_t *busy; ngx_http_chunked_t *chunked; ngx_http_client_body_handler_pt post_handler; + unsigned filter_need_buffering:1; + unsigned last_sent:1; + unsigned last_saved:1; } ngx_http_request_body_t; @@ -467,9 +471,6 @@ struct ngx_http_request_s { /* URI with "+" */ unsigned plus_in_uri:1; - /* URI with " " */ - unsigned space_in_uri:1; - /* URI with empty path */ unsigned empty_path_in_uri:1; diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c index 0cae88f..ad3549f 100644 --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -62,11 +62,16 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, /* * set by ngx_pcalloc(): * + * rb->temp_file = NULL; * rb->bufs = NULL; * rb->buf = NULL; * rb->free = NULL; * rb->busy = NULL; * rb->chunked = NULL; + * rb->received = 0; + * rb->filter_need_buffering = 0; + * rb->last_sent = 0; + * rb->last_saved = 0; */ rb->rest = -1; @@ -144,7 +149,7 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, } } - if (rb->rest == 0) { + if (rb->rest == 0 && rb->last_saved) { /* the whole request body was pre-read */ r->request_body_no_buffering = 0; post_handler(r); @@ -172,6 +177,10 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, size += preread; } + if (size == 0) { + size++; + } + } else { size = clcf->client_body_buffer_size; } @@ -270,6 +279,7 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) size_t size; ssize_t n; ngx_int_t rc; + ngx_uint_t flush; ngx_chain_t out; ngx_connection_t *c; ngx_http_request_body_t *rb; @@ -277,12 +287,17 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) c = r->connection; rb = r->request_body; + flush = 1; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http read client request body"); for ( ;; ) { for ( ;; ) { + if (rb->rest == 0) { + break; + } + if (rb->buf->last == rb->buf->end) { /* update chains */ @@ -306,12 +321,25 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) return NGX_AGAIN; } + if (rb->filter_need_buffering) { + clcf = ngx_http_get_module_loc_conf(r, + ngx_http_core_module); + ngx_add_timer(c->read, clcf->client_body_timeout); + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + return NGX_AGAIN; + } + ngx_log_error(NGX_LOG_ALERT, c->log, 0, "busy buffers after request body flush"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } + flush = 0; rb->buf->pos = rb->buf->start; rb->buf->last = rb->buf->start; } @@ -323,6 +351,10 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) size = (size_t) rest; } + if (size == 0) { + break; + } + n = c->recv(c, rb->buf->last, size); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, @@ -347,6 +379,7 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) /* pass buffer to request body filter chain */ + flush = 0; out.buf = rb->buf; out.next = NULL; @@ -368,11 +401,19 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http client request body rest %O", rb->rest); - if (rb->rest == 0) { + if (flush) { + rc = ngx_http_request_body_filter(r, NULL); + + if (rc != NGX_OK) { + return rc; + } + } + + if (rb->rest == 0 && rb->last_saved) { break; } - if (!c->read->ready) { + if (!c->read->ready || rb->rest == 0) { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_add_timer(c->read, clcf->client_body_timeout); @@ -939,15 +980,32 @@ ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in) rb = r->request_body; + out = NULL; + ll = &out; + if (rb->rest == -1) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http request body content length filter"); rb->rest = r->headers_in.content_length_n; - } - out = NULL; - ll = &out; + if (rb->rest == 0) { + + tl = ngx_chain_get_free_buf(r->pool, &rb->free); + if (tl == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + b = tl->buf; + + ngx_memzero(b, sizeof(ngx_buf_t)); + + b->last_buf = 1; + + *ll = tl; + ll = &tl->next; + } + } for (cl = in; cl; cl = cl->next) { @@ -1011,6 +1069,9 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) rb = r->request_body; + out = NULL; + ll = &out; + if (rb->rest == -1) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1027,9 +1088,6 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) rb->rest = cscf->large_client_header_buffers.size; } - out = NULL; - ll = &out; - for (cl = in; cl; cl = cl->next) { b = NULL; @@ -1186,15 +1244,16 @@ ngx_int_t ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_buf_t *b; - ngx_chain_t *cl; + ngx_chain_t *cl, *tl, **ll; ngx_http_request_body_t *rb; rb = r->request_body; -#if (NGX_DEBUG) + ll = &rb->bufs; + + for (cl = rb->bufs; cl; cl = cl->next) { #if 0 - for (cl = rb->bufs; cl; cl = cl->next) { ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "http body old buf t:%d f:%d %p, pos %p, size: %z " "file: %O, size: %O", @@ -1203,10 +1262,13 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) cl->buf->last - cl->buf->pos, cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); - } #endif + ll = &cl->next; + } + for (cl = in; cl; cl = cl->next) { + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "http body new buf t:%d f:%d %p, pos %p, size: %z " "file: %O, size: %O", @@ -1215,15 +1277,31 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) cl->buf->last - cl->buf->pos, cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); + + if (cl->buf->last_buf) { + + if (rb->last_saved) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "duplicate last buf in save filter"); + *ll = NULL; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + rb->last_saved = 1; + } + + tl = ngx_alloc_chain_link(r->pool); + if (tl == NULL) { + *ll = NULL; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + tl->buf = cl->buf; + *ll = tl; + ll = &tl->next; } -#endif - - /* TODO: coalesce neighbouring buffers */ - - if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } + *ll = NULL; if (r->request_body_no_buffering) { return NGX_OK; @@ -1231,7 +1309,7 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) if (rb->rest > 0) { - if (rb->buf && rb->buf->last == rb->buf->end + if (rb->bufs && rb->buf && rb->buf->last == rb->buf->end && ngx_http_write_request_body(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -1240,10 +1318,18 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) return NGX_OK; } - /* rb->rest == 0 */ + if (!rb->last_saved) { + return NGX_OK; + } if (rb->temp_file || r->request_body_in_file_only) { + if (rb->bufs && rb->bufs->buf->in_file) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "body already in file"); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + if (ngx_http_write_request_body(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c index 13c57d6..bebdbd9 100644 --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -250,7 +250,7 @@ ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) cv = (ngx_http_complex_value_t **) (p + cmd->offset); - if (*cv != NULL) { + if (*cv != NGX_CONF_UNSET_PTR && *cv != NULL) { return "is duplicate"; } @@ -275,6 +275,44 @@ ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +char * +ngx_http_set_complex_value_zero_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *p = conf; + + ngx_str_t *value; + ngx_http_complex_value_t **cv; + ngx_http_compile_complex_value_t ccv; + + cv = (ngx_http_complex_value_t **) (p + cmd->offset); + + if (*cv != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + *cv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); + if (*cv == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = *cv; + ccv.zero = 1; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + char * ngx_http_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h index a6b345e..4360038 100644 --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -216,6 +216,8 @@ size_t ngx_http_complex_value_size(ngx_http_request_t *r, ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv); char *ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_set_complex_value_zero_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); char *ngx_http_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index b682af5..ded833c 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -187,6 +187,8 @@ static void ngx_http_upstream_ssl_handshake(ngx_http_request_t *, static void ngx_http_upstream_ssl_save_session(ngx_connection_t *c); static ngx_int_t ngx_http_upstream_ssl_name(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_connection_t *c); +static ngx_int_t ngx_http_upstream_ssl_certificate(ngx_http_request_t *r, + ngx_http_upstream_t *u, ngx_connection_t *c); #endif @@ -1509,8 +1511,9 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, static void ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) { - ngx_int_t rc; - ngx_connection_t *c; + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_core_loc_conf_t *clcf; r->connection->log->action = "connecting to upstream"; @@ -1597,10 +1600,12 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */ + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + u->writer.out = NULL; u->writer.last = &u->writer.out; u->writer.connection = c; - u->writer.limit = 0; + u->writer.limit = clcf->sendfile_max_chunk; if (u->request_sent) { if (ngx_http_upstream_reinit(r, u) != NGX_OK) { @@ -1681,9 +1686,6 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, return; } - c->sendfile = 0; - u->output.sendfile = 0; - if (u->conf->ssl_server_name || u->conf->ssl_verify) { if (ngx_http_upstream_ssl_name(r, u, c) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, @@ -1692,6 +1694,16 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, } } + if (u->conf->ssl_certificate && (u->conf->ssl_certificate->lengths + || u->conf->ssl_certificate_key->lengths)) + { + if (ngx_http_upstream_ssl_certificate(r, u, c) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + } + if (u->conf->ssl_session_reuse) { c->ssl->save_session = ngx_http_upstream_ssl_save_session; @@ -1779,6 +1791,11 @@ ngx_http_upstream_ssl_handshake(ngx_http_request_t *r, ngx_http_upstream_t *u, } } + if (!c->ssl->sendfile) { + c->sendfile = 0; + u->output.sendfile = 0; + } + c->write->handler = ngx_http_upstream_handler; c->read->handler = ngx_http_upstream_handler; @@ -1912,6 +1929,45 @@ done: return NGX_OK; } + +static ngx_int_t +ngx_http_upstream_ssl_certificate(ngx_http_request_t *r, + ngx_http_upstream_t *u, ngx_connection_t *c) +{ + ngx_str_t cert, key; + + if (ngx_http_complex_value(r, u->conf->ssl_certificate, &cert) + != NGX_OK) + { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream ssl cert: \"%s\"", cert.data); + + if (*cert.data == '\0') { + return NGX_OK; + } + + if (ngx_http_complex_value(r, u->conf->ssl_certificate_key, &key) + != NGX_OK) + { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream ssl key: \"%s\"", key.data); + + if (ngx_ssl_connection_certificate(c, r->pool, &cert, &key, + u->conf->ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + + return NGX_OK; +} + #endif @@ -3791,6 +3847,7 @@ ngx_http_upstream_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) { ngx_str_t name; ngx_event_pipe_t *p; + ngx_connection_t *c; ngx_thread_pool_t *tp; ngx_http_request_t *r; ngx_http_core_loc_conf_t *clcf; @@ -3798,6 +3855,27 @@ ngx_http_upstream_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) r = file->thread_ctx; p = r->upstream->pipe; + if (r->aio) { + /* + * tolerate sendfile() calls if another operation is already + * running; this can happen due to subrequests, multiple calls + * of the next body filter from a filter, or in HTTP/2 due to + * a write event on the main connection + */ + + c = r->connection; + +#if (NGX_HTTP_V2) + if (r->stream) { + c = r->stream->connection->connection; + } +#endif + + if (task == c->sendfile_task) { + return NGX_OK; + } + } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); tp = clcf->thread_pool; @@ -3849,6 +3927,20 @@ ngx_http_upstream_thread_event_handler(ngx_event_t *ev) r->main->blocked--; r->aio = 0; +#if (NGX_HTTP_V2) + + if (r->stream) { + /* + * for HTTP/2, update write event to make sure processing will + * reach the main connection to handle sendfile() in threads + */ + + c->write->ready = 1; + c->write->active = 0; + } + +#endif + if (r->done) { /* * trigger connection event handler if the subrequest was diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index fd642c2..3db7b06 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -234,6 +234,10 @@ typedef struct { ngx_http_complex_value_t *ssl_name; ngx_flag_t ssl_server_name; ngx_flag_t ssl_verify; + + ngx_http_complex_value_t *ssl_certificate; + ngx_http_complex_value_t *ssl_certificate_key; + ngx_array_t *ssl_passwords; #endif ngx_str_t module; diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c index 6a5d957..932f26d 100644 --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -321,18 +321,13 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate); if (delay > 0) { - limit = 0; c->write->delayed = 1; ngx_add_timer(c->write, delay); } } - if (limit - && c->write->ready - && c->sent - sent >= limit - (off_t) (2 * ngx_pagesize)) - { - c->write->delayed = 1; - ngx_add_timer(c->write, 1); + if (chain && c->write->ready && !c->write->delayed) { + ngx_post_event(c->write, &ngx_posted_next_events); } for (cl = r->out; cl && cl != chain; /* void */) { diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 3611a2e..0e45a7b 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -173,7 +173,7 @@ static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r); static void ngx_http_v2_run_request(ngx_http_request_t *r); static void ngx_http_v2_run_request_handler(ngx_event_t *ev); static ngx_int_t ngx_http_v2_process_request_body(ngx_http_request_t *r, - u_char *pos, size_t size, ngx_uint_t last); + u_char *pos, size_t size, ngx_uint_t last, ngx_uint_t flush); static ngx_int_t ngx_http_v2_filter_request_body(ngx_http_request_t *r); static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r); @@ -1140,9 +1140,10 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, h2c->payload_bytes += size; if (r->request_body) { - rc = ngx_http_v2_process_request_body(r, pos, size, stream->in_closed); + rc = ngx_http_v2_process_request_body(r, pos, size, + stream->in_closed, 0); - if (rc != NGX_OK) { + if (rc != NGX_OK && rc != NGX_AGAIN) { stream->skip_data = 1; ngx_http_finalize_request(r, rc); } @@ -1599,10 +1600,10 @@ ngx_http_v2_state_field_huff(ngx_http_v2_connection_t *h2c, u_char *pos, h2c->state.length -= size; h2c->state.field_rest -= size; - if (ngx_http_v2_huff_decode(&h2c->state.field_state, pos, size, - &h2c->state.field_end, - h2c->state.field_rest == 0, - h2c->connection->log) + if (ngx_http_huff_decode(&h2c->state.field_state, pos, size, + &h2c->state.field_end, + h2c->state.field_rest == 0, + h2c->connection->log) != NGX_OK) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, @@ -3457,7 +3458,7 @@ ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header) continue; } - if (ch == '\0' || ch == LF || ch == CR || ch == ':' + if (ch <= 0x20 || ch == 0x7f || ch == ':' || (ch >= 'A' && ch <= 'Z')) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, @@ -3606,7 +3607,8 @@ ngx_http_v2_parse_method(ngx_http_request_t *r, ngx_str_t *value) { 4, "LOCK", NGX_HTTP_LOCK }, { 6, "UNLOCK", NGX_HTTP_UNLOCK }, { 5, "PATCH", NGX_HTTP_PATCH }, - { 5, "TRACE", NGX_HTTP_TRACE } + { 5, "TRACE", NGX_HTTP_TRACE }, + { 7, "CONNECT", NGX_HTTP_CONNECT } }, *test; if (r->method_name.len) { @@ -4026,16 +4028,30 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r) return NGX_OK; } + rb->rest = 1; + + /* set rb->filter_need_buffering */ + + rc = ngx_http_top_request_body_filter(r, NULL); + + if (rc != NGX_OK) { + stream->skip_data = 1; + return rc; + } + h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); len = r->headers_in.content_length_n; - if (r->request_body_no_buffering && !stream->in_closed) { + if (len < 0 || len > (off_t) clcf->client_body_buffer_size) { + len = clcf->client_body_buffer_size; - if (len < 0 || len > (off_t) clcf->client_body_buffer_size) { - len = clcf->client_body_buffer_size; - } + } else { + len++; + } + + if (r->request_body_no_buffering || rb->filter_need_buffering) { /* * We need a room to store data up to the stream's initial window size, @@ -4049,57 +4065,54 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r) if (len > NGX_HTTP_V2_MAX_WINDOW) { len = NGX_HTTP_V2_MAX_WINDOW; } - - rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); - - } else if (len >= 0 && len <= (off_t) clcf->client_body_buffer_size - && !r->request_body_in_file_only) - { - rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); - - } else { - rb->buf = ngx_calloc_buf(r->pool); - - if (rb->buf != NULL) { - rb->buf->sync = 1; - } } + rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); + if (rb->buf == NULL) { stream->skip_data = 1; return NGX_HTTP_INTERNAL_SERVER_ERROR; } - rb->rest = 1; - buf = stream->preread; if (stream->in_closed) { - r->request_body_no_buffering = 0; + if (!rb->filter_need_buffering) { + r->request_body_no_buffering = 0; + } if (buf) { rc = ngx_http_v2_process_request_body(r, buf->pos, - buf->last - buf->pos, 1); + buf->last - buf->pos, 1, 0); ngx_pfree(r->pool, buf->start); + + } else { + rc = ngx_http_v2_process_request_body(r, NULL, 0, 1, 0); + } + + if (rc != NGX_AGAIN) { return rc; } - return ngx_http_v2_process_request_body(r, NULL, 0, 1); + r->read_event_handler = ngx_http_v2_read_client_request_body_handler; + r->write_event_handler = ngx_http_request_empty_handler; + + return NGX_AGAIN; } if (buf) { rc = ngx_http_v2_process_request_body(r, buf->pos, - buf->last - buf->pos, 0); + buf->last - buf->pos, 0, 0); ngx_pfree(r->pool, buf->start); - if (rc != NGX_OK) { + if (rc != NGX_OK && rc != NGX_AGAIN) { stream->skip_data = 1; return rc; } } - if (r->request_body_no_buffering) { + if (r->request_body_no_buffering || rb->filter_need_buffering) { size = (size_t) len - h2scf->preread_size; } else { @@ -4141,9 +4154,9 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r) static ngx_int_t ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, - size_t size, ngx_uint_t last) + size_t size, ngx_uint_t last, ngx_uint_t flush) { - ngx_buf_t *buf; + size_t n; ngx_int_t rc; ngx_connection_t *fc; ngx_http_request_body_t *rb; @@ -4151,77 +4164,122 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, fc = r->connection; rb = r->request_body; - buf = rb->buf; - if (size) { - if (buf->sync) { - buf->pos = buf->start = pos; - buf->last = buf->end = pos + size; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 process request body"); - r->request_body_in_file_only = 1; + if (size == 0 && !last && !flush) { + return NGX_AGAIN; + } - } else { - if (size > (size_t) (buf->end - buf->last)) { - ngx_log_error(NGX_LOG_INFO, fc->log, 0, - "client intended to send body data " - "larger than declared"); + for ( ;; ) { + for ( ;; ) { + if (rb->buf->last == rb->buf->end && size) { - return NGX_HTTP_BAD_REQUEST; + if (r->request_body_no_buffering) { + + /* should never happen due to flow control */ + + ngx_log_error(NGX_LOG_ALERT, fc->log, 0, + "no space in http2 body buffer"); + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + /* update chains */ + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 body update chains"); + + rc = ngx_http_v2_filter_request_body(r); + + if (rc != NGX_OK) { + return rc; + } + + if (rb->busy != NULL) { + ngx_log_error(NGX_LOG_ALERT, fc->log, 0, + "busy buffers after request body flush"); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + rb->buf->pos = rb->buf->start; + rb->buf->last = rb->buf->start; } - buf->last = ngx_cpymem(buf->last, pos, size); + /* copy body data to the buffer */ + + n = rb->buf->end - rb->buf->last; + + if (n > size) { + n = size; + } + + if (n > 0) { + rb->buf->last = ngx_cpymem(rb->buf->last, pos, n); + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 request body recv %uz", n); + + pos += n; + size -= n; + + if (size == 0 && last) { + rb->rest = 0; + } + + if (size == 0) { + break; + } + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 request body rest %O", rb->rest); + + if (flush) { + rc = ngx_http_v2_filter_request_body(r); + + if (rc != NGX_OK) { + return rc; + } + } + + if (rb->rest == 0 && rb->last_saved) { + break; + } + + if (size == 0) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + ngx_add_timer(fc->read, clcf->client_body_timeout); + + if (!flush) { + ngx_post_event(fc->read, &ngx_posted_events); + } + + return NGX_AGAIN; } } - if (last) { - rb->rest = 0; - - if (fc->read->timer_set) { - ngx_del_timer(fc->read); - } - - if (r->request_body_no_buffering) { - ngx_post_event(fc->read, &ngx_posted_events); - return NGX_OK; - } - - rc = ngx_http_v2_filter_request_body(r); - - if (rc != NGX_OK) { - return rc; - } - - if (buf->sync) { - /* prevent reusing this buffer in the upstream module */ - rb->buf = NULL; - } - - if (r->headers_in.chunked) { - r->headers_in.content_length_n = rb->received; - } - - r->read_event_handler = ngx_http_block_reading; - rb->post_handler(r); - - return NGX_OK; + if (fc->read->timer_set) { + ngx_del_timer(fc->read); } - if (size == 0) { - return NGX_OK; - } - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_add_timer(fc->read, clcf->client_body_timeout); - if (r->request_body_no_buffering) { - ngx_post_event(fc->read, &ngx_posted_events); + if (!flush) { + ngx_post_event(fc->read, &ngx_posted_events); + } + return NGX_OK; } - if (buf->sync) { - return ngx_http_v2_filter_request_body(r); + if (r->headers_in.chunked) { + r->headers_in.content_length_n = rb->received; } + r->read_event_handler = ngx_http_block_reading; + rb->post_handler(r); + return NGX_OK; } @@ -4238,7 +4296,7 @@ ngx_http_v2_filter_request_body(ngx_http_request_t *r) rb = r->request_body; buf = rb->buf; - if (buf->pos == buf->last && rb->rest) { + if (buf->pos == buf->last && (rb->rest || rb->last_sent)) { cl = NULL; goto update; } @@ -4301,6 +4359,7 @@ ngx_http_v2_filter_request_body(ngx_http_request_t *r) } b->last_buf = 1; + rb->last_sent = 1; } b->tag = (ngx_buf_tag_t) &ngx_http_v2_filter_request_body; @@ -4320,7 +4379,12 @@ update: static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r) { - ngx_connection_t *fc; + size_t window; + ngx_buf_t *buf; + ngx_int_t rc; + ngx_connection_t *fc; + ngx_http_v2_stream_t *stream; + ngx_http_v2_connection_t *h2c; fc = r->connection; @@ -4346,6 +4410,75 @@ ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r) ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); return; } + + rc = ngx_http_v2_process_request_body(r, NULL, 0, r->stream->in_closed, 1); + + if (rc != NGX_OK && rc != NGX_AGAIN) { + r->stream->skip_data = 1; + ngx_http_finalize_request(r, rc); + return; + } + + if (rc == NGX_OK) { + return; + } + + if (r->stream->no_flow_control) { + return; + } + + if (r->request_body->rest == 0) { + return; + } + + if (r->request_body->busy != NULL) { + return; + } + + stream = r->stream; + h2c = stream->connection; + + buf = r->request_body->buf; + + buf->pos = buf->start; + buf->last = buf->start; + + window = buf->end - buf->start; + + if (h2c->state.stream == stream) { + window -= h2c->state.length; + } + + if (window <= stream->recv_window) { + if (window < stream->recv_window) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "http2 negative window update"); + + stream->skip_data = 1; + + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + return; + } + + if (ngx_http_v2_send_window_update(h2c, stream->node->id, + window - stream->recv_window) + == NGX_ERROR) + { + stream->skip_data = 1; + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + stream->recv_window = window; + + if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) { + stream->skip_data = 1; + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } } @@ -4358,11 +4491,13 @@ ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r) ngx_connection_t *fc; ngx_http_v2_stream_t *stream; ngx_http_v2_connection_t *h2c; - ngx_http_core_loc_conf_t *clcf; stream = r->stream; fc = r->connection; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 read unbuffered request body"); + if (fc->read->timedout) { if (stream->recv_window) { stream->skip_data = 1; @@ -4379,17 +4514,21 @@ ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r) return NGX_HTTP_BAD_REQUEST; } - rc = ngx_http_v2_filter_request_body(r); + rc = ngx_http_v2_process_request_body(r, NULL, 0, r->stream->in_closed, 1); - if (rc != NGX_OK) { + if (rc != NGX_OK && rc != NGX_AGAIN) { stream->skip_data = 1; return rc; } - if (!r->request_body->rest) { + if (rc == NGX_OK) { return NGX_OK; } + if (r->request_body->rest == 0) { + return NGX_AGAIN; + } + if (r->request_body->busy != NULL) { return NGX_AGAIN; } @@ -4430,11 +4569,6 @@ ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (stream->recv_window == 0) { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_add_timer(fc->read, clcf->client_body_timeout); - } - stream->recv_window = window; return NGX_AGAIN; diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 3492297..70ee287 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -13,8 +13,7 @@ #include -#define NGX_HTTP_V2_ALPN_ADVERTISE "\x02h2" -#define NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_V2_ALPN_ADVERTISE +#define NGX_HTTP_V2_ALPN_PROTO "\x02h2" #define NGX_HTTP_V2_STATE_BUFFER_SIZE 16 @@ -312,12 +311,6 @@ ngx_int_t ngx_http_v2_add_header(ngx_http_v2_connection_t *h2c, ngx_int_t ngx_http_v2_table_size(ngx_http_v2_connection_t *h2c, size_t size); -ngx_int_t ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, - u_char **dst, ngx_uint_t last, ngx_log_t *log); -size_t ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst, - ngx_uint_t lower); - - #define ngx_http_v2_prefix(bits) ((1 << (bits)) - 1) diff --git a/src/http/v2/ngx_http_v2_encode.c b/src/http/v2/ngx_http_v2_encode.c index ac79208..8798aa9 100644 --- a/src/http/v2/ngx_http_v2_encode.c +++ b/src/http/v2/ngx_http_v2_encode.c @@ -20,7 +20,7 @@ ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp, { size_t hlen; - hlen = ngx_http_v2_huff_encode(src, len, tmp, lower); + hlen = ngx_http_huff_encode(src, len, tmp, lower); if (hlen > 0) { *dst = NGX_HTTP_V2_ENCODE_HUFF; diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index a6e5e7d..9ffb155 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -1432,6 +1432,9 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) size = 0; #endif + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 send chain: %p", in); + while (in) { size = ngx_buf_size(in->buf); @@ -1450,12 +1453,8 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) return NGX_CHAIN_ERROR; } - if (stream->queued) { - fc->write->active = 1; - fc->write->ready = 0; - - } else { - fc->buffered &= ~NGX_HTTP_V2_BUFFERED; + if (ngx_http_v2_filter_send(fc, stream) == NGX_ERROR) { + return NGX_CHAIN_ERROR; } return NULL; @@ -1464,9 +1463,16 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) h2c = stream->connection; if (size && ngx_http_v2_flow_control(h2c, stream) == NGX_DECLINED) { - fc->write->active = 1; - fc->write->ready = 0; - return in; + + if (ngx_http_v2_filter_send(fc, stream) == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + if (ngx_http_v2_flow_control(h2c, stream) == NGX_DECLINED) { + fc->write->active = 1; + fc->write->ready = 0; + return in; + } } if (in->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_filter_get_shadow) { @@ -1809,6 +1815,11 @@ ngx_http_v2_waiting_queue(ngx_http_v2_connection_t *h2c, static ngx_inline ngx_int_t ngx_http_v2_filter_send(ngx_connection_t *fc, ngx_http_v2_stream_t *stream) { + if (stream->queued == 0) { + fc->buffered &= ~NGX_HTTP_V2_BUFFERED; + return NGX_OK; + } + stream->blocked = 1; if (ngx_http_v2_send_output_queue(stream->connection) == NGX_ERROR) { diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index b865a3b..e0c62b7 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -115,6 +115,8 @@ typedef struct { ngx_msec_t timeout; ngx_msec_t resolver_timeout; + ngx_uint_t max_errors; + ngx_str_t server_name; u_char *file_name; @@ -231,14 +233,15 @@ typedef struct { ngx_uint_t command; ngx_array_t args; + ngx_uint_t errors; ngx_uint_t login_attempt; /* used to parse POP3/IMAP/SMTP command */ ngx_uint_t state; + u_char *tag_start; u_char *cmd_start; u_char *arg_start; - u_char *arg_end; ngx_uint_t literal_len; } ngx_mail_session_t; @@ -321,6 +324,7 @@ typedef ngx_int_t (*ngx_mail_parse_command_pt)(ngx_mail_session_t *s); struct ngx_mail_protocol_s { ngx_str_t name; + ngx_str_t alpn; in_port_t port[4]; ngx_uint_t type; diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c index 2a198f4..27f64b9 100644 --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -1137,8 +1137,8 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, ngx_str_t login, passwd; ngx_connection_t *c; #if (NGX_MAIL_SSL) - ngx_str_t verify, subject, issuer, serial, fingerprint, - raw_cert, cert; + ngx_str_t protocol, cipher, verify, subject, issuer, + serial, fingerprint, raw_cert, cert; ngx_mail_ssl_conf_t *sslcf; #endif ngx_mail_core_srv_conf_t *cscf; @@ -1155,6 +1155,25 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, #if (NGX_MAIL_SSL) + if (c->ssl) { + + if (ngx_ssl_get_protocol(c, pool, &protocol) != NGX_OK) { + return NULL; + } + + protocol.len = ngx_strlen(protocol.data); + + if (ngx_ssl_get_cipher_name(c, pool, &cipher) != NGX_OK) { + return NULL; + } + + cipher.len = ngx_strlen(cipher.data); + + } else { + ngx_str_null(&protocol); + ngx_str_null(&cipher); + } + sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); if (c->ssl && sslcf->verify) { @@ -1252,6 +1271,10 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, if (c->ssl) { len += sizeof("Auth-SSL: on" CRLF) - 1 + + sizeof("Auth-SSL-Protocol: ") - 1 + protocol.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Cipher: ") - 1 + cipher.len + + sizeof(CRLF) - 1 + sizeof("Auth-SSL-Verify: ") - 1 + verify.len + sizeof(CRLF) - 1 + sizeof("Auth-SSL-Subject: ") - 1 + subject.len @@ -1373,6 +1396,20 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, b->last = ngx_cpymem(b->last, "Auth-SSL: on" CRLF, sizeof("Auth-SSL: on" CRLF) - 1); + if (protocol.len) { + b->last = ngx_cpymem(b->last, "Auth-SSL-Protocol: ", + sizeof("Auth-SSL-Protocol: ") - 1); + b->last = ngx_copy(b->last, protocol.data, protocol.len); + *b->last++ = CR; *b->last++ = LF; + } + + if (cipher.len) { + b->last = ngx_cpymem(b->last, "Auth-SSL-Cipher: ", + sizeof("Auth-SSL-Cipher: ") - 1); + b->last = ngx_copy(b->last, cipher.data, cipher.len); + *b->last++ = CR; *b->last++ = LF; + } + if (verify.len) { b->last = ngx_cpymem(b->last, "Auth-SSL-Verify: ", sizeof("Auth-SSL-Verify: ") - 1); diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index 4083124..115671c 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -85,6 +85,13 @@ static ngx_command_t ngx_mail_core_commands[] = { offsetof(ngx_mail_core_srv_conf_t, resolver_timeout), NULL }, + { ngx_string("max_errors"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_core_srv_conf_t, max_errors), + NULL }, + ngx_null_command }; @@ -163,6 +170,8 @@ ngx_mail_core_create_srv_conf(ngx_conf_t *cf) cscf->timeout = NGX_CONF_UNSET_MSEC; cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; + cscf->max_errors = NGX_CONF_UNSET_UINT; + cscf->resolver = NGX_CONF_UNSET_PTR; cscf->file_name = cf->conf_file->file.name.data; @@ -182,6 +191,7 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout, 30000); + ngx_conf_merge_uint_value(conf->max_errors, prev->max_errors, 5); ngx_conf_merge_str_value(conf->server_name, prev->server_name, ""); diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index 0aaa0e7..246ba97 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -833,20 +833,23 @@ ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c) ngx_str_t l; ngx_mail_core_srv_conf_t *cscf; - n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last); + if (s->buffer->last < s->buffer->end) { - if (n == NGX_ERROR || n == 0) { - ngx_mail_close_connection(c); - return NGX_ERROR; - } + n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last); - if (n > 0) { - s->buffer->last += n; - } + if (n == NGX_ERROR || n == 0) { + ngx_mail_close_connection(c); + return NGX_ERROR; + } - if (n == NGX_AGAIN) { - if (s->buffer->pos == s->buffer->last) { - return NGX_AGAIN; + if (n > 0) { + s->buffer->last += n; + } + + if (n == NGX_AGAIN) { + if (s->buffer->pos == s->buffer->last) { + return NGX_AGAIN; + } } } @@ -871,7 +874,20 @@ ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c) return NGX_MAIL_PARSE_INVALID_COMMAND; } - if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) { + if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) { + + s->errors++; + + if (s->errors >= cscf->max_errors) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent too many invalid commands"); + s->quit = 1; + } + + return rc; + } + + if (rc == NGX_IMAP_NEXT) { return rc; } diff --git a/src/mail/ngx_mail_imap_handler.c b/src/mail/ngx_mail_imap_handler.c index 5dfdd76..291e87a 100644 --- a/src/mail/ngx_mail_imap_handler.c +++ b/src/mail/ngx_mail_imap_handler.c @@ -101,10 +101,9 @@ ngx_mail_imap_init_protocol(ngx_event_t *rev) void ngx_mail_imap_auth_state(ngx_event_t *rev) { - u_char *p, *dst, *src, *end; - ngx_str_t *arg; + u_char *p; ngx_int_t rc; - ngx_uint_t tag, i; + ngx_uint_t tag; ngx_connection_t *c; ngx_mail_session_t *s; @@ -158,27 +157,6 @@ ngx_mail_imap_auth_state(ngx_event_t *rev) ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap auth command: %i", s->command); - if (s->backslash) { - - arg = s->args.elts; - - for (i = 0; i < s->args.nelts; i++) { - dst = arg[i].data; - end = dst + arg[i].len; - - for (src = dst; src < end; dst++) { - *dst = *src; - if (*src++ == '\\') { - *dst = *src++; - } - } - - arg[i].len = dst - arg[i].data; - } - - s->backslash = 0; - } - switch (s->mail_state) { case ngx_imap_start: @@ -248,6 +226,10 @@ ngx_mail_imap_auth_state(ngx_event_t *rev) ngx_str_set(&s->out, imap_next); } + if (s->buffer->pos < s->buffer->last) { + s->blocked = 1; + } + switch (rc) { case NGX_DONE: @@ -297,13 +279,14 @@ ngx_mail_imap_auth_state(ngx_event_t *rev) if (s->state) { /* preserve tag */ - s->arg_start = s->buffer->start + s->tag.len; - s->buffer->pos = s->arg_start; - s->buffer->last = s->arg_start; + s->arg_start = s->buffer->pos; } else { - s->buffer->pos = s->buffer->start; - s->buffer->last = s->buffer->start; + if (s->buffer->pos == s->buffer->last) { + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; + } + s->tag.len = 0; } } @@ -481,6 +464,8 @@ ngx_mail_imap_starttls(ngx_mail_session_t *s, ngx_connection_t *c) if (c->ssl == NULL) { sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); if (sslcf->starttls) { + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; c->read->handler = ngx_mail_starttls_handler; return NGX_OK; } diff --git a/src/mail/ngx_mail_imap_module.c b/src/mail/ngx_mail_imap_module.c index 1f187fd..02c684c 100644 --- a/src/mail/ngx_mail_imap_module.c +++ b/src/mail/ngx_mail_imap_module.c @@ -46,6 +46,7 @@ static ngx_str_t ngx_mail_imap_auth_methods_names[] = { static ngx_mail_protocol_t ngx_mail_imap_protocol = { ngx_string("imap"), + ngx_string("\x04imap"), { 143, 993, 0, 0 }, NGX_MAIL_IMAP_PROTOCOL, diff --git a/src/mail/ngx_mail_parse.c b/src/mail/ngx_mail_parse.c index 2c2cdff..4db1f18 100644 --- a/src/mail/ngx_mail_parse.c +++ b/src/mail/ngx_mail_parse.c @@ -21,6 +21,8 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) ngx_str_t *arg; enum { sw_start = 0, + sw_command, + sw_invalid, sw_spaces_before_argument, sw_argument, sw_almost_done @@ -35,8 +37,14 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) /* POP3 command */ case sw_start: + s->cmd_start = p; + state = sw_command; + + /* fall through */ + + case sw_command: if (ch == ' ' || ch == CR || ch == LF) { - c = s->buffer->start; + c = s->cmd_start; if (p - c == 4) { @@ -85,6 +93,9 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) goto invalid; } + s->cmd.data = s->cmd_start; + s->cmd.len = p - s->cmd_start; + switch (ch) { case ' ': state = sw_spaces_before_argument; @@ -104,16 +115,17 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) break; + case sw_invalid: + goto invalid; + case sw_spaces_before_argument: switch (ch) { case ' ': break; case CR: state = sw_almost_done; - s->arg_end = p; break; case LF: - s->arg_end = p; goto done; default: if (s->args.nelts <= 2) { @@ -188,37 +200,39 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) done: s->buffer->pos = p + 1; - - if (s->arg_start) { - arg = ngx_array_push(&s->args); - if (arg == NULL) { - return NGX_ERROR; - } - arg->len = s->arg_end - s->arg_start; - arg->data = s->arg_start; - s->arg_start = NULL; - } - s->state = (s->command != NGX_POP3_AUTH) ? sw_start : sw_argument; return NGX_OK; invalid: - s->state = sw_start; - s->arg_start = NULL; + s->state = sw_invalid; - return NGX_MAIL_PARSE_INVALID_COMMAND; + /* skip invalid command till LF */ + + for ( /* void */ ; p < s->buffer->last; p++) { + if (*p == LF) { + s->state = sw_start; + s->buffer->pos = p + 1; + return NGX_MAIL_PARSE_INVALID_COMMAND; + } + } + + s->buffer->pos = p; + + return NGX_AGAIN; } ngx_int_t ngx_mail_imap_parse_command(ngx_mail_session_t *s) { - u_char ch, *p, *c; + u_char ch, *p, *c, *dst, *src, *end; ngx_str_t *arg; enum { sw_start = 0, + sw_tag, + sw_invalid, sw_spaces_before_command, sw_command, sw_spaces_before_argument, @@ -241,31 +255,45 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) /* IMAP tag */ case sw_start: + s->tag_start = p; + state = sw_tag; + + /* fall through */ + + case sw_tag: switch (ch) { case ' ': - s->tag.len = p - s->buffer->start + 1; - s->tag.data = s->buffer->start; + s->tag.len = p - s->tag_start + 1; + s->tag.data = s->tag_start; state = sw_spaces_before_command; break; case CR: - s->state = sw_start; - return NGX_MAIL_PARSE_INVALID_COMMAND; case LF: - s->state = sw_start; - return NGX_MAIL_PARSE_INVALID_COMMAND; + goto invalid; + default: + if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') + && (ch < '0' || ch > '9') && ch != '-' && ch != '.' + && ch != '_') + { + goto invalid; + } + if (p - s->tag_start > 31) { + goto invalid; + } + break; } break; + case sw_invalid: + goto invalid; + case sw_spaces_before_command: switch (ch) { case ' ': break; case CR: - s->state = sw_start; - return NGX_MAIL_PARSE_INVALID_COMMAND; case LF: - s->state = sw_start; - return NGX_MAIL_PARSE_INVALID_COMMAND; + goto invalid; default: s->cmd_start = p; state = sw_command; @@ -385,6 +413,9 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) goto invalid; } + s->cmd.data = s->cmd_start; + s->cmd.len = p - s->cmd_start; + switch (ch) { case ' ': state = sw_spaces_before_argument; @@ -410,10 +441,8 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) break; case CR: state = sw_almost_done; - s->arg_end = p; break; case LF: - s->arg_end = p; goto done; case '"': if (s->args.nelts <= 2) { @@ -460,6 +489,22 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) } arg->len = p - s->arg_start; arg->data = s->arg_start; + + if (s->backslash) { + dst = s->arg_start; + end = p; + + for (src = dst; src < end; dst++) { + *dst = *src; + if (*src++ == '\\') { + *dst = *src++; + } + } + + arg->len = dst - s->arg_start; + s->backslash = 0; + } + s->arg_start = NULL; switch (ch) { @@ -588,34 +633,46 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) done: s->buffer->pos = p + 1; - - if (s->arg_start) { - arg = ngx_array_push(&s->args); - if (arg == NULL) { - return NGX_ERROR; - } - arg->len = s->arg_end - s->arg_start; - arg->data = s->arg_start; - - s->arg_start = NULL; - s->cmd_start = NULL; - s->quoted = 0; - s->no_sync_literal = 0; - s->literal_len = 0; - } - s->state = (s->command != NGX_IMAP_AUTHENTICATE) ? sw_start : sw_argument; return NGX_OK; invalid: - s->state = sw_start; + s->state = sw_invalid; s->quoted = 0; + s->backslash = 0; s->no_sync_literal = 0; s->literal_len = 0; - return NGX_MAIL_PARSE_INVALID_COMMAND; + /* skip invalid command till LF */ + + for ( /* void */ ; p < s->buffer->last; p++) { + if (*p == LF) { + s->state = sw_start; + s->buffer->pos = p + 1; + + /* detect non-synchronizing literals */ + + if ((size_t) (p - s->buffer->start) > sizeof("{1+}") - 1) { + p--; + + if (*p == CR) { + p--; + } + + if (*p == '}' && *(p - 1) == '+') { + s->quit = 1; + } + } + + return NGX_MAIL_PARSE_INVALID_COMMAND; + } + } + + s->buffer->pos = p; + + return NGX_AGAIN; } @@ -758,10 +815,8 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s) break; case CR: state = sw_almost_done; - s->arg_end = p; break; case LF: - s->arg_end = p; goto done; default: if (s->args.nelts <= 10) { @@ -821,17 +876,6 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s) done: s->buffer->pos = p + 1; - - if (s->arg_start) { - arg = ngx_array_push(&s->args); - if (arg == NULL) { - return NGX_ERROR; - } - arg->len = s->arg_end - s->arg_start; - arg->data = s->arg_start; - s->arg_start = NULL; - } - s->state = (s->command != NGX_SMTP_AUTH) ? sw_start : sw_argument; return NGX_OK; @@ -839,21 +883,20 @@ done: invalid: s->state = sw_invalid; - s->arg_start = NULL; /* skip invalid command till LF */ - for (p = s->buffer->pos; p < s->buffer->last; p++) { + for ( /* void */ ; p < s->buffer->last; p++) { if (*p == LF) { s->state = sw_start; - p++; - break; + s->buffer->pos = p + 1; + return NGX_MAIL_PARSE_INVALID_COMMAND; } } s->buffer->pos = p; - return NGX_MAIL_PARSE_INVALID_COMMAND; + return NGX_AGAIN; } diff --git a/src/mail/ngx_mail_pop3_handler.c b/src/mail/ngx_mail_pop3_handler.c index edfd986..226e741 100644 --- a/src/mail/ngx_mail_pop3_handler.c +++ b/src/mail/ngx_mail_pop3_handler.c @@ -262,6 +262,10 @@ ngx_mail_pop3_auth_state(ngx_event_t *rev) } } + if (s->buffer->pos < s->buffer->last) { + s->blocked = 1; + } + switch (rc) { case NGX_DONE: @@ -283,11 +287,14 @@ ngx_mail_pop3_auth_state(ngx_event_t *rev) case NGX_OK: s->args.nelts = 0; - s->buffer->pos = s->buffer->start; - s->buffer->last = s->buffer->start; + + if (s->buffer->pos == s->buffer->last) { + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; + } if (s->state) { - s->arg_start = s->buffer->start; + s->arg_start = s->buffer->pos; } if (ngx_handle_read_event(c->read, 0) != NGX_OK) { @@ -400,6 +407,8 @@ ngx_mail_pop3_stls(ngx_mail_session_t *s, ngx_connection_t *c) if (c->ssl == NULL) { sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); if (sslcf->starttls) { + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; c->read->handler = ngx_mail_starttls_handler; return NGX_OK; } diff --git a/src/mail/ngx_mail_pop3_module.c b/src/mail/ngx_mail_pop3_module.c index a673070..a257b5a 100644 --- a/src/mail/ngx_mail_pop3_module.c +++ b/src/mail/ngx_mail_pop3_module.c @@ -46,6 +46,7 @@ static ngx_str_t ngx_mail_pop3_auth_methods_names[] = { static ngx_mail_protocol_t ngx_mail_pop3_protocol = { ngx_string("pop3"), + ngx_string("\x04pop3"), { 110, 995, 0, 0 }, NGX_MAIL_POP3_PROTOCOL, diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c index 66aa0ba..a7ab077 100644 --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -327,6 +327,10 @@ ngx_mail_proxy_pop3_handler(ngx_event_t *rev) c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); + if (s->buffer->pos < s->buffer->last) { + ngx_post_event(c->write, &ngx_posted_events); + } + ngx_mail_proxy_handler(s->connection->write); return; @@ -482,6 +486,10 @@ ngx_mail_proxy_imap_handler(ngx_event_t *rev) c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); + if (s->buffer->pos < s->buffer->last) { + ngx_post_event(c->write, &ngx_posted_events); + } + ngx_mail_proxy_handler(s->connection->write); return; @@ -813,13 +821,12 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); - if (s->buffer->pos == s->buffer->last) { - ngx_mail_proxy_handler(s->connection->write); - - } else { - ngx_mail_proxy_handler(c->write); + if (s->buffer->pos < s->buffer->last) { + ngx_post_event(c->write, &ngx_posted_events); } + ngx_mail_proxy_handler(s->connection->write); + return; default: diff --git a/src/mail/ngx_mail_smtp_module.c b/src/mail/ngx_mail_smtp_module.c index 3b5a2d8..0e05fdc 100644 --- a/src/mail/ngx_mail_smtp_module.c +++ b/src/mail/ngx_mail_smtp_module.c @@ -39,6 +39,7 @@ static ngx_str_t ngx_mail_smtp_auth_methods_names[] = { static ngx_mail_protocol_t ngx_mail_smtp_protocol = { ngx_string("smtp"), + ngx_string("\x04smtp"), { 25, 465, 587, 0 }, NGX_MAIL_SMTP_PROTOCOL, diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c index 7eae83e..2a1043e 100644 --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -14,6 +14,12 @@ #define NGX_DEFAULT_ECDH_CURVE "auto" +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation +static int ngx_mail_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, + const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg); +#endif + static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf); static char *ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child); @@ -244,6 +250,54 @@ ngx_module_t ngx_mail_ssl_module = { static ngx_str_t ngx_mail_ssl_sess_id_ctx = ngx_string("MAIL"); +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + +static int +ngx_mail_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, + unsigned char *outlen, const unsigned char *in, unsigned int inlen, + void *arg) +{ + unsigned int srvlen; + unsigned char *srv; + ngx_connection_t *c; + ngx_mail_session_t *s; + ngx_mail_core_srv_conf_t *cscf; +#if (NGX_DEBUG) + unsigned int i; +#endif + + c = ngx_ssl_get_connection(ssl_conn); + s = c->data; + +#if (NGX_DEBUG) + for (i = 0; i < inlen; i += in[i] + 1) { + ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0, + "SSL ALPN supported by client: %*s", + (size_t) in[i], &in[i + 1]); + } +#endif + + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + + srv = cscf->protocol->alpn.data; + srvlen = cscf->protocol->alpn.len; + + if (SSL_select_next_proto((unsigned char **) out, outlen, srv, srvlen, + in, inlen) + != OPENSSL_NPN_NEGOTIATED) + { + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0, + "SSL ALPN selected: %*s", (size_t) *outlen, *out); + + return SSL_TLSEXT_ERR_OK; +} + +#endif + + static void * ngx_mail_ssl_create_conf(ngx_conf_t *cf) { @@ -394,6 +448,17 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) cln->handler = ngx_ssl_cleanup_ctx; cln->data = &conf->ssl; +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_mail_ssl_alpn_select, NULL); +#endif + + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, + conf->prefer_server_ciphers) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates, conf->certificate_keys, conf->passwords) != NGX_OK) @@ -430,13 +495,6 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) } } - if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, - conf->prefer_server_ciphers) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { return NGX_CONF_ERROR; } diff --git a/src/os/unix/ngx_atomic.h b/src/os/unix/ngx_atomic.h index 74b8b7f..fcab2d6 100644 --- a/src/os/unix/ngx_atomic.h +++ b/src/os/unix/ngx_atomic.h @@ -38,6 +38,39 @@ typedef volatile ngx_atomic_uint_t ngx_atomic_t; #define ngx_cpu_pause() +#elif (NGX_HAVE_GCC_ATOMIC) + +/* GCC 4.1 builtin atomic operations */ + +#define NGX_HAVE_ATOMIC_OPS 1 + +typedef long ngx_atomic_int_t; +typedef unsigned long ngx_atomic_uint_t; + +#if (NGX_PTR_SIZE == 8) +#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) +#else +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) +#endif + +typedef volatile ngx_atomic_uint_t ngx_atomic_t; + + +#define ngx_atomic_cmp_set(lock, old, set) \ + __sync_bool_compare_and_swap(lock, old, set) + +#define ngx_atomic_fetch_add(value, add) \ + __sync_fetch_and_add(value, add) + +#define ngx_memory_barrier() __sync_synchronize() + +#if ( __i386__ || __i386 || __amd64__ || __amd64 ) +#define ngx_cpu_pause() __asm__ ("pause") +#else +#define ngx_cpu_pause() +#endif + + #elif (NGX_DARWIN_ATOMIC) /* @@ -88,39 +121,6 @@ typedef uint32_t ngx_atomic_uint_t; typedef volatile ngx_atomic_uint_t ngx_atomic_t; -#elif (NGX_HAVE_GCC_ATOMIC) - -/* GCC 4.1 builtin atomic operations */ - -#define NGX_HAVE_ATOMIC_OPS 1 - -typedef long ngx_atomic_int_t; -typedef unsigned long ngx_atomic_uint_t; - -#if (NGX_PTR_SIZE == 8) -#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) -#else -#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) -#endif - -typedef volatile ngx_atomic_uint_t ngx_atomic_t; - - -#define ngx_atomic_cmp_set(lock, old, set) \ - __sync_bool_compare_and_swap(lock, old, set) - -#define ngx_atomic_fetch_add(value, add) \ - __sync_fetch_and_add(value, add) - -#define ngx_memory_barrier() __sync_synchronize() - -#if ( __i386__ || __i386 || __amd64__ || __amd64 ) -#define ngx_cpu_pause() __asm__ ("pause") -#else -#define ngx_cpu_pause() -#endif - - #elif ( __i386__ || __i386 ) typedef int32_t ngx_atomic_int_t; diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c index 3d415bd..5c6a830 100644 --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -32,23 +32,22 @@ ngx_chain_t * ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { - int rc, flags; - off_t send, prev_send, sent; - size_t file_size; - ssize_t n; - ngx_uint_t eintr, eagain; - ngx_err_t err; - ngx_buf_t *file; - ngx_event_t *wev; - ngx_chain_t *cl; - ngx_iovec_t header, trailer; - struct sf_hdtr hdtr; - struct iovec headers[NGX_IOVS_PREALLOCATE]; - struct iovec trailers[NGX_IOVS_PREALLOCATE]; -#if (NGX_HAVE_AIO_SENDFILE) - ngx_uint_t ebusy; - ngx_event_aio_t *aio; + int rc, flags; + off_t send, prev_send, sent; + size_t file_size; + ssize_t n; + ngx_err_t err; + ngx_buf_t *file; + ngx_uint_t eintr, eagain; +#if (NGX_HAVE_SENDFILE_NODISKIO) + ngx_uint_t ebusy; #endif + ngx_event_t *wev; + ngx_chain_t *cl; + ngx_iovec_t header, trailer; + struct sf_hdtr hdtr; + struct iovec headers[NGX_IOVS_PREALLOCATE]; + struct iovec trailers[NGX_IOVS_PREALLOCATE]; wev = c->write; @@ -77,11 +76,6 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) eagain = 0; flags = 0; -#if (NGX_HAVE_AIO_SENDFILE && NGX_SUPPRESS_WARN) - aio = NULL; - file = NULL; -#endif - header.iovs = headers; header.nalloc = NGX_IOVS_PREALLOCATE; @@ -90,7 +84,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) for ( ;; ) { eintr = 0; -#if (NGX_HAVE_AIO_SENDFILE) +#if (NGX_HAVE_SENDFILE_NODISKIO) ebusy = 0; #endif prev_send = send; @@ -179,9 +173,14 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) sent = 0; -#if (NGX_HAVE_AIO_SENDFILE) - aio = file->file->aio; - flags = (aio && aio->preload_handler) ? SF_NODISKIO : 0; +#if (NGX_HAVE_SENDFILE_NODISKIO) + + flags = (c->busy_count <= 2) ? SF_NODISKIO : 0; + + if (file->file->directio) { + flags |= SF_NOCACHE; + } + #endif rc = sendfile(file->file->fd, c->fd, file->file_pos, @@ -199,7 +198,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) eintr = 1; break; -#if (NGX_HAVE_AIO_SENDFILE) +#if (NGX_HAVE_SENDFILE_NODISKIO) case NGX_EBUSY: ebusy = 1; break; @@ -252,54 +251,30 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) in = ngx_chain_update_sent(in, sent); -#if (NGX_HAVE_AIO_SENDFILE) +#if (NGX_HAVE_SENDFILE_NODISKIO) if (ebusy) { - if (aio->event.active) { - /* - * tolerate duplicate calls; they can happen due to subrequests - * or multiple calls of the next body filter from a filter - */ - - if (sent) { - c->busy_count = 0; - } - - return in; - } - if (sent == 0) { c->busy_count++; - if (c->busy_count > 2) { - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "sendfile(%V) returned busy again", - &file->file->name); - - c->busy_count = 0; - aio->preload_handler = NULL; - - send = prev_send; - continue; - } + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendfile() busy, count:%d", c->busy_count); } else { c->busy_count = 0; } - n = aio->preload_handler(file); - - if (n > 0) { - send = prev_send + sent; - continue; + if (wev->posted) { + ngx_delete_posted_event(wev); } + ngx_post_event(wev, &ngx_posted_next_events); + + wev->ready = 0; return in; } - if (flags == SF_NODISKIO) { - c->busy_count = 0; - } + c->busy_count = 0; #endif diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c index 5695839..101d91a 100644 --- a/src/os/unix/ngx_linux_sendfile_chain.c +++ b/src/os/unix/ngx_linux_sendfile_chain.c @@ -38,6 +38,9 @@ static void ngx_linux_sendfile_thread_handler(void *data, ngx_log_t *log); * On Linux up to 2.6.16 sendfile() does not allow to pass the count parameter * more than 2G-1 bytes even on 64-bit platforms: it returns EINVAL, * so we limit it to 2G-1 bytes. + * + * On Linux 2.6.16 and later, sendfile() silently limits the count parameter + * to 2G minus the page size, even on 64-bit platforms. */ #define NGX_SENDFILE_MAXSIZE 2147483647L @@ -216,7 +219,6 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) */ send = prev_send + sent; - continue; } if (send >= limit || in == NULL) { @@ -377,15 +379,6 @@ ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size) return ctx->sent; } - if (task->event.active && ctx->file == file) { - /* - * tolerate duplicate calls; they can happen due to subrequests - * or multiple calls of the next body filter from a filter - */ - - return NGX_DONE; - } - ctx->file = file; ctx->socket = c->fd; ctx->size = size; diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c index b31485f..07cd05e 100644 --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -398,6 +398,8 @@ ngx_pass_open_channel(ngx_cycle_t *cycle) ngx_int_t i; ngx_channel_t ch; + ngx_memzero(&ch, sizeof(ngx_channel_t)); + ch.command = NGX_CMD_OPEN_CHANNEL; ch.pid = ngx_processes[ngx_process_slot].pid; ch.slot = ngx_process_slot; diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c index a3577ce..b1ae4b5 100644 --- a/src/os/unix/ngx_readv_chain.c +++ b/src/os/unix/ngx_readv_chain.c @@ -96,7 +96,7 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) iov->iov_len += n; } else { - if (vec.nelts >= IOV_MAX) { + if (vec.nelts == vec.nalloc) { break; } diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c index 7835675..3304c84 100644 --- a/src/stream/ngx_stream.c +++ b/src/stream/ngx_stream.c @@ -510,6 +510,10 @@ ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) ls->ipv6only = addr[i].opt.ipv6only; #endif +#if (NGX_HAVE_TCP_FASTOPEN) + ls->fastopen = addr[i].opt.fastopen; +#endif + #if (NGX_HAVE_REUSEPORT) ls->reuseport = addr[i].opt.reuseport; #endif diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h index 9e35832..46c3622 100644 --- a/src/stream/ngx_stream.h +++ b/src/stream/ngx_stream.h @@ -65,6 +65,9 @@ typedef struct { int backlog; int rcvbuf; int sndbuf; +#if (NGX_HAVE_TCP_FASTOPEN) + int fastopen; +#endif int type; } ngx_stream_listen_t; diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c index 9b6afe9..d96d27a 100644 --- a/src/stream/ngx_stream_core_module.c +++ b/src/stream/ngx_stream_core_module.c @@ -615,6 +615,10 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ls->type = SOCK_STREAM; ls->ctx = cf->ctx; +#if (NGX_HAVE_TCP_FASTOPEN) + ls->fastopen = -1; +#endif + #if (NGX_HAVE_INET6) ls->ipv6only = 1; #endif @@ -635,6 +639,21 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } +#if (NGX_HAVE_TCP_FASTOPEN) + if (ngx_strncmp(value[i].data, "fastopen=", 9) == 0) { + ls->fastopen = ngx_atoi(value[i].data + 9, value[i].len - 9); + ls->bind = 1; + + if (ls->fastopen == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid fastopen \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + continue; + } +#endif + if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) { ls->backlog = ngx_atoi(value[i].data + 8, value[i].len - 8); ls->bind = 1; @@ -859,6 +878,12 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ls->proxy_protocol) { return "\"proxy_protocol\" parameter is incompatible with \"udp\""; } + +#if (NGX_HAVE_TCP_FASTOPEN) + if (ls->fastopen != -1) { + return "\"fastopen\" parameter is incompatible with \"udp\""; + } +#endif } als = cmcf->listen.elts; diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 01cda7a..934e7d8 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -31,6 +31,7 @@ typedef struct { ngx_uint_t next_upstream_tries; ngx_flag_t next_upstream; ngx_flag_t proxy_protocol; + ngx_flag_t half_close; ngx_stream_upstream_local_t *local; ngx_flag_t socket_keepalive; @@ -46,8 +47,8 @@ typedef struct { ngx_uint_t ssl_verify_depth; ngx_str_t ssl_trusted_certificate; ngx_str_t ssl_crl; - ngx_str_t ssl_certificate; - ngx_str_t ssl_certificate_key; + ngx_stream_complex_value_t *ssl_certificate; + ngx_stream_complex_value_t *ssl_certificate_key; ngx_array_t *ssl_passwords; ngx_array_t *ssl_conf_commands; @@ -101,6 +102,7 @@ static void ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s); static void ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc); static void ngx_stream_proxy_ssl_save_session(ngx_connection_t *c); static ngx_int_t ngx_stream_proxy_ssl_name(ngx_stream_session_t *s); +static ngx_int_t ngx_stream_proxy_ssl_certificate(ngx_stream_session_t *s); static ngx_int_t ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf); @@ -244,6 +246,13 @@ static ngx_command_t ngx_stream_proxy_commands[] = { offsetof(ngx_stream_proxy_srv_conf_t, proxy_protocol), NULL }, + { ngx_string("proxy_half_close"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, half_close), + NULL }, + #if (NGX_STREAM_SSL) { ngx_string("proxy_ssl"), @@ -318,14 +327,14 @@ static ngx_command_t ngx_stream_proxy_commands[] = { { ngx_string("proxy_ssl_certificate"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_stream_set_complex_value_zero_slot, NGX_STREAM_SRV_CONF_OFFSET, offsetof(ngx_stream_proxy_srv_conf_t, ssl_certificate), NULL }, { ngx_string("proxy_ssl_certificate_key"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_stream_set_complex_value_zero_slot, NGX_STREAM_SRV_CONF_OFFSET, offsetof(ngx_stream_proxy_srv_conf_t, ssl_certificate_key), NULL }, @@ -1060,6 +1069,15 @@ ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s) } } + if (pscf->ssl_certificate && (pscf->ssl_certificate->lengths + || pscf->ssl_certificate_key->lengths)) + { + if (ngx_stream_proxy_ssl_certificate(s) != NGX_OK) { + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + } + if (pscf->ssl_session_reuse) { pc->ssl->save_session = ngx_stream_proxy_ssl_save_session; @@ -1247,6 +1265,50 @@ done: return NGX_OK; } + +static ngx_int_t +ngx_stream_proxy_ssl_certificate(ngx_stream_session_t *s) +{ + ngx_str_t cert, key; + ngx_connection_t *c; + ngx_stream_proxy_srv_conf_t *pscf; + + c = s->upstream->peer.connection; + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + + if (ngx_stream_complex_value(s, pscf->ssl_certificate, &cert) + != NGX_OK) + { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream upstream ssl cert: \"%s\"", cert.data); + + if (*cert.data == '\0') { + return NGX_OK; + } + + if (ngx_stream_complex_value(s, pscf->ssl_certificate_key, &key) + != NGX_OK) + { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream upstream ssl key: \"%s\"", key.data); + + if (ngx_ssl_connection_certificate(c, c->pool, &cert, &key, + pscf->ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + + return NGX_OK; +} + #endif @@ -1701,6 +1763,24 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, } if (dst) { + + if (dst->type == SOCK_STREAM && pscf->half_close + && src->read->eof && !u->half_closed && !dst->buffered) + { + if (ngx_shutdown_socket(dst->fd, NGX_WRITE_SHUTDOWN) == -1) { + ngx_connection_error(c, ngx_socket_errno, + ngx_shutdown_socket_n " failed"); + + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + + u->half_closed = 1; + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream proxy %s socket shutdown", + from_upstream ? "client" : "upstream"); + } + if (ngx_handle_write_event(dst->write, 0) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; @@ -1779,6 +1859,13 @@ ngx_stream_proxy_test_finalize(ngx_stream_session_t *s, return NGX_DECLINED; } + if (pscf->half_close) { + /* avoid closing live connections until both read ends get EOF */ + if (!(c->read->eof && pc->read->eof && !c->buffered && !pc->buffered)) { + return NGX_DECLINED; + } + } + handler = c->log->handler; c->log->handler = NULL; @@ -1977,14 +2064,9 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) * * conf->ssl_protocols = 0; * conf->ssl_ciphers = { 0, NULL }; - * conf->ssl_name = NULL; * conf->ssl_trusted_certificate = { 0, NULL }; * conf->ssl_crl = { 0, NULL }; - * conf->ssl_certificate = { 0, NULL }; - * conf->ssl_certificate_key = { 0, NULL }; * - * conf->upload_rate = NULL; - * conf->download_rate = NULL; * conf->ssl = NULL; * conf->upstream = NULL; * conf->upstream_value = NULL; @@ -1994,6 +2076,8 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) conf->timeout = NGX_CONF_UNSET_MSEC; conf->next_upstream_timeout = NGX_CONF_UNSET_MSEC; conf->buffer_size = NGX_CONF_UNSET_SIZE; + conf->upload_rate = NGX_CONF_UNSET_PTR; + conf->download_rate = NGX_CONF_UNSET_PTR; conf->requests = NGX_CONF_UNSET_UINT; conf->responses = NGX_CONF_UNSET_UINT; conf->next_upstream_tries = NGX_CONF_UNSET_UINT; @@ -2001,13 +2085,17 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) conf->proxy_protocol = NGX_CONF_UNSET; conf->local = NGX_CONF_UNSET_PTR; conf->socket_keepalive = NGX_CONF_UNSET; + conf->half_close = NGX_CONF_UNSET; #if (NGX_STREAM_SSL) conf->ssl_enable = NGX_CONF_UNSET; conf->ssl_session_reuse = NGX_CONF_UNSET; + conf->ssl_name = NGX_CONF_UNSET_PTR; conf->ssl_server_name = NGX_CONF_UNSET; conf->ssl_verify = NGX_CONF_UNSET; conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; + conf->ssl_certificate = NGX_CONF_UNSET_PTR; + conf->ssl_certificate_key = NGX_CONF_UNSET_PTR; conf->ssl_passwords = NGX_CONF_UNSET_PTR; conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif @@ -2034,13 +2122,9 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 16384); - if (conf->upload_rate == NULL) { - conf->upload_rate = prev->upload_rate; - } + ngx_conf_merge_ptr_value(conf->upload_rate, prev->upload_rate, NULL); - if (conf->download_rate == NULL) { - conf->download_rate = prev->download_rate; - } + ngx_conf_merge_ptr_value(conf->download_rate, prev->download_rate, NULL); ngx_conf_merge_uint_value(conf->requests, prev->requests, 0); @@ -2060,6 +2144,8 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->socket_keepalive, prev->socket_keepalive, 0); + ngx_conf_merge_value(conf->half_close, prev->half_close, 0); + #if (NGX_STREAM_SSL) ngx_conf_merge_value(conf->ssl_enable, prev->ssl_enable, 0); @@ -2073,9 +2159,7 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); - if (conf->ssl_name == NULL) { - conf->ssl_name = prev->ssl_name; - } + ngx_conf_merge_ptr_value(conf->ssl_name, prev->ssl_name, NULL); ngx_conf_merge_value(conf->ssl_server_name, prev->ssl_server_name, 0); @@ -2089,11 +2173,11 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); - ngx_conf_merge_str_value(conf->ssl_certificate, - prev->ssl_certificate, ""); + ngx_conf_merge_ptr_value(conf->ssl_certificate, + prev->ssl_certificate, NULL); - ngx_conf_merge_str_value(conf->ssl_certificate_key, - prev->ssl_certificate_key, ""); + ngx_conf_merge_ptr_value(conf->ssl_certificate_key, + prev->ssl_certificate_key, NULL); ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); @@ -2137,27 +2221,41 @@ ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf) cln->handler = ngx_ssl_cleanup_ctx; cln->data = pscf->ssl; - if (pscf->ssl_certificate.len) { - - if (pscf->ssl_certificate_key.len == 0) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"proxy_ssl_certificate_key\" is defined " - "for certificate \"%V\"", &pscf->ssl_certificate); - return NGX_ERROR; - } - - if (ngx_ssl_certificate(cf, pscf->ssl, &pscf->ssl_certificate, - &pscf->ssl_certificate_key, pscf->ssl_passwords) - != NGX_OK) - { - return NGX_ERROR; - } - } - if (ngx_ssl_ciphers(cf, pscf->ssl, &pscf->ssl_ciphers, 0) != NGX_OK) { return NGX_ERROR; } + if (pscf->ssl_certificate) { + + if (pscf->ssl_certificate_key == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"proxy_ssl_certificate_key\" is defined " + "for certificate \"%V\"", + &pscf->ssl_certificate->value); + return NGX_ERROR; + } + + if (pscf->ssl_certificate->lengths + || pscf->ssl_certificate_key->lengths) + { + pscf->ssl_passwords = + ngx_ssl_preserve_passwords(cf, pscf->ssl_passwords); + if (pscf->ssl_passwords == NULL) { + return NGX_ERROR; + } + + } else { + if (ngx_ssl_certificate(cf, pscf->ssl, + &pscf->ssl_certificate->value, + &pscf->ssl_certificate_key->value, + pscf->ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + } + } + if (pscf->ssl_verify) { if (pscf->ssl_trusted_certificate.len == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, diff --git a/src/stream/ngx_stream_script.c b/src/stream/ngx_stream_script.c index a15f772..c447e15 100644 --- a/src/stream/ngx_stream_script.c +++ b/src/stream/ngx_stream_script.c @@ -252,7 +252,7 @@ ngx_stream_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, cv = (ngx_stream_complex_value_t **) (p + cmd->offset); - if (*cv != NULL) { + if (*cv != NGX_CONF_UNSET_PTR && *cv != NULL) { return "is duplicate"; } @@ -277,6 +277,44 @@ ngx_stream_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, } +char * +ngx_stream_set_complex_value_zero_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *p = conf; + + ngx_str_t *value; + ngx_stream_complex_value_t **cv; + ngx_stream_compile_complex_value_t ccv; + + cv = (ngx_stream_complex_value_t **) (p + cmd->offset); + + if (*cv != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + *cv = ngx_palloc(cf->pool, sizeof(ngx_stream_complex_value_t)); + if (*cv == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = *cv; + ccv.zero = 1; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + char * ngx_stream_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) diff --git a/src/stream/ngx_stream_script.h b/src/stream/ngx_stream_script.h index a481ca3..d8f3740 100644 --- a/src/stream/ngx_stream_script.h +++ b/src/stream/ngx_stream_script.h @@ -112,6 +112,8 @@ ngx_int_t ngx_stream_compile_complex_value( ngx_stream_compile_complex_value_t *ccv); char *ngx_stream_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_stream_set_complex_value_zero_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); char *ngx_stream_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index d8c0471..c530832 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -23,7 +23,13 @@ static ngx_int_t ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c); static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c); #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME -int ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg); +static int ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, + void *arg); +#endif +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation +static int ngx_stream_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, + const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg); #endif #ifdef SSL_R_CERT_CB_ERROR static int ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg); @@ -45,6 +51,8 @@ static char *ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_stream_ssl_alpn(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data); @@ -211,6 +219,13 @@ static ngx_command_t ngx_stream_ssl_commands[] = { offsetof(ngx_stream_ssl_conf_t, conf_commands), &ngx_stream_ssl_conf_command_post }, + { ngx_string("ssl_alpn"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE, + ngx_stream_ssl_alpn, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + ngx_null_command }; @@ -254,6 +269,9 @@ static ngx_stream_variable_t ngx_stream_ssl_vars[] = { { ngx_string("ssl_ciphers"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_ciphers, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_curve"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_curve, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_curves"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_curves, NGX_STREAM_VAR_CHANGEABLE, 0 }, @@ -266,6 +284,9 @@ static ngx_stream_variable_t ngx_stream_ssl_vars[] = { { ngx_string("ssl_server_name"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_server_name, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_alpn_protocol"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_alpn_protocol, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_cert"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_certificate, NGX_STREAM_VAR_CHANGEABLE, 0 }, @@ -434,7 +455,7 @@ ngx_stream_ssl_handshake_handler(ngx_connection_t *c) #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME -int +static int ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) { return SSL_TLSEXT_ERR_OK; @@ -443,9 +464,49 @@ ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) #endif +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + +static int +ngx_stream_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, + unsigned char *outlen, const unsigned char *in, unsigned int inlen, + void *arg) +{ + ngx_str_t *alpn; +#if (NGX_DEBUG) + unsigned int i; + ngx_connection_t *c; + + c = ngx_ssl_get_connection(ssl_conn); + + for (i = 0; i < inlen; i += in[i] + 1) { + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, c->log, 0, + "SSL ALPN supported by client: %*s", + (size_t) in[i], &in[i + 1]); + } + +#endif + + alpn = arg; + + if (SSL_select_next_proto((unsigned char **) out, outlen, alpn->data, + alpn->len, in, inlen) + != OPENSSL_NPN_NEGOTIATED) + { + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, c->log, 0, + "SSL ALPN selected: %*s", (size_t) *outlen, *out); + + return SSL_TLSEXT_ERR_OK; +} + +#endif + + #ifdef SSL_R_CERT_CB_ERROR -int +static int ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) { ngx_str_t cert, key; @@ -602,6 +663,7 @@ ngx_stream_ssl_create_conf(ngx_conf_t *cf) * scf->client_certificate = { 0, NULL }; * scf->trusted_certificate = { 0, NULL }; * scf->crl = { 0, NULL }; + * scf->alpn = { 0, NULL }; * scf->ciphers = { 0, NULL }; * scf->shm_zone = NULL; */ @@ -660,6 +722,7 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->trusted_certificate, prev->trusted_certificate, ""); ngx_conf_merge_str_value(conf->crl, prev->crl, ""); + ngx_conf_merge_str_value(conf->alpn, prev->alpn, ""); ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve, NGX_DEFAULT_ECDH_CURVE); @@ -720,6 +783,20 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_stream_ssl_servername); #endif +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + if (conf->alpn.len) { + SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_stream_ssl_alpn_select, + &conf->alpn); + } +#endif + + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, + conf->prefer_server_ciphers) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + if (ngx_stream_ssl_compile_certificates(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; } @@ -752,13 +829,6 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) } } - if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, - conf->prefer_server_ciphers) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - if (conf->verify) { if (conf->client_certificate.len == 0 && conf->verify != 3) { @@ -1056,6 +1126,60 @@ invalid: } +static char * +ngx_stream_ssl_alpn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + + ngx_stream_ssl_conf_t *scf = conf; + + u_char *p; + size_t len; + ngx_str_t *value; + ngx_uint_t i; + + if (scf->alpn.len) { + return "is duplicate"; + } + + value = cf->args->elts; + + len = 0; + + for (i = 1; i < cf->args->nelts; i++) { + + if (value[i].len > 255) { + return "protocol too long"; + } + + len += value[i].len + 1; + } + + scf->alpn.data = ngx_pnalloc(cf->pool, len); + if (scf->alpn.data == NULL) { + return NGX_CONF_ERROR; + } + + p = scf->alpn.data; + + for (i = 1; i < cf->args->nelts; i++) { + *p++ = value[i].len; + p = ngx_cpymem(p, value[i].data, value[i].len); + } + + scf->alpn.len = len; + + return NGX_CONF_OK; + +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the \"ssl_alpn\" directive requires OpenSSL " + "with ALPN support"); + return NGX_CONF_ERROR; +#endif +} + + static char * ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) { diff --git a/src/stream/ngx_stream_ssl_module.h b/src/stream/ngx_stream_ssl_module.h index c6e24be..e7c825e 100644 --- a/src/stream/ngx_stream_ssl_module.h +++ b/src/stream/ngx_stream_ssl_module.h @@ -42,6 +42,7 @@ typedef struct { ngx_str_t client_certificate; ngx_str_t trusted_certificate; ngx_str_t crl; + ngx_str_t alpn; ngx_str_t ciphers; diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h index 9857e0b..f561779 100644 --- a/src/stream/ngx_stream_upstream.h +++ b/src/stream/ngx_stream_upstream.h @@ -142,6 +142,7 @@ typedef struct { ngx_stream_upstream_state_t *state; unsigned connected:1; unsigned proxy_protocol:1; + unsigned half_closed:1; } ngx_stream_upstream_t; From 24d9bd02907266424ef4a74ad7de298be7723631 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 24 May 2022 14:20:28 -0400 Subject: [PATCH 434/651] Update changelog --- debian/changelog | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 3b9b5b7..98db79b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,7 +1,9 @@ -nginx (1.20.2-3) UNRELEASED; urgency=medium +nginx (1.22.0-1) UNRELEASED; urgency=medium - * d/conf/mime.types: Fix a typo in font/woff2 extension in - mime.types. (Closes: #1010798) + * New upstream release (1.22.0) + * Additional changes: + * d/conf/mime.types: Fix a typo in font/woff2 extension in + mime.types. (Closes: #1010798) -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 From 5900bc832a071308bdd1b10ae01796389fbf4e7b Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 24 May 2022 14:24:29 -0400 Subject: [PATCH 435/651] Changelog update --- debian/changelog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/debian/changelog b/debian/changelog index 98db79b..04b3aa1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,11 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * Additional changes: * d/conf/mime.types: Fix a typo in font/woff2 extension in mime.types. (Closes: #1010798) + * d/upstream/signing-key.asc: Additional signing keys observed + in upstream (Konstantin Pavlov ) during + upstream merge/import by Thomas Ward, additional signing key + was added to the keyring while keeping Maxim's key in signing + keys as wel. -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 From c394d8d99931a56d9a37543e2673caf7b321e8ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 25 May 2022 07:01:01 +0200 Subject: [PATCH 436/651] d/p/CVE-2021-3618.patch removed, fix is included in new upstream release --- debian/changelog | 5 ++ debian/patches/CVE-2021-3618.patch | 84 ------------------------------ debian/patches/series | 1 - 3 files changed, 5 insertions(+), 85 deletions(-) delete mode 100644 debian/patches/CVE-2021-3618.patch diff --git a/debian/changelog b/debian/changelog index 04b3aa1..16e6b2d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,6 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium + [ Thomas Ward ] * New upstream release (1.22.0) * Additional changes: * d/conf/mime.types: Fix a typo in font/woff2 extension in @@ -10,6 +11,10 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium was added to the keyring while keeping Maxim's key in signing keys as wel. + [ Jan Mojžíš ] + * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream + release + -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 nginx (1.20.2-2) unstable; urgency=medium diff --git a/debian/patches/CVE-2021-3618.patch b/debian/patches/CVE-2021-3618.patch deleted file mode 100644 index 10f37a9..0000000 --- a/debian/patches/CVE-2021-3618.patch +++ /dev/null @@ -1,84 +0,0 @@ -Subject: Patch mitigation for CVE-2021-3618 - Mail: max_errors directive. - . - Similarly to smtpd_hard_error_limit in Postfix and smtp_max_unknown_commands - in Exim, specifies the number of errors after which the connection is closed. -Origin: upstream, http://hg.nginx.org/nginx/rev/ec1071830799 -Bug-Debian: https://bugs.debian.org/991328 - ---- a/src/mail/ngx_mail.h -+++ b/src/mail/ngx_mail.h -@@ -115,6 +115,8 @@ - ngx_msec_t timeout; - ngx_msec_t resolver_timeout; - -+ ngx_uint_t max_errors; -+ - ngx_str_t server_name; - - u_char *file_name; -@@ -231,6 +233,7 @@ - ngx_uint_t command; - ngx_array_t args; - -+ ngx_uint_t errors; - ngx_uint_t login_attempt; - - /* used to parse POP3/IMAP/SMTP command */ ---- a/src/mail/ngx_mail_core_module.c -+++ b/src/mail/ngx_mail_core_module.c -@@ -85,6 +85,13 @@ - offsetof(ngx_mail_core_srv_conf_t, resolver_timeout), - NULL }, - -+ { ngx_string("max_errors"), -+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, -+ ngx_conf_set_num_slot, -+ NGX_MAIL_SRV_CONF_OFFSET, -+ offsetof(ngx_mail_core_srv_conf_t, max_errors), -+ NULL }, -+ - ngx_null_command - }; - -@@ -163,6 +170,8 @@ - cscf->timeout = NGX_CONF_UNSET_MSEC; - cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; - -+ cscf->max_errors = NGX_CONF_UNSET_UINT; -+ - cscf->resolver = NGX_CONF_UNSET_PTR; - - cscf->file_name = cf->conf_file->file.name.data; -@@ -182,6 +191,7 @@ - ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout, - 30000); - -+ ngx_conf_merge_uint_value(conf->max_errors, prev->max_errors, 5); - - ngx_conf_merge_str_value(conf->server_name, prev->server_name, ""); - ---- a/src/mail/ngx_mail_handler.c -+++ b/src/mail/ngx_mail_handler.c -@@ -871,7 +871,20 @@ - return NGX_MAIL_PARSE_INVALID_COMMAND; - } - -- if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) { -+ if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) { -+ -+ s->errors++; -+ -+ if (s->errors >= cscf->max_errors) { -+ ngx_log_error(NGX_LOG_INFO, c->log, 0, -+ "client sent too many invalid commands"); -+ s->quit = 1; -+ } -+ -+ return rc; -+ } -+ -+ if (rc == NGX_IMAP_NEXT) { - return rc; - } - diff --git a/debian/patches/series b/debian/patches/series index 4e43575..5b6b799 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,3 +1,2 @@ 0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch 0003-define_gnu_source-on-other-glibc-based-platforms.patch -CVE-2021-3618.patch From 7224e5e7ca7a1a8bd6f692082b176830ae3657bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 25 May 2022 11:04:30 +0200 Subject: [PATCH 437/651] d/control: removed ppc64el from list of luajit platforms. --- debian/changelog | 1 + debian/control | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 16e6b2d..eb42d36 100644 --- a/debian/changelog +++ b/debian/changelog @@ -14,6 +14,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream release + * d/control: removed ppc64el from list of luajit platforms. (Closes: #1011303) -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 diff --git a/debian/control b/debian/control index cc32589..3a2b586 100644 --- a/debian/control +++ b/debian/control @@ -12,8 +12,8 @@ Build-Depends: debhelper-compat (= 13), libgd-dev, libgeoip-dev, libhiredis-dev, - liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !ppc64el], - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 ppc64el], + liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64], + libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64], libmaxminddb-dev, libmhash-dev, libpam0g-dev, From a013b18ff66b9ac1d899827ed5725589f9900701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 25 May 2022 11:19:06 +0200 Subject: [PATCH 438/651] d/changelog fix whitespaces --- debian/changelog | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/debian/changelog b/debian/changelog index eb42d36..713a937 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,7 +3,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium [ Thomas Ward ] * New upstream release (1.22.0) * Additional changes: - * d/conf/mime.types: Fix a typo in font/woff2 extension in + * d/conf/mime.types: Fix a typo in font/woff2 extension in mime.types. (Closes: #1010798) * d/upstream/signing-key.asc: Additional signing keys observed in upstream (Konstantin Pavlov ) during @@ -21,7 +21,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium nginx (1.20.2-2) unstable; urgency=medium [ Thomas Ward ] - * d/patches/CVE-2021-3618.patch: Include upstream changeset from NGINX + * d/patches/CVE-2021-3618.patch: Include upstream changeset from NGINX that adds mitigations into the Mail module for CVE-2021-3618.patch. (Closes: #991328) @@ -46,7 +46,7 @@ nginx (1.20.2-1) unstable; urgency=medium * d/conf/mime.types: Update mime.types to more match upstream mime.types and include upstream changes with mime.types from 1.21.x via nginx.org mercurial repository versions. - * d/control: Remove self from Uploaders per other Debian devs, who want + * d/control: Remove self from Uploaders per other Debian devs, who want that commit to be done by someone on the current uploaders/maintainers group instead. @@ -65,7 +65,7 @@ nginx (1.18.0-9) unstable; urgency=medium * d/watch: Update watch syntax to match all even versions of NGINX releases rather than use a watch syntax that is static to one specific version. This will fix the untracked "New upstream stable versions" problem. - * d/control: Update 'uploaders' as Thomas Ward is now a maintainer in + * d/control: Update 'uploaders' as Thomas Ward is now a maintainer in the Salsa repository. -- Jan Mojžíš Tue, 05 Apr 2022 19:11:47 +0200 From 5eec971e2717232ed1d8a88ce193edccb495e582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 25 May 2022 17:13:14 +0200 Subject: [PATCH 439/651] d/copyright: - bump nginx copyright years - added copyright for src/stream/ngx_stream_set_module.c --- debian/changelog | 2 ++ debian/copyright | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 713a937..53399e7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -15,6 +15,8 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream release * d/control: removed ppc64el from list of luajit platforms. (Closes: #1011303) + * d/copyright: bump nginx copyright years + * d/copyright: added copyright for src/stream/ngx_stream_set_module.c -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 diff --git a/debian/copyright b/debian/copyright index f82fc2d..a3f59eb 100644 --- a/debian/copyright +++ b/debian/copyright @@ -3,8 +3,8 @@ Upstream-Name: nginx Source: https://nginx.org/en/download.html Files: * -Copyright: 2002-2019, Igor Sysoev - 2011-2019, Nginx, Inc. +Copyright: 2002-2021, Igor Sysoev + 2011-2022, Nginx, Inc. Maxim Dounin Valentin V. Bartenev Roman Arutyunyan @@ -15,6 +15,11 @@ Files: src/core/ngx_murmurhash.c Copyright: Copyright (C) Austin Appleby License: BSD-2-clause +Files: src/stream/ngx_stream_set_module.c +Copyright: Copyright (C) Pavel Pautov + Copyright (C) Nginx, Inc. +License: BSD-2-clause + Files: src/http/modules/ngx_http_scgi_module.c src/http/modules/ngx_http_uwsgi_module.c Copyright: 2009-2010, Unbit S.a.s. From c3f9fc730b23255d7b2fce09b34a98583f9dcfc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 25 May 2022 17:45:49 +0200 Subject: [PATCH 440/651] d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c --- debian/changelog | 1 + debian/copyright | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/debian/changelog b/debian/changelog index 53399e7..1c01d3f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -17,6 +17,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/control: removed ppc64el from list of luajit platforms. (Closes: #1011303) * d/copyright: bump nginx copyright years * d/copyright: added copyright for src/stream/ngx_stream_set_module.c + * d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 diff --git a/debian/copyright b/debian/copyright index a3f59eb..d5c191a 100644 --- a/debian/copyright +++ b/debian/copyright @@ -28,12 +28,6 @@ Copyright: 2009-2010, Unbit S.a.s. Nginx, Inc. License: BSD-2-clause -Files: src/http/v2/ngx_http_v2_huff_encode.c -Copyright: 2015, Vlad Krasnov - Nginx, Inc. - Valentin V. Bartenev -License: BSD-2-clause - Files: contrib/geo2nginx.pl Copyright: 2005, Andrei Nigmatulin License: BSD-2-clause From a8ebc4ba0c136b1df2c7bd2effffa467dc821f0d Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Thu, 26 May 2022 23:15:02 -0400 Subject: [PATCH 441/651] Update d/copyright for murmurhash license being public-domain --- debian/changelog | 5 ++++- debian/copyright | 9 +++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 1c01d3f..4874df2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,7 +9,10 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium in upstream (Konstantin Pavlov ) during upstream merge/import by Thomas Ward, additional signing key was added to the keyring while keeping Maxim's key in signing - keys as wel. + keys as well. + * d/copyright: Updated copyright for src/core/ngx_murmurhash.c + and debian/modules/http-ndk/src/hash/murmurhash2.c to be + public-domain (Closes: #1011936) [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream diff --git a/debian/copyright b/debian/copyright index d5c191a..59dfc09 100644 --- a/debian/copyright +++ b/debian/copyright @@ -13,7 +13,10 @@ License: BSD-2-clause Files: src/core/ngx_murmurhash.c Copyright: Copyright (C) Austin Appleby -License: BSD-2-clause +License: public-domain + All MurmurHash versions are public domain software, and the author + disclaims all copyright to their code. + Files: src/stream/ngx_stream_set_module.c Copyright: Copyright (C) Pavel Pautov @@ -65,7 +68,9 @@ License: BSD-4-clause Files: debian/modules/http-ndk/src/hash/murmurhash2.c Copyright: Austin Appleby -License: BSD-3-clause +License: public-domain + All MurmurHash versions are public domain software, and the author + disclaims all copyright to their code. Files: debian/modules/http-auth-pam/* Copyright: 2008-2020, Sergio Talens Oliag From 20eb8ab414656c56632795454156ce014532972d Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Wed, 8 Jun 2022 15:22:49 -0400 Subject: [PATCH 442/651] ppc64el FTBFS fixed in luajit, nginx: no action needed --- debian/changelog | 1 - debian/control | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 4874df2..3b92437 100644 --- a/debian/changelog +++ b/debian/changelog @@ -17,7 +17,6 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream release - * d/control: removed ppc64el from list of luajit platforms. (Closes: #1011303) * d/copyright: bump nginx copyright years * d/copyright: added copyright for src/stream/ngx_stream_set_module.c * d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c diff --git a/debian/control b/debian/control index 3a2b586..cc32589 100644 --- a/debian/control +++ b/debian/control @@ -12,8 +12,8 @@ Build-Depends: debhelper-compat (= 13), libgd-dev, libgeoip-dev, libhiredis-dev, - liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64], - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64], + liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !ppc64el], + libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 ppc64el], libmaxminddb-dev, libmhash-dev, libpam0g-dev, From 4b7212e74500151248dab2f0baf45837e39a266d Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Wed, 8 Jun 2022 16:15:40 -0400 Subject: [PATCH 443/651] Enable luajit for s390x --- debian/changelog | 5 +++++ debian/control | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 3b92437..48897b5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -13,6 +13,11 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/copyright: Updated copyright for src/core/ngx_murmurhash.c and debian/modules/http-ndk/src/hash/murmurhash2.c to be public-domain (Closes: #1011936) + * d/control: Use libluajit-5.1-dev for s390x. + Due to src:luajit2 landing in Unstable, superseding src:luajit, + and due to luajit2 having s390x support, we can use s390x now + with luajit instead of standard Lua. + Thanks to Paul Gevers for the heads up on luajit2 supporting s390x. [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream diff --git a/debian/control b/debian/control index cc32589..bbec75a 100644 --- a/debian/control +++ b/debian/control @@ -12,8 +12,8 @@ Build-Depends: debhelper-compat (= 13), libgd-dev, libgeoip-dev, libhiredis-dev, - liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !ppc64el], - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 ppc64el], + liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !ppc64el !s390x], + libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 ppc64el s390x], libmaxminddb-dev, libmhash-dev, libpam0g-dev, From 333875401c6fa18c4f37d39f6ea6411ef1e1b60a Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Sat, 25 Jun 2022 17:31:16 -0400 Subject: [PATCH 444/651] Return ppc64el to liblua, luajit2 still broken on ppc64el. --- debian/changelog | 2 ++ debian/control | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 48897b5..fec8e1d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -18,6 +18,8 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium and due to luajit2 having s390x support, we can use s390x now with luajit instead of standard Lua. Thanks to Paul Gevers for the heads up on luajit2 supporting s390x. + * d/control: Use liblua for ppc64el - src:luajit2 is still not ppc64el + stable and there seems to be nobody willing to support it. [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream diff --git a/debian/control b/debian/control index bbec75a..5ae14c8 100644 --- a/debian/control +++ b/debian/control @@ -12,8 +12,8 @@ Build-Depends: debhelper-compat (= 13), libgd-dev, libgeoip-dev, libhiredis-dev, - liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !ppc64el !s390x], - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 ppc64el s390x], + liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !s390x], + libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 s390x], libmaxminddb-dev, libmhash-dev, libpam0g-dev, From d4b9d6a1daf9e64816e6d69d4d10083a032e251c Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Fri, 4 Feb 2022 00:00:41 +0800 Subject: [PATCH 445/651] Adding nginx-dev package for tools for building out-of-tree modules Nginx does not officially provide a mechanism to build out-of-tree modules, however, this can be achieved by using all the headers and the configure scripts in the auto/ directory. As a result, a nginx-dev package can thus be developed for build out-of-tree modules. The detailed steps to build an out-of-tree module in the headers-only nginx source tree is: 1. Execute the configure script of nginx, with the same configure arguments (excluding the reference to other dynamic modules, but including the reference to depending modules as a built-in module). To prevent the configure scripts modifying the nginx ource tree, we can 1. point the build dir to a directory elsewhere, to generate all the build time files outside; 2. slightly patch the configure scripts to prevent generating a makefile directly in the source tree, which simply includes the generated makefile at the build dir. 2. Execute make at the source tree, but providing the generated makefile in the build dir. The command is `make -C /path/to/nginx/source -f /path/to/build_dir/Makefile modules` To make sure the compiled module is compatible with the nginx binary and the nginx binaries with the same upstream version, the key points are: - Module signature: A module signature containing the (upstream) version number and encoding the necessary configuration flags is put in each module as well as the nginx binary itself. When loading a module, nginx will compare the signature on the module with its own. As long as the configure flags, especially those encoded in the signature, and the version of the nginx source used to build the module are the same as thoes used to build the nginx binary, the moudle can pass the signature check. As a result, the module can depend on the exact nginx upstream version, ignoring the debian revison. - ABI compatibility: We should maintain nginx precisely, to prevent making any ABI changes between different debian revisions. - Build check: When building the module, we can perform a simple module loading check via `nginx -t`. This test serves as a "smoking test", to ensure we are actually building loadable modules. Summing all the above up and adding the necessary automation scripts for module packaging, the nginx-dev package can be composed, including the following parts: - The headers and configure scripts: generated and filtered out from the source tree. The scripts are slightly patched to prevent generating a makefile directly in the source tree, as stated above; - The recorded configure options: all the modules built should include these options when configured; - dh_nginx script and its man page: modified from the original dh_nginx script, adding a "--in-nginx-tree" option. When specified, the behavior remains the same as the original version (so the option is added in the rule building the in-package modules). When not specified, the dependency added into misc:Depends will be the exact upstream nginx version, ignoring the debian revision. E.g. nginx-common >= 1.20.2, << 1.20.2.1~ - a debhelper sequence plugin which can be enabled by module packages with `dh --with=nginx`, inserting `dh_nginx` after `dh_install` - a build system plugin which can bu enabled by module packages with `dh --buildsystem=nginx_mod`, automating the module building process using the steps mentioned before. - autoscript templates used by dh_nginx are also installed without modification. Currently. the architecture of nginx-dev is any because nginx has arch related dependencies, which is brought in by http-lua module. After it is removed from the nginx source tree, the architecture can be changed to all since no binary is included in this package. --- debian/control | 13 +++++ debian/debhelper/nginx.pm | 8 +++ debian/debhelper/nginx_mod.pm | 96 +++++++++++++++++++++++++++++++++++ debian/dh_nginx | 18 ++++++- debian/nginx-dev.install | 8 +++ debian/nginx-dev.manpages | 1 + debian/rules | 31 ++++++++--- 7 files changed, 165 insertions(+), 10 deletions(-) create mode 100644 debian/debhelper/nginx.pm create mode 100644 debian/debhelper/nginx_mod.pm create mode 100644 debian/nginx-dev.install create mode 100644 debian/nginx-dev.manpages diff --git a/debian/control b/debian/control index 5ae14c8..9f31ba4 100644 --- a/debian/control +++ b/debian/control @@ -68,6 +68,19 @@ Description: small, powerful, scalable web/proxy server - common files This package contains base configuration files used by all versions of nginx. +Package: nginx-dev +Architecture: any +Depends: ${misc:Depends}, ${S:Build-Depends}, + nginx-core (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}) +Description: nginx web/proxy server - development headers + Nginx ("engine X") is a high-performance web and reverse proxy server + created by Igor Sysoev. It can be used both as a standalone web server + and as a proxy to reduce the load on back-end HTTP or mail servers. + . + This package provides development headers and necessary config scripts + for the nginx web/proxy server, useful to develop and link third party + additions to the Debian nginx web/proxy server packages. + Package: nginx-core Architecture: any Depends: libnginx-mod-http-geoip (= ${binary:Version}), diff --git a/debian/debhelper/nginx.pm b/debian/debhelper/nginx.pm new file mode 100644 index 0000000..0473815 --- /dev/null +++ b/debian/debhelper/nginx.pm @@ -0,0 +1,8 @@ +#!/usr/bin/perl +use warnings; +use strict; +use Debian::Debhelper::Dh_Lib; + +insert_after("dh_install", "dh_nginx"); + +1; diff --git a/debian/debhelper/nginx_mod.pm b/debian/debhelper/nginx_mod.pm new file mode 100644 index 0000000..af37fda --- /dev/null +++ b/debian/debhelper/nginx_mod.pm @@ -0,0 +1,96 @@ +# A build system class for handling nginx modules. +# +# Copyright: © 2022 Miao Wang +# License: MIT + +package Debian::Debhelper::Buildsystem::nginx_mod; + +use strict; +use warnings; +use Debian::Debhelper::Dh_Lib qw(error doit); +use File::Spec; +use parent qw(Debian::Debhelper::Buildsystem::makefile); +use Config; + +sub DESCRIPTION { + "Nginx Module (config)" +} + +sub check_auto_buildable { + my ($this, $step) = @_; + + return 1 if -e $this->get_sourcepath("config"); +} + +sub _NGINX_SRC_DIR { + "/usr/share/nginx/src" +} + +sub new { + my $class=shift; + my $this= $class->SUPER::new(@_); + $this->prefer_out_of_source_building(@_); + return $this; +} + +sub configure { + my $this=shift; + + doit({ + "chdir" => $this->_NGINX_SRC_DIR, + "update_env" => { + "src_dir" => $this->get_sourcedir, + "bld_dir" => $this->get_builddir, + "pwd_dir" => $this->{cwd}, + }, + }, "bash", "-c", '. ./conf_flags + ./configure \\ + --with-cc-opt="$(cd "$pwd_dir/$src_dir"; dpkg-buildflags --get CFLAGS) -fPIC $(cd "$pwd_dir/$src_dir"; dpkg-buildflags --get CPPFLAGS)" \\ + --with-ld-opt="$(cd "$pwd_dir/$src_dir"; dpkg-buildflags --get LDFLAGS) -fPIC" \\ + "${NGX_CONF_FLAGS[@]}" \\ + --add-dynamic-module="$pwd_dir/$src_dir" \\ + --builddir="$pwd_dir/$bld_dir" \\ + "$@"', "dummy", @_); +} + +sub build { + my $this=shift; + + $this->do_make("-f", File::Spec->catfile($this->{cwd}, $this->get_buildpath("Makefile")), "-C", $this->_NGINX_SRC_DIR, "modules"); +} + +sub test { + my $this=shift; + $this->doit_in_builddir("bash", "-e", "-o", "pipefail", "-c", ' + tmp_conf=$(mktemp -p .) + for pre_dep in "$@"; do + echo "load_module modules/$pre_dep;" >> "$tmp_conf" + done + for i in *.so; do + echo "load_module $PWD/$i;" >> "$tmp_conf" + done + echo "events{}" >> "$tmp_conf" + nginx -g "error_log /dev/null; pid /dev/null;" -t -q -c "$PWD/$tmp_conf" + rm -f "$tmp_conf" + ', "dummy", @_); +} + +sub install { + my $this=shift; + my $destdir=shift; + + $this->doit_in_builddir("bash", "-e", "-o", "pipefail", "-c", ' + destdir=$1 + mkdir -p "$destdir/usr/lib/nginx/modules" + for i in *.so; do + cp "$i" "$destdir/usr/lib/nginx/modules/" + done + ', "dummy", $destdir); +} + +sub clean { + my $this=shift; + $this->rmdir_builddir(); +} + +1 diff --git a/debian/dh_nginx b/debian/dh_nginx index 8e6ce3b..4853568 100755 --- a/debian/dh_nginx +++ b/debian/dh_nginx @@ -48,7 +48,7 @@ sub nginx_modules_conf_installdir =head1 SYNOPSIS -B [S>] [B<-n>|B<--noscripts>] +B [S>] [B<-n>|B<--noscripts>] [B<--in-nginx-tree>] =head1 DESCRIPTION @@ -63,6 +63,8 @@ It supports the following configuration types =item * Nginx modules +=back + =head1 INVOCATION %: @@ -128,6 +130,10 @@ configuration by default. Do not modify F/F/F maintainer scripts. +=item B<--in-nginx-tree> + +Specify this option when building in-tree modules along with nginx. When +specified, nginx abi version is not required in package name. =back @@ -150,8 +156,11 @@ dh_nginx is heavily influnced by dh_apache2 written by Arno Toell ## main code starts here ## +my $nginx_in_tree; + init(options => { "e|noenable" => \$dh{NOENABLE}, + "in-nginx-tree" => \$nginx_in_tree, }); foreach my $package ((@{$dh{DOPACKAGES}})) @@ -231,7 +240,12 @@ foreach my $package ((@{$dh{DOPACKAGES}})) { warning("Package $package appears to be an Nginx module. It should comply to the package naming scheme libnginx-mod-\n"); } - addsubstvar($package, "misc:Depends", nginx_depends()); + if ($nginx_in_tree){ + addsubstvar($package, "misc:Depends", nginx_depends()); + } else { + my $ngx_ver = `grep 'define NGINX_VERSION' /usr/share/nginx/src/src/core/nginx.h | sed -e 's/^.*"\\(.*\\)".*/\\1/'`; + addsubstvar($package, "misc:Depends", "nginx-common (>= $ngx_ver), nginx-common (<< $ngx_ver.1~)"); + } my $modules = ""; foreach my $module (@{$PACKAGE_TYPE{'has_a_module'}}) diff --git a/debian/nginx-dev.install b/debian/nginx-dev.install new file mode 100644 index 0000000..6a2ad43 --- /dev/null +++ b/debian/nginx-dev.install @@ -0,0 +1,8 @@ +debian/build-src/auto usr/share/nginx/src/ +debian/build-src/src usr/share/nginx/src/ +debian/build-src/conf_flags usr/share/nginx/src/ +debian/build-src/configure usr/share/nginx/src/ +debian/debhelper/nginx.pm usr/share/perl5/Debian/Debhelper/Sequence/ +debian/dh_nginx usr/bin/ +debian/debhelper/nginx_mod.pm usr/share/perl5/Debian/Debhelper/Buildsystem/ +debian/autoscripts/* usr/share/debhelper/autoscripts/ diff --git a/debian/nginx-dev.manpages b/debian/nginx-dev.manpages new file mode 100644 index 0000000..0ece920 --- /dev/null +++ b/debian/nginx-dev.manpages @@ -0,0 +1 @@ +debian/build-src/dh_nginx.1 diff --git a/debian/rules b/debian/rules index f777843..68ed613 100755 --- a/debian/rules +++ b/debian/rules @@ -32,7 +32,7 @@ DYN_MODS := \ MODULESDIR = $(CURDIR)/debian/modules BASEDIR = $(CURDIR) -$(foreach flavour,$(FLAVOURS),$(eval BUILDDIR_$(flavour) = $(CURDIR)/debian/build-$(flavour))) +$(foreach flavour,$(FLAVOURS) src,$(eval BUILDDIR_$(flavour) = $(CURDIR)/debian/build-$(flavour))) DEB_BUILD_ARCH ?=$(shell dpkg-architecture -qDEB_BUILD_ARCH) ifeq ($(DEB_BUILD_ARCH),sparc) @@ -48,9 +48,7 @@ MODULESPATCHDIR = $(CURDIR)/debian/modules/patches modules_with_patches := $(notdir $(wildcard $(CURDIR)/debian/modules/patches/*)) # configure flags -common_configure_flags := \ - --with-cc-opt="$(debian_cflags)" \ - --with-ld-opt="$(debian_ldflags)" \ +basic_configure_flags := \ --prefix=/usr/share/nginx \ --conf-path=/etc/nginx/nginx.conf \ --http-log-path=/var/log/nginx/access.log \ @@ -75,6 +73,11 @@ common_configure_flags := \ --with-http_slice_module \ --with-threads +common_configure_flags := \ + --with-cc-opt="$(debian_cflags)" \ + --with-ld-opt="$(debian_ldflags)" \ + $(basic_configure_flags) + light_configure_flags := \ $(common_configure_flags) \ --with-http_gzip_static_module \ @@ -132,15 +135,15 @@ extras_configure_flags := \ %: dh $@ --without autoreconf -override_dh_auto_configure: config_patch_modules $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) -override_dh_auto_build: $(foreach flavour,$(FLAVOURS),build.arch.$(flavour)) +override_dh_auto_configure: config_patch_modules $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) config.src +override_dh_auto_build: $(foreach flavour,$(FLAVOURS),build.arch.$(flavour)) build.src override_dh_strip: $(foreach flavour,$(FLAVOURS),strip.arch.$(flavour)) $(foreach mod,$(DYN_MODS),strip.mods.$(mod)) -override_dh_clean: clean_patch_modules $(foreach flavour,$(FLAVOURS),clean.$(flavour)) +override_dh_clean: clean_patch_modules $(foreach flavour,$(FLAVOURS),clean.$(flavour)) clean.src dh_clean override_dh_install: dh_install - DH_AUTOSCRIPTDIR=$(CURDIR)/debian/autoscripts debian/dh_nginx + DH_AUTOSCRIPTDIR=$(CURDIR)/debian/autoscripts debian/dh_nginx --in-nginx-tree override_dh_installinit: dh_installinit --no-stop-on-upgrade --no-start --name=nginx @@ -154,6 +157,14 @@ override_dh_installlogrotate: build.arch.%: $(MAKE) -C $(BUILDDIR_$*) build +build.src: + cp -Pa $(CURDIR)/auto $(BUILDDIR_src)/ + sed -i '/^# create Makefile/,/^END$$/d' $(BUILDDIR_src)/auto/make $(BUILDDIR_src)/auto/init $(BUILDDIR_src)/auto/install + find $(CURDIR)/src -type f -name '*.h' -printf 'src/%P\0' | tar -C $(CURDIR) --null --files-from - -c | tar -C $(BUILDDIR_src)/ -x + if [ -e $(CURDIR)/configure ]; then cp $(CURDIR)/configure $(BUILDDIR_src)/; fi + echo "NGX_CONF_FLAGS=(" $(basic_configure_flags) ")" > $(BUILDDIR_src)/conf_flags + pod2man debian/dh_nginx > $(BUILDDIR_src)/dh_nginx.1 + strip.arch.%: dh_strip --package=nginx-$(*) -O--dbgsym-migration='nginx-$(*)-dbg (<< 1.10.1-3~)' @@ -182,6 +193,10 @@ config.arch.%: cp -Pa $(CURDIR)/man $(BUILDDIR_$*)/ cd $(BUILDDIR_$*) && ./configure $($*_configure_flags) +config.src: + dh_testdir + mkdir -p $(BUILDDIR_src) + clean.%: rm -rf $(BUILDDIR_$*) From 87b5e38f6d10b13e7fd567c9e430153c48d7bafc Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Thu, 26 May 2022 15:48:54 +0800 Subject: [PATCH 446/651] nginx-dev: simplify dependencies nginx-dev depends on ${S:Build-Depends} before this commit, to include all the build-depdencies of nginx source packages. However, this also includes build dependency for those in-tree 3rd party modules, which are unnecessary. This commit removes them and explicitly list those packages needed to build a general module. The architecture of nginx-dev can thus be changed to all instead of any. When all 3rd party modules are removed, the dependency can be changed back to ${S:Build-Depends} to make the config less redundant. --- debian/control | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/debian/control b/debian/control index 9f31ba4..f6b11ba 100644 --- a/debian/control +++ b/debian/control @@ -69,9 +69,21 @@ Description: small, powerful, scalable web/proxy server - common files nginx. Package: nginx-dev -Architecture: any -Depends: ${misc:Depends}, ${S:Build-Depends}, - nginx-core (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}) +Architecture: all +Depends: ${misc:Depends}, + debhelper-compat (= 13), + dpkg-dev (>= 1.15.5), + libgd-dev, + libgeoip-dev, + libpcre3-dev, + libperl-dev, + libssl-dev, + libxslt1-dev, + po-debconf, + quilt, + zlib1g-dev, + nginx-core (<< ${source:Version}.1~) | nginx-light (<< ${source:Version}.1~) | nginx-extras (<< ${source:Version}.1~), + nginx-core (>= ${source:Version}) | nginx-light (>= ${source:Version}) | nginx-extras (>= ${source:Version}) Description: nginx web/proxy server - development headers Nginx ("engine X") is a high-performance web and reverse proxy server created by Igor Sysoev. It can be used both as a standalone web server From 2784d3f935d26fab5d485caa6843221f2691686b Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Fri, 27 May 2022 00:09:29 +0800 Subject: [PATCH 447/651] nginx-dev: fix nginx version subtracting in dh_nginx --- debian/dh_nginx | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/dh_nginx b/debian/dh_nginx index 4853568..e07ffe1 100755 --- a/debian/dh_nginx +++ b/debian/dh_nginx @@ -244,6 +244,7 @@ foreach my $package ((@{$dh{DOPACKAGES}})) addsubstvar($package, "misc:Depends", nginx_depends()); } else { my $ngx_ver = `grep 'define NGINX_VERSION' /usr/share/nginx/src/src/core/nginx.h | sed -e 's/^.*"\\(.*\\)".*/\\1/'`; + chomp($ngx_ver); addsubstvar($package, "misc:Depends", "nginx-common (>= $ngx_ver), nginx-common (<< $ngx_ver.1~)"); } From 15c55ec59b0f542e9cecf7205e5e54a0d6beba2e Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Fri, 6 May 2022 18:59:25 +0800 Subject: [PATCH 448/651] dh_nginx: move to debian/debhelper Move dh_nginx script to debian/debhelper so that all debhelper scripts are located together. --- debian/{ => debhelper}/dh_nginx | 0 debian/nginx-dev.install | 2 +- debian/rules | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) rename debian/{ => debhelper}/dh_nginx (100%) diff --git a/debian/dh_nginx b/debian/debhelper/dh_nginx similarity index 100% rename from debian/dh_nginx rename to debian/debhelper/dh_nginx diff --git a/debian/nginx-dev.install b/debian/nginx-dev.install index 6a2ad43..efc1578 100644 --- a/debian/nginx-dev.install +++ b/debian/nginx-dev.install @@ -3,6 +3,6 @@ debian/build-src/src usr/share/nginx/src/ debian/build-src/conf_flags usr/share/nginx/src/ debian/build-src/configure usr/share/nginx/src/ debian/debhelper/nginx.pm usr/share/perl5/Debian/Debhelper/Sequence/ -debian/dh_nginx usr/bin/ +debian/debhelper/dh_nginx usr/bin/ debian/debhelper/nginx_mod.pm usr/share/perl5/Debian/Debhelper/Buildsystem/ debian/autoscripts/* usr/share/debhelper/autoscripts/ diff --git a/debian/rules b/debian/rules index 68ed613..d4ddc7e 100755 --- a/debian/rules +++ b/debian/rules @@ -143,7 +143,7 @@ override_dh_clean: clean_patch_modules $(foreach flavour,$(FLAVOURS),cl override_dh_install: dh_install - DH_AUTOSCRIPTDIR=$(CURDIR)/debian/autoscripts debian/dh_nginx --in-nginx-tree + DH_AUTOSCRIPTDIR=$(CURDIR)/debian/autoscripts debian/debhelper/dh_nginx --in-nginx-tree override_dh_installinit: dh_installinit --no-stop-on-upgrade --no-start --name=nginx @@ -163,7 +163,7 @@ build.src: find $(CURDIR)/src -type f -name '*.h' -printf 'src/%P\0' | tar -C $(CURDIR) --null --files-from - -c | tar -C $(BUILDDIR_src)/ -x if [ -e $(CURDIR)/configure ]; then cp $(CURDIR)/configure $(BUILDDIR_src)/; fi echo "NGX_CONF_FLAGS=(" $(basic_configure_flags) ")" > $(BUILDDIR_src)/conf_flags - pod2man debian/dh_nginx > $(BUILDDIR_src)/dh_nginx.1 + pod2man debian/debhelper/dh_nginx > $(BUILDDIR_src)/dh_nginx.1 strip.arch.%: dh_strip --package=nginx-$(*) -O--dbgsym-migration='nginx-$(*)-dbg (<< 1.10.1-3~)' From 509adba304b06ff3fcb99b0baa8ef689e4bed40d Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Fri, 6 May 2022 19:09:50 +0800 Subject: [PATCH 449/651] dh_nginx: support auto generating module config files This patch adds support of auto generating module config files for modules in the naming pattern of libnginx-mod-* but with missing .nginx file. The module load file and its loading priority is inferred from the package name in this case. Using this feature, the repeated files d/libnginx-mod-*.nginx and d/libnginx-mod.conf/ can be removed, and the packaging for out-of-tree modules can be simplified. --- debian/debhelper/dh_nginx | 122 ++++++++++++++++++++++++-------------- 1 file changed, 79 insertions(+), 43 deletions(-) diff --git a/debian/debhelper/dh_nginx b/debian/debhelper/dh_nginx index e07ffe1..f2b9bb5 100755 --- a/debian/debhelper/dh_nginx +++ b/debian/debhelper/dh_nginx @@ -84,6 +84,11 @@ Lists files to be registered with the Nginx HTTP server. The file is interpreted as line separated list of installation stanzas, where each entry consists of whitespace separated values conforming to the file semantics below. +When this file is missing but the name of the package looks like a nginx module, +the module load file and its loading priority is automatically generated inferring +from the package name. In this case, IB<.install> or other mechanisms +should be used for copying the B<.so> library into the correct place. + =head2 FILE SEMANTICS Each line consists of a triple @@ -171,65 +176,96 @@ foreach my $package ((@{$dh{DOPACKAGES}})) my $file = pkgfile($package, "nginx"); my $tmp = tmpdir($package); + my $installdir = $tmp . "/" . nginx_modules_conf_installdir(); + my $modinstalldir = $tmp . "/" . nginx_api_installdir(); - my @files_to_register = filedoublearray($file, ".") if $file; - foreach my $line (@files_to_register) - { - my $type = lc(shift @{$line}) if $line->[0]; - my $source = shift @{$line} if $line->[0]; - my @arguments = @{$line}; - my $destination; - - $type = "modules" if $type eq "mod"; - my $installdir = $tmp . "/" . nginx_modules_conf_installdir(); - - verbose_print("$type -- $source -- @arguments\n\n"); - - if ($type eq "modules") + if ($file){ + my @files_to_register = filedoublearray($file, ".") if $file; + foreach my $line (@files_to_register) { - my $basesource = basename($source); + my $type = lc(shift @{$line}) if $line->[0]; + my $source = shift @{$line} if $line->[0]; + my @arguments = @{$line}; + my $destination; + + $type = "modules" if $type eq "mod"; + + verbose_print("$type -- $source -- @arguments\n\n"); if ($type eq "modules") { - if ($basesource =~ m/\.conf$/) + my $basesource = basename($source); + + if ($type eq "modules") { - my $enablename = $basesource; - my $prio = $#arguments >= 0 ? $arguments[0] : 50; - $destination = "$prio-$basesource"; - push @{$PACKAGE_TYPE{'has_a_module'}}, "$enablename:$destination"; - verbose_print("Installing module configuration $enablename into $installdir prio:$prio\n"); - } - elsif ($basesource =~ m/\.so$/) - { - my $modinstalldir = $tmp . "/" . nginx_api_installdir(); - verbose_print("Installing module binary $source into $modinstalldir\n"); - if (! -d $modinstalldir) + if ($basesource =~ m/\.conf$/) { - complex_doit("mkdir","-p", $modinstalldir); - complex_doit("chmod","755","$modinstalldir"); + my $enablename = $basesource; + my $prio = $#arguments >= 0 ? $arguments[0] : 50; + $destination = "$prio-$basesource"; + push @{$PACKAGE_TYPE{'has_a_module'}}, "$enablename:$destination"; + verbose_print("Installing module configuration $enablename into $installdir prio:$prio\n"); } - complex_doit("cp", $source, $modinstalldir); - next; + elsif ($basesource =~ m/\.so$/) + { + verbose_print("Installing module binary $source into $modinstalldir\n"); + if (! -d $modinstalldir) + { + complex_doit("mkdir","-p", $modinstalldir); + complex_doit("chmod","755","$modinstalldir"); + } + complex_doit("cp", $source, $modinstalldir); + next; + } + + # TODO + error("module: \"$basesource\" needs .conf, .so or suffix") if $basesource !~ m/\.(conf|so)/; } - # TODO - error("module: \"$basesource\" needs .conf, .so or suffix") if $basesource !~ m/\.(conf|so)/; - } + if (! -d $installdir) + { + complex_doit("mkdir","-p",$installdir); + complex_doit("chmod","755","$installdir"); + } + complex_doit("cp",$source,$installdir); + complex_doit("chmod","644","$installdir/$basesource"); - if (! -d $installdir) + } + else { - complex_doit("mkdir","-p",$installdir); - complex_doit("chmod","755","$installdir"); + error("Unknown parameter: $type\n"); } - complex_doit("cp",$source,$installdir); - complex_doit("chmod","644","$installdir/$basesource"); } - else - { - error("Unknown parameter: $type\n"); - } + } elsif ($package =~ /^libnginx-mod-/){ + verbose_print("$package might be a nginx module\n"); + my $module = $package; + $module =~ s/^libnginx-mod-//; + verbose_print("Guessed module name: $module\n"); + + my $modulepath = $module; + $modulepath =~ s/-/_/g; + + if (-e "$modinstalldir/ngx_${modulepath}_module.so"){ + my $prio = 50; + if ($module =~ /^\w+-/ && !($module =~ /^http-/) ){ + $prio = 70; + } + verbose_print("Guessed load priority: $prio\n"); + + my $conf_name = "mod-$module.conf"; + install_dir($installdir); + verbose_print("Installing module configuration $conf_name into $installdir prio:$prio\n"); + open(MOD_CONF, $dh{NO_ACT} ? ">&STDERR" : ">$installdir/$conf_name") or error("open($installdir/$conf_name): $!"); + print(MOD_CONF "load_module modules/ngx_${modulepath}_module.so;\n"); + close(MOD_CONF); + chmod(0644, "$installdir/$conf_name") or error("chmod(0644, $installdir/$conf_name): $!"); + push @{$PACKAGE_TYPE{'has_a_module'}}, "$conf_name:$prio-$conf_name"; + } else { + verbose_print("$package is not a nginx module because $modinstalldir/ngx_${modulepath}_module.so not found"); + verbose_print("If it is not correct, check if the module is installed before invoking this script"); + } } my @postinst_autoscripts; From ed5bc15213993766af66189792d5a7ed496681e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 15 May 2022 09:12:16 +0200 Subject: [PATCH 450/651] Remove 0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch --- ...ure-stays-the-same-in-all-nginx-buil.patch | 28 ------------------- debian/patches/series | 1 - 2 files changed, 29 deletions(-) delete mode 100644 debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch diff --git a/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch b/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch deleted file mode 100644 index 9e27e1a..0000000 --- a/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch +++ /dev/null @@ -1,28 +0,0 @@ -From: Christos Trochalakis -Date: Wed, 30 Mar 2016 09:47:11 +0300 -Subject: Make sure signature stays the same in all nginx builds - -NGX_HTTP_HEADERS is part of nginx signature. When a dyn -modules is loaded the signature of the module is compared -to the one of the nginx binary. - -dyn modules are build from nginx-full, so in order to make -them loadable in other flavors we need to make sure all the -binaries share the same signature. ---- - configure | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/configure -+++ b/configure -@@ -58,6 +58,10 @@ - . auto/unix - fi - -+# Debian -+# Make sure signature stays the same on all nginx flavors -+have=NGX_HTTP_HEADERS . auto/have -+ - . auto/threads - . auto/modules - . auto/lib/conf diff --git a/debian/patches/series b/debian/patches/series index 5b6b799..04030f9 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1 @@ -0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch 0003-define_gnu_source-on-other-glibc-based-platforms.patch From 9f1044b9401f8b40ebefa306761ecd9a951750ba Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Sun, 26 Jun 2022 15:26:40 +0800 Subject: [PATCH 451/651] changelog: update changelog --- debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index fec8e1d..581bd2e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -28,6 +28,14 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/copyright: added copyright for src/stream/ngx_stream_set_module.c * d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c + [ Miao Wang ] + * dh_nginx: support auto generating module config files + * adding a new nginx-dev package including necessary headers and debhelper + scripts to build and package a 3rd party module. + * d/p/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch + removed, because feature already implemented with --with-compat configure + option since 1.11.5 + -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 nginx (1.20.2-2) unstable; urgency=medium From 83ca2994f8be7c48e6cfe82236d5268bc3e29f93 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 17 May 2022 15:42:18 -0400 Subject: [PATCH 452/651] Copyright file needed updated (caught by Bage, who emailed a patch to teward) --- debian/changelog | 3 +++ debian/copyright | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index 581bd2e..542e5a6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -28,6 +28,9 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/copyright: added copyright for src/stream/ngx_stream_set_module.c * d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c + [ Bastian Germann ] + * d/copyright: Update copyright for d/debhelper/* + [ Miao Wang ] * dh_nginx: support auto generating module config files * adding a new nginx-dev package including necessary headers and debhelper diff --git a/debian/copyright b/debian/copyright index 59dfc09..6449e69 100644 --- a/debian/copyright +++ b/debian/copyright @@ -47,6 +47,10 @@ Copyright: 2007-2009, Fabio Tranchitella 2020-2022, Ondřej Nový License: BSD-2-clause +Files: debian/debhelper/* +Copyright: 2022 Miao Wang +License: Expat + Files: debian/modules/http-headers-more-filter/* Copyright: 2009-2017, Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. 2010-2013, Bernd Dorn From bf9c433dbbb5d6accb5546a805dacf59e04f5d99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 26 Jun 2022 14:35:33 +0200 Subject: [PATCH 453/651] d/control: bump Standards-Version to 4.6.1, no changes --- debian/changelog | 1 + debian/control | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 542e5a6..fe5fc20 100644 --- a/debian/changelog +++ b/debian/changelog @@ -27,6 +27,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/copyright: bump nginx copyright years * d/copyright: added copyright for src/stream/ngx_stream_set_module.c * d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c + * d/control: bump Standards-Version to 4.6.1, no changes [ Bastian Germann ] * d/copyright: Update copyright for d/debhelper/* diff --git a/debian/control b/debian/control index f6b11ba..21eb530 100644 --- a/debian/control +++ b/debian/control @@ -24,7 +24,7 @@ Build-Depends: debhelper-compat (= 13), po-debconf, quilt, zlib1g-dev -Standards-Version: 4.6.0 +Standards-Version: 4.6.1 Homepage: https://nginx.org Vcs-Git: https://salsa.debian.org/nginx-team/nginx.git Vcs-Browser: https://salsa.debian.org/nginx-team/nginx From 7df2636a9d22b2fb385f06af25a61f929b9b4bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 26 Jun 2022 16:16:08 +0200 Subject: [PATCH 454/651] d/changelog fix whitespace --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index fe5fc20..68a4ac4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,7 +11,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium was added to the keyring while keeping Maxim's key in signing keys as well. * d/copyright: Updated copyright for src/core/ngx_murmurhash.c - and debian/modules/http-ndk/src/hash/murmurhash2.c to be + and debian/modules/http-ndk/src/hash/murmurhash2.c to be public-domain (Closes: #1011936) * d/control: Use libluajit-5.1-dev for s390x. Due to src:luajit2 landing in Unstable, superseding src:luajit, From 172eb7b12a8ba0bf4667e54835b5d2024adadc23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 26 Jun 2022 16:16:58 +0200 Subject: [PATCH 455/651] d/changelog close #1013807 bug --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 68a4ac4..a12536e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -19,7 +19,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium with luajit instead of standard Lua. Thanks to Paul Gevers for the heads up on luajit2 supporting s390x. * d/control: Use liblua for ppc64el - src:luajit2 is still not ppc64el - stable and there seems to be nobody willing to support it. + stable and there seems to be nobody willing to support it. (Closes: 1013807) [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream From 42508c8556723f6e499bba2850f13a97665374fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 26 Jun 2022 16:20:26 +0200 Subject: [PATCH 456/651] create var/www/html in nginx-common.postinst --- debian/nginx-common.dirs | 1 - debian/nginx-common.lintian-overrides | 2 -- debian/nginx-common.postinst | 1 + 3 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 debian/nginx-common.lintian-overrides diff --git a/debian/nginx-common.dirs b/debian/nginx-common.dirs index 65bb651..8e5d7bf 100644 --- a/debian/nginx-common.dirs +++ b/debian/nginx-common.dirs @@ -10,4 +10,3 @@ usr/share/vim/addons usr/share/vim/registry var/lib/nginx var/log/nginx -var/www/html diff --git a/debian/nginx-common.lintian-overrides b/debian/nginx-common.lintian-overrides deleted file mode 100644 index 35cc9bc..0000000 --- a/debian/nginx-common.lintian-overrides +++ /dev/null @@ -1,2 +0,0 @@ -# /var/www/html is the default document root -nginx-common: dir-or-file-in-var-www var/www/html/ diff --git a/debian/nginx-common.postinst b/debian/nginx-common.postinst index 9e0610e..0d44608 100644 --- a/debian/nginx-common.postinst +++ b/debian/nginx-common.postinst @@ -39,6 +39,7 @@ case "$1" in # Create a default index page when not already present. if [ ! -e /var/www/html/index.nginx-debian.html ]; then + mkdir -p /var/www/html cp /usr/share/nginx/html/index.html /var/www/html/index.nginx-debian.html fi From 1a3b0014140ee9b085732cf31457435d70f9a713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 26 Jun 2022 16:41:06 +0200 Subject: [PATCH 457/651] d/changelog close #985133 bug --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index a12536e..1409f33 100644 --- a/debian/changelog +++ b/debian/changelog @@ -35,7 +35,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium [ Miao Wang ] * dh_nginx: support auto generating module config files * adding a new nginx-dev package including necessary headers and debhelper - scripts to build and package a 3rd party module. + scripts to build and package a 3rd party module. (Closes: 985133) * d/p/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch removed, because feature already implemented with --with-compat configure option since 1.11.5 From 035ed7f34a7c35aee9e008eb26f5a5c99f15ca82 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Sat, 9 Jul 2022 20:14:24 -0400 Subject: [PATCH 458/651] Unstable upload --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 1409f33..46c9e92 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.22.0-1) UNRELEASED; urgency=medium +nginx (1.22.0-1) unstable; urgency=medium [ Thomas Ward ] * New upstream release (1.22.0) From ccd67189200544340c52c67bebd8eeea797a5b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 10 Jul 2022 08:21:23 +0200 Subject: [PATCH 459/651] d/nginx-common.nginx.service update --- debian/changelog | 12 ++++++++++++ debian/nginx-common.nginx.service | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 46c9e92..609ac41 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,15 @@ +nginx (1.22.0-2) UNRELEASED; urgency=medium + + * d/nginx-common.nginx.service: added Systemd dependency + Wants=network-online.target and updated Systemd "After" dependency to + recommended NGINX values, namely: + - syslog.target + - network-online.target (Closes: 61261) (Closes: 1000406) + - remote-fs.target (Closes: 898896) + - nss-lookup.target + + -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 + nginx (1.22.0-1) unstable; urgency=medium [ Thomas Ward ] diff --git a/debian/nginx-common.nginx.service b/debian/nginx-common.nginx.service index 78bf0ce..a46a725 100644 --- a/debian/nginx-common.nginx.service +++ b/debian/nginx-common.nginx.service @@ -13,7 +13,8 @@ [Unit] Description=A high performance web server and a reverse proxy server Documentation=man:nginx(8) -After=network.target nss-lookup.target +After=syslog.target network-online.target remote-fs.target nss-lookup.target +Wants=network-online.target [Service] Type=forking From 88d4d1577a0387abc4cf2d6b039711bfd7c142af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 10 Jul 2022 08:29:08 +0200 Subject: [PATCH 460/651] d/p/0003-define_gnu_source-on-other-glibc-based-platforms.patch forwarded to upstream --- debian/changelog | 2 ++ .../0003-define_gnu_source-on-other-glibc-based-platforms.patch | 1 + 2 files changed, 3 insertions(+) diff --git a/debian/changelog b/debian/changelog index 609ac41..749ec29 100644 --- a/debian/changelog +++ b/debian/changelog @@ -7,6 +7,8 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium - network-online.target (Closes: 61261) (Closes: 1000406) - remote-fs.target (Closes: 898896) - nss-lookup.target + * d/p/0003-define_gnu_source-on-other-glibc-based-platforms.patch: forwarded + to upstream (Closes: 859082) -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 diff --git a/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch b/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch index d43fd23..caf155f 100644 --- a/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch +++ b/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch @@ -1,6 +1,7 @@ Date: Sat, 16 Jul 2016 23:52:50 +0100 From: Steven Chamberlain Subject: Use _GNU_SOURCE on GNU/kFreeBSD +Forwarded: https://trac.nginx.org/nginx/ticket/2366 Define _GNU_SOURCE not only on GNU/Hurd, but also other glibc-based platforms including GNU/kFreeBSD. From ff7cd7012d526745b8b5bc514877e2be0a487da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 10 Jul 2022 18:32:08 +0200 Subject: [PATCH 461/651] d/t/reboot: added, tests if nginx works after reboot --- debian/changelog | 1 + debian/tests/control | 4 ++++ debian/tests/reboot | 15 +++++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 debian/tests/reboot diff --git a/debian/changelog b/debian/changelog index 749ec29..adf2e41 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,7 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium - nss-lookup.target * d/p/0003-define_gnu_source-on-other-glibc-based-platforms.patch: forwarded to upstream (Closes: 859082) + * d/t/reboot: added, tests if nginx works after reboot -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 diff --git a/debian/tests/control b/debian/tests/control index 52690ae..4a24735 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -125,3 +125,7 @@ Depends: nginx-extras, libnginx-mod-stream-geoip, libnginx-mod-stream-geoip2, libnginx-mod-stream, + +Tests: reboot +Restrictions: isolation-container, needs-root, needs-reboot +Depends: nginx-light, curl diff --git a/debian/tests/reboot b/debian/tests/reboot new file mode 100644 index 0000000..a90a6c9 --- /dev/null +++ b/debian/tests/reboot @@ -0,0 +1,15 @@ +#!/bin/sh +# 20220710 +# Jan Mojzis +# Public domain + +#change directory to $AUTOPKGTEST_TMP +cd "${AUTOPKGTEST_TMP}" + +# do simple curl +curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ + +# test if nginx runs after reboot +if [ x"${AUTOPKGTEST_REBOOT_MARK}" = x ]; then + /tmp/autopkgtest-reboot rebootmark +fi From 461acc4f5141c73b01531283c035580608073e97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 10 Jul 2022 20:12:32 +0200 Subject: [PATCH 462/651] d/nginx-common.nginx.service: remove systemd 'After' dependency syslog.target, is obsolete --- debian/changelog | 1 - debian/nginx-common.nginx.service | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index adf2e41..d9adaf3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,7 +3,6 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium * d/nginx-common.nginx.service: added Systemd dependency Wants=network-online.target and updated Systemd "After" dependency to recommended NGINX values, namely: - - syslog.target - network-online.target (Closes: 61261) (Closes: 1000406) - remote-fs.target (Closes: 898896) - nss-lookup.target diff --git a/debian/nginx-common.nginx.service b/debian/nginx-common.nginx.service index a46a725..a63fa0f 100644 --- a/debian/nginx-common.nginx.service +++ b/debian/nginx-common.nginx.service @@ -13,7 +13,7 @@ [Unit] Description=A high performance web server and a reverse proxy server Documentation=man:nginx(8) -After=syslog.target network-online.target remote-fs.target nss-lookup.target +After=network-online.target remote-fs.target nss-lookup.target Wants=network-online.target [Service] From 0d813834ef16b455986c8aea98f9f0a1158eff02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 11 Jul 2022 20:33:33 +0200 Subject: [PATCH 463/651] http-subs-filter add PCRE2 support --- debian/changelog | 1 + .../patches/http-subs-filter/pcre2.patch | 24 +++++++++++++++++++ .../modules/patches/http-subs-filter/series | 1 + 3 files changed, 26 insertions(+) create mode 100644 debian/modules/patches/http-subs-filter/pcre2.patch diff --git a/debian/changelog b/debian/changelog index d9adaf3..9fb216f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,7 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium * d/p/0003-define_gnu_source-on-other-glibc-based-platforms.patch: forwarded to upstream (Closes: 859082) * d/t/reboot: added, tests if nginx works after reboot + * d/m/p/http-subs-filter/pcre2.patch: added PCRE2 support -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 diff --git a/debian/modules/patches/http-subs-filter/pcre2.patch b/debian/modules/patches/http-subs-filter/pcre2.patch new file mode 100644 index 0000000..692257c --- /dev/null +++ b/debian/modules/patches/http-subs-filter/pcre2.patch @@ -0,0 +1,24 @@ +Author: shmux8 <75251845+shmux8@users.noreply.github.com> +Date: Tue Dec 28 11:15:00 2021 +0300 +Subject: [PATCH] pcre2 support +Origin: https://github.com/yaoweibin/ngx_http_substitutions_filter_module/commit/cc494d7f5c5273a7a8ae503faebf1101689d75c0 + + PCRE2 support added + + Use pcre2_pattern_info call if nginx built with PCRE2. + +diff --git a/debian/modules/http-subs-filter/ngx_http_subs_filter_module.c b/debian/modules/http-subs-filter/ngx_http_subs_filter_module.c +index 483c9c3..11a5b79 100644 +--- a/ngx_http_subs_filter_module.c ++++ b/ngx_http_subs_filter_module.c +@@ -1203,7 +1203,9 @@ ngx_http_subs_regex_capture_count(ngx_regex_t *re) + + n = 0; + +-#if defined(nginx_version) && nginx_version >= 1002002 ++#if (NGX_PCRE2) ++ rc = pcre2_pattern_info(re, PCRE2_INFO_CAPTURECOUNT, &n); ++#elif defined(nginx_version) && nginx_version >= 1002002 + rc = pcre_fullinfo(re->code, NULL, PCRE_INFO_CAPTURECOUNT, &n); + #elif defined(nginx_version) && nginx_version >= 1001012 + rc = pcre_fullinfo(re->pcre, NULL, PCRE_INFO_CAPTURECOUNT, &n); diff --git a/debian/modules/patches/http-subs-filter/series b/debian/modules/patches/http-subs-filter/series index f9b9360..4344c0b 100644 --- a/debian/modules/patches/http-subs-filter/series +++ b/debian/modules/patches/http-subs-filter/series @@ -1 +1,2 @@ dynamic-module.patch +pcre2.patch From 0e2eaec4b255c46654b049f593a03368083d7b48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:40:40 +0200 Subject: [PATCH 464/651] d/gitlab-ci.yml removed in GL switched to salsa-ci team recipes/debian.yml@salsa-ci-team/pipeline --- debian/gitlab-ci.yml | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 debian/gitlab-ci.yml diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml deleted file mode 100644 index 557434c..0000000 --- a/debian/gitlab-ci.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -include: - - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml - - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml - -# Disable reprotest which is failing now -variables: - SALSA_CI_DISABLE_REPROTEST: 1 From 142c95ade023fd91eed22a5c1b7c2525b79b13d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:46:55 +0200 Subject: [PATCH 465/651] add libnginx-mod-http-ndk-dev to nginx to build ngx-lua --- debian/changelog | 5 +++++ debian/control | 16 +++++++++++++++ debian/libnginx-mod-http-ndk-dev.install | 5 +++++ debian/rules | 26 ++++++++++++++++++++---- 4 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 debian/libnginx-mod-http-ndk-dev.install diff --git a/debian/changelog b/debian/changelog index 9fb216f..194e492 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,10 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium + [ Miao Wang ] + * adding a new libnginx-mod-http-ndk-dev package including necessary + headers to build a 3rd party module depending on ndk. + + [ Jan Mojžíš ] * d/nginx-common.nginx.service: added Systemd dependency Wants=network-online.target and updated Systemd "After" dependency to recommended NGINX values, namely: diff --git a/debian/control b/debian/control index 21eb530..4736a9f 100644 --- a/debian/control +++ b/debian/control @@ -398,6 +398,22 @@ Description: Nginx Development Kit module features that are seen from a user's point of view - it's just designed to help reduce the code that Nginx module developers need to write. +Package: libnginx-mod-http-ndk-dev +Architecture: all +Depends: libnginx-mod-http-ndk (<< ${source:Version}.1~), libnginx-mod-http-ndk (>= ${source:Version}), + nginx-dev (>= ${source:Version}), nginx-dev (<< ${source:Version}.1~), ${misc:Depends} +Description: Nginx Development Kit module - development files + The NDK is an Nginx module that is designed to extend the core functionality of + the excellent Nginx webserver in a way that can be used as a basis of other + Nginx modules. + . + This package provides development headers and necessary config scripts + for the Nginx development kit module, useful to develop and link third party + additions to the Debian nginx web/proxy server packages using Nginx + development kit module. + . + Development files. + Package: libnginx-mod-nchan Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, diff --git a/debian/libnginx-mod-http-ndk-dev.install b/debian/libnginx-mod-http-ndk-dev.install new file mode 100644 index 0000000..980066f --- /dev/null +++ b/debian/libnginx-mod-http-ndk-dev.install @@ -0,0 +1,5 @@ +debian/build-ndksrc/auto usr/share/nginx-ndk/src/ +debian/build-ndksrc/src usr/share/nginx-ndk/src/ +debian/build-ndksrc/objs usr/share/nginx-ndk/src/ +debian/build-ndksrc/config usr/share/nginx-ndk/src/ +debian/build-ndksrc/ngx_auto_lib_core usr/share/nginx-ndk/src/ \ No newline at end of file diff --git a/debian/rules b/debian/rules index d4ddc7e..4471089 100755 --- a/debian/rules +++ b/debian/rules @@ -32,7 +32,7 @@ DYN_MODS := \ MODULESDIR = $(CURDIR)/debian/modules BASEDIR = $(CURDIR) -$(foreach flavour,$(FLAVOURS) src,$(eval BUILDDIR_$(flavour) = $(CURDIR)/debian/build-$(flavour))) +$(foreach flavour,$(FLAVOURS) src ndksrc,$(eval BUILDDIR_$(flavour) = $(CURDIR)/debian/build-$(flavour))) DEB_BUILD_ARCH ?=$(shell dpkg-architecture -qDEB_BUILD_ARCH) ifeq ($(DEB_BUILD_ARCH),sparc) @@ -135,10 +135,10 @@ extras_configure_flags := \ %: dh $@ --without autoreconf -override_dh_auto_configure: config_patch_modules $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) config.src -override_dh_auto_build: $(foreach flavour,$(FLAVOURS),build.arch.$(flavour)) build.src +override_dh_auto_configure: config_patch_modules $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) config.src config.ndksrc +override_dh_auto_build: $(foreach flavour,$(FLAVOURS),build.arch.$(flavour)) build.src build.ndksrc override_dh_strip: $(foreach flavour,$(FLAVOURS),strip.arch.$(flavour)) $(foreach mod,$(DYN_MODS),strip.mods.$(mod)) -override_dh_clean: clean_patch_modules $(foreach flavour,$(FLAVOURS),clean.$(flavour)) clean.src +override_dh_clean: clean_patch_modules $(foreach flavour,$(FLAVOURS),clean.$(flavour)) clean.src clean.ndksrc dh_clean override_dh_install: @@ -165,6 +165,16 @@ build.src: echo "NGX_CONF_FLAGS=(" $(basic_configure_flags) ")" > $(BUILDDIR_src)/conf_flags pod2man debian/debhelper/dh_nginx > $(BUILDDIR_src)/dh_nginx.1 +build.ndksrc: + cp -Pa $(CURDIR)/debian/modules/http-ndk/auto \ + $(CURDIR)/debian/modules/http-ndk/config \ + $(CURDIR)/debian/modules/http-ndk/ngx_auto_lib_core $(BUILDDIR_ndksrc)/ + for i in src objs; do \ + find $(CURDIR)/debian/modules/http-ndk/$$i -type f -name '*.h' -printf "$$i/%P\0" | \ + tar -C $(CURDIR)/debian/modules/http-ndk --null --files-from - -c | tar -C $(BUILDDIR_ndksrc)/ -x; \ + done + chmod +x $(CURDIR)/debian/build-ndksrc/auto/build + strip.arch.%: dh_strip --package=nginx-$(*) -O--dbgsym-migration='nginx-$(*)-dbg (<< 1.10.1-3~)' @@ -192,11 +202,19 @@ config.arch.%: cp -Pa $(CURDIR)/src $(BUILDDIR_$*)/ cp -Pa $(CURDIR)/man $(BUILDDIR_$*)/ cd $(BUILDDIR_$*) && ./configure $($*_configure_flags) + if [ "$(BUILDDIR_$*)" = "$(BUILDDIR_extras)" ]; then \ + have="NDK_SET_VAR"; \ + /bin/echo -e "#ifndef $$have\n#define $$have 1\n#endif" >> $(BUILDDIR_$*)/objs/ngx_auto_config.h; \ + fi config.src: dh_testdir mkdir -p $(BUILDDIR_src) +config.ndksrc: + dh_testdir + mkdir -p $(BUILDDIR_ndksrc) + clean.%: rm -rf $(BUILDDIR_$*) From 43b9a879c9a5b7573336e339a0b43113e45a56ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:48:06 +0200 Subject: [PATCH 466/651] Remove constraints unnecessary since buster * Build-Depends: Drop versioned constraint on dpkg-dev. * nginx-common: Drop versioned constraint on lsb-base in Depends. * nginx-core: Drop versioned constraint on nginx in Breaks. * nginx-full: Drop versioned constraint on nginx in Breaks. * nginx-light: Drop versioned constraint on nginx in Breaks. * nginx-extras: Drop versioned constraint on nginx in Breaks. * libnginx-mod-http-perl: Drop versioned constraint on nginx-extras in Replaces. * Remove 5 maintscript entries from 1 files. --- debian/changelog | 12 ++++++++++++ debian/control | 10 ++-------- debian/nginx-common.maintscript | 8 -------- 3 files changed, 14 insertions(+), 16 deletions(-) delete mode 100644 debian/nginx-common.maintscript diff --git a/debian/changelog b/debian/changelog index 194e492..c0cbcdb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -16,6 +16,18 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium * d/t/reboot: added, tests if nginx works after reboot * d/m/p/http-subs-filter/pcre2.patch: added PCRE2 support + [ Debian Janitor ] + * Remove constraints unnecessary since buster: + + Build-Depends: Drop versioned constraint on dpkg-dev. + + nginx-common: Drop versioned constraint on lsb-base in Depends. + + nginx-core: Drop versioned constraint on nginx in Breaks. + + nginx-full: Drop versioned constraint on nginx in Breaks. + + nginx-light: Drop versioned constraint on nginx in Breaks. + + nginx-extras: Drop versioned constraint on nginx in Breaks. + + libnginx-mod-http-perl: Drop versioned constraint on nginx-extras in + Replaces. + + Remove 5 maintscript entries from 1 files. + -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 nginx (1.22.0-1) unstable; urgency=medium diff --git a/debian/control b/debian/control index 4736a9f..c8aa03c 100644 --- a/debian/control +++ b/debian/control @@ -7,7 +7,6 @@ Uploaders: Christos Trochalakis , Thomas Ward , Jan Mojžíš , Build-Depends: debhelper-compat (= 13), - dpkg-dev (>= 1.15.5), libexpat-dev, libgd-dev, libgeoip-dev, @@ -58,7 +57,7 @@ Description: small, powerful, scalable web/proxy server - documentation Package: nginx-common Architecture: all Multi-Arch: foreign -Depends: lsb-base (>= 3.0-6), ${misc:Depends} +Depends: lsb-base, ${misc:Depends} Suggests: fcgiwrap, nginx-doc, ssl-cert Description: small, powerful, scalable web/proxy server - common files Nginx ("engine X") is a high-performance web and reverse proxy server @@ -105,8 +104,7 @@ Depends: libnginx-mod-http-geoip (= ${binary:Version}), iproute2, ${misc:Depends}, ${shlibs:Depends} -Breaks: nginx (<< 1.4.5-1), - nginx-full (<< 1.18.0-1), +Breaks: nginx-full (<< 1.18.0-1), Replaces: nginx-full (<< 1.18.0-1), Provides: httpd, httpd-cgi, nginx Conflicts: nginx-extras, nginx-light @@ -146,7 +144,6 @@ Depends: libnginx-mod-http-auth-pam, nginx-core (<< ${source:Version}.1~), ${misc:Depends}, ${shlibs:Depends} -Breaks: nginx (<< 1.4.5-1) Provides: httpd, httpd-cgi, nginx Suggests: nginx-doc (= ${source:Version}) Description: nginx web/proxy server (standard version with 3rd parties) @@ -181,7 +178,6 @@ Depends: libnginx-mod-http-echo (= ${binary:Version}), iproute2, ${misc:Depends}, ${shlibs:Depends} -Breaks: nginx (<< 1.4.5-1) Provides: httpd, httpd-cgi, nginx Conflicts: nginx-extras, nginx-core Suggests: nginx-doc (= ${source:Version}) @@ -228,7 +224,6 @@ Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), iproute2, ${misc:Depends}, ${shlibs:Depends} -Breaks: nginx (<< 1.4.5-1) Provides: httpd, httpd-cgi, nginx Conflicts: nginx-core, nginx-light Suggests: nginx-doc (= ${source:Version}) @@ -351,7 +346,6 @@ Package: libnginx-mod-http-perl Architecture: any Depends: ${misc:Depends}, ${perl:Depends}, ${shlibs:Depends}, Recommends: nginx, -Replaces: nginx-extras (<< 1.9.14-1) Description: Perl module for Nginx Embed Perl runtime into nginx. . diff --git a/debian/nginx-common.maintscript b/debian/nginx-common.maintscript deleted file mode 100644 index e1e7f53..0000000 --- a/debian/nginx-common.maintscript +++ /dev/null @@ -1,8 +0,0 @@ -# Handle naxsi removal -rm_conffile /etc/nginx/naxsi.rules 1.6.2-2~ -rm_conffile /etc/nginx/naxsi_core.rules 1.6.2-2~ -rm_conffile /etc/nginx/naxsi-ui.conf.1.4.1 1.6.2-2~ -rm_conffile /etc/nginx/naxsi-ui.conf 1.6.2-2~ - -# Handle upstart removal -rm_conffile /etc/init/nginx.conf 1.13.5-1~ From 861f1be8692fccce5996e26ee7f210c927ea6ceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:49:48 +0200 Subject: [PATCH 467/651] d/p/nginx-fix-pidfile.patch backport from Ubuntu --- debian/changelog | 2 + debian/patches/nginx-fix-pidfile.patch | 89 ++++++++++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 92 insertions(+) create mode 100644 debian/patches/nginx-fix-pidfile.patch diff --git a/debian/changelog b/debian/changelog index c0cbcdb..7d70e35 100644 --- a/debian/changelog +++ b/debian/changelog @@ -15,6 +15,8 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium to upstream (Closes: 859082) * d/t/reboot: added, tests if nginx works after reboot * d/m/p/http-subs-filter/pcre2.patch: added PCRE2 support + * d/p/nginx-fix-pidfile.patch: Fix NGINX PIDfile handling to avoid + SystemD race condition, this fix is backported from Ubuntu (Closes: 876365) [ Debian Janitor ] * Remove constraints unnecessary since buster: diff --git a/debian/patches/nginx-fix-pidfile.patch b/debian/patches/nginx-fix-pidfile.patch new file mode 100644 index 0000000..47a16ff --- /dev/null +++ b/debian/patches/nginx-fix-pidfile.patch @@ -0,0 +1,89 @@ +Description: Fix NGINX pidfile handling +Author: Tj +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/nginx/+bug/1581864 +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=876365 +Last-Update: 2020-06-24 +--- +This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ +diff --git a/src/core/nginx.c b/src/core/nginx.c +index 9fcb0eb2..083eba1d 100644 +--- a/src/core/nginx.c ++++ b/src/core/nginx.c +@@ -338,14 +338,21 @@ main(int argc, char *const *argv) + ngx_process = NGX_PROCESS_MASTER; + } + ++ /* tell-tale to detect if this is parent or child process */ ++ ngx_int_t child_pid = NGX_BUSY; ++ + #if !(NGX_WIN32) + + if (ngx_init_signals(cycle->log) != NGX_OK) { + return 1; + } + ++ /* tell-tale that this code has been executed */ ++ child_pid--; ++ + if (!ngx_inherited && ccf->daemon) { +- if (ngx_daemon(cycle->log) != NGX_OK) { ++ child_pid = ngx_daemon(cycle->log); ++ if (child_pid == NGX_ERROR) { + return 1; + } + +@@ -358,8 +365,19 @@ main(int argc, char *const *argv) + + #endif + +- if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) { +- return 1; ++ /* If ngx_daemon() returned the child's PID in the parent process ++ * after the fork() set ngx_pid to the child_pid, which gets ++ * written to the PID file, then exit. ++ * For NGX_WIN32 always write the PID file ++ * For others, only write it from the parent process */ ++ if (child_pid < NGX_OK || child_pid > NGX_OK) { ++ ngx_pid = child_pid > NGX_OK ? child_pid : ngx_pid; ++ if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) { ++ return 1; ++ } ++ } ++ if (child_pid > NGX_OK) { ++ exit(0); + } + + if (ngx_log_redirect_stderr(cycle) != NGX_OK) { +diff --git a/src/os/unix/ngx_daemon.c b/src/os/unix/ngx_daemon.c +index 385c49b6..3719854c 100644 +--- a/src/os/unix/ngx_daemon.c ++++ b/src/os/unix/ngx_daemon.c +@@ -7,14 +7,17 @@ + + #include + #include ++#include + + + ngx_int_t + ngx_daemon(ngx_log_t *log) + { + int fd; ++ /* retain the return value for passing back to caller */ ++ pid_t pid_child = fork(); + +- switch (fork()) { ++ switch (pid_child) { + case -1: + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fork() failed"); + return NGX_ERROR; +@@ -23,7 +26,8 @@ ngx_daemon(ngx_log_t *log) + break; + + default: +- exit(0); ++ /* let caller do the exit() */ ++ return pid_child; + } + + ngx_parent = ngx_pid; diff --git a/debian/patches/series b/debian/patches/series index 04030f9..5e15dcc 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1 +1,2 @@ 0003-define_gnu_source-on-other-glibc-based-platforms.patch +nginx-fix-pidfile.patch From c9a408aa6f2309b43efaa2b04c5cf788aa546fa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:50:45 +0200 Subject: [PATCH 468/651] d/apport/source_nginx.py: Add apport hooks for additional bug information gathering, the script is backported from Ubuntu --- debian/apport/source_nginx.py | 19 +++++++++++++++++++ debian/changelog | 3 +++ debian/nginx-common.install | 1 + 3 files changed, 23 insertions(+) create mode 100644 debian/apport/source_nginx.py diff --git a/debian/apport/source_nginx.py b/debian/apport/source_nginx.py new file mode 100644 index 0000000..aec6e8e --- /dev/null +++ b/debian/apport/source_nginx.py @@ -0,0 +1,19 @@ +''' +apport package hook for nginx packages + +Copyright (c) 2015, Thomas Ward +''' + +import apport.hookutils +import os +import subprocess + +def add_info(report, ui): + if (report['Package'].split()[0] != 'nginx-common' + and report['ProblemType'] == 'Package' + and os.path.isdir('/run/systemd/system')): + report['Journalctl_Nginx.txt'] = apport.hookutils.command_output( + ['journalctl', '-xe', '--unit=nginx.service']) + report['SystemctlStatusFull_Nginx.txt'] = subprocess.Popen( + ['systemctl', '-l', 'status', 'nginx.service'], + stdout=subprocess.PIPE).communicate()[0] diff --git a/debian/changelog b/debian/changelog index 7d70e35..0124d12 100644 --- a/debian/changelog +++ b/debian/changelog @@ -17,6 +17,9 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium * d/m/p/http-subs-filter/pcre2.patch: added PCRE2 support * d/p/nginx-fix-pidfile.patch: Fix NGINX PIDfile handling to avoid SystemD race condition, this fix is backported from Ubuntu (Closes: 876365) + * d/apport/source_nginx.py: Add apport hooks for additional bug + information gathering, the script is backported from Ubuntu (Closes: 963668) + * d/nginx-common.install: Add install rule for apport hooks. [ Debian Janitor ] * Remove constraints unnecessary since buster: diff --git a/debian/nginx-common.install b/debian/nginx-common.install index 90f173b..20109fa 100644 --- a/debian/nginx-common.install +++ b/debian/nginx-common.install @@ -1,5 +1,6 @@ contrib/vim/* usr/share/vim/addons debian/conf/* etc/nginx +debian/apport/source_nginx.py usr/share/apport/package-hooks debian/ufw/nginx etc/ufw/applications.d debian/vim/nginx.yaml usr/share/vim/registry html/index.html usr/share/nginx/html/ From 13a5fc3501349113ac90636d8f47d007ffafd033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:40:40 +0200 Subject: [PATCH 469/651] d/gitlab-ci.yml removed in GL switched to salsa-ci team recipes/debian.yml@salsa-ci-team/pipeline --- debian/gitlab-ci.yml | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 debian/gitlab-ci.yml diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml deleted file mode 100644 index 557434c..0000000 --- a/debian/gitlab-ci.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -include: - - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml - - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml - -# Disable reprotest which is failing now -variables: - SALSA_CI_DISABLE_REPROTEST: 1 From 08de4d4bc7e6ba11051ab1f6ef5460989b161513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lal?= Date: Sun, 7 Aug 2022 16:15:09 +0200 Subject: [PATCH 470/651] Release to unstable --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 0124d12..6bb8afa 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.22.0-2) UNRELEASED; urgency=medium +nginx (1.22.0-2) unstable; urgency=medium [ Miao Wang ] * adding a new libnginx-mod-http-ndk-dev package including necessary @@ -33,7 +33,7 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium Replaces. + Remove 5 maintscript entries from 1 files. - -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 + -- Jan Mojžíš Sun, 07 Aug 2022 16:14:59 +0200 nginx (1.22.0-1) unstable; urgency=medium From a316cb99e4dcc4ba7306b4741f474500784c270f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 8 Aug 2022 12:30:21 +0200 Subject: [PATCH 471/651] d/changelog: fix typo in bug number 61261 -> 861261 --- debian/changelog | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 6bb8afa..9ac858c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +nginx (1.22.0-3) UNRELEASED; urgency=medium + + * d/changelog: fixed typo in bug number 61261 -> 861261 (Closes: 861261) + + -- Jan Mojžíš Mon, 08 Aug 2022 12:29:34 +0200 + nginx (1.22.0-2) unstable; urgency=medium [ Miao Wang ] @@ -8,7 +14,7 @@ nginx (1.22.0-2) unstable; urgency=medium * d/nginx-common.nginx.service: added Systemd dependency Wants=network-online.target and updated Systemd "After" dependency to recommended NGINX values, namely: - - network-online.target (Closes: 61261) (Closes: 1000406) + - network-online.target (Closes: 861261) (Closes: 1000406) - remote-fs.target (Closes: 898896) - nss-lookup.target * d/p/0003-define_gnu_source-on-other-glibc-based-platforms.patch: forwarded From caf389149afa0b5923116bc4425978a179829c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 8 Aug 2022 12:32:23 +0200 Subject: [PATCH 472/651] d/p/nginx-ssl_cert_cb_yield.patch add --- debian/changelog | 1 + debian/patches/nginx-ssl_cert_cb_yield.patch | 40 ++++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 42 insertions(+) create mode 100644 debian/patches/nginx-ssl_cert_cb_yield.patch diff --git a/debian/changelog b/debian/changelog index 9ac858c..a41d64e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,7 @@ nginx (1.22.0-3) UNRELEASED; urgency=medium * d/changelog: fixed typo in bug number 61261 -> 861261 (Closes: 861261) + * d/p/nginx-ssl_cert_cb_yield.patch added (Closes: 884434) -- Jan Mojžíš Mon, 08 Aug 2022 12:29:34 +0200 diff --git a/debian/patches/nginx-ssl_cert_cb_yield.patch b/debian/patches/nginx-ssl_cert_cb_yield.patch new file mode 100644 index 0000000..96e06e1 --- /dev/null +++ b/debian/patches/nginx-ssl_cert_cb_yield.patch @@ -0,0 +1,40 @@ +Description: SSL: handled SSL_CTX_set_cert_cb() callback yielding. +Author: Yichun Zhang +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=884434 +Origin: https://raw.githubusercontent.com/openresty/openresty/v1.11.2.2/patches/nginx-1.11.2-ssl_cert_cb_yield.patch +Last-Update: 2016-01-02 + +OpenSSL 1.0.2+ introduces SSL_CTX_set_cert_cb() to allow custom +callbacks to serve the SSL certificiates and private keys dynamically +and lazily. The callbacks may yield for nonblocking I/O or sleeping. +Here we added support for such usage in NGINX 3rd-party modules +(like ngx_lua) in NGINX's event handlers for downstream SSL +connections. + +diff -r 78b4e10b4367 -r 449f0461859c src/event/ngx_event_openssl.c +--- a/src/event/ngx_event_openssl.c Thu Dec 17 16:39:15 2015 +0300 ++++ b/src/event/ngx_event_openssl.c Sat Jan 02 11:14:44 2016 -0800 +@@ -1210,6 +1210,23 @@ + return NGX_AGAIN; + } + ++#if OPENSSL_VERSION_NUMBER >= 0x10002000L ++ if (sslerr == SSL_ERROR_WANT_X509_LOOKUP) { ++ c->read->handler = ngx_ssl_handshake_handler; ++ c->write->handler = ngx_ssl_handshake_handler; ++ ++ if (ngx_handle_read_event(c->read, 0) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ ++ if (ngx_handle_write_event(c->write, 0) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ ++ return NGX_AGAIN; ++ } ++#endif ++ + err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; + + c->ssl->no_wait_shutdown = 1; diff --git a/debian/patches/series b/debian/patches/series index 5e15dcc..52e1dc4 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1,3 @@ 0003-define_gnu_source-on-other-glibc-based-platforms.patch nginx-fix-pidfile.patch +nginx-ssl_cert_cb_yield.patch From 212327ed576d26fc3b35feb30a43079d10fc5cea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 8 Aug 2022 12:34:00 +0200 Subject: [PATCH 473/651] http-lua: remove --- debian/changelog | 1 + debian/control | 18 +- debian/copyright | 9 - debian/libnginx-mod-http-lua.nginx | 13 - debian/modules/http-lua/README.markdown | 8332 ----------------- debian/modules/http-lua/config | 532 -- .../modules/http-lua/doc/HttpLuaModule.wiki | 7073 -------------- .../http-lua/dtrace/ngx_lua_provider.d | 61 - .../http-lua/misc/recv-until-pm/Makefile | 3 - .../misc/recv-until-pm/lib/RecvUntil.pm | 138 - .../http-lua/misc/recv-until-pm/t/sanity.t | 140 - .../http-lua/src/api/ngx_http_lua_api.h | 62 - debian/modules/http-lua/src/ddebug.h | 85 - .../http-lua/src/ngx_http_lua_accessby.c | 398 - .../http-lua/src/ngx_http_lua_accessby.h | 22 - .../modules/http-lua/src/ngx_http_lua_api.c | 216 - .../modules/http-lua/src/ngx_http_lua_args.c | 555 -- .../modules/http-lua/src/ngx_http_lua_args.h | 20 - .../http-lua/src/ngx_http_lua_balancer.c | 763 -- .../http-lua/src/ngx_http_lua_balancer.h | 27 - .../http-lua/src/ngx_http_lua_bodyfilterby.c | 633 -- .../http-lua/src/ngx_http_lua_bodyfilterby.h | 31 - .../modules/http-lua/src/ngx_http_lua_cache.c | 296 - .../modules/http-lua/src/ngx_http_lua_cache.h | 24 - .../http-lua/src/ngx_http_lua_capturefilter.c | 176 - .../http-lua/src/ngx_http_lua_capturefilter.h | 20 - .../http-lua/src/ngx_http_lua_clfactory.c | 887 -- .../http-lua/src/ngx_http_lua_clfactory.h | 22 - .../http-lua/src/ngx_http_lua_common.h | 593 -- .../http-lua/src/ngx_http_lua_config.c | 70 - .../http-lua/src/ngx_http_lua_config.h | 19 - .../http-lua/src/ngx_http_lua_consts.c | 202 - .../http-lua/src/ngx_http_lua_consts.h | 20 - .../http-lua/src/ngx_http_lua_contentby.c | 387 - .../http-lua/src/ngx_http_lua_contentby.h | 26 - .../http-lua/src/ngx_http_lua_control.c | 555 -- .../http-lua/src/ngx_http_lua_control.h | 20 - .../http-lua/src/ngx_http_lua_coroutine.c | 387 - .../http-lua/src/ngx_http_lua_coroutine.h | 23 - .../modules/http-lua/src/ngx_http_lua_ctx.c | 216 - .../modules/http-lua/src/ngx_http_lua_ctx.h | 23 - .../http-lua/src/ngx_http_lua_directive.c | 1831 ---- .../http-lua/src/ngx_http_lua_directive.h | 78 - .../http-lua/src/ngx_http_lua_exception.c | 58 - .../http-lua/src/ngx_http_lua_exception.h | 33 - .../src/ngx_http_lua_headerfilterby.c | 302 - .../src/ngx_http_lua_headerfilterby.h | 29 - .../http-lua/src/ngx_http_lua_headers.c | 1529 --- .../http-lua/src/ngx_http_lua_headers.h | 25 - .../http-lua/src/ngx_http_lua_headers_in.c | 835 -- .../http-lua/src/ngx_http_lua_headers_in.h | 22 - .../http-lua/src/ngx_http_lua_headers_out.c | 637 -- .../http-lua/src/ngx_http_lua_headers_out.h | 23 - .../http-lua/src/ngx_http_lua_initby.c | 42 - .../http-lua/src/ngx_http_lua_initby.h | 23 - .../http-lua/src/ngx_http_lua_initworkerby.c | 357 - .../http-lua/src/ngx_http_lua_initworkerby.h | 25 - .../modules/http-lua/src/ngx_http_lua_lex.c | 8251 ---------------- .../modules/http-lua/src/ngx_http_lua_lex.h | 17 - .../modules/http-lua/src/ngx_http_lua_log.c | 456 - .../modules/http-lua/src/ngx_http_lua_log.h | 24 - .../http-lua/src/ngx_http_lua_log_ringbuf.c | 225 - .../http-lua/src/ngx_http_lua_log_ringbuf.h | 31 - .../modules/http-lua/src/ngx_http_lua_logby.c | 266 - .../modules/http-lua/src/ngx_http_lua_logby.h | 22 - .../modules/http-lua/src/ngx_http_lua_misc.c | 292 - .../modules/http-lua/src/ngx_http_lua_misc.h | 22 - .../http-lua/src/ngx_http_lua_module.c | 1312 --- .../modules/http-lua/src/ngx_http_lua_ndk.c | 191 - .../modules/http-lua/src/ngx_http_lua_ndk.h | 21 - .../http-lua/src/ngx_http_lua_output.c | 808 -- .../http-lua/src/ngx_http_lua_output.h | 28 - .../http-lua/src/ngx_http_lua_pcrefix.c | 106 - .../http-lua/src/ngx_http_lua_pcrefix.h | 23 - .../modules/http-lua/src/ngx_http_lua_phase.c | 128 - .../modules/http-lua/src/ngx_http_lua_phase.h | 13 - .../modules/http-lua/src/ngx_http_lua_probe.h | 86 - .../modules/http-lua/src/ngx_http_lua_regex.c | 2548 ----- .../modules/http-lua/src/ngx_http_lua_regex.h | 24 - .../http-lua/src/ngx_http_lua_req_body.c | 1188 --- .../http-lua/src/ngx_http_lua_req_body.h | 20 - .../http-lua/src/ngx_http_lua_req_method.c | 253 - .../http-lua/src/ngx_http_lua_req_method.h | 19 - .../http-lua/src/ngx_http_lua_rewriteby.c | 380 - .../http-lua/src/ngx_http_lua_rewriteby.h | 22 - .../http-lua/src/ngx_http_lua_script.c | 538 -- .../http-lua/src/ngx_http_lua_script.h | 86 - .../http-lua/src/ngx_http_lua_semaphore.c | 578 -- .../http-lua/src/ngx_http_lua_semaphore.h | 53 - .../modules/http-lua/src/ngx_http_lua_setby.c | 216 - .../modules/http-lua/src/ngx_http_lua_setby.h | 15 - .../http-lua/src/ngx_http_lua_shdict.c | 3027 ------ .../http-lua/src/ngx_http_lua_shdict.h | 67 - .../modules/http-lua/src/ngx_http_lua_sleep.c | 219 - .../modules/http-lua/src/ngx_http_lua_sleep.h | 20 - .../http-lua/src/ngx_http_lua_socket_tcp.c | 5521 ----------- .../http-lua/src/ngx_http_lua_socket_tcp.h | 156 - .../http-lua/src/ngx_http_lua_socket_udp.c | 1657 ---- .../http-lua/src/ngx_http_lua_socket_udp.h | 65 - .../modules/http-lua/src/ngx_http_lua_ssl.c | 37 - .../modules/http-lua/src/ngx_http_lua_ssl.h | 47 - .../http-lua/src/ngx_http_lua_ssl_certby.c | 1325 --- .../http-lua/src/ngx_http_lua_ssl_certby.h | 37 - .../http-lua/src/ngx_http_lua_ssl_ocsp.c | 506 - .../src/ngx_http_lua_ssl_session_fetchby.c | 614 -- .../src/ngx_http_lua_ssl_session_fetchby.h | 38 - .../src/ngx_http_lua_ssl_session_storeby.c | 618 -- .../src/ngx_http_lua_ssl_session_storeby.h | 34 - .../http-lua/src/ngx_http_lua_string.c | 767 -- .../http-lua/src/ngx_http_lua_string.h | 20 - .../http-lua/src/ngx_http_lua_subrequest.c | 1782 ---- .../http-lua/src/ngx_http_lua_subrequest.h | 46 - .../modules/http-lua/src/ngx_http_lua_time.c | 349 - .../modules/http-lua/src/ngx_http_lua_time.h | 21 - .../modules/http-lua/src/ngx_http_lua_timer.c | 909 -- .../modules/http-lua/src/ngx_http_lua_timer.h | 20 - .../modules/http-lua/src/ngx_http_lua_uri.c | 110 - .../modules/http-lua/src/ngx_http_lua_uri.h | 20 - .../http-lua/src/ngx_http_lua_uthread.c | 285 - .../http-lua/src/ngx_http_lua_uthread.h | 36 - .../modules/http-lua/src/ngx_http_lua_util.c | 4132 -------- .../modules/http-lua/src/ngx_http_lua_util.h | 468 - .../http-lua/src/ngx_http_lua_variable.c | 509 - .../http-lua/src/ngx_http_lua_variable.h | 20 - .../http-lua/src/ngx_http_lua_worker.c | 193 - .../http-lua/src/ngx_http_lua_worker.h | 17 - debian/modules/http-lua/t/000--init.t | 85 - debian/modules/http-lua/t/000-sanity.t | 33 - debian/modules/http-lua/t/001-set.t | 797 -- debian/modules/http-lua/t/002-content.t | 844 -- debian/modules/http-lua/t/003-errors.t | 128 - debian/modules/http-lua/t/004-require.t | 211 - debian/modules/http-lua/t/005-exit.t | 725 -- debian/modules/http-lua/t/006-escape.t | 199 - debian/modules/http-lua/t/007-md5.t | 102 - debian/modules/http-lua/t/008-today.t | 38 - debian/modules/http-lua/t/009-log.t | 544 -- debian/modules/http-lua/t/010-request_body.t | 272 - debian/modules/http-lua/t/011-md5_bin.t | 170 - debian/modules/http-lua/t/012-now.t | 118 - debian/modules/http-lua/t/013-base64.t | 245 - debian/modules/http-lua/t/014-bugs.t | 1020 -- debian/modules/http-lua/t/015-status.t | 293 - debian/modules/http-lua/t/016-resp-header.t | 1701 ---- debian/modules/http-lua/t/017-exec.t | 596 -- debian/modules/http-lua/t/018-ndk.t | 173 - debian/modules/http-lua/t/019-const.t | 46 - debian/modules/http-lua/t/020-subrequest.t | 2879 ------ debian/modules/http-lua/t/021-cookie-time.t | 45 - debian/modules/http-lua/t/022-redirect.t | 322 - .../http-lua/t/023-rewrite/client-abort.t | 850 -- debian/modules/http-lua/t/023-rewrite/exec.t | 400 - debian/modules/http-lua/t/023-rewrite/exit.t | 597 -- debian/modules/http-lua/t/023-rewrite/mixed.t | 169 - .../http-lua/t/023-rewrite/multi-capture.t | 394 - .../modules/http-lua/t/023-rewrite/on-abort.t | 656 -- .../modules/http-lua/t/023-rewrite/redirect.t | 164 - .../modules/http-lua/t/023-rewrite/req-body.t | 223 - .../http-lua/t/023-rewrite/req-socket.t | 534 -- .../http-lua/t/023-rewrite/request_body.t | 172 - .../modules/http-lua/t/023-rewrite/sanity.t | 801 -- debian/modules/http-lua/t/023-rewrite/sleep.t | 221 - .../http-lua/t/023-rewrite/socket-keepalive.t | 1009 -- .../http-lua/t/023-rewrite/subrequest.t | 641 -- .../t/023-rewrite/tcp-socket-timeout.t | 606 -- .../http-lua/t/023-rewrite/tcp-socket.t | 2392 ----- .../http-lua/t/023-rewrite/unix-socket.t | 152 - .../http-lua/t/023-rewrite/uthread-exec.t | 345 - .../http-lua/t/023-rewrite/uthread-exit.t | 1331 --- .../http-lua/t/023-rewrite/uthread-redirect.t | 188 - .../http-lua/t/023-rewrite/uthread-spawn.t | 1451 --- debian/modules/http-lua/t/024-access/auth.t | 109 - .../http-lua/t/024-access/client-abort.t | 852 -- debian/modules/http-lua/t/024-access/exec.t | 393 - debian/modules/http-lua/t/024-access/exit.t | 547 -- debian/modules/http-lua/t/024-access/mixed.t | 261 - .../http-lua/t/024-access/multi-capture.t | 394 - .../modules/http-lua/t/024-access/on-abort.t | 651 -- .../modules/http-lua/t/024-access/redirect.t | 124 - .../modules/http-lua/t/024-access/req-body.t | 220 - .../http-lua/t/024-access/request_body.t | 172 - debian/modules/http-lua/t/024-access/sanity.t | 743 -- .../modules/http-lua/t/024-access/satisfy.t | 211 - debian/modules/http-lua/t/024-access/sleep.t | 221 - .../http-lua/t/024-access/subrequest.t | 601 -- .../http-lua/t/024-access/uthread-exec.t | 346 - .../http-lua/t/024-access/uthread-exit.t | 1313 --- .../http-lua/t/024-access/uthread-redirect.t | 189 - .../http-lua/t/024-access/uthread-spawn.t | 1118 --- debian/modules/http-lua/t/025-codecache.t | 1246 --- debian/modules/http-lua/t/026-mysql.t | 130 - debian/modules/http-lua/t/027-multi-capture.t | 754 -- debian/modules/http-lua/t/028-req-header.t | 2010 ---- debian/modules/http-lua/t/029-http-time.t | 87 - debian/modules/http-lua/t/030-uri-args.t | 1549 --- debian/modules/http-lua/t/031-post-args.t | 406 - debian/modules/http-lua/t/032-iolist.t | 78 - debian/modules/http-lua/t/033-ctx.t | 442 - debian/modules/http-lua/t/034-match.t | 1192 --- debian/modules/http-lua/t/035-gmatch.t | 904 -- debian/modules/http-lua/t/036-sub.t | 757 -- debian/modules/http-lua/t/037-gsub.t | 699 -- debian/modules/http-lua/t/038-match-o.t | 742 -- debian/modules/http-lua/t/039-sub-o.t | 580 -- debian/modules/http-lua/t/040-gsub-o.t | 200 - debian/modules/http-lua/t/041-header-filter.t | 796 -- debian/modules/http-lua/t/042-crc32.t | 56 - debian/modules/http-lua/t/043-shdict.t | 2473 ----- debian/modules/http-lua/t/044-req-body.t | 1746 ---- debian/modules/http-lua/t/045-ngx-var.t | 230 - debian/modules/http-lua/t/046-hmac.t | 31 - debian/modules/http-lua/t/047-match-jit.t | 214 - debian/modules/http-lua/t/048-match-dfa.t | 209 - debian/modules/http-lua/t/049-gmatch-jit.t | 228 - debian/modules/http-lua/t/050-gmatch-dfa.t | 338 - debian/modules/http-lua/t/051-sub-jit.t | 149 - debian/modules/http-lua/t/052-sub-dfa.t | 235 - debian/modules/http-lua/t/053-gsub-jit.t | 149 - debian/modules/http-lua/t/054-gsub-dfa.t | 236 - debian/modules/http-lua/t/055-subreq-vars.t | 338 - debian/modules/http-lua/t/056-flush.t | 522 -- debian/modules/http-lua/t/057-flush-timeout.t | 320 - debian/modules/http-lua/t/058-tcp-socket.t | 3810 -------- debian/modules/http-lua/t/059-unix-socket.t | 203 - debian/modules/http-lua/t/060-lua-memcached.t | 168 - debian/modules/http-lua/t/061-lua-redis.t | 184 - debian/modules/http-lua/t/062-count.t | 570 -- debian/modules/http-lua/t/063-abort.t | 1019 -- debian/modules/http-lua/t/064-pcall.t | 106 - .../http-lua/t/065-tcp-socket-timeout.t | 1018 -- .../http-lua/t/066-socket-receiveuntil.t | 1331 --- debian/modules/http-lua/t/067-req-socket.t | 1098 --- .../modules/http-lua/t/068-socket-keepalive.t | 1553 --- debian/modules/http-lua/t/069-null.t | 95 - debian/modules/http-lua/t/070-sha1.t | 70 - debian/modules/http-lua/t/071-idle-socket.t | 433 - .../modules/http-lua/t/072-conditional-get.t | 90 - debian/modules/http-lua/t/073-backtrace.t | 189 - debian/modules/http-lua/t/074-prefix-var.t | 66 - debian/modules/http-lua/t/075-logby.t | 583 -- debian/modules/http-lua/t/076-no-postpone.t | 146 - debian/modules/http-lua/t/077-sleep.t | 502 - debian/modules/http-lua/t/078-hup-vars.t | 64 - .../http-lua/t/079-unused-directives.t | 342 - debian/modules/http-lua/t/080-hup-shdict.t | 84 - debian/modules/http-lua/t/081-bytecode.t | 373 - debian/modules/http-lua/t/082-body-filter.t | 839 -- debian/modules/http-lua/t/083-bad-sock-self.t | 138 - .../http-lua/t/084-inclusive-receiveuntil.t | 745 -- debian/modules/http-lua/t/085-if.t | 200 - debian/modules/http-lua/t/086-init-by.t | 323 - debian/modules/http-lua/t/087-udp-socket.t | 1176 --- debian/modules/http-lua/t/088-req-method.t | 264 - debian/modules/http-lua/t/089-phase.t | 178 - .../http-lua/t/090-log-socket-errors.t | 108 - debian/modules/http-lua/t/091-coroutine.t | 1317 --- debian/modules/http-lua/t/092-eof.t | 82 - debian/modules/http-lua/t/093-uthread-spawn.t | 1674 ---- debian/modules/http-lua/t/094-uthread-exit.t | 1650 ---- debian/modules/http-lua/t/095-uthread-exec.t | 425 - .../modules/http-lua/t/096-uthread-redirect.t | 279 - .../modules/http-lua/t/097-uthread-rewrite.t | 347 - debian/modules/http-lua/t/098-uthread-wait.t | 1323 --- debian/modules/http-lua/t/099-c-api.t | 397 - debian/modules/http-lua/t/100-client-abort.t | 1066 --- debian/modules/http-lua/t/101-on-abort.t | 848 -- .../modules/http-lua/t/102-req-start-time.t | 115 - debian/modules/http-lua/t/103-req-http-ver.t | 48 - .../modules/http-lua/t/104-req-raw-header.t | 990 -- debian/modules/http-lua/t/105-pressure.t | 53 - debian/modules/http-lua/t/106-timer.t | 2195 ----- debian/modules/http-lua/t/107-timer-errors.t | 1422 --- debian/modules/http-lua/t/108-timer-safe.t | 1397 --- debian/modules/http-lua/t/109-timer-hup.t | 502 - debian/modules/http-lua/t/110-etag.t | 83 - debian/modules/http-lua/t/111-req-header-ua.t | 675 -- .../modules/http-lua/t/112-req-header-conn.t | 148 - .../http-lua/t/113-req-header-cookie.t | 249 - debian/modules/http-lua/t/114-config.t | 48 - debian/modules/http-lua/t/115-quote-sql-str.t | 76 - .../modules/http-lua/t/116-raw-req-socket.t | 878 -- .../http-lua/t/117-raw-req-socket-timeout.t | 116 - .../modules/http-lua/t/118-use-default-type.t | 140 - debian/modules/http-lua/t/119-config-prefix.t | 32 - debian/modules/http-lua/t/120-re-find.t | 919 -- debian/modules/http-lua/t/121-version.t | 48 - debian/modules/http-lua/t/122-worker.t | 81 - debian/modules/http-lua/t/123-lua-path.t | 70 - debian/modules/http-lua/t/124-init-worker.t | 955 -- .../modules/http-lua/t/125-configure-args.t | 31 - debian/modules/http-lua/t/126-shdict-frag.t | 1266 --- debian/modules/http-lua/t/127-uthread-kill.t | 507 - .../http-lua/t/128-duplex-tcp-socket.t | 631 -- debian/modules/http-lua/t/129-ssl-socket.t | 2532 ----- debian/modules/http-lua/t/130-internal-api.t | 49 - .../http-lua/t/131-duplex-req-socket.t | 141 - debian/modules/http-lua/t/132-lua-blocks.t | 729 -- debian/modules/http-lua/t/133-worker-count.t | 72 - .../modules/http-lua/t/134-worker-count-5.t | 78 - debian/modules/http-lua/t/135-worker-id.t | 33 - debian/modules/http-lua/t/136-timer-counts.t | 111 - debian/modules/http-lua/t/137-req-misc.t | 61 - debian/modules/http-lua/t/138-balancer.t | 528 -- debian/modules/http-lua/t/139-ssl-cert-by.t | 2077 ---- debian/modules/http-lua/t/140-ssl-c-api.t | 813 -- debian/modules/http-lua/t/141-luajit.t | 48 - .../http-lua/t/142-ssl-session-store.t | 903 -- .../http-lua/t/143-ssl-session-fetch.t | 1116 --- .../modules/http-lua/t/144-shdict-incr-init.t | 226 - debian/modules/http-lua/t/145-shdict-list.t | 745 -- debian/modules/http-lua/t/146-malloc-trim.t | 342 - .../http-lua/t/147-tcp-socket-timeouts.t | 627 -- debian/modules/http-lua/t/148-fake-shm-zone.t | 170 - .../http-lua/t/149-hup-fake-shm-zone.t | 91 - .../http-lua/t/150-fake-delayed-load.t | 56 - debian/modules/http-lua/t/151-initby-hup.t | 168 - debian/modules/http-lua/t/152-timer-every.t | 385 - debian/modules/http-lua/t/153-semaphore-hup.t | 154 - debian/modules/http-lua/t/154-semaphore.t | 120 - debian/modules/http-lua/t/155-tls13.t | 106 - debian/modules/http-lua/t/StapThread.pm | 282 - debian/modules/http-lua/t/cert/dst-ca.crt | 63 - debian/modules/http-lua/t/cert/equifax.crt | 19 - debian/modules/http-lua/t/cert/test.crl | 11 - debian/modules/http-lua/t/cert/test.crt | 17 - debian/modules/http-lua/t/cert/test.key | 15 - debian/modules/http-lua/t/cert/test2.crt | 16 - debian/modules/http-lua/t/cert/test2.key | 15 - debian/modules/http-lua/t/cert/test_ecdsa.crt | 12 - debian/modules/http-lua/t/cert/test_ecdsa.key | 5 - .../t/data/fake-delayed-load-module/config | 3 - .../ngx_http_lua_fake_delayed_load_module.c | 77 - .../http-lua/t/data/fake-module/config | 3 - .../t/data/fake-module/ngx_http_fake_module.c | 118 - .../http-lua/t/data/fake-shm-module/config | 3 - .../ngx_http_lua_fake_shm_module.c | 294 - debian/modules/http-lua/t/lib/CRC32.lua | 173 - debian/modules/http-lua/t/lib/Memcached.lua | 567 -- debian/modules/http-lua/t/lib/Redis.lua | 1120 --- debian/modules/http-lua/t/lib/ljson.lua | 89 - debian/modules/http-lua/tapset/ngx_lua.stp | 5 - debian/modules/http-lua/util/build.sh | 66 - debian/modules/http-lua/util/fix-comments | 27 - debian/modules/http-lua/util/gen-lexer-c | 18 - debian/modules/http-lua/util/ngx-links | 62 - debian/modules/http-lua/util/releng | 8 - debian/modules/http-lua/util/retab | 8 - debian/modules/http-lua/util/revim | 102 - debian/modules/http-lua/util/run_test.sh | 10 - debian/modules/http-lua/util/update-readme.sh | 4 - debian/modules/http-lua/valgrind.suppress | 209 - .../patches/http-lua/CVE-2020-11724.patch | 856 -- .../http-lua/bug-994178-segfault.patch | 31 - .../http-lua/discover-luajit-2.1.patch | 47 - debian/modules/patches/http-lua/series | 3 - debian/rules | 2 - debian/tests/control | 12 +- debian/tests/lua | 18 - 358 files changed, 6 insertions(+), 182310 deletions(-) delete mode 100755 debian/libnginx-mod-http-lua.nginx delete mode 100644 debian/modules/http-lua/README.markdown delete mode 100644 debian/modules/http-lua/config delete mode 100644 debian/modules/http-lua/doc/HttpLuaModule.wiki delete mode 100644 debian/modules/http-lua/dtrace/ngx_lua_provider.d delete mode 100644 debian/modules/http-lua/misc/recv-until-pm/Makefile delete mode 100755 debian/modules/http-lua/misc/recv-until-pm/lib/RecvUntil.pm delete mode 100644 debian/modules/http-lua/misc/recv-until-pm/t/sanity.t delete mode 100644 debian/modules/http-lua/src/api/ngx_http_lua_api.h delete mode 100644 debian/modules/http-lua/src/ddebug.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_accessby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_accessby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_api.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_args.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_args.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_balancer.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_balancer.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_cache.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_cache.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_capturefilter.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_capturefilter.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_clfactory.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_clfactory.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_common.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_config.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_config.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_consts.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_consts.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_contentby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_contentby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_control.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_control.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_coroutine.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_coroutine.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ctx.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ctx.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_directive.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_directive.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_exception.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_exception.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headerfilterby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers_in.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers_in.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers_out.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers_out.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_initby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_initby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_initworkerby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_initworkerby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_lex.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_lex.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_log.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_log.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_log_ringbuf.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_log_ringbuf.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_logby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_logby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_misc.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_misc.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_module.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ndk.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ndk.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_output.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_output.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_pcrefix.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_pcrefix.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_phase.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_phase.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_probe.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_regex.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_regex.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_req_body.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_req_body.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_req_method.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_req_method.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_rewriteby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_rewriteby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_script.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_script.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_semaphore.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_semaphore.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_setby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_setby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_shdict.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_shdict.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_sleep.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_sleep.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_socket_udp.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_socket_udp.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_certby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_ocsp.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_string.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_string.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_subrequest.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_subrequest.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_time.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_time.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_timer.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_timer.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_uri.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_uri.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_uthread.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_uthread.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_util.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_util.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_variable.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_variable.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_worker.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_worker.h delete mode 100644 debian/modules/http-lua/t/000--init.t delete mode 100644 debian/modules/http-lua/t/000-sanity.t delete mode 100644 debian/modules/http-lua/t/001-set.t delete mode 100644 debian/modules/http-lua/t/002-content.t delete mode 100644 debian/modules/http-lua/t/003-errors.t delete mode 100644 debian/modules/http-lua/t/004-require.t delete mode 100644 debian/modules/http-lua/t/005-exit.t delete mode 100644 debian/modules/http-lua/t/006-escape.t delete mode 100644 debian/modules/http-lua/t/007-md5.t delete mode 100644 debian/modules/http-lua/t/008-today.t delete mode 100644 debian/modules/http-lua/t/009-log.t delete mode 100644 debian/modules/http-lua/t/010-request_body.t delete mode 100644 debian/modules/http-lua/t/011-md5_bin.t delete mode 100644 debian/modules/http-lua/t/012-now.t delete mode 100644 debian/modules/http-lua/t/013-base64.t delete mode 100644 debian/modules/http-lua/t/014-bugs.t delete mode 100644 debian/modules/http-lua/t/015-status.t delete mode 100644 debian/modules/http-lua/t/016-resp-header.t delete mode 100644 debian/modules/http-lua/t/017-exec.t delete mode 100644 debian/modules/http-lua/t/018-ndk.t delete mode 100644 debian/modules/http-lua/t/019-const.t delete mode 100644 debian/modules/http-lua/t/020-subrequest.t delete mode 100644 debian/modules/http-lua/t/021-cookie-time.t delete mode 100644 debian/modules/http-lua/t/022-redirect.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/client-abort.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/exec.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/exit.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/mixed.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/multi-capture.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/on-abort.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/redirect.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/req-body.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/req-socket.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/request_body.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/sanity.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/sleep.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/socket-keepalive.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/subrequest.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/tcp-socket.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/unix-socket.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/uthread-exec.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/uthread-exit.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/uthread-redirect.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/uthread-spawn.t delete mode 100644 debian/modules/http-lua/t/024-access/auth.t delete mode 100644 debian/modules/http-lua/t/024-access/client-abort.t delete mode 100644 debian/modules/http-lua/t/024-access/exec.t delete mode 100644 debian/modules/http-lua/t/024-access/exit.t delete mode 100644 debian/modules/http-lua/t/024-access/mixed.t delete mode 100644 debian/modules/http-lua/t/024-access/multi-capture.t delete mode 100644 debian/modules/http-lua/t/024-access/on-abort.t delete mode 100644 debian/modules/http-lua/t/024-access/redirect.t delete mode 100644 debian/modules/http-lua/t/024-access/req-body.t delete mode 100644 debian/modules/http-lua/t/024-access/request_body.t delete mode 100644 debian/modules/http-lua/t/024-access/sanity.t delete mode 100644 debian/modules/http-lua/t/024-access/satisfy.t delete mode 100644 debian/modules/http-lua/t/024-access/sleep.t delete mode 100644 debian/modules/http-lua/t/024-access/subrequest.t delete mode 100644 debian/modules/http-lua/t/024-access/uthread-exec.t delete mode 100644 debian/modules/http-lua/t/024-access/uthread-exit.t delete mode 100644 debian/modules/http-lua/t/024-access/uthread-redirect.t delete mode 100644 debian/modules/http-lua/t/024-access/uthread-spawn.t delete mode 100644 debian/modules/http-lua/t/025-codecache.t delete mode 100644 debian/modules/http-lua/t/026-mysql.t delete mode 100644 debian/modules/http-lua/t/027-multi-capture.t delete mode 100644 debian/modules/http-lua/t/028-req-header.t delete mode 100644 debian/modules/http-lua/t/029-http-time.t delete mode 100644 debian/modules/http-lua/t/030-uri-args.t delete mode 100644 debian/modules/http-lua/t/031-post-args.t delete mode 100644 debian/modules/http-lua/t/032-iolist.t delete mode 100644 debian/modules/http-lua/t/033-ctx.t delete mode 100644 debian/modules/http-lua/t/034-match.t delete mode 100644 debian/modules/http-lua/t/035-gmatch.t delete mode 100644 debian/modules/http-lua/t/036-sub.t delete mode 100644 debian/modules/http-lua/t/037-gsub.t delete mode 100644 debian/modules/http-lua/t/038-match-o.t delete mode 100644 debian/modules/http-lua/t/039-sub-o.t delete mode 100644 debian/modules/http-lua/t/040-gsub-o.t delete mode 100644 debian/modules/http-lua/t/041-header-filter.t delete mode 100644 debian/modules/http-lua/t/042-crc32.t delete mode 100644 debian/modules/http-lua/t/043-shdict.t delete mode 100644 debian/modules/http-lua/t/044-req-body.t delete mode 100644 debian/modules/http-lua/t/045-ngx-var.t delete mode 100644 debian/modules/http-lua/t/046-hmac.t delete mode 100644 debian/modules/http-lua/t/047-match-jit.t delete mode 100644 debian/modules/http-lua/t/048-match-dfa.t delete mode 100644 debian/modules/http-lua/t/049-gmatch-jit.t delete mode 100644 debian/modules/http-lua/t/050-gmatch-dfa.t delete mode 100644 debian/modules/http-lua/t/051-sub-jit.t delete mode 100644 debian/modules/http-lua/t/052-sub-dfa.t delete mode 100644 debian/modules/http-lua/t/053-gsub-jit.t delete mode 100644 debian/modules/http-lua/t/054-gsub-dfa.t delete mode 100644 debian/modules/http-lua/t/055-subreq-vars.t delete mode 100644 debian/modules/http-lua/t/056-flush.t delete mode 100644 debian/modules/http-lua/t/057-flush-timeout.t delete mode 100644 debian/modules/http-lua/t/058-tcp-socket.t delete mode 100644 debian/modules/http-lua/t/059-unix-socket.t delete mode 100644 debian/modules/http-lua/t/060-lua-memcached.t delete mode 100644 debian/modules/http-lua/t/061-lua-redis.t delete mode 100644 debian/modules/http-lua/t/062-count.t delete mode 100644 debian/modules/http-lua/t/063-abort.t delete mode 100644 debian/modules/http-lua/t/064-pcall.t delete mode 100644 debian/modules/http-lua/t/065-tcp-socket-timeout.t delete mode 100644 debian/modules/http-lua/t/066-socket-receiveuntil.t delete mode 100644 debian/modules/http-lua/t/067-req-socket.t delete mode 100644 debian/modules/http-lua/t/068-socket-keepalive.t delete mode 100644 debian/modules/http-lua/t/069-null.t delete mode 100644 debian/modules/http-lua/t/070-sha1.t delete mode 100644 debian/modules/http-lua/t/071-idle-socket.t delete mode 100644 debian/modules/http-lua/t/072-conditional-get.t delete mode 100644 debian/modules/http-lua/t/073-backtrace.t delete mode 100644 debian/modules/http-lua/t/074-prefix-var.t delete mode 100644 debian/modules/http-lua/t/075-logby.t delete mode 100644 debian/modules/http-lua/t/076-no-postpone.t delete mode 100644 debian/modules/http-lua/t/077-sleep.t delete mode 100644 debian/modules/http-lua/t/078-hup-vars.t delete mode 100644 debian/modules/http-lua/t/079-unused-directives.t delete mode 100644 debian/modules/http-lua/t/080-hup-shdict.t delete mode 100644 debian/modules/http-lua/t/081-bytecode.t delete mode 100644 debian/modules/http-lua/t/082-body-filter.t delete mode 100644 debian/modules/http-lua/t/083-bad-sock-self.t delete mode 100644 debian/modules/http-lua/t/084-inclusive-receiveuntil.t delete mode 100644 debian/modules/http-lua/t/085-if.t delete mode 100644 debian/modules/http-lua/t/086-init-by.t delete mode 100644 debian/modules/http-lua/t/087-udp-socket.t delete mode 100644 debian/modules/http-lua/t/088-req-method.t delete mode 100644 debian/modules/http-lua/t/089-phase.t delete mode 100644 debian/modules/http-lua/t/090-log-socket-errors.t delete mode 100644 debian/modules/http-lua/t/091-coroutine.t delete mode 100644 debian/modules/http-lua/t/092-eof.t delete mode 100644 debian/modules/http-lua/t/093-uthread-spawn.t delete mode 100644 debian/modules/http-lua/t/094-uthread-exit.t delete mode 100644 debian/modules/http-lua/t/095-uthread-exec.t delete mode 100644 debian/modules/http-lua/t/096-uthread-redirect.t delete mode 100644 debian/modules/http-lua/t/097-uthread-rewrite.t delete mode 100644 debian/modules/http-lua/t/098-uthread-wait.t delete mode 100644 debian/modules/http-lua/t/099-c-api.t delete mode 100644 debian/modules/http-lua/t/100-client-abort.t delete mode 100644 debian/modules/http-lua/t/101-on-abort.t delete mode 100644 debian/modules/http-lua/t/102-req-start-time.t delete mode 100644 debian/modules/http-lua/t/103-req-http-ver.t delete mode 100644 debian/modules/http-lua/t/104-req-raw-header.t delete mode 100644 debian/modules/http-lua/t/105-pressure.t delete mode 100644 debian/modules/http-lua/t/106-timer.t delete mode 100644 debian/modules/http-lua/t/107-timer-errors.t delete mode 100644 debian/modules/http-lua/t/108-timer-safe.t delete mode 100644 debian/modules/http-lua/t/109-timer-hup.t delete mode 100644 debian/modules/http-lua/t/110-etag.t delete mode 100644 debian/modules/http-lua/t/111-req-header-ua.t delete mode 100644 debian/modules/http-lua/t/112-req-header-conn.t delete mode 100644 debian/modules/http-lua/t/113-req-header-cookie.t delete mode 100644 debian/modules/http-lua/t/114-config.t delete mode 100644 debian/modules/http-lua/t/115-quote-sql-str.t delete mode 100644 debian/modules/http-lua/t/116-raw-req-socket.t delete mode 100644 debian/modules/http-lua/t/117-raw-req-socket-timeout.t delete mode 100644 debian/modules/http-lua/t/118-use-default-type.t delete mode 100644 debian/modules/http-lua/t/119-config-prefix.t delete mode 100644 debian/modules/http-lua/t/120-re-find.t delete mode 100644 debian/modules/http-lua/t/121-version.t delete mode 100644 debian/modules/http-lua/t/122-worker.t delete mode 100644 debian/modules/http-lua/t/123-lua-path.t delete mode 100644 debian/modules/http-lua/t/124-init-worker.t delete mode 100644 debian/modules/http-lua/t/125-configure-args.t delete mode 100644 debian/modules/http-lua/t/126-shdict-frag.t delete mode 100644 debian/modules/http-lua/t/127-uthread-kill.t delete mode 100644 debian/modules/http-lua/t/128-duplex-tcp-socket.t delete mode 100644 debian/modules/http-lua/t/129-ssl-socket.t delete mode 100644 debian/modules/http-lua/t/130-internal-api.t delete mode 100644 debian/modules/http-lua/t/131-duplex-req-socket.t delete mode 100644 debian/modules/http-lua/t/132-lua-blocks.t delete mode 100644 debian/modules/http-lua/t/133-worker-count.t delete mode 100644 debian/modules/http-lua/t/134-worker-count-5.t delete mode 100644 debian/modules/http-lua/t/135-worker-id.t delete mode 100644 debian/modules/http-lua/t/136-timer-counts.t delete mode 100644 debian/modules/http-lua/t/137-req-misc.t delete mode 100644 debian/modules/http-lua/t/138-balancer.t delete mode 100644 debian/modules/http-lua/t/139-ssl-cert-by.t delete mode 100644 debian/modules/http-lua/t/140-ssl-c-api.t delete mode 100644 debian/modules/http-lua/t/141-luajit.t delete mode 100644 debian/modules/http-lua/t/142-ssl-session-store.t delete mode 100644 debian/modules/http-lua/t/143-ssl-session-fetch.t delete mode 100644 debian/modules/http-lua/t/144-shdict-incr-init.t delete mode 100644 debian/modules/http-lua/t/145-shdict-list.t delete mode 100644 debian/modules/http-lua/t/146-malloc-trim.t delete mode 100644 debian/modules/http-lua/t/147-tcp-socket-timeouts.t delete mode 100644 debian/modules/http-lua/t/148-fake-shm-zone.t delete mode 100644 debian/modules/http-lua/t/149-hup-fake-shm-zone.t delete mode 100644 debian/modules/http-lua/t/150-fake-delayed-load.t delete mode 100644 debian/modules/http-lua/t/151-initby-hup.t delete mode 100644 debian/modules/http-lua/t/152-timer-every.t delete mode 100644 debian/modules/http-lua/t/153-semaphore-hup.t delete mode 100644 debian/modules/http-lua/t/154-semaphore.t delete mode 100644 debian/modules/http-lua/t/155-tls13.t delete mode 100644 debian/modules/http-lua/t/StapThread.pm delete mode 100644 debian/modules/http-lua/t/cert/dst-ca.crt delete mode 100644 debian/modules/http-lua/t/cert/equifax.crt delete mode 100644 debian/modules/http-lua/t/cert/test.crl delete mode 100644 debian/modules/http-lua/t/cert/test.crt delete mode 100644 debian/modules/http-lua/t/cert/test.key delete mode 100644 debian/modules/http-lua/t/cert/test2.crt delete mode 100644 debian/modules/http-lua/t/cert/test2.key delete mode 100644 debian/modules/http-lua/t/cert/test_ecdsa.crt delete mode 100644 debian/modules/http-lua/t/cert/test_ecdsa.key delete mode 100644 debian/modules/http-lua/t/data/fake-delayed-load-module/config delete mode 100644 debian/modules/http-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c delete mode 100644 debian/modules/http-lua/t/data/fake-module/config delete mode 100644 debian/modules/http-lua/t/data/fake-module/ngx_http_fake_module.c delete mode 100644 debian/modules/http-lua/t/data/fake-shm-module/config delete mode 100644 debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c delete mode 100755 debian/modules/http-lua/t/lib/CRC32.lua delete mode 100755 debian/modules/http-lua/t/lib/Memcached.lua delete mode 100644 debian/modules/http-lua/t/lib/Redis.lua delete mode 100644 debian/modules/http-lua/t/lib/ljson.lua delete mode 100644 debian/modules/http-lua/tapset/ngx_lua.stp delete mode 100755 debian/modules/http-lua/util/build.sh delete mode 100644 debian/modules/http-lua/util/fix-comments delete mode 100755 debian/modules/http-lua/util/gen-lexer-c delete mode 100755 debian/modules/http-lua/util/ngx-links delete mode 100755 debian/modules/http-lua/util/releng delete mode 100755 debian/modules/http-lua/util/retab delete mode 100755 debian/modules/http-lua/util/revim delete mode 100755 debian/modules/http-lua/util/run_test.sh delete mode 100755 debian/modules/http-lua/util/update-readme.sh delete mode 100644 debian/modules/http-lua/valgrind.suppress delete mode 100644 debian/modules/patches/http-lua/CVE-2020-11724.patch delete mode 100644 debian/modules/patches/http-lua/bug-994178-segfault.patch delete mode 100644 debian/modules/patches/http-lua/discover-luajit-2.1.patch delete mode 100644 debian/modules/patches/http-lua/series delete mode 100644 debian/tests/lua diff --git a/debian/changelog b/debian/changelog index a41d64e..fff7b8f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,7 @@ nginx (1.22.0-3) UNRELEASED; urgency=medium * d/changelog: fixed typo in bug number 61261 -> 861261 (Closes: 861261) * d/p/nginx-ssl_cert_cb_yield.patch added (Closes: 884434) + * http-lua: removed the http-lua module and moved it to a separate package -- Jan Mojžíš Mon, 08 Aug 2022 12:29:34 +0200 diff --git a/debian/control b/debian/control index c8aa03c..206523f 100644 --- a/debian/control +++ b/debian/control @@ -11,8 +11,6 @@ Build-Depends: debhelper-compat (= 13), libgd-dev, libgeoip-dev, libhiredis-dev, - liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !s390x], - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 s390x], libmaxminddb-dev, libmhash-dev, libpam0g-dev, @@ -209,7 +207,7 @@ Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), libnginx-mod-http-geoip2 (= ${binary:Version}), libnginx-mod-http-headers-more-filter (= ${binary:Version}), libnginx-mod-http-image-filter (= ${binary:Version}), - libnginx-mod-http-lua (= ${binary:Version}), + libnginx-mod-http-lua [amd64 arm64 armel armhf i386 mips64el mipsel s390x], libnginx-mod-http-perl (= ${binary:Version}), libnginx-mod-http-subs-filter (= ${binary:Version}), libnginx-mod-http-uploadprogress (= ${binary:Version}), @@ -364,20 +362,6 @@ Description: PAM authentication module for Nginx The module uses PAM as a backend for simple http authentication. It also allows setting the pam service name to allow more fine grained control. -Package: libnginx-mod-http-lua -Architecture: any -Depends: libnginx-mod-http-ndk (= ${binary:Version}), - ${misc:Depends}, - ${shlibs:Depends}, -Recommends: nginx, -Description: Lua module for Nginx - Embed Lua runtime into nginx. - . - This module embeds Lua, via the standard Lua 5.1 interpreter or LuaJIT - 2.0/2.1, into Nginx and by leveraging Nginx's subrequests, allows the - integration of the powerful Lua threads (Lua coroutines) into the Nginx event - model. - Package: libnginx-mod-http-ndk Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, diff --git a/debian/copyright b/debian/copyright index 6449e69..2aabc8d 100644 --- a/debian/copyright +++ b/debian/copyright @@ -84,15 +84,6 @@ Files: debian/modules/http-echo/* Copyright: 2009-2014, Yichun "agentzh" Zhang License: BSD-2-clause -Files: debian/modules/http-lua/* -Copyright: 2009-2017, by Xiaozhe Wang (chaoslawful) . - 2009-2018, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. -License: BSD-2-clause - -Files: debian/modules/http-lua/t/lib/CRC32.lua -Copyright: 2007-2008, Neil Richardson (nrich@iinet.net.au) -License: Expat - Files: debian/modules/http-upstream-fair/* Copyright: 2007, Grzegorz Nosek Igor Sysoev diff --git a/debian/libnginx-mod-http-lua.nginx b/debian/libnginx-mod-http-lua.nginx deleted file mode 100755 index 78c206f..0000000 --- a/debian/libnginx-mod-http-lua.nginx +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl -w - -use File::Basename; - -# Guess module name -$module = basename($0, '.nginx'); -$module =~ s/^libnginx-mod-//; - -$modulepath = $module; -$modulepath =~ s/-/_/g; - -print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; -print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/modules/http-lua/README.markdown b/debian/modules/http-lua/README.markdown deleted file mode 100644 index 15ad00e..0000000 --- a/debian/modules/http-lua/README.markdown +++ /dev/null @@ -1,8332 +0,0 @@ - - -Name -==== - -ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers. - -*This module is not distributed with the Nginx source.* See [the installation instructions](#installation). - -Table of Contents -================= - -* [Name](#name) -* [Status](#status) -* [Version](#version) -* [Synopsis](#synopsis) -* [Description](#description) -* [Typical Uses](#typical-uses) -* [Nginx Compatibility](#nginx-compatibility) -* [Installation](#installation) - * [Building as a dynamic module](#building-as-a-dynamic-module) - * [C Macro Configurations](#c-macro-configurations) - * [Installation on Ubuntu 11.10](#installation-on-ubuntu-1110) -* [Community](#community) - * [English Mailing List](#english-mailing-list) - * [Chinese Mailing List](#chinese-mailing-list) -* [Code Repository](#code-repository) -* [Bugs and Patches](#bugs-and-patches) -* [Lua/LuaJIT bytecode support](#lualuajit-bytecode-support) -* [System Environment Variable Support](#system-environment-variable-support) -* [HTTP 1.0 support](#http-10-support) -* [Statically Linking Pure Lua Modules](#statically-linking-pure-lua-modules) -* [Data Sharing within an Nginx Worker](#data-sharing-within-an-nginx-worker) -* [Known Issues](#known-issues) - * [TCP socket connect operation issues](#tcp-socket-connect-operation-issues) - * [Lua Coroutine Yielding/Resuming](#lua-coroutine-yieldingresuming) - * [Lua Variable Scope](#lua-variable-scope) - * [Locations Configured by Subrequest Directives of Other Modules](#locations-configured-by-subrequest-directives-of-other-modules) - * [Cosockets Not Available Everywhere](#cosockets-not-available-everywhere) - * [Special Escaping Sequences](#special-escaping-sequences) - * [Mixing with SSI Not Supported](#mixing-with-ssi-not-supported) - * [SPDY Mode Not Fully Supported](#spdy-mode-not-fully-supported) - * [Missing data on short circuited requests](#missing-data-on-short-circuited-requests) -* [TODO](#todo) -* [Changes](#changes) -* [Test Suite](#test-suite) -* [Copyright and License](#copyright-and-license) -* [See Also](#see-also) -* [Directives](#directives) -* [Nginx API for Lua](#nginx-api-for-lua) -* [Obsolete Sections](#obsolete-sections) - * [Special PCRE Sequences](#special-pcre-sequences) - -Status -====== - -Production ready. - -Version -======= - -This document describes ngx_lua [v0.10.13](https://github.com/openresty/lua-nginx-module/tags) released on 22 April 2018. - -Synopsis -======== -```nginx - - # set search paths for pure Lua external libraries (';;' is the default path): - lua_package_path '/foo/bar/?.lua;/blah/?.lua;;'; - - # set search paths for Lua external libraries written in C (can also use ';;'): - lua_package_cpath '/bar/baz/?.so;/blah/blah/?.so;;'; - - server { - location /lua_content { - # MIME type determined by default_type: - default_type 'text/plain'; - - content_by_lua_block { - ngx.say('Hello,world!') - } - } - - location /nginx_var { - # MIME type determined by default_type: - default_type 'text/plain'; - - # try access /nginx_var?a=hello,world - content_by_lua_block { - ngx.say(ngx.var.arg_a) - } - } - - location = /request_body { - client_max_body_size 50k; - client_body_buffer_size 50k; - - content_by_lua_block { - ngx.req.read_body() -- explicitly read the req body - local data = ngx.req.get_body_data() - if data then - ngx.say("body data:") - ngx.print(data) - return - end - - -- body may get buffered in a temp file: - local file = ngx.req.get_body_file() - if file then - ngx.say("body is in file ", file) - else - ngx.say("no body found") - end - } - } - - # transparent non-blocking I/O in Lua via subrequests - # (well, a better way is to use cosockets) - location = /lua { - # MIME type determined by default_type: - default_type 'text/plain'; - - content_by_lua_block { - local res = ngx.location.capture("/some_other_location") - if res then - ngx.say("status: ", res.status) - ngx.say("body:") - ngx.print(res.body) - end - } - } - - location = /foo { - rewrite_by_lua_block { - res = ngx.location.capture("/memc", - { args = { cmd = "incr", key = ngx.var.uri } } - ) - } - - proxy_pass http://blah.blah.com; - } - - location = /mixed { - rewrite_by_lua_file /path/to/rewrite.lua; - access_by_lua_file /path/to/access.lua; - content_by_lua_file /path/to/content.lua; - } - - # use nginx var in code path - # CAUTION: contents in nginx var must be carefully filtered, - # otherwise there'll be great security risk! - location ~ ^/app/([-_a-zA-Z0-9/]+) { - set $path $1; - content_by_lua_file /path/to/lua/app/root/$path.lua; - } - - location / { - client_max_body_size 100k; - client_body_buffer_size 100k; - - access_by_lua_block { - -- check the client IP address is in our black list - if ngx.var.remote_addr == "132.5.72.3" then - ngx.exit(ngx.HTTP_FORBIDDEN) - end - - -- check if the URI contains bad words - if ngx.var.uri and - string.match(ngx.var.request_body, "evil") - then - return ngx.redirect("/terms_of_use.html") - end - - -- tests passed - } - - # proxy_pass/fastcgi_pass/etc settings - } - } -``` - -[Back to TOC](#table-of-contents) - -Description -=========== - -This module embeds Lua, via the standard Lua 5.1 interpreter or [LuaJIT 2.0/2.1](http://luajit.org/luajit.html), into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. - -Unlike [Apache's mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html) and [Lighttpd's mod_magnet](http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet), Lua code executed using this module can be *100% non-blocking* on network traffic as long as the [Nginx API for Lua](#nginx-api-for-lua) provided by this module is used to handle -requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. - -At least the following Lua libraries and Nginx modules can be used with this ngx_lua module: - -* [lua-resty-memcached](https://github.com/openresty/lua-resty-memcached) -* [lua-resty-mysql](https://github.com/openresty/lua-resty-mysql) -* [lua-resty-redis](https://github.com/openresty/lua-resty-redis) -* [lua-resty-dns](https://github.com/openresty/lua-resty-dns) -* [lua-resty-upload](https://github.com/openresty/lua-resty-upload) -* [lua-resty-websocket](https://github.com/openresty/lua-resty-websocket) -* [lua-resty-lock](https://github.com/openresty/lua-resty-lock) -* [lua-resty-logger-socket](https://github.com/cloudflare/lua-resty-logger-socket) -* [lua-resty-lrucache](https://github.com/openresty/lua-resty-lrucache) -* [lua-resty-string](https://github.com/openresty/lua-resty-string) -* [ngx_memc](http://github.com/openresty/memc-nginx-module) -* [ngx_postgres](https://github.com/FRiCKLE/ngx_postgres) -* [ngx_redis2](http://github.com/openresty/redis2-nginx-module) -* [ngx_redis](http://wiki.nginx.org/HttpRedisModule) -* [ngx_proxy](http://nginx.org/en/docs/http/ngx_http_proxy_module.html) -* [ngx_fastcgi](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html) - -Almost all the Nginx modules can be used with this ngx_lua module by means of [ngx.location.capture](#ngxlocationcapture) or [ngx.location.capture_multi](#ngxlocationcapture_multi) but it is recommended to use those `lua-resty-*` libraries instead of creating subrequests to access the Nginx upstream modules because the former is usually much more flexible and memory-efficient. - -The Lua interpreter or LuaJIT instance is shared across all the requests in a single nginx worker process but request contexts are segregated using lightweight Lua coroutines. - -Loaded Lua modules persist in the nginx worker process level resulting in a small memory footprint in Lua even when under heavy loads. - -This module is plugged into NGINX's "http" subsystem so it can only speaks downstream communication protocols in the HTTP family (HTTP 0.9/1.0/1.1/2.0, WebSockets, and etc). -If you want to do generic TCP communications with the downstream clients, then you should use the [ngx_stream_lua](https://github.com/openresty/stream-lua-nginx-module#readme) module instead -which has a compatible Lua API. - -[Back to TOC](#table-of-contents) - -Typical Uses -============ - -Just to name a few: - -* Mashup'ing and processing outputs of various nginx upstream outputs (proxy, drizzle, postgres, redis, memcached, and etc) in Lua, -* doing arbitrarily complex access control and security checks in Lua before requests actually reach the upstream backends, -* manipulating response headers in an arbitrary way (by Lua) -* fetching backend information from external storage backends (like redis, memcached, mysql, postgresql) and use that information to choose which upstream backend to access on-the-fly, -* coding up arbitrarily complex web applications in a content handler using synchronous but still non-blocking access to the database backends and other storage, -* doing very complex URL dispatch in Lua at rewrite phase, -* using Lua to implement advanced caching mechanism for Nginx's subrequests and arbitrary locations. - -The possibilities are unlimited as the module allows bringing together various elements within Nginx as well as exposing the power of the Lua language to the user. The module provides the full flexibility of scripting while offering performance levels comparable with native C language programs both in terms of CPU time as well as memory footprint. This is particularly the case when LuaJIT 2.x is enabled. - -Other scripting language implementations typically struggle to match this performance level. - -The Lua state (Lua VM instance) is shared across all the requests handled by a single nginx worker process to minimize memory use. - -[Back to TOC](#table-of-contents) - -Nginx Compatibility -=================== - -The latest version of this module is compatible with the following versions of Nginx: - -* 1.13.x (last tested: 1.13.6) -* 1.12.x -* 1.11.x (last tested: 1.11.2) -* 1.10.x -* 1.9.x (last tested: 1.9.15) -* 1.8.x -* 1.7.x (last tested: 1.7.10) -* 1.6.x - -Nginx cores older than 1.6.0 (exclusive) are *not* supported. - -[Back to TOC](#table-of-contents) - -Installation -============ - -It is *highly* recommended to use [OpenResty releases](http://openresty.org) which integrate Nginx, ngx_lua, LuaJIT 2.1, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. - -Alternatively, ngx_lua can be manually compiled into Nginx: - -1. Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuaJIT can be downloaded from the [LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuaJIT and/or Lua. -1. Download the latest version of the ngx_devel_kit (NDK) module [HERE](https://github.com/simplresty/ngx_devel_kit/tags). -1. Download the latest version of ngx_lua [HERE](https://github.com/openresty/lua-nginx-module/tags). -1. Download the latest version of Nginx [HERE](http://nginx.org/) (See [Nginx Compatibility](#nginx-compatibility)) - -Build the source with this module: - -```bash - - wget 'http://nginx.org/download/nginx-1.13.6.tar.gz' - tar -xzvf nginx-1.13.6.tar.gz - cd nginx-1.13.6/ - - # tell nginx's build system where to find LuaJIT 2.0: - export LUAJIT_LIB=/path/to/luajit/lib - export LUAJIT_INC=/path/to/luajit/include/luajit-2.0 - - # tell nginx's build system where to find LuaJIT 2.1: - export LUAJIT_LIB=/path/to/luajit/lib - export LUAJIT_INC=/path/to/luajit/include/luajit-2.1 - - # or tell where to find Lua if using Lua instead: - #export LUA_LIB=/path/to/lua/lib - #export LUA_INC=/path/to/lua/include - - # Here we assume Nginx is to be installed under /opt/nginx/. - ./configure --prefix=/opt/nginx \ - --with-ld-opt="-Wl,-rpath,/path/to/luajit-or-lua/lib" \ - --add-module=/path/to/ngx_devel_kit \ - --add-module=/path/to/lua-nginx-module - - # Note that you may also want to add `./configure` options which are used in your - # current nginx build. - # You can get usually those options using command nginx -V - - # you can change the parallism number 2 below to fit the number of spare CPU cores in your - # machine. - make -j2 - make install -``` - -[Back to TOC](#table-of-contents) - -Building as a dynamic module ----------------------------- - -Starting from NGINX 1.9.11, you can also compile this module as a dynamic module, by using the `--add-dynamic-module=PATH` option instead of `--add-module=PATH` on the -`./configure` command line above. And then you can explicitly load the module in your `nginx.conf` via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module) -directive, for example, - -```nginx - - load_module /path/to/modules/ndk_http_module.so; # assuming NDK is built as a dynamic module too - load_module /path/to/modules/ngx_http_lua_module.so; -``` - -[Back to TOC](#table-of-contents) - -C Macro Configurations ----------------------- - -While building this module either via OpenResty or with the NGINX core, you can define the following C macros via the C compiler options: - -* `NGX_LUA_USE_ASSERT` - When defined, will enable assertions in the ngx_lua C code base. Recommended for debugging or testing builds. It can introduce some (small) runtime overhead when enabled. This macro was first introduced in the `v0.9.10` release. -* `NGX_LUA_ABORT_AT_PANIC` - When the Lua/LuaJIT VM panics, ngx_lua will instruct the current nginx worker process to quit gracefully by default. By specifying this C macro, ngx_lua will abort the current nginx worker process (which usually result in a core dump file) immediately. This option is useful for debugging VM panics. This option was first introduced in the `v0.9.8` release. -* `NGX_LUA_NO_FFI_API` - Excludes pure C API functions for FFI-based Lua API for NGINX (as required by [lua-resty-core](https://github.com/openresty/lua-resty-core#readme), for example). Enabling this macro can make the resulting binary code size smaller. - -To enable one or more of these macros, just pass extra C compiler options to the `./configure` script of either NGINX or OpenResty. For instance, - - - ./configure --with-cc-opt="-DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC" - - -[Back to TOC](#table-of-contents) - -Installation on Ubuntu 11.10 ----------------------------- - -Note that it is recommended to use LuaJIT 2.0 or LuaJIT 2.1 instead of the standard Lua 5.1 interpreter wherever possible. - -If the standard Lua 5.1 interpreter is required however, run the following command to install it from the Ubuntu repository: - -```bash - - apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev -``` - -Everything should be installed correctly, except for one small tweak. - -Library name `liblua.so` has been changed in liblua5.1 package, it only comes with `liblua5.1.so`, which needs to be symlinked to `/usr/lib` so it could be found during the configuration process. - -```bash - - ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so -``` - -[Back to TOC](#table-of-contents) - -Community -========= - -[Back to TOC](#table-of-contents) - -English Mailing List --------------------- - -The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. - -[Back to TOC](#table-of-contents) - -Chinese Mailing List --------------------- - -The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. - -[Back to TOC](#table-of-contents) - -Code Repository -=============== - -The code repository of this project is hosted on github at [openresty/lua-nginx-module](https://github.com/openresty/lua-nginx-module). - -[Back to TOC](#table-of-contents) - -Bugs and Patches -================ - -Please submit bug reports, wishlists, or patches by - -1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-nginx-module/issues), -1. or posting to the [OpenResty community](#community). - -[Back to TOC](#table-of-contents) - -Lua/LuaJIT bytecode support -=========================== - -As from the `v0.5.0rc32` release, all `*_by_lua_file` configure directives (such as [content_by_lua_file](#content_by_lua_file)) support loading Lua 5.1 and LuaJIT 2.0/2.1 raw bytecode files directly. - -Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: - -```bash - - /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.ljbc -``` - -The `-bg` option can be used to include debug information in the LuaJIT bytecode file: - -```bash - - /path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.ljbc -``` - -Please refer to the official LuaJIT documentation on the `-b` option for more details: - - - -Also, the bytecode files generated by LuaJIT 2.1 is *not* compatible with LuaJIT 2.0, and vice versa. The support for LuaJIT 2.1 bytecode was first added in ngx_lua v0.9.3. - -Similarly, if using the standard Lua 5.1 interpreter with ngx_lua, Lua compatible bytecode files must be generated using the `luac` commandline utility as shown: - -```bash - - luac -o /path/to/output_file.luac /path/to/input_file.lua -``` - -Unlike as with LuaJIT, debug information is included in standard Lua 5.1 bytecode files by default. This can be striped out by specifying the `-s` option as shown: - -```bash - - luac -s -o /path/to/output_file.luac /path/to/input_file.lua -``` - -Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0/2.1 or vice versa, will result in an error message, such as that below, being logged into the Nginx `error.log` file: - - - [error] 13909#0: *1 failed to load Lua inlined code: bad byte-code header in /path/to/test_file.luac - - -Loading bytecode files via the Lua primitives like `require` and `dofile` should always work as expected. - -[Back to TOC](#table-of-contents) - -System Environment Variable Support -=================================== - -If you want to access the system environment variable, say, `foo`, in Lua via the standard Lua API [os.getenv](http://www.lua.org/manual/5.1/manual.html#pdf-os.getenv), then you should also list this environment variable name in your `nginx.conf` file via the [env directive](http://nginx.org/en/docs/ngx_core_module.html#env). For example, - -```nginx - - env foo; -``` - -[Back to TOC](#table-of-contents) - -HTTP 1.0 support -================ - -The HTTP 1.0 protocol does not support chunked output and requires an explicit `Content-Length` header when the response body is not empty in order to support the HTTP 1.0 keep-alive. -So when a HTTP 1.0 request is made and the [lua_http10_buffering](#lua_http10_buffering) directive is turned `on`, ngx_lua will buffer the -output of [ngx.say](#ngxsay) and [ngx.print](#ngxprint) calls and also postpone sending response headers until all the response body output is received. -At that time ngx_lua can calculate the total length of the body and construct a proper `Content-Length` header to return to the HTTP 1.0 client. -If the `Content-Length` response header is set in the running Lua code, however, this buffering will be disabled even if the [lua_http10_buffering](#lua_http10_buffering) directive is turned `on`. - -For large streaming output responses, it is important to disable the [lua_http10_buffering](#lua_http10_buffering) directive to minimise memory usage. - -Note that common HTTP benchmark tools such as `ab` and `http_load` issue HTTP 1.0 requests by default. -To force `curl` to send HTTP 1.0 requests, use the `-0` option. - -[Back to TOC](#table-of-contents) - -Statically Linking Pure Lua Modules -=================================== - -When LuaJIT 2.x is used, it is possible to statically link the bytecode of pure Lua modules into the Nginx executable. - -Basically you use the `luajit` executable to compile `.lua` Lua module files to `.o` object files containing the exported bytecode data, and then link the `.o` files directly in your Nginx build. - -Below is a trivial example to demonstrate this. Consider that we have the following `.lua` file named `foo.lua`: - -```lua - - -- foo.lua - local _M = {} - - function _M.go() - print("Hello from foo") - end - - return _M -``` - -And then we compile this `.lua` file to `foo.o` file: - - /path/to/luajit/bin/luajit -bg foo.lua foo.o - -What matters here is the name of the `.lua` file, which determines how you use this module later on the Lua land. The file name `foo.o` does not matter at all except the `.o` file extension (which tells `luajit` what output format is used). If you want to strip the Lua debug information from the resulting bytecode, you can just specify the `-b` option above instead of `-bg`. - -Then when building Nginx or OpenResty, pass the `--with-ld-opt="foo.o"` option to the `./configure` script: - -```bash - - ./configure --with-ld-opt="/path/to/foo.o" ... -``` - -Finally, you can just do the following in any Lua code run by ngx_lua: - -```lua - - local foo = require "foo" - foo.go() -``` - -And this piece of code no longer depends on the external `foo.lua` file any more because it has already been compiled into the `nginx` executable. - -If you want to use dot in the Lua module name when calling `require`, as in - -```lua - - local foo = require "resty.foo" -``` - -then you need to rename the `foo.lua` file to `resty_foo.lua` before compiling it down to a `.o` file with the `luajit` command-line utility. - -It is important to use exactly the same version of LuaJIT when compiling `.lua` files to `.o` files as building nginx + ngx_lua. This is because the LuaJIT bytecode format may be incompatible between different LuaJIT versions. When the bytecode format is incompatible, you will see a Lua runtime error saying that the Lua module is not found. - -When you have multiple `.lua` files to compile and link, then just specify their `.o` files at the same time in the value of the `--with-ld-opt` option. For instance, - -```bash - - ./configure --with-ld-opt="/path/to/foo.o /path/to/bar.o" ... -``` - -If you have just too many `.o` files, then it might not be feasible to name them all in a single command. In this case, you can build a static library (or archive) for your `.o` files, as in - -```bash - - ar rcus libmyluafiles.a *.o -``` - -then you can link the `myluafiles` archive as a whole to your nginx executable: - -```bash - - ./configure \ - --with-ld-opt="-L/path/to/lib -Wl,--whole-archive -lmyluafiles -Wl,--no-whole-archive" -``` - -where `/path/to/lib` is the path of the directory containing the `libmyluafiles.a` file. It should be noted that the linker option `--whole-archive` is required here because otherwise our archive will be skipped because no symbols in our archive are mentioned in the main parts of the nginx executable. - -[Back to TOC](#table-of-contents) - -Data Sharing within an Nginx Worker -=================================== - -To globally share data among all the requests handled by the same nginx worker process, encapsulate the shared data into a Lua module, use the Lua `require` builtin to import the module, and then manipulate the shared data in Lua. This works because required Lua modules are loaded only once and all coroutines will share the same copy of the module (both its code and data). Note however that Lua global variables (note, not module-level variables) WILL NOT persist between requests because of the one-coroutine-per-request isolation design. - -Here is a complete small example: - -```lua - - -- mydata.lua - local _M = {} - - local data = { - dog = 3, - cat = 4, - pig = 5, - } - - function _M.get_age(name) - return data[name] - end - - return _M -``` - -and then accessing it from `nginx.conf`: - -```nginx - - location /lua { - content_by_lua_block { - local mydata = require "mydata" - ngx.say(mydata.get_age("dog")) - } - } -``` - -The `mydata` module in this example will only be loaded and run on the first request to the location `/lua`, -and all subsequent requests to the same nginx worker process will use the reloaded instance of the -module as well as the same copy of the data in it, until a `HUP` signal is sent to the Nginx master process to force a reload. -This data sharing technique is essential for high performance Lua applications based on this module. - -Note that this data sharing is on a *per-worker* basis and not on a *per-server* basis. That is, when there are multiple nginx worker processes under an Nginx master, data sharing cannot cross the process boundary between these workers. - -It is usually recommended to share read-only data this way. You can also share changeable data among all the concurrent requests of each nginx worker process as -long as there is *no* nonblocking I/O operations (including [ngx.sleep](#ngxsleep)) -in the middle of your calculations. As long as you do not give the -control back to the nginx event loop and ngx_lua's light thread -scheduler (even implicitly), there can never be any race conditions in -between. For this reason, always be very careful when you want to share changeable data on the -worker level. Buggy optimizations can easily lead to hard-to-debug -race conditions under load. - -If server-wide data sharing is required, then use one or more of the following approaches: - -1. Use the [ngx.shared.DICT](#ngxshareddict) API provided by this module. -1. Use only a single nginx worker and a single server (this is however not recommended when there is a multi core CPU or multiple CPUs in a single machine). -1. Use data storage mechanisms such as `memcached`, `redis`, `MySQL` or `PostgreSQL`. [The OpenResty bundle](http://openresty.org) associated with this module comes with a set of companion Nginx modules and Lua libraries that provide interfaces with these data storage mechanisms. - -[Back to TOC](#table-of-contents) - -Known Issues -============ - -[Back to TOC](#table-of-contents) - -TCP socket connect operation issues ------------------------------------ -The [tcpsock:connect](#tcpsockconnect) method may indicate `success` despite connection failures such as with `Connection Refused` errors. - -However, later attempts to manipulate the cosocket object will fail and return the actual error status message generated by the failed connect operation. - -This issue is due to limitations in the Nginx event model and only appears to affect Mac OS X. - -[Back to TOC](#table-of-contents) - -Lua Coroutine Yielding/Resuming -------------------------------- -* Because Lua's `dofile` and `require` builtins are currently implemented as C functions in both Lua 5.1 and LuaJIT 2.0/2.1, if the Lua file being loaded by `dofile` or `require` invokes [ngx.location.capture*](#ngxlocationcapture), [ngx.exec](#ngxexec), [ngx.exit](#ngxexit), or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. -* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [ngx.location.capture](#ngxlocationcapture), [ngx.location.capture_multi](#ngxlocationcapture_multi), [ngx.redirect](#ngxredirect), [ngx.exec](#ngxexec), and [ngx.exit](#ngxexit) cannot be used within the context of a Lua [pcall()](http://www.lua.org/manual/5.1/manual.html#pdf-pcall) or [xpcall()](http://www.lua.org/manual/5.1/manual.html#pdf-xpcall) or even the first line of the `for ... in ...` statement when the standard Lua 5.1 interpreter is used and the `attempt to yield across metamethod/C-call boundary` error will be produced. Please use LuaJIT 2.x, which supports a fully resumable VM, to avoid this. - -[Back to TOC](#table-of-contents) - -Lua Variable Scope ------------------- -Care must be taken when importing modules and this form should be used: - -```lua - - local xxx = require('xxx') -``` - -instead of the old deprecated form: - -```lua - - require('xxx') -``` - -Here is the reason: by design, the global environment has exactly the same lifetime as the Nginx request handler associated with it. Each request handler has its own set of Lua global variables and that is the idea of request isolation. The Lua module is actually loaded by the first Nginx request handler and is cached by the `require()` built-in in the `package.loaded` table for later reference, and the `module()` builtin used by some Lua modules has the side effect of setting a global variable to the loaded module table. But this global variable will be cleared at the end of the request handler, and every subsequent request handler all has its own (clean) global environment. So one will get Lua exception for accessing the `nil` value. - -The use of Lua global variables is a generally inadvisable in the ngx_lua context as: - -1. the misuse of Lua globals has detrimental side effects on concurrent requests when such variables should instead be local in scope, -1. Lua global variables require Lua table look-ups in the global environment which is computationally expensive, and -1. some Lua global variable references may include typing errors which make such difficult to debug. - -It is therefore *highly* recommended to always declare such within an appropriate local scope instead. - -```lua - - -- Avoid - foo = 123 - -- Recommended - local foo = 123 - - -- Avoid - function foo() return 123 end - -- Recommended - local function foo() return 123 end -``` - - -To find all instances of Lua global variables in your Lua code, run the [lua-releng tool](https://github.com/openresty/nginx-devel-utils/blob/master/lua-releng) across all `.lua` source files: - - $ lua-releng - Checking use of Lua global variables in file lib/foo/bar.lua ... - 1 [1489] SETGLOBAL 7 -1 ; contains - 55 [1506] GETGLOBAL 7 -3 ; setvar - 3 [1545] GETGLOBAL 3 -4 ; varexpand - -The output says that the line 1489 of file `lib/foo/bar.lua` writes to a global variable named `contains`, the line 1506 reads from the global variable `setvar`, and line 1545 reads the global `varexpand`. - -This tool will guarantee that local variables in the Lua module functions are all declared with the `local` keyword, otherwise a runtime exception will be thrown. It prevents undesirable race conditions while accessing such variables. See [Data Sharing within an Nginx Worker](#data-sharing-within-an-nginx-worker) for the reasons behind this. - -[Back to TOC](#table-of-contents) - -Locations Configured by Subrequest Directives of Other Modules --------------------------------------------------------------- -The [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) directives cannot capture locations that include the [add_before_body](http://nginx.org/en/docs/http/ngx_http_addition_module.html#add_before_body), [add_after_body](http://nginx.org/en/docs/http/ngx_http_addition_module.html#add_after_body), [auth_request](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html#auth_request), [echo_location](http://github.com/openresty/echo-nginx-module#echo_location), [echo_location_async](http://github.com/openresty/echo-nginx-module#echo_location_async), [echo_subrequest](http://github.com/openresty/echo-nginx-module#echo_subrequest), or [echo_subrequest_async](http://github.com/openresty/echo-nginx-module#echo_subrequest_async) directives. - -```nginx - - location /foo { - content_by_lua_block { - res = ngx.location.capture("/bar") - } - } - location /bar { - echo_location /blah; - } - location /blah { - echo "Success!"; - } -``` - -```nginx - - $ curl -i http://example.com/foo -``` - -will not work as expected. - -[Back to TOC](#table-of-contents) - -Cosockets Not Available Everywhere ----------------------------------- - -Due to internal limitations in the nginx core, the cosocket API is disabled in the following contexts: [set_by_lua*](#set_by_lua), [log_by_lua*](#log_by_lua), [header_filter_by_lua*](#header_filter_by_lua), and [body_filter_by_lua](#body_filter_by_lua). - -The cosockets are currently also disabled in the [init_by_lua*](#init_by_lua) and [init_worker_by_lua*](#init_worker_by_lua) directive contexts but we may add support for these contexts in the future because there is no limitation in the nginx core (or the limitation might be worked around). - -There exists a work-around, however, when the original context does *not* need to wait for the cosocket results. That is, creating a zero-delay timer via the [ngx.timer.at](#ngxtimerat) API and do the cosocket results in the timer handler, which runs asynchronously as to the original context creating the timer. - -[Back to TOC](#table-of-contents) - -Special Escaping Sequences --------------------------- - -**NOTE** Following the `v0.9.17` release, this pitfall can be avoided by using the `*_by_lua_block {}` configuration directives. - -PCRE sequences such as `\d`, `\s`, or `\w`, require special attention because in string literals, the backslash character, `\`, is stripped out by both the Lua language parser and by the nginx config file parser before processing if not within a `*_by_lua_block {}` directive. So the following snippet will not work as expected: - -```nginx - - # nginx.conf - ? location /test { - ? content_by_lua ' - ? local regex = "\d+" -- THIS IS WRONG OUTSIDE OF A *_by_lua_block DIRECTIVE - ? local m = ngx.re.match("hello, 1234", regex) - ? if m then ngx.say(m[0]) else ngx.say("not matched!") end - ? '; - ? } - # evaluates to "not matched!" -``` - -To avoid this, *double* escape the backslash: - -```nginx - - # nginx.conf - location /test { - content_by_lua ' - local regex = "\\\\d+" - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - '; - } - # evaluates to "1234" -``` - -Here, `\\\\d+` is stripped down to `\\d+` by the Nginx config file parser and this is further stripped down to `\d+` by the Lua language parser before running. - -Alternatively, the regex pattern can be presented as a long-bracketed Lua string literal by encasing it in "long brackets", `[[...]]`, in which case backslashes have to only be escaped once for the Nginx config file parser. - -```nginx - - # nginx.conf - location /test { - content_by_lua ' - local regex = [[\\d+]] - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - '; - } - # evaluates to "1234" -``` - -Here, `[[\\d+]]` is stripped down to `[[\d+]]` by the Nginx config file parser and this is processed correctly. - -Note that a longer from of the long bracket, `[=[...]=]`, may be required if the regex pattern contains `[...]` sequences. -The `[=[...]=]` form may be used as the default form if desired. - -```nginx - - # nginx.conf - location /test { - content_by_lua ' - local regex = [=[[0-9]+]=] - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - '; - } - # evaluates to "1234" -``` - -An alternative approach to escaping PCRE sequences is to ensure that Lua code is placed in external script files and executed using the various `*_by_lua_file` directives. -With this approach, the backslashes are only stripped by the Lua language parser and therefore only need to be escaped once each. - -```lua - - -- test.lua - local regex = "\\d+" - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - -- evaluates to "1234" -``` - -Within external script files, PCRE sequences presented as long-bracketed Lua string literals do not require modification. - -```lua - - -- test.lua - local regex = [[\d+]] - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - -- evaluates to "1234" -``` - -As noted earlier, PCRE sequences presented within `*_by_lua_block {}` directives (available following the `v0.9.17` release) do not require modification. - -```nginx - - # nginx.conf - location /test { - content_by_lua_block { - local regex = [[\d+]] - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - } - } - # evaluates to "1234" -``` - - -[Back to TOC](#table-of-contents) - -Mixing with SSI Not Supported ------------------------------ - -Mixing SSI with ngx_lua in the same Nginx request is not supported at all. Just use ngx_lua exclusively. Everything you can do with SSI can be done atop ngx_lua anyway and it can be more efficient when using ngx_lua. - -[Back to TOC](#table-of-contents) - -SPDY Mode Not Fully Supported ------------------------------ - -Certain Lua APIs provided by ngx_lua do not work in Nginx's SPDY mode yet: [ngx.location.capture](#ngxlocationcapture), [ngx.location.capture_multi](#ngxlocationcapture_multi), and [ngx.req.socket](#ngxreqsocket). - -[Back to TOC](#table-of-contents) - -Missing data on short circuited requests ----------------------------------------- - -Nginx may terminate a request early with (at least): - -* 400 (Bad Request) -* 405 (Not Allowed) -* 408 (Request Timeout) -* 413 (Request Entity Too Large) -* 414 (Request URI Too Large) -* 494 (Request Headers Too Large) -* 499 (Client Closed Request) -* 500 (Internal Server Error) -* 501 (Not Implemented) - -This means that phases that normally run are skipped, such as the rewrite or -access phase. This also means that later phases that are run regardless, e.g. -[log_by_lua](#log_by_lua), will not have access to information that is normally set in those -phases. - -[Back to TOC](#table-of-contents) - -TODO -==== - -* cosocket: implement LuaSocket's unconnected UDP API. -* port this module to the "datagram" subsystem of NGINX for implementing general UDP servers instead of HTTP -servers in Lua. For example, -```lua - - datagram { - server { - listen 1953; - handler_by_lua_block { - -- custom Lua code implementing the special UDP server... - } - } - } -``` -* shm: implement a "shared queue API" to complement the existing [shared dict](#lua_shared_dict) API. -* cosocket: add support in the context of [init_by_lua*](#init_by_lua). -* cosocket: implement the `bind()` method for stream-typed cosockets. -* cosocket: pool-based backend concurrency level control: implement automatic `connect` queueing when the backend concurrency exceeds its connection pool limit. -* cosocket: review and merge aviramc's [patch](https://github.com/openresty/lua-nginx-module/pull/290) for adding the `bsdrecv` method. -* add new API function `ngx.resp.add_header` to emulate the standard `add_header` config directive. -* review and apply vadim-pavlov's patch for [ngx.location.capture](#ngxlocationcapture)'s `extra_headers` option -* use `ngx_hash_t` to optimize the built-in header look-up process for [ngx.req.set_header](#ngxreqset_header), [ngx.header.HEADER](#ngxheaderheader), and etc. -* add configure options for different strategies of handling the cosocket connection exceeding in the pools. -* add directives to run Lua codes when nginx stops. -* add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) methods, to allow micro performance tuning on the user side. -* add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. -* add `stat` mode similar to [mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html). -* cosocket: add client SSL certificate support. - -[Back to TOC](#table-of-contents) - -Changes -======= - -The changes made in every release of this module are listed in the change logs of the OpenResty bundle: - - - -[Back to TOC](#table-of-contents) - -Test Suite -========== - -The following dependencies are required to run the test suite: - -* Nginx version >= 1.4.2 - -* Perl modules: - * Test::Nginx: - -* Nginx modules: - * [ngx_devel_kit](https://github.com/simplresty/ngx_devel_kit) - * [ngx_set_misc](https://github.com/openresty/set-misc-nginx-module) - * [ngx_auth_request](http://mdounin.ru/files/ngx_http_auth_request_module-0.2.tar.gz) (this is not needed if you're using Nginx 1.5.4+. - * [ngx_echo](https://github.com/openresty/echo-nginx-module) - * [ngx_memc](https://github.com/openresty/memc-nginx-module) - * [ngx_srcache](https://github.com/openresty/srcache-nginx-module) - * ngx_lua (i.e., this module) - * [ngx_lua_upstream](https://github.com/openresty/lua-upstream-nginx-module) - * [ngx_headers_more](https://github.com/openresty/headers-more-nginx-module) - * [ngx_drizzle](https://github.com/openresty/drizzle-nginx-module) - * [ngx_rds_json](https://github.com/openresty/rds-json-nginx-module) - * [ngx_coolkit](https://github.com/FRiCKLE/ngx_coolkit) - * [ngx_redis2](https://github.com/openresty/redis2-nginx-module) - -The order in which these modules are added during configuration is important because the position of any filter module in the -filtering chain determines the final output, for example. The correct adding order is shown above. - -* 3rd-party Lua libraries: - * [lua-cjson](http://www.kyne.com.au/~mark/software/lua-cjson.php) - -* Applications: - * mysql: create database 'ngx_test', grant all privileges to user 'ngx_test', password is 'ngx_test' - * memcached: listening on the default port, 11211. - * redis: listening on the default port, 6379. - -See also the [developer build script](https://github.com/openresty/lua-nginx-module/blob/master/util/build.sh) for more details on setting up the testing environment. - -To run the whole test suite in the default testing mode: - - cd /path/to/lua-nginx-module - export PATH=/path/to/your/nginx/sbin:$PATH - prove -I/path/to/test-nginx/lib -r t - - -To run specific test files: - - cd /path/to/lua-nginx-module - export PATH=/path/to/your/nginx/sbin:$PATH - prove -I/path/to/test-nginx/lib t/002-content.t t/003-errors.t - - -To run a specific test block in a particular test file, add the line `--- ONLY` to the test block you want to run, and then use the `prove` utility to run that `.t` file. - -There are also various testing modes based on mockeagain, valgrind, and etc. Refer to the [Test::Nginx documentation](http://search.cpan.org/perldoc?Test::Nginx) for more details for various advanced testing modes. See also the test reports for the Nginx test cluster running on Amazon EC2: . - -[Back to TOC](#table-of-contents) - -Copyright and License -===================== - -This module is licensed under the BSD license. - -Copyright (C) 2009-2017, by Xiaozhe Wang (chaoslawful) . - -Copyright (C) 2009-2018, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. - -All rights reserved. - -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. - -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 HOLDER 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. - -[Back to TOC](#table-of-contents) - -See Also -======== - -* [ngx_stream_lua_module](https://github.com/openresty/stream-lua-nginx-module#readme) for an official port of this module for the NGINX "stream" subsystem (doing generic downstream TCP communications). -* [lua-resty-memcached](https://github.com/openresty/lua-resty-memcached) library based on ngx_lua cosocket. -* [lua-resty-redis](https://github.com/openresty/lua-resty-redis) library based on ngx_lua cosocket. -* [lua-resty-mysql](https://github.com/openresty/lua-resty-mysql) library based on ngx_lua cosocket. -* [lua-resty-upload](https://github.com/openresty/lua-resty-upload) library based on ngx_lua cosocket. -* [lua-resty-dns](https://github.com/openresty/lua-resty-dns) library based on ngx_lua cosocket. -* [lua-resty-websocket](https://github.com/openresty/lua-resty-websocket) library for both WebSocket server and client, based on ngx_lua cosocket. -* [lua-resty-string](https://github.com/openresty/lua-resty-string) library based on [LuaJIT FFI](http://luajit.org/ext_ffi.html). -* [lua-resty-lock](https://github.com/openresty/lua-resty-lock) library for a nonblocking simple lock API. -* [lua-resty-cookie](https://github.com/cloudflare/lua-resty-cookie) library for HTTP cookie manipulation. -* [Routing requests to different MySQL queries based on URI arguments](http://openresty.org/#RoutingMySQLQueriesBasedOnURIArgs) -* [Dynamic Routing Based on Redis and Lua](http://openresty.org/#DynamicRoutingBasedOnRedis) -* [Using LuaRocks with ngx_lua](http://openresty.org/#UsingLuaRocks) -* [Introduction to ngx_lua](https://github.com/openresty/lua-nginx-module/wiki/Introduction) -* [ngx_devel_kit](https://github.com/simplresty/ngx_devel_kit) -* [echo-nginx-module](http://github.com/openresty/echo-nginx-module) -* [drizzle-nginx-module](http://github.com/openresty/drizzle-nginx-module) -* [postgres-nginx-module](https://github.com/FRiCKLE/ngx_postgres) -* [memc-nginx-module](http://github.com/openresty/memc-nginx-module) -* [The OpenResty bundle](http://openresty.org) -* [Nginx Systemtap Toolkit](https://github.com/openresty/nginx-systemtap-toolkit) - -[Back to TOC](#table-of-contents) - -Directives -========== - -* [lua_capture_error_log](#lua_capture_error_log) -* [lua_use_default_type](#lua_use_default_type) -* [lua_malloc_trim](#lua_malloc_trim) -* [lua_code_cache](#lua_code_cache) -* [lua_regex_cache_max_entries](#lua_regex_cache_max_entries) -* [lua_regex_match_limit](#lua_regex_match_limit) -* [lua_package_path](#lua_package_path) -* [lua_package_cpath](#lua_package_cpath) -* [init_by_lua](#init_by_lua) -* [init_by_lua_block](#init_by_lua_block) -* [init_by_lua_file](#init_by_lua_file) -* [init_worker_by_lua](#init_worker_by_lua) -* [init_worker_by_lua_block](#init_worker_by_lua_block) -* [init_worker_by_lua_file](#init_worker_by_lua_file) -* [set_by_lua](#set_by_lua) -* [set_by_lua_block](#set_by_lua_block) -* [set_by_lua_file](#set_by_lua_file) -* [content_by_lua](#content_by_lua) -* [content_by_lua_block](#content_by_lua_block) -* [content_by_lua_file](#content_by_lua_file) -* [rewrite_by_lua](#rewrite_by_lua) -* [rewrite_by_lua_block](#rewrite_by_lua_block) -* [rewrite_by_lua_file](#rewrite_by_lua_file) -* [access_by_lua](#access_by_lua) -* [access_by_lua_block](#access_by_lua_block) -* [access_by_lua_file](#access_by_lua_file) -* [header_filter_by_lua](#header_filter_by_lua) -* [header_filter_by_lua_block](#header_filter_by_lua_block) -* [header_filter_by_lua_file](#header_filter_by_lua_file) -* [body_filter_by_lua](#body_filter_by_lua) -* [body_filter_by_lua_block](#body_filter_by_lua_block) -* [body_filter_by_lua_file](#body_filter_by_lua_file) -* [log_by_lua](#log_by_lua) -* [log_by_lua_block](#log_by_lua_block) -* [log_by_lua_file](#log_by_lua_file) -* [balancer_by_lua_block](#balancer_by_lua_block) -* [balancer_by_lua_file](#balancer_by_lua_file) -* [lua_need_request_body](#lua_need_request_body) -* [ssl_certificate_by_lua_block](#ssl_certificate_by_lua_block) -* [ssl_certificate_by_lua_file](#ssl_certificate_by_lua_file) -* [ssl_session_fetch_by_lua_block](#ssl_session_fetch_by_lua_block) -* [ssl_session_fetch_by_lua_file](#ssl_session_fetch_by_lua_file) -* [ssl_session_store_by_lua_block](#ssl_session_store_by_lua_block) -* [ssl_session_store_by_lua_file](#ssl_session_store_by_lua_file) -* [lua_shared_dict](#lua_shared_dict) -* [lua_socket_connect_timeout](#lua_socket_connect_timeout) -* [lua_socket_send_timeout](#lua_socket_send_timeout) -* [lua_socket_send_lowat](#lua_socket_send_lowat) -* [lua_socket_read_timeout](#lua_socket_read_timeout) -* [lua_socket_buffer_size](#lua_socket_buffer_size) -* [lua_socket_pool_size](#lua_socket_pool_size) -* [lua_socket_keepalive_timeout](#lua_socket_keepalive_timeout) -* [lua_socket_log_errors](#lua_socket_log_errors) -* [lua_ssl_ciphers](#lua_ssl_ciphers) -* [lua_ssl_crl](#lua_ssl_crl) -* [lua_ssl_protocols](#lua_ssl_protocols) -* [lua_ssl_trusted_certificate](#lua_ssl_trusted_certificate) -* [lua_ssl_verify_depth](#lua_ssl_verify_depth) -* [lua_http10_buffering](#lua_http10_buffering) -* [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone) -* [access_by_lua_no_postpone](#access_by_lua_no_postpone) -* [lua_transform_underscores_in_response_headers](#lua_transform_underscores_in_response_headers) -* [lua_check_client_abort](#lua_check_client_abort) -* [lua_max_pending_timers](#lua_max_pending_timers) -* [lua_max_running_timers](#lua_max_running_timers) - - -The basic building blocks of scripting Nginx with Lua are directives. Directives are used to specify when the user Lua code is run and -how the result will be used. Below is a diagram showing the order in which directives are executed. - -![Lua Nginx Modules Directives](https://cloud.githubusercontent.com/assets/2137369/15272097/77d1c09e-1a37-11e6-97ef-d9767035fc3e.png) - -[Back to TOC](#table-of-contents) - -lua_capture_error_log ---------------------- -**syntax:** *lua_capture_error_log size* - -**default:** *none* - -**context:** *http* - -Enables a buffer of the specified `size` for capturing all the nginx error log message data (not just those produced -by this module or the nginx http subsystem, but everything) without touching files or disks. - -You can use units like `k` and `m` in the `size` value, as in - -```nginx - - lua_capture_error_log 100k; -``` - -As a rule of thumb, a 4KB buffer can usually hold about 20 typical error log messages. So do the maths! - -This buffer never grows. If it is full, new error log messages will replace the oldest ones in the buffer. - -The size of the buffer must be bigger than the maximum length of a single error log message (which is 4K in OpenResty and 2K in stock NGINX). - -You can read the messages in the buffer on the Lua land via the -[get_logs()](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#get_logs) -function of the -[ngx.errlog](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#readme) -module of the [lua-resty-core](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#readme) -library. This Lua API function will return the captured error log messages and -also remove these already read from the global capturing buffer, making room -for any new error log data. For this reason, the user should not configure this -buffer to be too big if the user read the buffered error log data fast enough. - -Note that the log level specified in the standard [error_log](http://nginx.org/r/error_log) directive -*does* have effect on this capturing facility. It only captures log -messages of a level no lower than the specified log level in the [error_log](http://nginx.org/r/error_log) directive. -The user can still choose to set an even higher filtering log level on the fly via the Lua API function -[errlog.set_filter_level](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#set_filter_level). -So it is more flexible than the static [error_log](http://nginx.org/r/error_log) directive. - -It is worth noting that there is no way to capture the debugging logs -without building OpenResty or NGINX with the `./configure` -option `--with-debug`. And enabling debugging logs is -strongly discouraged in production builds due to high overhead. - -This directive was first introduced in the `v0.10.9` release. - -[Back to TOC](#directives) - -lua_use_default_type --------------------- -**syntax:** *lua_use_default_type on | off* - -**default:** *lua_use_default_type on* - -**context:** *http, server, location, location if* - -Specifies whether to use the MIME type specified by the [default_type](http://nginx.org/en/docs/http/ngx_http_core_module.html#default_type) directive for the default value of the `Content-Type` response header. Deactivate this directive if a default `Content-Type` response header for Lua request handlers is not desired. - -This directive is turned on by default. - -This directive was first introduced in the `v0.9.1` release. - -[Back to TOC](#directives) - -lua_malloc_trim ---------------- -**syntax:** *lua_malloc_trim <request-count>* - -**default:** *lua_malloc_trim 1000* - -**context:** *http* - -Asks the underlying `libc` runtime library to release its cached free memory back to the operating system every -`N` requests processed by the NGINX core. By default, `N` is 1000. You can configure the request count -by using your own numbers. Smaller numbers mean more frequent releases, which may introduce higher CPU time consumption and -smaller memory footprint while larger numbers usually lead to less CPU time overhead and relatively larger memory footprint. -Just tune the number for your own use cases. - -Configuring the argument to `0` essentially turns off the periodical memory trimming altogether. - -```nginx - - lua_malloc_trim 0; # turn off trimming completely -``` - -The current implementation uses an NGINX log phase handler to do the request counting. So the appearance of the -[log_subrequest on](http://nginx.org/en/docs/http/ngx_http_core_module.html#log_subrequest) directives in `nginx.conf` -may make the counting faster when subrequests are involved. By default, only "main requests" count. - -Note that this directive does *not* affect the memory allocated by LuaJIT's own allocator based on the `mmap` -system call. - -This directive was first introduced in the `v0.10.7` release. - -[Back to TOC](#directives) - -lua_code_cache --------------- -**syntax:** *lua_code_cache on | off* - -**default:** *lua_code_cache on* - -**context:** *http, server, location, location if* - -Enables or disables the Lua code cache for Lua code in `*_by_lua_file` directives (like [set_by_lua_file](#set_by_lua_file) and -[content_by_lua_file](#content_by_lua_file)) and Lua modules. - -When turning off, every request served by ngx_lua will run in a separate Lua VM instance, starting from the `0.9.3` release. So the Lua files referenced in [set_by_lua_file](#set_by_lua_file), -[content_by_lua_file](#content_by_lua_file), [access_by_lua_file](#access_by_lua_file), -and etc will not be cached -and all Lua modules used will be loaded from scratch. With this in place, developers can adopt an edit-and-refresh approach. - -Please note however, that Lua code written inlined within nginx.conf -such as those specified by [set_by_lua](#set_by_lua), [content_by_lua](#content_by_lua), -[access_by_lua](#access_by_lua), and [rewrite_by_lua](#rewrite_by_lua) will not be updated when you edit the inlined Lua code in your `nginx.conf` file because only the Nginx config file parser can correctly parse the `nginx.conf` -file and the only way is to reload the config file -by sending a `HUP` signal or just to restart Nginx. - -Even when the code cache is enabled, Lua files which are loaded by `dofile` or `loadfile` -in *_by_lua_file cannot be cached (unless you cache the results yourself). Usually you can either use the [init_by_lua](#init_by_lua) -or [init_by_lua_file](#init-by_lua_file) directives to load all such files or just make these Lua files true Lua modules -and load them via `require`. - -The ngx_lua module does not support the `stat` mode available with the -Apache `mod_lua` module (yet). - -Disabling the Lua code cache is strongly -discouraged for production use and should only be used during -development as it has a significant negative impact on overall performance. For example, the performance of a "hello world" Lua example can drop by an order of magnitude after disabling the Lua code cache. - -[Back to TOC](#directives) - -lua_regex_cache_max_entries ---------------------------- -**syntax:** *lua_regex_cache_max_entries <num>* - -**default:** *lua_regex_cache_max_entries 1024* - -**context:** *http* - -Specifies the maximum number of entries allowed in the worker process level compiled regex cache. - -The regular expressions used in [ngx.re.match](#ngxrematch), [ngx.re.gmatch](#ngxregmatch), [ngx.re.sub](#ngxresub), and [ngx.re.gsub](#ngxregsub) will be cached within this cache if the regex option `o` (i.e., compile-once flag) is specified. - -The default number of entries allowed is 1024 and when this limit is reached, new regular expressions will not be cached (as if the `o` option was not specified) and there will be one, and only one, warning in the `error.log` file: - - - 2011/08/27 23:18:26 [warn] 31997#0: *1 lua exceeding regex cache max entries (1024), ... - - -If you are using the `ngx.re.*` implementation of [lua-resty-core](https://github.com/openresty/lua-resty-core) by loading the `resty.core.regex` module (or just the `resty.core` module), then an LRU cache is used for the regex cache being used here. - -Do not activate the `o` option for regular expressions (and/or `replace` string arguments for [ngx.re.sub](#ngxresub) and [ngx.re.gsub](#ngxregsub)) that are generated *on the fly* and give rise to infinite variations to avoid hitting the specified limit. - -[Back to TOC](#directives) - -lua_regex_match_limit ---------------------- -**syntax:** *lua_regex_match_limit <num>* - -**default:** *lua_regex_match_limit 0* - -**context:** *http* - -Specifies the "match limit" used by the PCRE library when executing the [ngx.re API](#ngxrematch). To quote the PCRE manpage, "the limit ... has the effect of limiting the amount of backtracking that can take place." - -When the limit is hit, the error string "pcre_exec() failed: -8" will be returned by the [ngx.re API](#ngxrematch) functions on the Lua land. - -When setting the limit to 0, the default "match limit" when compiling the PCRE library is used. And this is the default value of this directive. - -This directive was first introduced in the `v0.8.5` release. - -[Back to TOC](#directives) - -lua_package_path ----------------- - -**syntax:** *lua_package_path <lua-style-path-str>* - -**default:** *The content of LUA_PATH environment variable or Lua's compiled-in defaults.* - -**context:** *http* - -Sets the Lua module search path used by scripts specified by [set_by_lua](#set_by_lua), -[content_by_lua](#content_by_lua) and others. The path string is in standard Lua path form, and `;;` -can be used to stand for the original search paths. - -As from the `v0.5.0rc29` release, the special notation `$prefix` or `${prefix}` can be used in the search path string to indicate the path of the `server prefix` usually determined by the `-p PATH` command-line option while starting the Nginx server. - -[Back to TOC](#directives) - -lua_package_cpath ------------------ - -**syntax:** *lua_package_cpath <lua-style-cpath-str>* - -**default:** *The content of LUA_CPATH environment variable or Lua's compiled-in defaults.* - -**context:** *http* - -Sets the Lua C-module search path used by scripts specified by [set_by_lua](#set_by_lua), -[content_by_lua](#content_by_lua) and others. The cpath string is in standard Lua cpath form, and `;;` -can be used to stand for the original cpath. - -As from the `v0.5.0rc29` release, the special notation `$prefix` or `${prefix}` can be used in the search path string to indicate the path of the `server prefix` usually determined by the `-p PATH` command-line option while starting the Nginx server. - -[Back to TOC](#directives) - -init_by_lua ------------ - -**syntax:** *init_by_lua <lua-script-str>* - -**context:** *http* - -**phase:** *loading-config* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [init_by_lua_block](#init_by_lua_block) directive instead. - -Runs the Lua code specified by the argument `` on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file. - -When Nginx receives the `HUP` signal and starts reloading the config file, the Lua VM will also be re-created and `init_by_lua` will run again on the new Lua VM. In case that the [lua_code_cache](#lua_code_cache) directive is turned off (default on), the `init_by_lua` handler will run upon every request because in this special mode a standalone Lua VM is always created for each request. - -Usually you can pre-load Lua modules at server start-up by means of this hook and take advantage of modern operating systems' copy-on-write (COW) optimization. Here is an example for pre-loading Lua modules: - -```nginx - - # this runs before forking out nginx worker processes: - init_by_lua_block { require "cjson" } - - server { - location = /api { - content_by_lua_block { - -- the following require() will just return - -- the alrady loaded module from package.loaded: - ngx.say(require "cjson".encode{dog = 5, cat = 6}) - } - } - } -``` - -You can also initialize the [lua_shared_dict](#lua_shared_dict) shm storage at this phase. Here is an example for this: - -```nginx - - lua_shared_dict dogs 1m; - - init_by_lua_block { - local dogs = ngx.shared.dogs; - dogs:set("Tom", 56) - } - - server { - location = /api { - content_by_lua_block { - local dogs = ngx.shared.dogs; - ngx.say(dogs:get("Tom")) - } - } - } -``` - -But note that, the [lua_shared_dict](#lua_shared_dict)'s shm storage will not be cleared through a config reload (via the `HUP` signal, for example). So if you do *not* want to re-initialize the shm storage in your `init_by_lua` code in this case, then you just need to set a custom flag in the shm storage and always check the flag in your `init_by_lua` code. - -Because the Lua code in this context runs before Nginx forks its worker processes (if any), data or code loaded here will enjoy the [Copy-on-write (COW)](http://en.wikipedia.org/wiki/Copy-on-write) feature provided by many operating systems among all the worker processes, thus saving a lot of memory. - -Do *not* initialize your own Lua global variables in this context because use of Lua global variables have performance penalties and can lead to global namespace pollution (see the [Lua Variable Scope](#lua-variable-scope) section for more details). The recommended way is to use proper [Lua module](http://www.lua.org/manual/5.1/manual.html#5.3) files (but do not use the standard Lua function [module()](http://www.lua.org/manual/5.1/manual.html#pdf-module) to define Lua modules because it pollutes the global namespace as well) and call [require()](http://www.lua.org/manual/5.1/manual.html#pdf-require) to load your own module files in `init_by_lua` or other contexts ([require()](http://www.lua.org/manual/5.1/manual.html#pdf-require) does cache the loaded Lua modules in the global `package.loaded` table in the Lua registry so your modules will only loaded once for the whole Lua VM instance). - -Only a small set of the [Nginx API for Lua](#nginx-api-for-lua) is supported in this context: - -* Logging APIs: [ngx.log](#ngxlog) and [print](#print), -* Shared Dictionary API: [ngx.shared.DICT](#ngxshareddict). - -More Nginx APIs for Lua may be supported in this context upon future user requests. - -Basically you can safely use Lua libraries that do blocking I/O in this very context because blocking the master process during server start-up is completely okay. Even the Nginx core does blocking I/O (at least on resolving upstream's host names) at the configure-loading phase. - -You should be very careful about potential security vulnerabilities in your Lua code registered in this context because the Nginx master process is often run under the `root` account. - -This directive was first introduced in the `v0.5.5` release. - -[Back to TOC](#directives) - -init_by_lua_block ------------------ - -**syntax:** *init_by_lua_block { lua-script }* - -**context:** *http* - -**phase:** *loading-config* - -Similar to the [init_by_lua](#init_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - init_by_lua_block { - print("I need no extra escaping here, for example: \r\nblah") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -init_by_lua_file ----------------- - -**syntax:** *init_by_lua_file <path-to-lua-script-file>* - -**context:** *http* - -**phase:** *loading-config* - -Equivalent to [init_by_lua](#init_by_lua), except that the file specified by `` contains the Lua code or [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.5.5` release. - -[Back to TOC](#directives) - -init_worker_by_lua ------------------- - -**syntax:** *init_worker_by_lua <lua-script-str>* - -**context:** *http* - -**phase:** *starting-worker* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [init_worker_by_lua_block](#init_worker_by_lua_block) directive instead. - -Runs the specified Lua code upon every Nginx worker process's startup when the master process is enabled. When the master process is disabled, this hook will just run after [init_by_lua*](#init_by_lua). - -This hook is often used to create per-worker reoccurring timers (via the [ngx.timer.at](#ngxtimerat) Lua API), either for backend health-check or other timed routine work. Below is an example, - -```nginx - - init_worker_by_lua ' - local delay = 3 -- in seconds - local new_timer = ngx.timer.at - local log = ngx.log - local ERR = ngx.ERR - local check - - check = function(premature) - if not premature then - -- do the health check or other routine work - local ok, err = new_timer(delay, check) - if not ok then - log(ERR, "failed to create timer: ", err) - return - end - end - end - - local hdl, err = new_timer(delay, check) - if not hdl then - log(ERR, "failed to create timer: ", err) - return - end - '; -``` - -This directive was first introduced in the `v0.9.5` release. - -This hook no longer runs in the cache manager and cache loader processes since the `v0.10.12` release. - -[Back to TOC](#directives) - -init_worker_by_lua_block ------------------------- - -**syntax:** *init_worker_by_lua_block { lua-script }* - -**context:** *http* - -**phase:** *starting-worker* - -Similar to the [init_worker_by_lua](#init_worker_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - init_worker_by_lua_block { - print("I need no extra escaping here, for example: \r\nblah") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -This hook no longer runs in the cache manager and cache loader processes since the `v0.10.12` release. - -[Back to TOC](#directives) - -init_worker_by_lua_file ------------------------ - -**syntax:** *init_worker_by_lua_file <lua-file-path>* - -**context:** *http* - -**phase:** *starting-worker* - -Similar to [init_worker_by_lua](#init_worker_by_lua), but accepts the file path to a Lua source file or Lua bytecode file. - -This directive was first introduced in the `v0.9.5` release. - -This hook no longer runs in the cache manager and cache loader processes since the `v0.10.12` release. - -[Back to TOC](#directives) - -set_by_lua ----------- - -**syntax:** *set_by_lua $res <lua-script-str> [$arg1 $arg2 ...]* - -**context:** *server, server if, location, location if* - -**phase:** *rewrite* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [set_by_lua_block](#set_by_lua_block) directive instead. - -Executes code specified in `` with optional input arguments `$arg1 $arg2 ...`, and returns string output to `$res`. -The code in `` can make [API calls](#nginx-api-for-lua) and can retrieve input arguments from the `ngx.arg` table (index starts from `1` and increases sequentially). - -This directive is designed to execute short, fast running code blocks as the Nginx event loop is blocked during code execution. Time consuming code sequences should therefore be avoided. - -This directive is implemented by injecting custom commands into the standard [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html)'s command list. Because [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html) does not support nonblocking I/O in its commands, Lua APIs requiring yielding the current Lua "light thread" cannot work in this directive. - -At least the following API functions are currently disabled within the context of `set_by_lua`: - -* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.exit](#ngxexit)) -* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). -* Sleeping API function [ngx.sleep](#ngxsleep). - -In addition, note that this directive can only write out a value to a single Nginx variable at -a time. However, a workaround is possible using the [ngx.var.VARIABLE](#ngxvarvariable) interface. - -```nginx - - location /foo { - set $diff ''; # we have to predefine the $diff variable here - - set_by_lua $sum ' - local a = 32 - local b = 56 - - ngx.var.diff = a - b; -- write to $diff directly - return a + b; -- return the $sum value normally - '; - - echo "sum = $sum, diff = $diff"; - } -``` - -This directive can be freely mixed with all directives of the [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html), [set-misc-nginx-module](http://github.com/openresty/set-misc-nginx-module), and [array-var-nginx-module](http://github.com/openresty/array-var-nginx-module) modules. All of these directives will run in the same order as they appear in the config file. - -```nginx - - set $foo 32; - set_by_lua $bar 'return tonumber(ngx.var.foo) + 1'; - set $baz "bar: $bar"; # $baz == "bar: 33" -``` - -As from the `v0.5.0rc29` release, Nginx variable interpolation is disabled in the `` argument of this directive and therefore, the dollar sign character (`$`) can be used directly. - -This directive requires the [ngx_devel_kit](https://github.com/simplresty/ngx_devel_kit) module. - -[Back to TOC](#directives) - -set_by_lua_block ----------------- - -**syntax:** *set_by_lua_block $res { lua-script }* - -**context:** *server, server if, location, location if* - -**phase:** *rewrite* - -Similar to the [set_by_lua](#set_by_lua) directive except that - -1. this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping), and -1. this directive does not support extra arguments after the Lua script as in [set_by_lua](#set_by_lua). - -For example, - -```nginx - - set_by_lua_block $res { return 32 + math.cos(32) } - # $res now has the value "32.834223360507" or alike. -``` - -No special escaping is required in the Lua code block. - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -set_by_lua_file ---------------- -**syntax:** *set_by_lua_file $res <path-to-lua-script-file> [$arg1 $arg2 ...]* - -**context:** *server, server if, location, location if* - -**phase:** *rewrite* - -Equivalent to [set_by_lua](#set_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -Nginx variable interpolation is supported in the `` argument string of this directive. But special care must be taken for injection attacks. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached -and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by -switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. - -This directive requires the [ngx_devel_kit](https://github.com/simplresty/ngx_devel_kit) module. - -[Back to TOC](#directives) - -content_by_lua --------------- - -**syntax:** *content_by_lua <lua-script-str>* - -**context:** *location, location if* - -**phase:** *content* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [content_by_lua_block](#content_by_lua_block) directive instead. - -Acts as a "content handler" and executes Lua code string specified in `` for every request. -The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). - -Do not use this directive and other content handler directives in the same location. For example, this directive and the [proxy_pass](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass) directive should not be used in the same location. - -[Back to TOC](#directives) - -content_by_lua_block --------------------- - -**syntax:** *content_by_lua_block { lua-script }* - -**context:** *location, location if* - -**phase:** *content* - -Similar to the [content_by_lua](#content_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - content_by_lua_block { - ngx.say("I need no extra escaping here, for example: \r\nblah") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -content_by_lua_file -------------------- - -**syntax:** *content_by_lua_file <path-to-lua-script-file>* - -**context:** *location, location if* - -**phase:** *content* - -Equivalent to [content_by_lua](#content_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -Nginx variables can be used in the `` string to provide flexibility. This however carries some risks and is not ordinarily recommended. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached -and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by -switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. - -Nginx variables are supported in the file path for dynamic dispatch, for example: - -```nginx - - # CAUTION: contents in nginx var must be carefully filtered, - # otherwise there'll be great security risk! - location ~ ^/app/([-_a-zA-Z0-9/]+) { - set $path $1; - content_by_lua_file /path/to/lua/app/root/$path.lua; - } -``` - -But be very careful about malicious user inputs and always carefully validate or filter out the user-supplied path components. - -[Back to TOC](#directives) - -rewrite_by_lua --------------- - -**syntax:** *rewrite_by_lua <lua-script-str>* - -**context:** *http, server, location, location if* - -**phase:** *rewrite tail* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [rewrite_by_lua_block](#rewrite_by_lua_block) directive instead. - -Acts as a rewrite phase handler and executes Lua code string specified in `` for every request. -The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). - -Note that this handler always runs *after* the standard [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html). So the following will work as expected: - -```nginx - - location /foo { - set $a 12; # create and initialize $a - set $b ""; # create and initialize $b - rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; - echo "res = $b"; - } -``` - -because `set $a 12` and `set $b ""` run *before* [rewrite_by_lua](#rewrite_by_lua). - -On the other hand, the following will not work as expected: - -```nginx - - ? location /foo { - ? set $a 12; # create and initialize $a - ? set $b ''; # create and initialize $b - ? rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; - ? if ($b = '13') { - ? rewrite ^ /bar redirect; - ? break; - ? } - ? - ? echo "res = $b"; - ? } -``` - -because `if` runs *before* [rewrite_by_lua](#rewrite_by_lua) even if it is placed after [rewrite_by_lua](#rewrite_by_lua) in the config. - -The right way of doing this is as follows: - -```nginx - - location /foo { - set $a 12; # create and initialize $a - set $b ''; # create and initialize $b - rewrite_by_lua ' - ngx.var.b = tonumber(ngx.var.a) + 1 - if tonumber(ngx.var.b) == 13 then - return ngx.redirect("/bar"); - end - '; - - echo "res = $b"; - } -``` - -Note that the [ngx_eval](http://www.grid.net.ru/nginx/eval.en.html) module can be approximated by using [rewrite_by_lua](#rewrite_by_lua). For example, - -```nginx - - location / { - eval $res { - proxy_pass http://foo.com/check-spam; - } - - if ($res = 'spam') { - rewrite ^ /terms-of-use.html redirect; - } - - fastcgi_pass ...; - } -``` - -can be implemented in ngx_lua as: - -```nginx - - location = /check-spam { - internal; - proxy_pass http://foo.com/check-spam; - } - - location / { - rewrite_by_lua ' - local res = ngx.location.capture("/check-spam") - if res.body == "spam" then - return ngx.redirect("/terms-of-use.html") - end - '; - - fastcgi_pass ...; - } -``` - -Just as any other rewrite phase handlers, [rewrite_by_lua](#rewrite_by_lua) also runs in subrequests. - -Note that when calling `ngx.exit(ngx.OK)` within a [rewrite_by_lua](#rewrite_by_lua) handler, the nginx request processing control flow will still continue to the content handler. To terminate the current request from within a [rewrite_by_lua](#rewrite_by_lua) handler, calling [ngx.exit](#ngxexit) with status >= 200 (`ngx.HTTP_OK`) and status < 300 (`ngx.HTTP_SPECIAL_RESPONSE`) for successful quits and `ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)` (or its friends) for failures. - -If the [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html)'s [rewrite](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) directive is used to change the URI and initiate location re-lookups (internal redirections), then any [rewrite_by_lua](#rewrite_by_lua) or [rewrite_by_lua_file](#rewrite_by_lua_file) code sequences within the current location will not be executed. For example, - -```nginx - - location /foo { - rewrite ^ /bar; - rewrite_by_lua 'ngx.exit(503)'; - } - location /bar { - ... - } -``` - -Here the Lua code `ngx.exit(503)` will never run. This will be the case if `rewrite ^ /bar last` is used as this will similarly initiate an internal redirection. If the `break` modifier is used instead, there will be no internal redirection and the `rewrite_by_lua` code will be executed. - -The `rewrite_by_lua` code will always run at the end of the `rewrite` request-processing phase unless [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone) is turned on. - -[Back to TOC](#directives) - -rewrite_by_lua_block --------------------- - -**syntax:** *rewrite_by_lua_block { lua-script }* - -**context:** *http, server, location, location if* - -**phase:** *rewrite tail* - -Similar to the [rewrite_by_lua](#rewrite_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - rewrite_by_lua_block { - do_something("hello, world!\nhiya\n") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -rewrite_by_lua_file -------------------- - -**syntax:** *rewrite_by_lua_file <path-to-lua-script-file>* - -**context:** *http, server, location, location if* - -**phase:** *rewrite tail* - -Equivalent to [rewrite_by_lua](#rewrite_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -Nginx variables can be used in the `` string to provide flexibility. This however carries some risks and is not ordinarily recommended. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. - -The `rewrite_by_lua_file` code will always run at the end of the `rewrite` request-processing phase unless [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone) is turned on. - -Nginx variables are supported in the file path for dynamic dispatch just as in [content_by_lua_file](#content_by_lua_file). - -[Back to TOC](#directives) - -access_by_lua -------------- - -**syntax:** *access_by_lua <lua-script-str>* - -**context:** *http, server, location, location if* - -**phase:** *access tail* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [access_by_lua_block](#access_by_lua_block) directive instead. - -Acts as an access phase handler and executes Lua code string specified in `` for every request. -The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). - -Note that this handler always runs *after* the standard [ngx_http_access_module](http://nginx.org/en/docs/http/ngx_http_access_module.html). So the following will work as expected: - -```nginx - - location / { - deny 192.168.1.1; - allow 192.168.1.0/24; - allow 10.1.1.0/16; - deny all; - - access_by_lua ' - local res = ngx.location.capture("/mysql", { ... }) - ... - '; - - # proxy_pass/fastcgi_pass/... - } -``` - -That is, if a client IP address is in the blacklist, it will be denied before the MySQL query for more complex authentication is executed by [access_by_lua](#access_by_lua). - -Note that the [ngx_auth_request](http://mdounin.ru/hg/ngx_http_auth_request_module/) module can be approximated by using [access_by_lua](#access_by_lua): - -```nginx - - location / { - auth_request /auth; - - # proxy_pass/fastcgi_pass/postgres_pass/... - } -``` - -can be implemented in ngx_lua as: - -```nginx - - location / { - access_by_lua ' - local res = ngx.location.capture("/auth") - - if res.status == ngx.HTTP_OK then - return - end - - if res.status == ngx.HTTP_FORBIDDEN then - ngx.exit(res.status) - end - - ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) - '; - - # proxy_pass/fastcgi_pass/postgres_pass/... - } -``` - -As with other access phase handlers, [access_by_lua](#access_by_lua) will *not* run in subrequests. - -Note that when calling `ngx.exit(ngx.OK)` within a [access_by_lua](#access_by_lua) handler, the nginx request processing control flow will still continue to the content handler. To terminate the current request from within a [access_by_lua](#access_by_lua) handler, calling [ngx.exit](#ngxexit) with status >= 200 (`ngx.HTTP_OK`) and status < 300 (`ngx.HTTP_SPECIAL_RESPONSE`) for successful quits and `ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)` (or its friends) for failures. - -Starting from the `v0.9.20` release, you can use the [access_by_lua_no_postpone](#access_by_lua_no_postpone) -directive to control when to run this handler inside the "access" request-processing phase -of NGINX. - -[Back to TOC](#directives) - -access_by_lua_block -------------------- - -**syntax:** *access_by_lua_block { lua-script }* - -**context:** *http, server, location, location if* - -**phase:** *access tail* - -Similar to the [access_by_lua](#access_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - access_by_lua_block { - do_something("hello, world!\nhiya\n") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -access_by_lua_file ------------------- - -**syntax:** *access_by_lua_file <path-to-lua-script-file>* - -**context:** *http, server, location, location if* - -**phase:** *access tail* - -Equivalent to [access_by_lua](#access_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -Nginx variables can be used in the `` string to provide flexibility. This however carries some risks and is not ordinarily recommended. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached -and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid repeatedly reloading Nginx. - -Nginx variables are supported in the file path for dynamic dispatch just as in [content_by_lua_file](#content_by_lua_file). - -[Back to TOC](#directives) - -header_filter_by_lua --------------------- - -**syntax:** *header_filter_by_lua <lua-script-str>* - -**context:** *http, server, location, location if* - -**phase:** *output-header-filter* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [header_filter_by_lua_block](#header_filter_by_lua_block) directive instead. - -Uses Lua code specified in `` to define an output header filter. - -Note that the following API functions are currently disabled within this context: - -* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.redirect](#ngxredirect) and [ngx.exec](#ngxexec)) -* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). - -Here is an example of overriding a response header (or adding one if absent) in our Lua header filter: - -```nginx - - location / { - proxy_pass http://mybackend; - header_filter_by_lua 'ngx.header.Foo = "blah"'; - } -``` - -This directive was first introduced in the `v0.2.1rc20` release. - -[Back to TOC](#directives) - -header_filter_by_lua_block --------------------------- - -**syntax:** *header_filter_by_lua_block { lua-script }* - -**context:** *http, server, location, location if* - -**phase:** *output-header-filter* - -Similar to the [header_filter_by_lua](#header_filter_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - header_filter_by_lua_block { - ngx.header["content-length"] = nil - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -header_filter_by_lua_file -------------------------- - -**syntax:** *header_filter_by_lua_file <path-to-lua-script-file>* - -**context:** *http, server, location, location if* - -**phase:** *output-header-filter* - -Equivalent to [header_filter_by_lua](#header_filter_by_lua), except that the file specified by `` contains the Lua code, or as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.2.1rc20` release. - -[Back to TOC](#directives) - -body_filter_by_lua ------------------- - -**syntax:** *body_filter_by_lua <lua-script-str>* - -**context:** *http, server, location, location if* - -**phase:** *output-body-filter* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [body_filter_by_lua_block](#body_filter_by_lua_block) directive instead. - -Uses Lua code specified in `` to define an output body filter. - -The input data chunk is passed via [ngx.arg](#ngxarg)\[1\] (as a Lua string value) and the "eof" flag indicating the end of the response body data stream is passed via [ngx.arg](#ngxarg)\[2\] (as a Lua boolean value). - -Behind the scene, the "eof" flag is just the `last_buf` (for main requests) or `last_in_chain` (for subrequests) flag of the Nginx chain link buffers. (Before the `v0.7.14` release, the "eof" flag does not work at all in subrequests.) - -The output data stream can be aborted immediately by running the following Lua statement: - -```lua - - return ngx.ERROR -``` - -This will truncate the response body and usually result in incomplete and also invalid responses. - -The Lua code can pass its own modified version of the input data chunk to the downstream Nginx output body filters by overriding [ngx.arg](#ngxarg)\[1\] with a Lua string or a Lua table of strings. For example, to transform all the lowercase letters in the response body, we can just write: - -```nginx - - location / { - proxy_pass http://mybackend; - body_filter_by_lua 'ngx.arg[1] = string.upper(ngx.arg[1])'; - } -``` - -When setting `nil` or an empty Lua string value to `ngx.arg[1]`, no data chunk will be passed to the downstream Nginx output filters at all. - -Likewise, new "eof" flag can also be specified by setting a boolean value to [ngx.arg](#ngxarg)\[2\]. For example, - -```nginx - - location /t { - echo hello world; - echo hiya globe; - - body_filter_by_lua ' - local chunk = ngx.arg[1] - if string.match(chunk, "hello") then - ngx.arg[2] = true -- new eof - return - end - - -- just throw away any remaining chunk data - ngx.arg[1] = nil - '; - } -``` - -Then `GET /t` will just return the output - - - hello world - - -That is, when the body filter sees a chunk containing the word "hello", then it will set the "eof" flag to true immediately, resulting in truncated but still valid responses. - -When the Lua code may change the length of the response body, then it is required to always clear out the `Content-Length` response header (if any) in a header filter to enforce streaming output, as in - -```nginx - - location /foo { - # fastcgi_pass/proxy_pass/... - - header_filter_by_lua_block { ngx.header.content_length = nil } - body_filter_by_lua 'ngx.arg[1] = string.len(ngx.arg[1]) .. "\\n"'; - } -``` - -Note that the following API functions are currently disabled within this context due to the limitations in NGINX output filter's current implementation: - -* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.exit](#ngxexit) and [ngx.exec](#ngxexec)) -* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). - -Nginx output filters may be called multiple times for a single request because response body may be delivered in chunks. Thus, the Lua code specified by in this directive may also run multiple times in the lifetime of a single HTTP request. - -This directive was first introduced in the `v0.5.0rc32` release. - -[Back to TOC](#directives) - -body_filter_by_lua_block ------------------------- - -**syntax:** *body_filter_by_lua_block { lua-script-str }* - -**context:** *http, server, location, location if* - -**phase:** *output-body-filter* - -Similar to the [body_filter_by_lua](#body_filter_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - body_filter_by_lua_block { - local data, eof = ngx.arg[1], ngx.arg[2] - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -body_filter_by_lua_file ------------------------ - -**syntax:** *body_filter_by_lua_file <path-to-lua-script-file>* - -**context:** *http, server, location, location if* - -**phase:** *output-body-filter* - -Equivalent to [body_filter_by_lua](#body_filter_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.5.0rc32` release. - -[Back to TOC](#directives) - -log_by_lua ----------- - -**syntax:** *log_by_lua <lua-script-str>* - -**context:** *http, server, location, location if* - -**phase:** *log* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [log_by_lua_block](#log_by_lua_block) directive instead. - -Runs the Lua source code inlined as the `` at the `log` request processing phase. This does not replace the current access logs, but runs before. - -Note that the following API functions are currently disabled within this context: - -* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.exit](#ngxexit)) -* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). - -Here is an example of gathering average data for [$upstream_response_time](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#var_upstream_response_time): - -```nginx - - lua_shared_dict log_dict 5M; - - server { - location / { - proxy_pass http://mybackend; - - log_by_lua ' - local log_dict = ngx.shared.log_dict - local upstream_time = tonumber(ngx.var.upstream_response_time) - - local sum = log_dict:get("upstream_time-sum") or 0 - sum = sum + upstream_time - log_dict:set("upstream_time-sum", sum) - - local newval, err = log_dict:incr("upstream_time-nb", 1) - if not newval and err == "not found" then - log_dict:add("upstream_time-nb", 0) - log_dict:incr("upstream_time-nb", 1) - end - '; - } - - location = /status { - content_by_lua_block { - local log_dict = ngx.shared.log_dict - local sum = log_dict:get("upstream_time-sum") - local nb = log_dict:get("upstream_time-nb") - - if nb and sum then - ngx.say("average upstream response time: ", sum / nb, - " (", nb, " reqs)") - else - ngx.say("no data yet") - end - } - } - } -``` - -This directive was first introduced in the `v0.5.0rc31` release. - -[Back to TOC](#directives) - -log_by_lua_block ----------------- - -**syntax:** *log_by_lua_block { lua-script }* - -**context:** *http, server, location, location if* - -**phase:** *log* - -Similar to the [log_by_lua](#log_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - log_by_lua_block { - print("I need no extra escaping here, for example: \r\nblah") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -log_by_lua_file ---------------- - -**syntax:** *log_by_lua_file <path-to-lua-script-file>* - -**context:** *http, server, location, location if* - -**phase:** *log* - -Equivalent to [log_by_lua](#log_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.5.0rc31` release. - -[Back to TOC](#directives) - -balancer_by_lua_block ---------------------- - -**syntax:** *balancer_by_lua_block { lua-script }* - -**context:** *upstream* - -**phase:** *content* - -This directive runs Lua code as an upstream balancer for any upstream entities defined -by the `upstream {}` configuration block. - -For instance, - -```nginx - - upstream foo { - server 127.0.0.1; - balancer_by_lua_block { - -- use Lua to do something interesting here - -- as a dynamic balancer - } - } - - server { - location / { - proxy_pass http://foo; - } - } -``` - -The resulting Lua load balancer can work with any existing nginx upstream modules -like [ngx_proxy](http://nginx.org/en/docs/http/ngx_http_proxy_module.html) and -[ngx_fastcgi](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html). - -Also, the Lua load balancer can work with the standard upstream connection pool mechanism, -i.e., the standard [keepalive](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive) directive. -Just ensure that the [keepalive](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive) directive -is used *after* this `balancer_by_lua_block` directive in a single `upstream {}` configuration block. - -The Lua load balancer can totally ignore the list of servers defined in the `upstream {}` block -and select peer from a completely dynamic server list (even changing per request) via the -[ngx.balancer](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md) module -from the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. - -The Lua code handler registered by this directive might get called more than once in a single -downstream request when the nginx upstream mechanism retries the request on conditions -specified by directives like the [proxy_next_upstream](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream) -directive. - -This Lua code execution context does not support yielding, so Lua APIs that may yield -(like cosockets and "light threads") are disabled in this context. One can usually work -around this limitation by doing such operations in an earlier phase handler (like -[access_by_lua*](#access_by_lua)) and passing along the result into this context -via the [ngx.ctx](#ngxctx) table. - -This directive was first introduced in the `v0.10.0` release. - -[Back to TOC](#directives) - -balancer_by_lua_file --------------------- - -**syntax:** *balancer_by_lua_file <path-to-lua-script-file>* - -**context:** *upstream* - -**phase:** *content* - -Equivalent to [balancer_by_lua_block](#balancer_by_lua_block), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.10.0` release. - -[Back to TOC](#directives) - -lua_need_request_body ---------------------- - -**syntax:** *lua_need_request_body <on|off>* - -**default:** *off* - -**context:** *http, server, location, location if* - -**phase:** *depends on usage* - -Determines whether to force the request body data to be read before running rewrite/access/access_by_lua* or not. The Nginx core does not read the client request body by default and if request body data is required, then this directive should be turned `on` or the [ngx.req.read_body](#ngxreqread_body) function should be called within the Lua code. - -To read the request body data within the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable, -[client_body_buffer_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size) must have the same value as [client_max_body_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size). Because when the content length exceeds [client_body_buffer_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size) but less than [client_max_body_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size), Nginx will buffer the data into a temporary file on the disk, which will lead to empty value in the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable. - -If the current location includes [rewrite_by_lua*](#rewrite_by_lua) directives, -then the request body will be read just before the [rewrite_by_lua*](#rewrite_by_lua) code is run (and also at the -`rewrite` phase). Similarly, if only [content_by_lua](#content_by_lua) is specified, -the request body will not be read until the content handler's Lua code is -about to run (i.e., the request body will be read during the content phase). - -It is recommended however, to use the [ngx.req.read_body](#ngxreqread_body) and [ngx.req.discard_body](#ngxreqdiscard_body) functions for finer control over the request body reading process instead. - -This also applies to [access_by_lua*](#access_by_lua). - -[Back to TOC](#directives) - -ssl_certificate_by_lua_block ----------------------------- - -**syntax:** *ssl_certificate_by_lua_block { lua-script }* - -**context:** *server* - -**phase:** *right-before-SSL-handshake* - -This directive runs user Lua code when NGINX is about to start the SSL handshake for the downstream -SSL (https) connections. - -It is particularly useful for setting the SSL certificate chain and the corresponding private key on a per-request -basis. It is also useful to load such handshake configurations nonblockingly from the remote (for example, -with the [cosocket](#ngxsockettcp) API). And one can also do per-request OCSP stapling handling in pure -Lua here as well. - -Another typical use case is to do SSL handshake traffic control nonblockingly in this context, -with the help of the [lua-resty-limit-traffic#readme](https://github.com/openresty/lua-resty-limit-traffic) -library, for example. - -One can also do interesting things with the SSL handshake requests from the client side, like -rejecting old SSL clients using the SSLv3 protocol or even below selectively. - -The [ngx.ssl](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md) -and [ngx.ocsp](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md) Lua modules -provided by the [lua-resty-core](https://github.com/openresty/lua-resty-core/#readme) -library are particularly useful in this context. You can use the Lua API offered by these two Lua modules -to manipulate the SSL certificate chain and private key for the current SSL connection -being initiated. - -This Lua handler does not run at all, however, when NGINX/OpenSSL successfully resumes -the SSL session via SSL session IDs or TLS session tickets for the current SSL connection. In -other words, this Lua handler only runs when NGINX has to initiate a full SSL handshake. - -Below is a trivial example using the -[ngx.ssl](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md) module -at the same time: - -```nginx - - server { - listen 443 ssl; - server_name test.com; - - ssl_certificate_by_lua_block { - print("About to initiate a new SSL handshake!") - } - - location / { - root html; - } - } -``` - -See more complicated examples in the [ngx.ssl](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md) -and [ngx.ocsp](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md) -Lua modules' official documentation. - -Uncaught Lua exceptions in the user Lua code immediately abort the current SSL session, so does the -[ngx.exit](#ngxexit) call with an error code like `ngx.ERROR`. - -This Lua code execution context *does* support yielding, so Lua APIs that may yield -(like cosockets, sleeping, and "light threads") -are enabled in this context. - -Note, however, you still need to configure the [ssl_certificate](http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate) and -[ssl_certificate_key](http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate_key) -directives even though you will not use this static certificate and private key at all. This is -because the NGINX core requires their appearance otherwise you are seeing the following error -while starting NGINX: - - - nginx: [emerg] no ssl configured for the server - - -This directive currently requires the following NGINX core patch to work correctly: - - - -The bundled version of the NGINX core in OpenResty 1.9.7.2 (or above) already has this -patch applied. - -Furthermore, one needs at least OpenSSL 1.0.2e for this directive to work. - -This directive was first introduced in the `v0.10.0` release. - -[Back to TOC](#directives) - -ssl_certificate_by_lua_file ---------------------------- - -**syntax:** *ssl_certificate_by_lua_file <path-to-lua-script-file>* - -**context:** *server* - -**phase:** *right-before-SSL-handshake* - -Equivalent to [ssl_certificate_by_lua_block](#ssl_certificate_by_lua_block), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.10.0` release. - -[Back to TOC](#directives) - -ssl_session_fetch_by_lua_block ------------------------------- - -**syntax:** *ssl_session_fetch_by_lua_block { lua-script }* - -**context:** *http* - -**phase:** *right-before-SSL-handshake* - -This directive runs Lua code to look up and load the SSL session (if any) according to the session ID -provided by the current SSL handshake request for the downstream. - -The Lua API for obtaining the current session ID and loading a cached SSL session data -is provided in the [ngx.ssl.session](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl/session.md) -Lua module shipped with the [lua-resty-core](https://github.com/openresty/lua-resty-core#readme) -library. - -Lua APIs that may yield, like [ngx.sleep](#ngxsleep) and [cosockets](#ngxsockettcp), -are enabled in this context. - -This hook, together with the [ssl_session_store_by_lua*](#ssl_session_store_by_lua_block) hook, -can be used to implement distributed caching mechanisms in pure Lua (based -on the [cosocket](#ngxsockettcp) API, for example). If a cached SSL session is found -and loaded into the current SSL connection context, -SSL session resumption can then get immediately initiated and bypass the full SSL handshake process which is very expensive in terms of CPU time. - -Please note that TLS session tickets are very different and it is the clients' responsibility -to cache the SSL session state when session tickets are used. SSL session resumptions based on -TLS session tickets would happen automatically without going through this hook (nor the -[ssl_session_store_by_lua_block](#ssl_session_store_by_lua) hook). This hook is mainly -for older or less capable SSL clients that can only do SSL sessions by session IDs. - -When [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) is specified at the same time, -this hook usually runs before [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block). -When the SSL session is found and successfully loaded for the current SSL connection, -SSL session resumption will happen and thus bypass the [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) -hook completely. In this case, NGINX also bypasses the [ssl_session_store_by_lua_block](#ssl_session_store_by_lua) -hook, for obvious reasons. - -To easily test this hook locally with a modern web browser, you can temporarily put the following line -in your https server block to disable the TLS session ticket support: - - ssl_session_tickets off; - -But do not forget to comment this line out before publishing your site to the world. - -If you are using the [official pre-built packages](http://openresty.org/en/linux-packages.html) for [OpenResty](https://openresty.org/) -1.11.2.1 or later, then everything should work out of the box. - -If you are using OpenSSL libraries not provided by [OpenResty](https://openresty.org), -then you need to apply the following patch for OpenSSL 1.0.2h or later: - - - -If you are not using the NGINX core shipped with [OpenResty](https://openresty.org) 1.11.2.1 or later, then you need to -apply the following patch to the standard NGINX core 1.11.2 or later: - - - -This directive was first introduced in the `v0.10.6` release. - -Note that: this directive is only allowed to used in **http context** from the `v0.10.7` release -(because SSL session resumption happens before server name dispatch). - -[Back to TOC](#directives) - -ssl_session_fetch_by_lua_file ------------------------------ - -**syntax:** *ssl_session_fetch_by_lua_file <path-to-lua-script-file>* - -**context:** *http* - -**phase:** *right-before-SSL-handshake* - -Equivalent to [ssl_session_fetch_by_lua_block](#ssl_session_fetch_by_lua_block), except that the file specified by `` contains the Lua code, or rather, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.10.6` release. - -Note that: this directive is only allowed to used in **http context** from the `v0.10.7` release -(because SSL session resumption happens before server name dispatch). - -[Back to TOC](#directives) - -ssl_session_store_by_lua_block ------------------------------- - -**syntax:** *ssl_session_store_by_lua_block { lua-script }* - -**context:** *http* - -**phase:** *right-after-SSL-handshake* - -This directive runs Lua code to fetch and save the SSL session (if any) according to the session ID -provided by the current SSL handshake request for the downstream. The saved or cached SSL -session data can be used for future SSL connections to resume SSL sessions without going -through the full SSL handshake process (which is very expensive in terms of CPU time). - -Lua APIs that may yield, like [ngx.sleep](#ngxsleep) and [cosockets](#ngxsockettcp), -are *disabled* in this context. You can still, however, use the [ngx.timer.at](#ngxtimerat) API -to create 0-delay timers to save the SSL session data asynchronously to external services (like `redis` or `memcached`). - -The Lua API for obtaining the current session ID and the associated session state data -is provided in the [ngx.ssl.session](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl/session.md#readme) -Lua module shipped with the [lua-resty-core](https://github.com/openresty/lua-resty-core#readme) -library. - -To easily test this hook locally with a modern web browser, you can temporarily put the following line -in your https server block to disable the TLS session ticket support: - - ssl_session_tickets off; - -But do not forget to comment this line out before publishing your site to the world. - -This directive was first introduced in the `v0.10.6` release. - -Note that: this directive is only allowed to used in **http context** from the `v0.10.7` release -(because SSL session resumption happens before server name dispatch). - -[Back to TOC](#directives) - -ssl_session_store_by_lua_file ------------------------------ - -**syntax:** *ssl_session_store_by_lua_file <path-to-lua-script-file>* - -**context:** *http* - -**phase:** *right-after-SSL-handshake* - -Equivalent to [ssl_session_store_by_lua_block](#ssl_session_store_by_lua_block), except that the file specified by `` contains the Lua code, or rather, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.10.6` release. - -Note that: this directive is only allowed to used in **http context** from the `v0.10.7` release -(because SSL session resumption happens before server name dispatch). - -[Back to TOC](#directives) - -lua_shared_dict ---------------- - -**syntax:** *lua_shared_dict <name> <size>* - -**default:** *no* - -**context:** *http* - -**phase:** *depends on usage* - -Declares a shared memory zone, ``, to serve as storage for the shm based Lua dictionary `ngx.shared.`. - -Shared memory zones are always shared by all the nginx worker processes in the current nginx server instance. - -The `` argument accepts size units such as `k` and `m`: - -```nginx - - http { - lua_shared_dict dogs 10m; - ... - } -``` - -The hard-coded minimum size is 8KB while the practical minimum size depends -on actual user data set (some people start with 12KB). - -See [ngx.shared.DICT](#ngxshareddict) for details. - -This directive was first introduced in the `v0.3.1rc22` release. - -[Back to TOC](#directives) - -lua_socket_connect_timeout --------------------------- - -**syntax:** *lua_socket_connect_timeout <time>* - -**default:** *lua_socket_connect_timeout 60s* - -**context:** *http, server, location* - -This directive controls the default timeout value used in TCP/unix-domain socket object's [connect](#tcpsockconnect) method and can be overridden by the [settimeout](#tcpsocksettimeout) or [settimeouts](#tcpsocksettimeouts) methods. - -The `