BBlack (Code Review)
2017-04-25 12:08:06 UTC
BBlack has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/350178 )
Change subject: nginx lua module fixups
......................................................................
nginx lua module fixups
New patch: update upstream source from 0.10.7 to 0.10.8, and then
past that a few commits in master for nginx-1.11.x build fixups.
Updated OpenSSL-1.1.0 patch to account for a minor conflict with
the above.
Change-Id: I1a82df8da0d0fe8b1dc3612eff19a7996434491e
---
A debian/modules/patches/nginx-lua/lua-update.patch
M debian/modules/patches/nginx-lua/openssl-1.1.0.patch
M debian/modules/patches/nginx-lua/series
3 files changed, 5,777 insertions(+), 1 deletion(-)
git pull ssh://gerrit.wikimedia.org:29418/operations/software/nginx refs/changes/78/350178/1
diff --git a/debian/modules/patches/nginx-lua/lua-update.patch b/debian/modules/patches/nginx-lua/lua-update.patch
new file mode 100644
index 0000000..2306efc
--- /dev/null
+++ b/debian/modules/patches/nginx-lua/lua-update.patch
@@ -0,0 +1,5775 @@
+# This updates from debian's 0.10.7 to master a few commits past 0.10.8 (to include latest nginx-1.11 fixups)
+# --bblack
+
+diff --git a/README.markdown b/README.markdown
+index 3699a72..16d56bf 100644
+--- a/README.markdown
++++ b/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.8](https://github.com/openresty/lua-nginx-module/tags) released on 8 April 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)
+@@ -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.
++
++```lua
++
++ -- Avoid
++ foo = 123
++ -- Recomended
++ local foo = 123
++
++ -- Avoid
++ function foo() return 123 end
++ -- Recomended
++ local function foo() return 123 end
++```
+
+-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:
++
++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.
+@@ -886,7 +921,7 @@ servers in Lua. For example,
+ 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>
+
+@@ -957,7 +992,7 @@ This module is licensed under the BSD license.
+
+ Copyright (C) 2009-2016, by Xiaozhe Wang (chaoslawful) <***@gmail.com>.
+
+-Copyright (C) 2009-2016, by Yichun "agentzh" Zhang (章亦春) <***@gmail.com>, CloudFlare Inc.
++Copyright (C) 2009-2017, by Yichun "agentzh" Zhang (章亦春) <***@gmail.com>, OpenResty Inc.
+
+ All rights reserved.
+
+@@ -1082,7 +1117,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 +1188,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 +1211,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 +1278,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 `<lua-script-str>` on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file.
+
+@@ -1358,7 +1394,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).
+
+@@ -1447,7 +1483,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 `<lua-script-str>` with optional input arguments `$arg1 $arg2 ...`, and returns string output to `$res`.
+ The code in `<lua-script-str>` 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 +1573,15 @@ set_by_lua_file
+
+ **phase:** *rewrite*
+
+-Equivalent to [set_by_lua](#set_by_lua), except that the file specified by `<path-to-lua-script-file>` 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 `<path-to-lua-script-file>` 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 `<path-to-lua-script-file>` 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 +1597,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 `<lua-script-str>` for every request.
++Acts as a "content handler" and executes Lua code string specified in `<lua-script-str>` 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 +1648,16 @@ Nginx variables can be used in the `<path-to-lua-script-file>` 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 +1678,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 `<lua-script-str>` 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 +1854,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 `<lua-script-str>` 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 +1966,7 @@ Nginx variables can be used in the `<path-to-lua-script-file>` 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 +1983,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 `<lua-script-str>` to define an output header filter.
+
+@@ -2029,8 +2061,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 `<lua-script-str>` to define an output body filter.
+
+@@ -2166,15 +2197,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 `<lua-script-str>` 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 +2913,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 +2981,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`).
+
+@@ -3280,7 +3310,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 +3468,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 +3571,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 +3579,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 <code>ctx</code> variable is on the Lua module level
+ -- and thus is per-nginx-worker.
+ local ctx = ngx.ctx
+
+@@ -3701,7 +3731,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 +3798,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 +3883,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 +4023,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 +4055,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 +4566,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 +4627,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 +5029,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 +5268,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 +5282,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 +5290,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...
+ }
+ }
+@@ -6006,7 +6037,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
+
+@@ -6495,7 +6526,7 @@ Fetch a list of the keys from the dictionary, up to `<max_count>`.
+
+ By default, only the first 1024 keys (if any) are returned. When the `<max_count>` 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 +7311,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
+
+diff --git a/config b/config
+index 01a6b3c..5d2ee65 100644
+--- a/config
++++ b/config
+@@ -472,33 +472,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 <unistd.h>
+-#include <stdlib.h>
+-#include <stdint.h>
+-#include <sys/mman.h>
+-#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/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki
+index be454af..e496672 100644
+--- a/doc/HttpLuaModule.wiki
++++ b/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.8] released on 8 April 2017.
+
+ = Synopsis =
+ <geshi lang="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()
+@@ -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: <code>./configure --with-luajit && make && make install</code>.
++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
+ </geshi>
+
+ == 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 <code>--add-dynamic-module=PATH</code> option instead of <code>--add-module=PATH</code> on the
++<code>./configure</code> command line above. And then you can explicitly load the module in your <code>nginx.conf</code> via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module)
+ directive, for example,
+
+-```nginx
++<geshi lang="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;
+-```
++</geshi>
+
+ == C Macro Configurations ==
+
+@@ -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 <code>success</code> despite connection failures such as with <code>Connection Refused</code> errors.
++The [[#tcpsock:connect|tcpsock:connect]] method may indicate <code>success</code> despite connection failures such as with <code>Connection Refused</code> 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 <code>require()</code> built-in in the <code>package.loaded</code> table for later reference, and the <code>module()</code> 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 <code>nil</code> 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:
++
++# 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 is therefore *highly* recommended to always declare such within an appropriate local scope instead.
++
++<geshi lang="lua">
++ -- Avoid
++ foo = 123
++ -- Recomended
++ local foo = 123
+
+-# 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.
++ -- Avoid
++ function foo() return 123 end
++ -- Recomended
++ local function foo() return 123 end
++</geshi>
+
+-It's *highly* recommended to always declare them via "local" in the scope that is reasonable.
+
+-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:
++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 <code>.lua</code> source files:
+ <geshi lang="text">
+ $ 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
+-<code>*_by_lua_block {}</code> configuration directives.
++'''NOTE''' Following the <code>v0.9.17</code> release, this pitfall can be avoided by using the <code>*_by_lua_block {}</code> configuration directives.
+
+-PCRE sequences such as <code>\d</code>, <code>\s</code>, or <code>\w</code>, require special attention because in string literals, the backslash character, <code>\</code>, 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 <code>\d</code>, <code>\s</code>, or <code>\w</code>, require special attention because in string literals, the backslash character, <code>\</code>, is stripped out by both the Lua language parser and by the nginx config file parser before processing if not within a <code>*_by_lua_block {}</code> directive. So the following snippet will not work as expected:
+
+ <geshi lang="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
+ ? ';
+@@ -606,7 +624,7 @@ To avoid this, ''double'' escape the backslash:
+
+ Here, <code>\\\\d+</code> is stripped down to <code>\\d+</code> by the Nginx config file parser and this is further stripped down to <code>\d+</code> 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", <code>[[...]]</code>, 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", <code>[[...]]</code>, in which case backslashes have to only be escaped once for the Nginx config file parser.
+
+ <geshi lang="nginx">
+ # nginx.conf
+@@ -622,7 +640,7 @@ Alternatively, the regex pattern can be presented as a long-bracketed Lua string
+
+ Here, <code>[[\\d+]]</code> is stripped down to <code>[[\d+]]</code> by the Nginx config file parser and this is processed correctly.
+
+-Note that a longer from of the long bracket, <code>[=[...]=]</code>, may be required if the regex pattern contains <code>[...]</code> sequences.
++Note that a longer from of the long bracket, <code>[=[...]=]</code>, may be required if the regex pattern contains <code>[...]</code> sequences.
+ The <code>[=[...]=]</code> form may be used as the default form if desired.
+
+ <geshi lang="nginx">
+@@ -637,7 +655,7 @@ The <code>[=[...]=]</code> form may be used as the default form if desired.
+ # evaluates to "1234"
+ </geshi>
+
+-An alternative approach to escaping PCRE sequences is to ensure that Lua code is placed in external script files and executed using the various <code>*_by_lua_file</code> 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 <code>*_by_lua_file</code> directives.
+ With this approach, the backslashes are only stripped by the Lua language parser and therefore only need to be escaped once each.
+
+ <geshi lang="lua">
+@@ -648,8 +666,8 @@ With this approach, the backslashes are only stripped by the Lua language parser
+ -- evaluates to "1234"
+ </geshi>
+
+-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.
++
+ <geshi lang="lua">
+ -- test.lua
+ local regex = [[\d+]]
+@@ -658,6 +676,21 @@ Within external script files, PCRE sequences presented as long-bracketed Lua str
+ -- evaluates to "1234"
+ </geshi>
+
++As noted earlier, PCRE sequences presented within <code>*_by_lua_block {}</code> directives (available following the <code>v0.9.17</code> release) do not require modification.
++
++<geshi lang="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"
++</geshi>
++
++
+ == 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 <code>connect</code> 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 <code>bsdrecv</code> method.
+ * add new API function <code>ngx.resp.add_header</code> to emulate the standard <code>add_header</code> config directive.
+-* review and apply Jader H. Silva's patch for <code>ngx.re.split()</code>.
+ * review and apply vadim-pavlov's patch for [[#ngx.location.capture|ngx.location.capture]]'s <code>extra_headers</code> option
+ * use <code>ngx_hash_t</code> 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.
+@@ -717,7 +749,7 @@ servers in Lua. For example,
+
+ = 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
+ </geshi>
+
+-To run a specific test block in a particular test file, add the line <code>--- ONLY</code> to the test block you want to run, and then use the `prove` utility to run that <code>.t</code> file.
++To run a specific test block in a particular test file, add the line <code>--- ONLY</code> to the test block you want to run, and then use the <code>prove</code> utility to run that <code>.t</code> 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.
+
+@@ -782,7 +814,7 @@ This module is licensed under the BSD license.
+
+ Copyright (C) 2009-2016, by Xiaozhe Wang (chaoslawful) <***@gmail.com>.
+
+-Copyright (C) 2009-2016, by Yichun "agentzh" Zhang (章亦春) <***@gmail.com>, CloudFlare Inc.
++Copyright (C) 2009-2017, by Yichun "agentzh" Zhang (章亦春) <***@gmail.com>, OpenResty Inc.
+
+ All rights reserved.
+
+@@ -834,7 +866,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 <code>Content-Type</code> response header. If you do not want a default <code>Content-Type</code> 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 <code>Content-Type</code> response header. Deactivate this directive if a default <code>Content-Type</code> response header for Lua request handlers is not desired.
+
+ This directive is turned on by default.
+
+@@ -898,8 +930,8 @@ The ngx_lua module does not support the <code>stat</code> mode available with th
+ Apache <code>mod_lua</code> 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 <num>''
+@@ -918,6 +950,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), ...
+ </geshi>
+
++If you are using the <code>ngx.re.*</code> implementation of [lua-resty-core](https://github.com/openresty/lua-resty-core) by loading the <code>resty.core.regex</code> module (or just the <code>resty.core</code> module), then an LRU cache is used for the regex cache being used here.
++
+ Do not activate the <code>o</code> option for regular expressions (and/or <code>replace</code> 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 +1005,7 @@ As from the <code>v0.5.0rc29</code> release, the special notation <code>$prefix<
+
+ '''phase:''' ''loading-config''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> release. Use the [[#init_by_lua_block|init_by_lua_block]] directive instead.
+
+ Runs the Lua code specified by the argument <code><lua-script-str></code> on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file.
+
+@@ -1041,7 +1074,7 @@ This directive was first introduced in the <code>v0.5.5</code> 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 (<code>{}</code>) instead of in an NGINX string literal (which requires
+ special character escaping).
+
+ For instance,
+@@ -1076,7 +1109,7 @@ This directive was first introduced in the <code>v0.5.5</code> release.
+
+ '''phase:''' ''starting-worker''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> 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*]].
+
+@@ -1121,7 +1154,7 @@ This directive was first introduced in the <code>v0.9.5</code> 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 (<code>{}</code>) instead of in an NGINX string literal (which requires
+ special character escaping).
+
+ For instance,
+@@ -1154,7 +1187,7 @@ This directive was first introduced in the <code>v0.9.5</code> release.
+
+ '''phase:''' ''rewrite''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> release. Use the [[#set_by_lua_block|set_by_lua_block]] directive instead.
+
+ Executes code specified in <code><lua-script-str></code> with optional input arguments <code>$arg1 $arg2 ...</code>, and returns string output to <code>$res</code>.
+ The code in <code><lua-script-str></code> can make [[#Nginx API for Lua|API calls]] and can retrieve input arguments from the <code>ngx.arg</code> table (index starts from <code>1</code> and increases sequentially).
+@@ -1177,15 +1210,15 @@ a time. However, a workaround is possible using the [[#ngx.var.VARIABLE|ngx.var.
+ <geshi lang="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";
+ }
+ </geshi>
+@@ -1213,7 +1246,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 (<code>{}</code>) 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 +1268,15 @@ This directive was first introduced in the <code>v0.9.17</code> release.
+
+ '''phase:''' ''rewrite''
+
+-Equivalent to [[#set_by_lua|set_by_lua]], except that the file specified by <code><path-to-lua-script-file></code> contains the Lua code, or, as from the <code>v0.5.0rc32</code> 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 <code><path-to-lua-script-file></code> contains the Lua code, or, as from the <code>v0.5.0rc32</code> release, the [[#Lua/LuaJIT bytecode support|Lua/LuaJIT bytecode]] to be executed.
+
+ Nginx variable interpolation is supported in the <code><path-to-lua-script-file></code> argument string of this directive. But special care must be taken for injection attacks.
+
+ When a relative path like <code>foo/bar.lua</code> is given, they will be turned into the absolute path relative to the <code>server prefix</code> path determined by the <code>-p PATH</code> 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]] <code>off</code> in <code>nginx.conf</code> to avoid reloading Nginx.
+
+ This directive requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_kit] module.
+@@ -1256,10 +1289,9 @@ This directive requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_ki
+
+ '''phase:''' ''content''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> 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 <code><lua-script-str></code> for every request.
++Acts as a "content handler" and executes Lua code string specified in <code><lua-script-str></code> 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 +1306,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 (<code>{}</code>) instead of in an NGINX string literal (which requires
+ special character escaping).
+
+ For instance,
+@@ -1301,15 +1333,15 @@ Nginx variables can be used in the <code><path-to-lua-script-file></code> string
+
+ When a relative path like <code>foo/bar.lua</code> is given, they will be turned into the absolute path relative to the <code>server prefix</code> path determined by the <code>-p PATH</code> 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]] <code>off</code> in <code>nginx.conf</code> to avoid reloading Nginx.
+
+ Nginx variables are supported in the file path for dynamic dispatch, for example:
+
+ <geshi lang="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;
+@@ -1327,8 +1359,7 @@ But be very careful about malicious user inputs and always carefully validate or
+
+ '''phase:''' ''rewrite tail''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> 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 <code><lua-script-str></code> 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 +1407,7 @@ The right way of doing this is as follows:
+ return ngx.redirect("/bar");
+ end
+ ';
+-
++
+ echo "res = $b";
+ }
+ </geshi>
+@@ -1388,11 +1419,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 ...;
+ }
+ </geshi>
+@@ -1404,7 +1435,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 +1443,7 @@ can be implemented in ngx_lua as:
+ return ngx.redirect("/terms-of-use.html")
+ end
+ ';
+-
++
+ fastcgi_pass ...;
+ }
+ </geshi>
+@@ -1447,7 +1478,7 @@ The <code>rewrite_by_lua</code> code will always run at the end of the <code>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 (<code>{}</code>) instead of in an NGINX string literal (which requires
+ special character escaping).
+
+ For instance,
+@@ -1488,8 +1519,7 @@ Nginx variables are supported in the file path for dynamic dispatch just as in [
+
+ '''phase:''' ''access tail''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> 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 <code><lua-script-str></code> 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 +1532,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/...
+ }
+ </geshi>
+@@ -1519,7 +1549,7 @@ Note that the [http://mdounin.ru/hg/ngx_http_auth_request_module/ ngx_auth_reque
+ <geshi lang="nginx">
+ location / {
+ auth_request /auth;
+-
++
+ # proxy_pass/fastcgi_pass/postgres_pass/...
+ }
+ </geshi>
+@@ -1530,18 +1560,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/...
+ }
+ </geshi>
+@@ -1564,7 +1594,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 (<code>{}</code>) instead of in an NGINX string literal (which requires
+ special character escaping).
+
+ For instance,
+@@ -1591,7 +1621,7 @@ Nginx variables can be used in the <code><path-to-lua-script-file></code> string
+
+ When a relative path like <code>foo/bar.lua</code> is given, they will be turned into the absolute path relative to the <code>server prefix</code> path determined by the <code>-p PATH</code> 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]] <code>off</code> in <code>nginx.conf</code> to avoid repeatedly reloading Nginx.
+
+@@ -1605,8 +1635,7 @@ Nginx variables are supported in the file path for dynamic dispatch just as in [
+
+ '''phase:''' ''output-header-filter''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> release. Use the [[#header_filter_by_lua_block|header_filter_by_lua_block]] directive instead.
+
+ Uses Lua code specified in <code><lua-script-str></code> to define an output header filter.
+
+@@ -1638,7 +1667,7 @@ This directive was first introduced in the <code>v0.2.1rc20</code> 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 (<code>{}</code>) instead of in an NGINX string literal (which requires
+ special character escaping).
+
+ For instance,
+@@ -1673,8 +1702,7 @@ This directive was first introduced in the <code>v0.2.1rc20</code> release.
+
+ '''phase:''' ''output-body-filter''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> release. Use the [[#body_filter_by_lua_block|body_filter_by_lua_block]] directive instead.
+
+ Uses Lua code specified in <code><lua-script-str></code> to define an output body filter.
+
+@@ -1761,7 +1789,7 @@ This directive was first introduced in the <code>v0.5.0rc32</code> 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 (<code>{}</code>) instead of in an NGINX string literal (which requires
+ special character escaping).
+
+ For instance,
+@@ -1796,15 +1824,14 @@ This directive was first introduced in the <code>v0.5.0rc32</code> release.
+
+ '''phase:''' ''log''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> release. Use the [[#log_by_lua_block|log_by_lua_block]] directive instead.
+
+ Runs the Lua source code inlined as the <code><lua-script-str></code> at the <code>log</code> 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 +1865,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 +1889,7 @@ This directive was first introduced in the <code>v0.5.0rc31</code> 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 (<code>{}</code>) instead of in an NGINX string literal (which requires
+ special character escaping).
+
+ For instance,
+@@ -2430,7 +2457,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 <code>Content-Length</code> 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 <code>Content-Length</code> response header.
+
+ If the Lua code explicitly sets a <code>Content-Length</code> 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 +2513,7 @@ This directive was first introduced in the <code>v0.5.0rc32</code> 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 <code>nil</code>).
+
+@@ -2592,11 +2619,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;
+ }
+ </geshi>
+@@ -2646,7 +2673,7 @@ Setting <code>ngx.var.Foo</code> to a <code>nil</code> value will unset the <cod
+ ngx.var.args = nil
+ </geshi>
+
+-'''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,
+
+ <geshi lang="lua">
+ local val = ngx.var.some_var
+@@ -2655,7 +2682,7 @@ Setting <code>ngx.var.Foo</code> to a <code>nil</code> value will unset the <cod
+
+ to prevent (temporary) memory leaking within the current request's lifetime. Another way of caching the result is to use the [[#ngx.ctx|ngx.ctx]] table.
+
+-Undefined NGINX variables are evaluated to `nil` while uninitialized (but defined) NGINX variables are evaluated to an empty Lua string.
++Undefined NGINX variables are evaluated to <code>nil</code> 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 +2807,7 @@ There is a hard coded <code>2048</code> 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 +2843,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 +2874,7 @@ Internal redirection will destroy the original request <code>ngx.ctx</code> data
+ ngx.say(ngx.ctx.foo)
+ }
+ }
+-
++
+ location /orig {
+ content_by_lua_block {
+ ngx.ctx.foo = "hello"
+@@ -2876,14 +2903,14 @@ When being used in the context of [[#init_worker_by_lua|init_worker_by_lua*]], t
+
+ The <code>ngx.ctx</code> 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 <code>ngx.ctx</code> 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 <code>ngx.ctx</code> 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:
+
+ <geshi lang="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
++-- data while this <code>ctx</code> variable is on the Lua module level
+ -- and thus is per-nginx-worker.
+ local ctx = ngx.ctx
+
+@@ -2907,7 +2934,7 @@ end
+ return _M
+ </geshi>
+
+-That is, let the caller pass the `ctx` table explicitly via a function argument.
++That is, let the caller pass the <code>ctx</code> table explicitly via a function argument.
+
+ == ngx.location.capture ==
+ '''syntax:''' ''res = ngx.location.capture(uri, options?)''
+@@ -3024,7 +3051,7 @@ The <code>args</code> option can also take plain query strings:
+
+ This is functionally identical to the previous examples.
+
+-The <code>share_all_vars</code> option controls whether to share nginx variables among the current request and its subrequests.
++The <code>share_all_vars</code> option controls whether to share nginx variables among the current request and its subrequests.
+ If this option is set to <code>true</code>, 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 <code>args</code>, <code>vars</code>, or <code>copy_all_vars</code> options are generally preferable instead.
+@@ -3089,7 +3116,7 @@ In addition to the two settings above, it is possible to specify
+ values for variables in the subrequest using the <code>vars</code> 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.
+
+ <geshi lang="nginx">
+@@ -3171,7 +3198,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 <code>ngx_proxy</code> 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 <code>off</code> in subrequest locations.
+
+ When the <code>body</code> option is not specified and the <code>always_forward_body</code> option is false (the default value), the <code>POST</code> and <code>PUT</code> subrequests will inherit the request bodies of the parent request (if any).
+@@ -3201,11 +3228,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 +3250,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 +3305,7 @@ The header names are matched case-insensitively.
+ <geshi lang="lua">
+ -- equivalent to ngx.header["Content-Type"] = 'text/plain'
+ ngx.header.content_type = 'text/plain';
+-
++
+ ngx.header["X-My-Header"] = 'blah blah';
+ </geshi>
+
+@@ -3295,7 +3322,7 @@ will yield
+ Set-Cookie: b=4; path=/
+ </geshi>
+
+-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 <code>Content-Type</code> that only accept a single value).
+
+@@ -3323,7 +3350,7 @@ The same applies to assigning an empty table:
+
+ Setting <code>ngx.header.HEADER</code> 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 <code>ngx.header.HEADER</code> will return the value of the response header named <code>HEADER</code>.
++Reading <code>ngx.header.HEADER</code> will return the value of the response header named <code>HEADER</code>.
+
+ Underscores (<code>_</code>) in the header names will also be replaced by dashes (<code>-</code>) and the header names will be matched case-insensitively. If the response header is not present at all, <code>nil</code> will be returned.
+
+@@ -3655,8 +3682,8 @@ Arguments without the <code>=<value></code> parts are treated as boolean argumen
+ That is, they will take Lua boolean values <code>true</code>. However, they are different from arguments taking empty string values. <code>GET /test?foo=&bar=</code> will give something like
+
+ <geshi lang="bash">
+- foo:
+- bar:
++ foo:
++ bar:
+ </geshi>
+
+ Empty key arguments are discarded. <code>GET /test?=hello&=world</code> will yield an empty output for instance.
+@@ -3760,13 +3787,13 @@ Arguments without the <code>=<value></code> parts are treated as boolean argumen
+ That is, they will take Lua boolean values <code>true</code>. However, they are different from arguments taking empty string values. <code>POST /test</code> with request body <code>foo=&bar=</code> will return something like
+
+ <geshi lang="bash">
+- foo:
+- bar:
++ foo:
++ bar:
+ </geshi>
+
+ Empty key arguments are discarded. <code>POST /test</code> with body <code>=hello&=world</code> 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 <code>max_args</code> function argument can be used to override this limit:
+
+@@ -3818,7 +3845,7 @@ the value of <code>ngx.req.get_headers()["Foo"]</code> will be a Lua (array) tab
+ {"foo", "bar", "baz"}
+ </geshi>
+
+-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 <code>max_headers</code> function argument can be used to override this limit:
+
+@@ -4164,6 +4191,7 @@ The optional <code>status</code> parameter specifies the HTTP status code to be
+
+ * <code>301</code>
+ * <code>302</code> (default)
++* <code>303</code>
+ * <code>307</code>
+
+ It is <code>302</code> (<code>ngx.HTTP_MOVED_TEMPORARILY</code>) by default.
+@@ -4367,7 +4395,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 <code>return</code> statement, i.e., <code>return ngx.exit(...)</code> 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*]], <code>ngx.exit()</code> is
+ an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use <code>return</code> in combination as suggested above.
+
+@@ -4378,14 +4406,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:
+
+ <geshi lang="nginx">
+ 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...
+ }
+ }
+@@ -5024,7 +5052,7 @@ When the <code>replace</code> is a string, then it is treated as a special templ
+
+ where <code>$0</code> referring to the whole substring matched by the pattern and <code>$1</code> 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:
+
+ <geshi lang="lua">
+ local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "${0}00")
+@@ -5343,7 +5371,7 @@ The <code>value</code> argument and <code>init</code> argument can be any valid
+
+ This method was first introduced in the <code>v0.3.1rc22</code> release.
+
+-The optional `init` parameter was first added in the <code>v0.10.6</code> release.
++The optional <code>init</code> parameter was first added in the <code>v0.10.6</code> release.
+
+ See also [[#ngx.shared.DICT|ngx.shared.DICT]].
+
+@@ -5445,7 +5473,7 @@ Fetch a list of the keys from the dictionary, up to <code><max_count></code>.
+
+ By default, only the first 1024 keys (if any) are returned. When the <code><max_count></code> argument is given the value <code>0</code>, 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 <code>v0.7.3</code> release.
+
+@@ -5724,7 +5752,7 @@ session userdata returned by a previous <code>sslhandshake</code>
+ 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
++<code>nil</code>. If this argument takes the boolean <code>false</code> 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 +5765,7 @@ also used to validate the server name specified in the server certificate sent f
+ the remote.
+
+ The optional <code>ssl_verify</code> 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 <code>true</code>, 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 +6176,7 @@ Then it will generate the output
+ 4
+ </geshi>
+
+-"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):
+
+ <geshi lang="lua">
+ -- query mysql, memcached, and a remote http service at the same time,
+@@ -6187,7 +6215,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
+ </geshi>
+
+ This API was first enabled in the <code>v0.7.0</code> release.
+@@ -6413,7 +6441,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)
+@@ -6481,8 +6509,8 @@ This directive was first introduced in the <code>v0.9.20</code> 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 <code>"http"</code>. For
++[https://github.com/openresty/stream-lua-nginx-module#readme ngx_stream_lua_module], however, this field takes the value <code>"stream"</code>.
+
+ This field was first introduced in the <code>0.10.1</code>.
+
+@@ -6563,7 +6591,7 @@ This API was first introduced in the <code>0.9.5</code> 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 <code>nginx.conf</code>).
+
+ This API was first introduced in the <code>0.9.20</code> release.
+
+@@ -6575,11 +6603,11 @@ This API was first introduced in the <code>0.9.20</code> 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 <code>N</code>, then this method may return a number between 0
++and <code>N - 1</code> (inclusive).
+
+ This function returns meaningful values only for NGINX 1.9.1+. With earlier versions of NGINX, it
+-always returns `nil`.
++always returns <code>nil</code>.
+
+ See also [[#ngx.worker.count|ngx.worker.count]].
+
+diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h
+index 3737149..b0df5ae 100644
+--- a/src/api/ngx_http_lua_api.h
++++ b/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 10008
+
+
+ typedef struct {
+diff --git a/src/ngx_http_lua_api.c b/src/ngx_http_lua_api.c
+index b72c707..7b590e7 100644
+--- a/src/ngx_http_lua_api.c
++++ b/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/src/ngx_http_lua_args.c b/src/ngx_http_lua_args.c
+index 0c307d6..b43697c 100644
+--- a/src/ngx_http_lua_args.c
++++ b/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/src/ngx_http_lua_balancer.c b/src/ngx_http_lua_balancer.c
+index 0adf787..03d9eac 100644
+--- a/src/ngx_http_lua_balancer.c
++++ b/src/ngx_http_lua_balancer.c
+@@ -640,7 +640,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 +681,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/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h
+index 267952b..f37d776 100644
+--- a/src/ngx_http_lua_common.h
++++ b/src/ngx_http_lua_common.h
+@@ -138,7 +138,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 {
+@@ -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_control.c b/src/ngx_http_lua_control.c
+index 249d763..ae36505 100644
+--- a/src/ngx_http_lua_control.c
++++ b/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/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c
+index 0af56f6..6700ce8 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) {
+@@ -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/src/ngx_http_lua_headers.h b/src/ngx_http_lua_headers.h
+index 39f1114..ee4d21c 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 6e93c8e..72f934d 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);
+@@ -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);
+
+@@ -592,13 +585,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 +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
+
+@@ -730,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");
+
+@@ -955,7 +952,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 +964,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 +1264,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/src/ngx_http_lua_semaphore.c b/src/ngx_http_lua_semaphore.c
+index 8a3f832..604d943 100644
+--- a/src/ngx_http_lua_semaphore.c
++++ b/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) {
+diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c
+index 6db6e2d..4981116 100644
+--- a/src/ngx_http_lua_socket_tcp.c
++++ b/src/ngx_http_lua_socket_tcp.c
+@@ -501,6 +501,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 +1214,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 +1334,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);
+diff --git a/src/ngx_http_lua_ssl.h b/src/ngx_http_lua_ssl.h
+index 7a245ff..acb8c4b 100644
+--- a/src/ngx_http_lua_ssl.h
++++ b/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/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c
+index aca4735..84e3093 100644
+--- a/src/ngx_http_lua_ssl_certby.c
++++ b/src/ngx_http_lua_ssl_certby.c
+@@ -1129,7 +1129,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/t/000--init.t b/t/000--init.t
+index 364334f..ad2d70e 100644
+--- a/t/000--init.t
++++ b/t/000--init.t
+@@ -84,4 +84,3 @@ GET /flush
+ --- timeout: 10
+ --- no_error_log
+ [error]
+-
+diff --git a/t/000-sanity.t b/t/000-sanity.t
+index 3f66752..87854ef 100644
+--- a/t/000-sanity.t
++++ b/t/000-sanity.t
+@@ -31,4 +31,3 @@ GET /lua
+ GET /lua
+ --- response_body
+ helloworld
+-
+diff --git a/t/001-set.t b/t/001-set.t
+index 2295a2d..ba8f22c 100644
+--- a/t/001-set.t
++++ b/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/t/002-content.t b/t/002-content.t
+index e6cb62d..3f2460e 100644
+--- a/t/002-content.t
++++ b/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/t/003-errors.t b/t/003-errors.t
+index 764300a..ad3a506 100644
+--- a/t/003-errors.t
++++ b/t/003-errors.t
+@@ -126,4 +126,3 @@ GET /main
+ GET /main
+ --- response_body
+ 500
+-
+diff --git a/t/004-require.t b/t/004-require.t
+index 3250b2f..ec74116 100644
+--- a/t/004-require.t
++++ b/t/004-require.t
+@@ -208,4 +208,3 @@ GET /ndk
+ GET /ndk
+ --- response_body
+ %20
+-
+diff --git a/t/005-exit.t b/t/005-exit.t
+index 781531f..a5a28b3 100644
+--- a/t/005-exit.t
++++ b/t/005-exit.t
+@@ -723,4 +723,3 @@ GET /t
+ --- response_body
+ --- no_error_log
+ [error]
+-
+diff --git a/t/006-escape.t b/t/006-escape.t
+index 7b26bba..0fb67a3 100644
+--- a/t/006-escape.t
++++ b/t/006-escape.t
+@@ -180,4 +180,3 @@ GET /t
+ GET /t
+ --- response_body
+ [32]
+-
+diff --git a/t/007-md5.t b/t/007-md5.t
+index 501e3af..2ae9efb 100644
+--- a/t/007-md5.t
++++ b/t/007-md5.t
+@@ -100,4 +100,3 @@ d41d8cd98f00b204e9800998ecf8427e
+ GET /md5
+ --- response_body
+ 6c8349cc7260ae62e3b1396831a8398f
+-
+diff --git a/t/008-today.t b/t/008-today.t
+index 54bd949..ec2f433 100644
+--- a/t/008-today.t
++++ b/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/t/009-log.t b/t/009-log.t
+index 0c6a9a5..68c057f 100644
+--- a/t/009-log.t
++++ b/t/009-log.t
+@@ -542,4 +542,3 @@ ok
+ [error]
+ --- error_log eval
+ "2: hello\0world, client: "
+-
+diff --git a/t/010-request_body.t b/t/010-request_body.t
+index 2640a54..e669d94 100644
+--- a/t/010-request_body.t
++++ b/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/t/012-now.t b/t/012-now.t
+index abcb735..5885187 100644
+--- a/t/012-now.t
++++ b/t/012-now.t
+@@ -116,4 +116,3 @@ GET /time
+ --- request
+ GET /time
+ --- response_body_like: ^\d{10,}(\.\d{1,3})?$
+-
+diff --git a/t/014-bugs.t b/t/014-bugs.t
+index 44337e3..9aadff0 100644
+--- a/t/014-bugs.t
++++ b/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/t/016-resp-header.t b/t/016-resp-header.t
+index 179b411..1fae292 100644
+--- a/t/016-resp-header.t
++++ b/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/t/017-exec.t b/t/017-exec.t
+index 4c7a918..535c4ab 100644
+--- a/t/017-exec.t
++++ b/t/017-exec.t
+@@ -572,4 +572,3 @@ hello, bah
+ ["dummy", "dummy"]
+ --- no_error_log
+ [error]
+-
+diff --git a/t/018-ndk.t b/t/018-ndk.t
+index d68306b..1429377 100644
+--- a/t/018-ndk.t
++++ b/t/018-ndk.t
+@@ -171,4 +171,3 @@ ok
+ foo = a b
+ --- no_error_log
+ [error]
+-
+diff --git a/t/019-const.t b/t/019-const.t
+index fe79bfb..4f9c764 100644
+--- a/t/019-const.t
++++ b/t/019-const.t
+@@ -44,4 +44,3 @@ GET /read
+ GET /read
+ --- response_body
+ 504
+-
+diff --git a/t/021-cookie-time.t b/t/021-cookie-time.t
+index c00bbea..b05e401 100644
+--- a/t/021-cookie-time.t
++++ b/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/t/022-redirect.t b/t/022-redirect.t
+index 57c7add..fae39e3 100644
+--- a/t/022-redirect.t
++++ b/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/t/023-rewrite/client-abort.t b/t/023-rewrite/client-abort.t
+index e970802..117d17e 100644
+--- a/t/023-rewrite/client-abort.t
++++ b/t/023-rewrite/client-abort.t
+@@ -848,4 +848,3 @@ delete thread 1
+ --- no_error_log
+ [error]
+ [alert]
+-
+diff --git a/t/023-rewrite/exec.t b/t/023-rewrite/exec.t
+index a063b5b..bd97968 100644
+--- a/t/023-rewrite/exec.t
++++ b/t/023-rewrite/exec.t
+@@ -376,4 +376,3 @@ ngx.exec("@proxy")
+ GET /main
+ --- response_body
+ hello, bah
+-
+diff --git a/t/023-rewrite/exit.t b/t/023-rewrite/exit.t
+index 9d292f7..39ea5cb 100644
+--- a/t/023-rewrite/exit.t
++++ b/t/023-rewrite/exit.t
+@@ -595,4 +595,3 @@ F(ngx_http_send_header) {
+ --- error_code: 204
+ --- no_error_log
+ [error]
+-
+diff --git a/t/023-rewrite/mixed.t b/t/023-rewrite/mixed.t
+index 1156567..0f742b2 100644
+--- a/t/023-rewrite/mixed.t
++++ b/t/023-rewrite/mixed.t
+@@ -167,4 +167,3 @@ world\x03\x04\xff
+ hello\x00\x01\x02
+ world\x03\x04\xff
+ "
+-
+diff --git a/t/023-rewrite/multi-capture.t b/t/023-rewrite/multi-capture.t
+index 44629b0..083ec78 100644
+--- a/t/023-rewrite/multi-capture.t
++++ b/t/023-rewrite/multi-capture.t
+@@ -392,4 +392,3 @@ res4.status = 201
+ res4.body = STORED\r
+
+ "
+-
+diff --git a/t/023-rewrite/on-abort.t b/t/023-rewrite/on-abort.t
+index aca2ab6..336b7ce 100644
+--- a/t/023-rewrite/on-abort.t
++++ b/t/023-rewrite/on-abort.t
+@@ -654,4 +654,3 @@ delete thread 2
+
+ --- no_error_log
+ [error]
+-
+diff --git a/t/023-rewrite/redirect.t b/t/023-rewrite/redirect.t
+index 8843f1a..99f3fd4 100644
+--- a/t/023-rewrite/redirect.t
++++ b/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/t/023-rewrite/req-body.t b/t/023-rewrite/req-body.t
+index 2f42e0a..13bdcb2 100644
+--- a/t/023-rewrite/req-body.t
++++ b/t/023-rewrite/req-body.t
+@@ -221,4 +221,3 @@ hiya, world"]
+ --- no_error_log
+ [error]
+ [alert]
+-
+diff --git a/t/023-rewrite/req-socket.t b/t/023-rewrite/req-socket.t
+index 34aedaa..87cbbbe 100644
+--- a/t/023-rewrite/req-socket.t
++++ b/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/t/023-rewrite/request_body.t b/t/023-rewrite/request_body.t
+index 0594001..b867d3a 100644
+--- a/t/023-rewrite/request_body.t
++++ b/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/t/023-rewrite/sanity.t b/t/023-rewrite/sanity.t
+index 20b00e2..b90aa0e 100644
+--- a/t/023-rewrite/sanity.t
++++ b/t/023-rewrite/sanity.t
+@@ -799,4 +799,3 @@ test
+ test
+ --- no_error_log
+ [alert]
+-
+diff --git a/t/023-rewrite/sleep.t b/t/023-rewrite/sleep.t
+index 1719784..8d4c2da 100644
+--- a/t/023-rewrite/sleep.t
++++ b/t/023-rewrite/sleep.t
+@@ -219,4 +219,3 @@ hello world
+ hello world
+ --- no_error_log
+ [error]
+-
+diff --git a/t/023-rewrite/socket-keepalive.t b/t/023-rewrite/socket-keepalive.t
+index 50de0b3..489a70f 100644
+--- a/t/023-rewrite/socket-keepalive.t
++++ b/t/023-rewrite/socket-keepalive.t
+@@ -1007,4 +1007,3 @@ Not found, dear...
+ --- error_code: 404
+ --- no_error_log
+ [error]
+-
+diff --git a/t/023-rewrite/subrequest.t b/t/023-rewrite/subrequest.t
+index a307388..5d1e8f0 100644
+--- a/t/023-rewrite/subrequest.t
++++ b/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/t/023-rewrite/tcp-socket-timeout.t b/t/023-rewrite/tcp-socket-timeout.t
+index 79cd0b9..15bec7f 100644
+--- a/t/023-rewrite/tcp-socket-timeout.t
++++ b/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/t/023-rewrite/tcp-socket.t b/t/023-rewrite/tcp-socket.t
+index cf9d80a..bff69a5 100644
+--- a/t/023-rewrite/tcp-socket.t
++++ b/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/t/023-rewrite/unix-socket.t b/t/023-rewrite/unix-socket.t
+index 098dd67..8a5f000 100644
+--- a/t/023-rewrite/unix-socket.t
++++ b/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/t/023-rewrite/uthread-redirect.t b/t/023-rewrite/uthread-redirect.t
+index 0f125e0..83de1a3 100644
+--- a/t/023-rewrite/uthread-redirect.t
++++ b/t/023-rewrite/uthread-redirect.t
+@@ -186,4 +186,3 @@ free request
+ --- error_code: 302
+ --- no_error_log
+ [error]
+-
+diff --git a/t/023-rewrite/uthread-spawn.t b/t/023-rewrite/uthread-spawn.t
+index 58af7d0..5552107 100644
+--- a/t/023-rewrite/uthread-spawn.t
++++ b/t/023-rewrite/uthread-spawn.t
+@@ -1449,4 +1449,3 @@ status: 204
+ --- no_error_log
+ [error]
+ --- timeout: 3
+-
+diff --git a/t/024-access/auth.t b/t/024-access/auth.t
+index 5da09cb..56e9862 100644
+--- a/t/024-access/auth.t
++++ b/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/t/024-access/client-abort.t b/t/024-access/client-abort.t
+index a94f822..c16f4ea 100644
+--- a/t/024-access/client-abort.t
++++ b/t/024-access/client-abort.t
+@@ -850,4 +850,3 @@ delete thread 1
+ --- no_error_log
+ [error]
+ [alert]
+-
+diff --git a/t/024-access/exit.t b/t/024-access/exit.t
+index 8470ab9..d6d66b8 100644
+--- a/t/024-access/exit.t
++++ b/t/024-access/exit.t
+@@ -545,4 +545,3 @@ Not found, dear...
+ --- response_body
+ Not found, dear...
+ --- error_code: 404
+-
+diff --git a/t/024-access/multi-capture.t b/t/024-access/multi-capture.t
+index 368d401..930b74d 100644
+--- a/t/024-access/multi-capture.t
++++ b/t/024-access/multi-capture.t
+@@ -392,4 +392,3 @@ res4.status = 201
+ res4.body = STORED\r
+
+ "
+-
+diff --git a/t/024-access/on-abort.t b/t/024-access/on-abort.t
+index 0c17b55..5bb948b 100644
+--- a/t/024-access/on-abort.t
++++ b/t/024-access/on-abort.t
+@@ -649,4 +649,3 @@ delete thread 2
+
+ --- no_error_log
+ [error]
+-
+diff --git a/t/024-access/redirect.t b/t/024-access/redirect.t
+index c7ce512..b45fac7 100644
+--- a/t/024-access/redirect.t
++++ b/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/t/024-access/req-body.t b/t/024-access/req-body.t
+index fd33aff..70db85c 100644
+--- a/t/024-access/req-body.t
++++ b/t/024-access/req-body.t
+@@ -218,4 +218,3 @@ hiya, world"]
+ --- no_error_log
+ [error]
+ [alert]
+-
+diff --git a/t/024-access/request_body.t b/t/024-access/request_body.t
+index a6fead2..fa03195 100644
+--- a/t/024-access/request_body.t
++++ b/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/t/024-access/sanity.t b/t/024-access/sanity.t
+index de63a68..7ff177f 100644
+--- a/t/024-access/sanity.t
++++ b/t/024-access/sanity.t
+@@ -741,4 +741,3 @@ test
+ test
+ --- no_error_log
+ [alert]
+-
+diff --git a/t/024-access/satisfy.t b/t/024-access/satisfy.t
+index 10d3ece..7902f49 100644
+--- a/t/024-access/satisfy.t
++++ b/t/024-access/satisfy.t
+@@ -209,4 +209,3 @@ something important
+ --- error_code: 200
+ --- no_error_log
+ [error]
+-
+diff --git a/t/024-access/sleep.t b/t/024-access/sleep.t
+index 2eb0822..fc1fc02 100644
+--- a/t/024-access/sleep.t
++++ b/t/024-access/sleep.t
+@@ -219,4 +219,3 @@ hello world
+ hello world
+ --- no_error_log
+ [error]
+-
+diff --git a/t/024-access/subrequest.t b/t/024-access/subrequest.t
+index bfe96d6..b6ccf11 100644
+--- a/t/024-access/subrequest.t
++++ b/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/t/024-access/uthread-exec.t b/t/024-access/uthread-exec.t
+index d7c2321..7add3d4 100644
+--- a/t/024-access/uthread-exec.t
++++ b/t/024-access/uthread-exec.t
+@@ -344,4 +344,3 @@ free request
+ end
+ --- error_log
+ attempt to abort with pending subrequests
+-
+diff --git a/t/024-access/uthread-exit.t b/t/024-access/uthread-exit.t
+index da4a9db..7c146ae 100644
+--- a/t/024-access/uthread-exit.t
++++ b/t/024-access/uthread-exit.t
+@@ -1311,4 +1311,3 @@ free request
+ end
+ --- error_log
+ attempt to abort with pending subrequests
+-
+diff --git a/t/024-access/uthread-redirect.t b/t/024-access/uthread-redirect.t
+index 8b030ac..4eb4759 100644
+--- a/t/024-access/uthread-redirect.t
++++ b/t/024-access/uthread-redirect.t
+@@ -187,4 +187,3 @@ free request
+ --- error_code: 302
+ --- no_error_log
+ [error]
+-
+diff --git a/t/024-access/uthread-spawn.t b/t/024-access/uthread-spawn.t
+index 415e4c0..7c7ba3b 100644
+--- a/t/024-access/uthread-spawn.t
++++ b/t/024-access/uthread-spawn.t
+@@ -1116,4 +1116,3 @@ body: hello world)$
+
+ --- no_error_log
+ [error]
+-
+diff --git a/t/025-codecache.t b/t/025-codecache.t
+index f33452a..0b02a27 100644
+--- a/t/025-codecache.t
++++ b/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/t/026-mysql.t b/t/026-mysql.t
+index e14ffb6..569f96f 100644
+--- a/t/026-mysql.t
++++ b/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/t/027-multi-capture.t b/t/027-multi-capture.t
+index 3588c69..9227fe5 100644
+--- a/t/027-multi-capture.t
++++ b/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/t/029-http-time.t b/t/029-http-time.t
+index 71a7758..ecef492 100644
+--- a/t/029-http-time.t
++++ b/t/029-http-time.t
+@@ -85,4 +85,3 @@ GET /lua
+ GET /lua
+ --- response_body
+ nil
+-
+diff --git a/t/030-uri-args.t b/t/030-uri-args.t
+index 8ee8401..30d66d0 100644
+--- a/t/030-uri-args.t
++++ b/t/030-uri-args.t
+@@ -1389,4 +1389,3 @@ GET /lua
+ GET /foo?world
+ --- response_body_like
+ ^HTTP/1.0 (a=3&b|b&a=3)$
+-
+diff --git a/t/031-post-args.t b/t/031-post-args.t
+index c2b6b8f..62c88c1 100644
+--- a/t/031-post-args.t
++++ b/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/t/032-iolist.t b/t/032-iolist.t
+index ddf3d7f..3c56032 100644
+--- a/t/032-iolist.t
++++ b/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/t/033-ctx.t b/t/033-ctx.t
+index eefb216..8fc50aa 100644
+--- a/t/033-ctx.t
++++ b/t/033-ctx.t
+@@ -440,4 +440,3 @@ lua release ngx.ctx at ref
+ --- response_body
+ --- no_error_log
+ [error]
+-
+diff --git a/t/034-match.t b/t/034-match.t
+index 35149f1..ebe5762 100644
+--- a/t/034-match.t
++++ b/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/t/035-gmatch.t b/t/035-gmatch.t
+index 69b9512..5b63ae4 100644
+--- a/t/035-gmatch.t
++++ b/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/t/036-sub.t b/t/036-sub.t
+index f08c50f..2b4b075 100644
+--- a/t/036-sub.t
++++ b/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/t/037-gsub.t b/t/037-gsub.t
+index 2a1e00f..4c5810d 100644
+--- a/t/037-gsub.t
++++ b/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/t/038-match-o.t b/t/038-match-o.t
+index 628e27f..d61ff1f 100644
+--- a/t/038-match-o.t
++++ b/t/038-match-o.t
+@@ -740,4 +740,3 @@ false
+ hello
+ false
+ false
+-
+diff --git a/t/039-sub-o.t b/t/039-sub-o.t
+index a861b6c..580a671 100644
+--- a/t/039-sub-o.t
++++ b/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/t/040-gsub-o.t b/t/040-gsub-o.t
+index 90619b0..5347266 100644
+--- a/t/040-gsub-o.t
++++ b/t/040-gsub-o.t
+@@ -198,4 +198,3 @@ hello, world
+ --- response_body
+ [hello,h], [world,w]
+ 2
+-
+diff --git a/t/041-header-filter.t b/t/041-header-filter.t
+index 553ee43..9cca3b7 100644
+--- a/t/041-header-filter.t
++++ b/t/041-header-filter.t
+@@ -790,4 +790,3 @@ GET /t
+ --- error_code: 302
+ --- no_error_log
+ [error]
+-
+diff --git a/t/042-crc32.t b/t/042-crc32.t
+index 86d9201..73aa1f4 100644
+--- a/t/042-crc32.t
++++ b/t/042-crc32.t
+@@ -54,4 +54,3 @@ GET /test
+ GET /test
+ --- response_body
+ 0
+-
+diff --git a/t/045-ngx-var.t b/t/045-ngx-var.t
+index 8f2dcb3..b5fcc81 100644
+--- a/t/045-ngx-var.t
++++ b/t/045-ngx-var.t
+@@ -226,4 +226,3 @@ GET /test?hello
+ --- error_log
+ variable "query_string" not changeable
+ --- error_code: 500
+-
+diff --git a/t/046-hmac.t b/t/046-hmac.t
+index 686b479..32e222b 100644
+--- a/t/046-hmac.t
++++ b/t/046-hmac.t
+@@ -29,4 +29,3 @@ __DATA__
+ GET /lua
+ --- response_body
+ R/pvxzHC4NLtj7S+kXFg/NePTmk=
+-
+diff --git a/t/047-match-jit.t b/t/047-match-jit.t
+index 077ebb6..2417a63 100644
+--- a/t/047-match-jit.t
++++ b/t/047-match-jit.t
+@@ -212,4 +212,3 @@ end
+ GET /re
+ --- response_body
+ failed to match
+-
+diff --git a/t/048-match-dfa.t b/t/048-match-dfa.t
+index 8a0a328..28b5a60 100644
+--- a/t/048-match-dfa.t
++++ b/t/048-match-dfa.t
+@@ -207,4 +207,3 @@ exec opts: 0
+ 你
+ --- no_error_log
+ [error]
+-
+diff --git a/t/049-gmatch-jit.t b/t/049-gmatch-jit.t
+index 614c440..5134d52 100644
+--- a/t/049-gmatch-jit.t
++++ b/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/t/051-sub-jit.t b/t/051-sub-jit.t
+index 789e897..c8a49c0 100644
+--- a/t/051-sub-jit.t
++++ b/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/t/053-gsub-jit.t b/t/053-gsub-jit.t
+index 3a2a1aa..3efc0a2 100644
+--- a/t/053-gsub-jit.t
++++ b/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/t/055-subreq-vars.t b/t/055-subreq-vars.t
+index 2fc6960..eb5e24d 100644
+--- a/t/055-subreq-vars.t
++++ b/t/055-subreq-vars.t
+@@ -336,4 +336,3 @@ dog = hiya
+ cat = 56
+ parent dog: blah
+ parent cat: foo
+-
+diff --git a/t/056-flush.t b/t/056-flush.t
+index d189cd5..6b697a4 100644
+--- a/t/056-flush.t
++++ b/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/t/057-flush-timeout.t b/t/057-flush-timeout.t
+index d6e0f86..a046539 100644
+--- a/t/057-flush-timeout.t
++++ b/t/057-flush-timeout.t
+@@ -318,4 +318,3 @@ qr/failed to flush: client aborted/,
+ --- timeout: 0.2
+ --- abort
+ --- wait: 1
+-
+diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t
+index acf69f0..1ee113b 100644
+--- a/t/058-tcp-socket.t
++++ b/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/t/060-lua-memcached.t b/t/060-lua-memcached.t
+index e1ebb92..0751238 100644
+--- a/t/060-lua-memcached.t
++++ b/t/060-lua-memcached.t
+@@ -166,4 +166,3 @@ some_key: hello 1234
+ [error]
+ --- error_log
+ lua reuse free buf memory
+-
+diff --git a/t/061-lua-redis.t b/t/061-lua-redis.t
+index d7b1876..ebfa6d1 100644
+--- a/t/061-lua-redis.t
++++ b/t/061-lua-redis.t
+@@ -182,4 +182,3 @@ abort: function
+ msg type: nil
+ --- no_error_log
+ [error]
+-
+diff --git a/t/063-abort.t b/t/063-abort.t
+index c112ee1..411a07e 100644
+--- a/t/063-abort.t
++++ b/t/063-abort.t
+@@ -1017,4 +1017,3 @@ foo
+ --- no_error_log
+ [error]
+ --- timeout: 2
+-
+diff --git a/t/064-pcall.t b/t/064-pcall.t
+index cf90a07..3011f3e 100644
+--- a/t/064-pcall.t
++++ b/t/064-pcall.t
+@@ -104,4 +104,3 @@ $/
+
+ --- no_error_log
+ [error]
+-
+diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t
+index ec79891..212766e 100644
+--- a/t/065-tcp-socket-timeout.t
++++ b/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/t/066-socket-receiveuntil.t b/t/066-socket-receiveuntil.t
+index 3bf5229..ffe74aa 100644
+--- a/t/066-socket-receiveuntil.t
++++ b/t/066-socket-receiveuntil.t
+@@ -1329,4 +1329,3 @@ this exposed a memory leak in receiveuntil
+ ok
+ --- no_error_log
+ [error]
+-
+diff --git a/t/067-req-socket.t b/t/067-req-socket.t
+index 30a653a..229d5cc 100644
+--- a/t/067-req-socket.t
++++ b/t/067-req-socket.t
+@@ -1096,4 +1096,3 @@ done
+ --- grep_error_log_out
+ lua finalize socket
+ GC cycle done
+-
+diff --git a/t/069-null.t b/t/069-null.t
+index 7761c91..e4c26af 100644
+--- a/t/069-null.t
++++ b/t/069-null.t
+@@ -93,4 +93,3 @@ done
+ ngx.null: null
+ --- no_error_log
+ [error]
+-
+diff --git a/t/071-idle-socket.t b/t/071-idle-socket.t
+index 55d25c6..c9002be 100644
+--- a/t/071-idle-socket.t
++++ b/t/071-idle-socket.t
+@@ -431,4 +431,3 @@ failed to set keepalive: unread data in buffer
+ }
+ --- no_error_log
+ [error]
+-
+diff --git a/t/072-conditional-get.t b/t/072-conditional-get.t
+index 4bb567a..7cf2dcd 100644
+--- a/t/072-conditional-get.t
++++ b/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/t/073-backtrace.t b/t/073-backtrace.t
+index aae4bae..6c54692 100644
+--- a/t/073-backtrace.t
++++ b/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/t/074-prefix-var.t b/t/074-prefix-var.t
+index 3cc4587..c116d84 100644
+--- a/t/074-prefix-var.t
++++ b/t/074-prefix-var.t
+@@ -64,4 +64,3 @@ GET /t
+ Greetings from module foo.
+ --- no_error_log
+ [error]
+-
+diff --git a/t/075-logby.t b/t/075-logby.t
+index f987c8e..520c62e 100644
+--- a/t/075-logby.t
++++ b/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/t/077-sleep.t b/t/077-sleep.t
+index a7c251a..7d295c2 100644
+--- a/t/077-sleep.t
++++ b/t/077-sleep.t
+@@ -404,4 +404,3 @@ ok
+ --- no_error_log
+ [error]
+ [alert]
+-
+diff --git a/t/078-hup-vars.t b/t/078-hup-vars.t
+index 8acc346..5072c4d 100644
+--- a/t/078-hup-vars.t
++++ b/t/078-hup-vars.t
+@@ -62,4 +62,3 @@ GET /t
+ localhost
+ --- no_error_log
+ [error]
+-
+diff --git a/t/079-unused-directives.t b/t/079-unused-directives.t
+index cba0e41..aacd0d3 100644
+--- a/t/079-unused-directives.t
++++ b/t/079-unused-directives.t
+@@ -340,4 +340,3 @@ GET /t
+ sub: sub
+ --- no_error_log
+ [error]
+-
+diff --git a/t/080-hup-shdict.t b/t/080-hup-shdict.t
+index f9a0278..c762556 100644
+--- a/t/080-hup-shdict.t
++++ b/t/080-hup-shdict.t
+@@ -82,4 +82,3 @@ GET /test
+ 10502 number
+ --- no_error_log
+ [error]
+-
+diff --git a/t/083-bad-sock-self.t b/t/083-bad-sock-self.t
+index b93849f..7a76752 100644
+--- a/t/083-bad-sock-self.t
++++ b/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/t/084-inclusive-receiveuntil.t b/t/084-inclusive-receiveuntil.t
+index c966015..f7d5d3d 100644
+--- a/t/084-inclusive-receiveuntil.t
++++ b/t/084-inclusive-receiveuntil.t
+@@ -743,4 +743,3 @@ close: 1 nil
+ }
+ --- no_error_log
+ [error]
+-
+diff --git a/t/085-if.t b/t/085-if.t
+index e08b43c..33f57ca 100644
+--- a/t/085-if.t
++++ b/t/085-if.t
+@@ -198,4 +198,3 @@ GET /proxy-pass-uri
+ --- response_body_like: It works!
+ --- no_error_log
+ [error]
+-
+diff --git a/t/086-init-by.t b/t/086-init-by.t
+index 3a474fe..bea34a4 100644
+--- a/t/086-init-by.t
++++ b/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/t/087-udp-socket.t b/t/087-udp-socket.t
+index 79ba452..a847031 100644
+--- a/t/087-udp-socket.t
++++ b/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/t/088-req-method.t b/t/088-req-method.t
+index 9ced40c..198b3b3 100644
+--- a/t/088-req-method.t
++++ b/t/088-req-method.t
+@@ -262,4 +262,3 @@ method: PATCH
+ method: TRACE
+ --- no_error_log
+ [error]
+-
+diff --git a/t/089-phase.t b/t/089-phase.t
+index 57921fc..94b7619 100644
+--- a/t/089-phase.t
++++ b/t/089-phase.t
+@@ -176,4 +176,3 @@ GET /lua
+ init_worker
+ --- no_error_log
+ [error]
+-
+diff --git a/t/090-log-socket-errors.t b/t/090-log-socket-errors.t
+index a5943c2..8e498cd 100644
+--- a/t/090-log-socket-errors.t
++++ b/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/t/091-coroutine.t b/t/091-coroutine.t
+index b047ccb..bceb512 100644
+--- a/t/091-coroutine.t
++++ b/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/t/092-eof.t b/t/092-eof.t
+index a75711f..86778de 100644
+--- a/t/092-eof.t
++++ b/t/092-eof.t
+@@ -80,4 +80,3 @@ GET /t
+ --- error_log
+ hello, tom
+ hello, jim
+-
+diff --git a/t/093-uthread-spawn.t b/t/093-uthread-spawn.t
+index 772e866..b622d30 100644
+--- a/t/093-uthread-spawn.t
++++ b/t/093-uthread-spawn.t
+@@ -1672,4 +1672,3 @@ delete thread 2
+ f
+ --- no_error_log
+ [error]
+-
+diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t
+index cd678c0..a623773 100644
+--- a/t/094-uthread-exit.t
++++ b/t/094-uthread-exit.t
+@@ -1648,4 +1648,3 @@ free request
+ [alert]
+ [error]
+ [warn]
+-
+diff --git a/t/095-uthread-exec.t b/t/095-uthread-exec.t
+index 4459360..56156c4 100644
+--- a/t/095-uthread-exec.t
++++ b/t/095-uthread-exec.t
+@@ -423,4 +423,3 @@ attempt to abort with pending subrequests
+ --- no_error_log
+ [alert]
+ [warn]
+-
+diff --git a/t/096-uthread-redirect.t b/t/096-uthread-redirect.t
+index b0258fb..003c642 100644
+--- a/t/096-uthread-redirect.t
++++ b/t/096-uthread-redirect.t
+@@ -277,4 +277,3 @@ attempt to abort with pending subrequests
+ --- no_error_log
+ [alert]
+ [warn]
+-
+diff --git a/t/097-uthread-rewrite.t b/t/097-uthread-rewrite.t
+index 178a374..a93adc8 100644
+--- a/t/097-uthread-rewrite.t
++++ b/t/097-uthread-rewrite.t
+@@ -344,4 +344,3 @@ free request
+ end
+ --- error_log
+ attempt to abort with pending subrequests
+-
+diff --git a/t/098-uthread-wait.t b/t/098-uthread-wait.t
+index aaf020a..4948596 100644
+--- a/t/098-uthread-wait.t
++++ b/t/098-uthread-wait.t
+@@ -1321,4 +1321,3 @@ $s;
+ --- no_error_log
+ [error]
+ [alert]
+-
+diff --git a/t/100-client-abort.t b/t/100-client-abort.t
+index cd46859..89c1f6a 100644
+--- a/t/100-client-abort.t
++++ b/t/100-client-abort.t
+@@ -1064,4 +1064,3 @@ GET /t
+ eof succeeded
+ --- error_log
+ eof failed: nginx output filter error
+-
+diff --git a/t/101-on-abort.t b/t/101-on-abort.t
+index 81cec78..182d12c 100644
+--- a/t/101-on-abort.t
++++ b/t/101-on-abort.t
+@@ -846,4 +846,3 @@ done
+ client prematurely closed connection
+ on abort called
+ main handler done
+-
+diff --git a/t/102-req-start-time.t b/t/102-req-start-time.t
+index 1d5fe28..3b041af 100644
+--- a/t/102-req-start-time.t
++++ b/t/102-req-start-time.t
+@@ -113,4 +113,3 @@ true$
+ --- no_error_log
+ [error]
+ --- SKIP
+-
+diff --git a/t/103-req-http-ver.t b/t/103-req-http-ver.t
+index 6ded75a..e6de238 100644
+--- a/t/103-req-http-ver.t
++++ b/t/103-req-http-ver.t
+@@ -46,4 +46,3 @@ GET /t HTTP/1.0
+ 1
+ --- no_error_log
+ [error]
+-
+diff --git a/t/104-req-raw-header.t b/t/104-req-raw-header.t
+index 439b9de..efea03c 100644
+--- a/t/104-req-raw-header.t
++++ b/t/104-req-raw-header.t
+@@ -876,4 +876,3 @@ Foo: bar\r
+ --- no_error_log
+ [error]
+ --- timeout: 5
+-
+diff --git a/t/105-pressure.t b/t/105-pressure.t
+index 10f495e..9d1ba1f 100644
+--- a/t/105-pressure.t
++++ b/t/105-pressure.t
+@@ -51,4 +51,3 @@ $::Id = int rand 10000;
+
+ --- no_error_log
+ [error]
+-
+diff --git a/t/106-timer.t b/t/106-timer.t
+index d0f6f36..04a532e 100644
+--- a/t/106-timer.t
++++ b/t/106-timer.t
+@@ -2193,4 +2193,3 @@ ok
+ --- error_log
+ Bad bad bad
+ --- skip_nginx: 4: < 1.7.1
+-
+diff --git a/t/107-timer-errors.t b/t/107-timer-errors.t
+index 9ed1334..3201612 100644
+--- a/t/107-timer-errors.t
++++ b/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/t/108-timer-safe.t b/t/108-timer-safe.t
+index 19c9f6d..2795998 100644
+--- a/t/108-timer-safe.t
++++ b/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/t/109-timer-hup.t b/t/109-timer-hup.t
+index 15aaa0e..0864046 100644
+--- a/t/109-timer-hup.t
++++ b/t/109-timer-hup.t
+@@ -500,4 +500,3 @@ ok
+ --- grep_error_log_out
+ lua found 8191 pending timers
+ --- timeout: 20
+-
+diff --git a/t/110-etag.t b/t/110-etag.t
+index 351fec4..0a94d3d 100644
+--- a/t/110-etag.t
++++ b/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/t/111-req-header-ua.t b/t/111-req-header-ua.t
+index 7c980d0..9e501e3 100644
+--- a/t/111-req-header-ua.t
++++ b/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/t/112-req-header-conn.t b/t/112-req-header-conn.t
+index 51df730..51bc8a4 100644
+--- a/t/112-req-header-conn.t
++++ b/t/112-req-header-conn.t
+@@ -146,4 +146,3 @@ content: conn type: 0
+ connection: bad
+ --- no_error_log
+ [error]
+-
+diff --git a/t/113-req-header-cookie.t b/t/113-req-header-cookie.t
+index b26b709..4a93053 100644
+--- a/t/113-req-header-cookie.t
++++ b/t/113-req-header-cookie.t
+@@ -247,4 +247,3 @@ Cookie: boo=123; foo=bar
+
+ --- no_error_log
+ [error]
+-
+diff --git a/t/115-quote-sql-str.t b/t/115-quote-sql-str.t
+index 0c20dfb..66553b1 100644
+--- a/t/115-quote-sql-str.t
++++ b/t/115-quote-sql-str.t
+@@ -74,4 +74,3 @@ GET /set
+ 'a\Zb\Z'
+ --- no_error_log
+ [error]
+-
+diff --git a/t/116-raw-req-socket.t b/t/116-raw-req-socket.t
+index 6518f0e..ab06ee4 100644
+--- a/t/116-raw-req-socket.t
++++ b/t/116-raw-req-socket.t
+@@ -876,4 +876,3 @@ request body: hey, hello world
+ --- no_error_log
+ [error]
+ [alert]
+-
+diff --git a/t/117-raw-req-socket-timeout.t b/t/117-raw-req-socket-timeout.t
+index 4e3929b..07abadc 100644
+--- a/t/117-raw-req-socket-timeout.t
++++ b/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/t/119-config-prefix.t b/t/119-config-prefix.t
+index 4581aa1..3f79320 100644
+--- a/t/119-config-prefix.t
++++ b/t/119-config-prefix.t
+@@ -30,4 +30,3 @@ GET /lua
+ ^prefix: \/\S+$
+ --- no_error_log
+ [error]
+-
+diff --git a/t/120-re-find.t b/t/120-re-find.t
+index 34c0207..73e6134 100644
+--- a/t/120-re-find.t
++++ b/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/t/121-version.t b/t/121-version.t
+index 2b7a306..9000eb3 100644
+--- a/t/121-version.t
++++ b/t/121-version.t
+@@ -46,4 +46,3 @@ GET /lua
+ ^version: \d+$
+ --- no_error_log
+ [error]
+-
+diff --git a/t/122-worker.t b/t/122-worker.t
+index fa42b1d..b74c81f 100644
+--- a/t/122-worker.t
++++ b/t/122-worker.t
+@@ -79,4 +79,3 @@ worker pid: \d+
+ worker pid is correct\.
+ --- no_error_log
+ [error]
+-
+diff --git a/t/123-lua-path.t b/t/123-lua-path.t
+index da97909..23681a9 100644
+--- a/t/123-lua-path.t
++++ b/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/t/124-init-worker.t b/t/124-init-worker.t
+index d6ea675..22a943e 100644
+--- a/t/124-init-worker.t
++++ b/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/t/125-configure-args.t b/t/125-configure-args.t
+index adec129..4160d4e 100644
+--- a/t/125-configure-args.t
++++ b/t/125-configure-args.t
+@@ -29,4 +29,3 @@ GET /configure_args
+ ^\s*\-\-[^-]+
+ --- no_error_log
+ [error]
+-
+diff --git a/t/126-shdict-frag.t b/t/126-shdict-frag.t
+index 94422fb..5a2aff8 100644
+--- a/t/126-shdict-frag.t
++++ b/t/126-shdict-frag.t
+@@ -1264,4 +1264,3 @@ ok
+ --- no_error_log
+ [error]
+ --- timeout: 60
+-
+diff --git a/t/127-uthread-kill.t b/t/127-uthread-kill.t
+index 2ab8abe..cc43c62 100644
+--- a/t/127-uthread-kill.t
++++ b/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/t/128-duplex-tcp-socket.t b/t/128-duplex-tcp-socket.t
+index d3ef3f5..e8434a3 100644
+--- a/t/128-duplex-tcp-socket.t
++++ b/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/t/129-ssl-socket.t b/t/129-ssl-socket.t
+index 9da9a5c..726b442 100644
+--- a/t/129-ssl-socket.t
++++ b/t/129-ssl-socket.t
+@@ -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;
+@@ -202,7 +202,7 @@ 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;
+@@ -280,7 +280,7 @@ SSL reused session
+ === TEST 4: ssl session reuse
+ --- 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;
+@@ -374,7 +374,7 @@ lua ssl free session
+ The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.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 {
+@@ -453,7 +453,7 @@ SSL reused session
+ The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.org".
+ --- config
+ server_tokens off;
+- resolver $TEST_NGINX_RESOLVER;
++ resolver $TEST_NGINX_RESOLVER ipv6=off;
+ lua_ssl_trusted_certificate ../html/trusted.crt;
+ lua_socket_log_errors off;
+ lua_ssl_verify_depth 2;
+@@ -532,7 +532,7 @@ SSL reused session
+ === TEST 7: certificate does not match host name (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;
+@@ -611,7 +611,7 @@ SSL reused session
+ === TEST 8: iscribblet.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 {
+@@ -696,7 +696,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 {
+@@ -774,7 +774,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;
+@@ -1033,7 +1033,7 @@ SSL reused session
+ === TEST 13: iscribblet.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 {
+@@ -1119,7 +1119,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;
+@@ -1198,7 +1198,7 @@ SSL reused session
+ === TEST 15: explicit cipher configuration
+ --- config
+ server_tokens off;
+- resolver $TEST_NGINX_RESOLVER;
++ resolver $TEST_NGINX_RESOLVER ipv6=off;
+ lua_ssl_ciphers RC4-SHA;
+ location /t {
+ #set $port 5000;
+@@ -1278,7 +1278,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;
+@@ -1358,7 +1358,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 {
+@@ -1435,7 +1435,7 @@ SSL reused session
+ === TEST 18: iscribblet.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 {
+@@ -1512,7 +1512,7 @@ SSL reused session
+ === TEST 19: iscribblet.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 {
+@@ -1592,7 +1592,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 {
+@@ -1647,7 +1647,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 +1750,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 +1854,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 +1946,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 +2031,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;
+@@ -2115,7 +2115,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;
+@@ -2183,7 +2183,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 +2254,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 +2328,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 +2405,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 +2510,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 +2589,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;
+@@ -2614,7 +2614,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/t/130-internal-api.t b/t/130-internal-api.t
+index d641ab5..eba0980 100644
+--- a/t/130-internal-api.t
++++ b/t/130-internal-api.t
+@@ -47,4 +47,3 @@ content req=0x[a-f0-9]{4,}
+ $
+ --- no_error_log
+ [error]
+-
+diff --git a/t/137-req-misc.t b/t/137-req-misc.t
+index 20ada3c..d56f80e 100644
+--- a/t/137-req-misc.t
++++ b/t/137-req-misc.t
+@@ -59,4 +59,3 @@ not internal
+ GET /test
+ --- response_body
+ internal
+-
+diff --git a/t/138-balancer.t b/t/138-balancer.t
+index 8d45c24..fc26173 100644
+--- a/t/138-balancer.t
++++ b/t/138-balancer.t
+@@ -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/t/140-ssl-c-api.t b/t/140-ssl-c-api.t
+index 44ad93d..854ff30 100644
+--- a/t/140-ssl-c-api.t
++++ b/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
+@@ -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
+diff --git a/t/141-luajit.t b/t/141-luajit.t
+index be03fe3..36418d1 100644
+--- a/t/141-luajit.t
++++ b/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/t/142-ssl-session-store.t b/t/142-ssl-session-store.t
+index 5c9fad3..73b6e19 100644
+--- a/t/142-ssl-session-store.t
++++ b/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/t/143-ssl-session-fetch.t b/t/143-ssl-session-fetch.t
+index bd800ff..701ead7 100644
+--- a/t/143-ssl-session-fetch.t
++++ b/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/t/146-malloc-trim.t b/t/146-malloc-trim.t
+index 45fb9f2..fc425ce 100644
+--- a/t/146-malloc-trim.t
++++ b/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/t/147-tcp-socket-timeouts.t b/t/147-tcp-socket-timeouts.t
+index 52f015a..0689a9b 100644
+--- a/t/147-tcp-socket-timeouts.t
++++ b/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/t/150-fake-delayed-load.t b/t/150-fake-delayed-load.t
+new file mode 100644
+index 0000000..232bbf3
+--- /dev/null
++++ b/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/t/151-initby-hup.t b/t/151-initby-hup.t
+new file mode 100644
+index 0000000..f278867
+--- /dev/null
++++ b/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/t/data/fake-delayed-load-module/config b/t/data/fake-delayed-load-module/config
+new file mode 100644
+index 0000000..a5fa6fb
+--- /dev/null
++++ b/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/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c b/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c
+new file mode 100644
+index 0000000..2898255
+--- /dev/null
++++ b/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 <ngx_config.h>
++#include <ngx_core.h>
++#include <ngx_http.h>
++#include <nginx.h>
++
++
++#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/t/data/fake-module/ngx_http_fake_module.c b/t/data/fake-module/ngx_http_fake_module.c
+index 42cde55..650f4f7 100644
+--- a/t/data/fake-module/ngx_http_fake_module.c
++++ b/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/util/build.sh b/util/build.sh
+index 7887fe9..e45c00a 100755
+--- a/util/build.sh
++++ b/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/util/reindex b/util/reindex
+index bd54c9d..d0a0927 100755
+--- a/util/reindex
++++ b/util/reindex
+@@ -1,8 +1,7 @@
+-#!/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
++#!/usr/bin/env perl
++
++#: reindexes .t files for Test::Base based test files
++#: Copyright (c) Yichun Zhang
+
+ use strict;
+ use warnings;
+@@ -44,7 +43,9 @@ sub reindex {
+ push @lines, $_;
+ }
+ close $in;
++
+ my $text = join '', @lines;
++ $text =~ s/\n\n+\z/\n/sm;
+ $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;
+diff --git a/valgrind.suppress b/valgrind.suppress
+index fe161e8..d0bcc56 100644
+--- a/valgrind.suppress
++++ b/valgrind.suppress
+@@ -149,3 +149,18 @@ fun:main
+ fun:__libc_res_nquerydomain
+ fun:__libc_res_nsearch
+ }
++{
++ <insert_a_suppression_name_here>
++ Memcheck:Leak
++ match-leak-kinds: definite
++ fun:malloc
++ fun:ngx_alloc
++ fun:ngx_set_environment
++ fun:ngx_single_process_cycle
++ fun:main
++}
++{
++ <insert_a_suppression_name_here>
++ Memcheck:Cond
++ obj:*
++}
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..b7b515b 100644
--- a/debian/modules/patches/nginx-lua/openssl-1.1.0.patch
+++ b/debian/modules/patches/nginx-lua/openssl-1.1.0.patch
@@ -935,7 +935,7 @@
@@ -1199,7 +1199,7 @@ SSL reused session
--- config
server_tokens off;
- resolver $TEST_NGINX_RESOLVER;
+ resolver $TEST_NGINX_RESOLVER ipv6=off;
- lua_ssl_ciphers RC4-SHA;
+ lua_ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256;
location /t {
diff --git a/debian/modules/patches/nginx-lua/series b/debian/modules/patches/nginx-lua/series
index ed0d540..cb106b4 100644
--- a/debian/modules/patches/nginx-lua/series
+++ b/debian/modules/patches/nginx-lua/series
@@ -1 +1,2 @@
+lua-update.patch
openssl-1.1.0.patch
--
To view, visit https://gerrit.wikimedia.org/r/350178
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I1a82df8da0d0fe8b1dc3612eff19a7996434491e
Gerrit-PatchSet: 1
Gerrit-Project: operations/software/nginx
Gerrit-Branch: wmf-1.11.10
Gerrit-Owner: BBlack <***@wikimedia.org>
Change subject: nginx lua module fixups
......................................................................
nginx lua module fixups
New patch: update upstream source from 0.10.7 to 0.10.8, and then
past that a few commits in master for nginx-1.11.x build fixups.
Updated OpenSSL-1.1.0 patch to account for a minor conflict with
the above.
Change-Id: I1a82df8da0d0fe8b1dc3612eff19a7996434491e
---
A debian/modules/patches/nginx-lua/lua-update.patch
M debian/modules/patches/nginx-lua/openssl-1.1.0.patch
M debian/modules/patches/nginx-lua/series
3 files changed, 5,777 insertions(+), 1 deletion(-)
git pull ssh://gerrit.wikimedia.org:29418/operations/software/nginx refs/changes/78/350178/1
diff --git a/debian/modules/patches/nginx-lua/lua-update.patch b/debian/modules/patches/nginx-lua/lua-update.patch
new file mode 100644
index 0000000..2306efc
--- /dev/null
+++ b/debian/modules/patches/nginx-lua/lua-update.patch
@@ -0,0 +1,5775 @@
+# This updates from debian's 0.10.7 to master a few commits past 0.10.8 (to include latest nginx-1.11 fixups)
+# --bblack
+
+diff --git a/README.markdown b/README.markdown
+index 3699a72..16d56bf 100644
+--- a/README.markdown
++++ b/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.8](https://github.com/openresty/lua-nginx-module/tags) released on 8 April 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)
+@@ -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.
++
++```lua
++
++ -- Avoid
++ foo = 123
++ -- Recomended
++ local foo = 123
++
++ -- Avoid
++ function foo() return 123 end
++ -- Recomended
++ local function foo() return 123 end
++```
+
+-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:
++
++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.
+@@ -886,7 +921,7 @@ servers in Lua. For example,
+ 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>
+
+@@ -957,7 +992,7 @@ This module is licensed under the BSD license.
+
+ Copyright (C) 2009-2016, by Xiaozhe Wang (chaoslawful) <***@gmail.com>.
+
+-Copyright (C) 2009-2016, by Yichun "agentzh" Zhang (章亦春) <***@gmail.com>, CloudFlare Inc.
++Copyright (C) 2009-2017, by Yichun "agentzh" Zhang (章亦春) <***@gmail.com>, OpenResty Inc.
+
+ All rights reserved.
+
+@@ -1082,7 +1117,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 +1188,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 +1211,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 +1278,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 `<lua-script-str>` on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file.
+
+@@ -1358,7 +1394,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).
+
+@@ -1447,7 +1483,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 `<lua-script-str>` with optional input arguments `$arg1 $arg2 ...`, and returns string output to `$res`.
+ The code in `<lua-script-str>` 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 +1573,15 @@ set_by_lua_file
+
+ **phase:** *rewrite*
+
+-Equivalent to [set_by_lua](#set_by_lua), except that the file specified by `<path-to-lua-script-file>` 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 `<path-to-lua-script-file>` 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 `<path-to-lua-script-file>` 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 +1597,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 `<lua-script-str>` for every request.
++Acts as a "content handler" and executes Lua code string specified in `<lua-script-str>` 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 +1648,16 @@ Nginx variables can be used in the `<path-to-lua-script-file>` 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 +1678,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 `<lua-script-str>` 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 +1854,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 `<lua-script-str>` 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 +1966,7 @@ Nginx variables can be used in the `<path-to-lua-script-file>` 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 +1983,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 `<lua-script-str>` to define an output header filter.
+
+@@ -2029,8 +2061,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 `<lua-script-str>` to define an output body filter.
+
+@@ -2166,15 +2197,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 `<lua-script-str>` 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 +2913,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 +2981,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`).
+
+@@ -3280,7 +3310,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 +3468,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 +3571,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 +3579,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 <code>ctx</code> variable is on the Lua module level
+ -- and thus is per-nginx-worker.
+ local ctx = ngx.ctx
+
+@@ -3701,7 +3731,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 +3798,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 +3883,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 +4023,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 +4055,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 +4566,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 +4627,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 +5029,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 +5268,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 +5282,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 +5290,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...
+ }
+ }
+@@ -6006,7 +6037,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
+
+@@ -6495,7 +6526,7 @@ Fetch a list of the keys from the dictionary, up to `<max_count>`.
+
+ By default, only the first 1024 keys (if any) are returned. When the `<max_count>` 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 +7311,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
+
+diff --git a/config b/config
+index 01a6b3c..5d2ee65 100644
+--- a/config
++++ b/config
+@@ -472,33 +472,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 <unistd.h>
+-#include <stdlib.h>
+-#include <stdint.h>
+-#include <sys/mman.h>
+-#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/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki
+index be454af..e496672 100644
+--- a/doc/HttpLuaModule.wiki
++++ b/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.8] released on 8 April 2017.
+
+ = Synopsis =
+ <geshi lang="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()
+@@ -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: <code>./configure --with-luajit && make && make install</code>.
++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
+ </geshi>
+
+ == 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 <code>--add-dynamic-module=PATH</code> option instead of <code>--add-module=PATH</code> on the
++<code>./configure</code> command line above. And then you can explicitly load the module in your <code>nginx.conf</code> via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module)
+ directive, for example,
+
+-```nginx
++<geshi lang="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;
+-```
++</geshi>
+
+ == C Macro Configurations ==
+
+@@ -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 <code>success</code> despite connection failures such as with <code>Connection Refused</code> errors.
++The [[#tcpsock:connect|tcpsock:connect]] method may indicate <code>success</code> despite connection failures such as with <code>Connection Refused</code> 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 <code>require()</code> built-in in the <code>package.loaded</code> table for later reference, and the <code>module()</code> 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 <code>nil</code> 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:
++
++# 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 is therefore *highly* recommended to always declare such within an appropriate local scope instead.
++
++<geshi lang="lua">
++ -- Avoid
++ foo = 123
++ -- Recomended
++ local foo = 123
+
+-# 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.
++ -- Avoid
++ function foo() return 123 end
++ -- Recomended
++ local function foo() return 123 end
++</geshi>
+
+-It's *highly* recommended to always declare them via "local" in the scope that is reasonable.
+
+-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:
++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 <code>.lua</code> source files:
+ <geshi lang="text">
+ $ 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
+-<code>*_by_lua_block {}</code> configuration directives.
++'''NOTE''' Following the <code>v0.9.17</code> release, this pitfall can be avoided by using the <code>*_by_lua_block {}</code> configuration directives.
+
+-PCRE sequences such as <code>\d</code>, <code>\s</code>, or <code>\w</code>, require special attention because in string literals, the backslash character, <code>\</code>, 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 <code>\d</code>, <code>\s</code>, or <code>\w</code>, require special attention because in string literals, the backslash character, <code>\</code>, is stripped out by both the Lua language parser and by the nginx config file parser before processing if not within a <code>*_by_lua_block {}</code> directive. So the following snippet will not work as expected:
+
+ <geshi lang="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
+ ? ';
+@@ -606,7 +624,7 @@ To avoid this, ''double'' escape the backslash:
+
+ Here, <code>\\\\d+</code> is stripped down to <code>\\d+</code> by the Nginx config file parser and this is further stripped down to <code>\d+</code> 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", <code>[[...]]</code>, 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", <code>[[...]]</code>, in which case backslashes have to only be escaped once for the Nginx config file parser.
+
+ <geshi lang="nginx">
+ # nginx.conf
+@@ -622,7 +640,7 @@ Alternatively, the regex pattern can be presented as a long-bracketed Lua string
+
+ Here, <code>[[\\d+]]</code> is stripped down to <code>[[\d+]]</code> by the Nginx config file parser and this is processed correctly.
+
+-Note that a longer from of the long bracket, <code>[=[...]=]</code>, may be required if the regex pattern contains <code>[...]</code> sequences.
++Note that a longer from of the long bracket, <code>[=[...]=]</code>, may be required if the regex pattern contains <code>[...]</code> sequences.
+ The <code>[=[...]=]</code> form may be used as the default form if desired.
+
+ <geshi lang="nginx">
+@@ -637,7 +655,7 @@ The <code>[=[...]=]</code> form may be used as the default form if desired.
+ # evaluates to "1234"
+ </geshi>
+
+-An alternative approach to escaping PCRE sequences is to ensure that Lua code is placed in external script files and executed using the various <code>*_by_lua_file</code> 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 <code>*_by_lua_file</code> directives.
+ With this approach, the backslashes are only stripped by the Lua language parser and therefore only need to be escaped once each.
+
+ <geshi lang="lua">
+@@ -648,8 +666,8 @@ With this approach, the backslashes are only stripped by the Lua language parser
+ -- evaluates to "1234"
+ </geshi>
+
+-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.
++
+ <geshi lang="lua">
+ -- test.lua
+ local regex = [[\d+]]
+@@ -658,6 +676,21 @@ Within external script files, PCRE sequences presented as long-bracketed Lua str
+ -- evaluates to "1234"
+ </geshi>
+
++As noted earlier, PCRE sequences presented within <code>*_by_lua_block {}</code> directives (available following the <code>v0.9.17</code> release) do not require modification.
++
++<geshi lang="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"
++</geshi>
++
++
+ == 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 <code>connect</code> 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 <code>bsdrecv</code> method.
+ * add new API function <code>ngx.resp.add_header</code> to emulate the standard <code>add_header</code> config directive.
+-* review and apply Jader H. Silva's patch for <code>ngx.re.split()</code>.
+ * review and apply vadim-pavlov's patch for [[#ngx.location.capture|ngx.location.capture]]'s <code>extra_headers</code> option
+ * use <code>ngx_hash_t</code> 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.
+@@ -717,7 +749,7 @@ servers in Lua. For example,
+
+ = 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
+ </geshi>
+
+-To run a specific test block in a particular test file, add the line <code>--- ONLY</code> to the test block you want to run, and then use the `prove` utility to run that <code>.t</code> file.
++To run a specific test block in a particular test file, add the line <code>--- ONLY</code> to the test block you want to run, and then use the <code>prove</code> utility to run that <code>.t</code> 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.
+
+@@ -782,7 +814,7 @@ This module is licensed under the BSD license.
+
+ Copyright (C) 2009-2016, by Xiaozhe Wang (chaoslawful) <***@gmail.com>.
+
+-Copyright (C) 2009-2016, by Yichun "agentzh" Zhang (章亦春) <***@gmail.com>, CloudFlare Inc.
++Copyright (C) 2009-2017, by Yichun "agentzh" Zhang (章亦春) <***@gmail.com>, OpenResty Inc.
+
+ All rights reserved.
+
+@@ -834,7 +866,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 <code>Content-Type</code> response header. If you do not want a default <code>Content-Type</code> 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 <code>Content-Type</code> response header. Deactivate this directive if a default <code>Content-Type</code> response header for Lua request handlers is not desired.
+
+ This directive is turned on by default.
+
+@@ -898,8 +930,8 @@ The ngx_lua module does not support the <code>stat</code> mode available with th
+ Apache <code>mod_lua</code> 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 <num>''
+@@ -918,6 +950,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), ...
+ </geshi>
+
++If you are using the <code>ngx.re.*</code> implementation of [lua-resty-core](https://github.com/openresty/lua-resty-core) by loading the <code>resty.core.regex</code> module (or just the <code>resty.core</code> module), then an LRU cache is used for the regex cache being used here.
++
+ Do not activate the <code>o</code> option for regular expressions (and/or <code>replace</code> 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 +1005,7 @@ As from the <code>v0.5.0rc29</code> release, the special notation <code>$prefix<
+
+ '''phase:''' ''loading-config''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> release. Use the [[#init_by_lua_block|init_by_lua_block]] directive instead.
+
+ Runs the Lua code specified by the argument <code><lua-script-str></code> on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file.
+
+@@ -1041,7 +1074,7 @@ This directive was first introduced in the <code>v0.5.5</code> 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 (<code>{}</code>) instead of in an NGINX string literal (which requires
+ special character escaping).
+
+ For instance,
+@@ -1076,7 +1109,7 @@ This directive was first introduced in the <code>v0.5.5</code> release.
+
+ '''phase:''' ''starting-worker''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> 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*]].
+
+@@ -1121,7 +1154,7 @@ This directive was first introduced in the <code>v0.9.5</code> 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 (<code>{}</code>) instead of in an NGINX string literal (which requires
+ special character escaping).
+
+ For instance,
+@@ -1154,7 +1187,7 @@ This directive was first introduced in the <code>v0.9.5</code> release.
+
+ '''phase:''' ''rewrite''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> release. Use the [[#set_by_lua_block|set_by_lua_block]] directive instead.
+
+ Executes code specified in <code><lua-script-str></code> with optional input arguments <code>$arg1 $arg2 ...</code>, and returns string output to <code>$res</code>.
+ The code in <code><lua-script-str></code> can make [[#Nginx API for Lua|API calls]] and can retrieve input arguments from the <code>ngx.arg</code> table (index starts from <code>1</code> and increases sequentially).
+@@ -1177,15 +1210,15 @@ a time. However, a workaround is possible using the [[#ngx.var.VARIABLE|ngx.var.
+ <geshi lang="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";
+ }
+ </geshi>
+@@ -1213,7 +1246,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 (<code>{}</code>) 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 +1268,15 @@ This directive was first introduced in the <code>v0.9.17</code> release.
+
+ '''phase:''' ''rewrite''
+
+-Equivalent to [[#set_by_lua|set_by_lua]], except that the file specified by <code><path-to-lua-script-file></code> contains the Lua code, or, as from the <code>v0.5.0rc32</code> 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 <code><path-to-lua-script-file></code> contains the Lua code, or, as from the <code>v0.5.0rc32</code> release, the [[#Lua/LuaJIT bytecode support|Lua/LuaJIT bytecode]] to be executed.
+
+ Nginx variable interpolation is supported in the <code><path-to-lua-script-file></code> argument string of this directive. But special care must be taken for injection attacks.
+
+ When a relative path like <code>foo/bar.lua</code> is given, they will be turned into the absolute path relative to the <code>server prefix</code> path determined by the <code>-p PATH</code> 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]] <code>off</code> in <code>nginx.conf</code> to avoid reloading Nginx.
+
+ This directive requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_kit] module.
+@@ -1256,10 +1289,9 @@ This directive requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_ki
+
+ '''phase:''' ''content''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> 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 <code><lua-script-str></code> for every request.
++Acts as a "content handler" and executes Lua code string specified in <code><lua-script-str></code> 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 +1306,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 (<code>{}</code>) instead of in an NGINX string literal (which requires
+ special character escaping).
+
+ For instance,
+@@ -1301,15 +1333,15 @@ Nginx variables can be used in the <code><path-to-lua-script-file></code> string
+
+ When a relative path like <code>foo/bar.lua</code> is given, they will be turned into the absolute path relative to the <code>server prefix</code> path determined by the <code>-p PATH</code> 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]] <code>off</code> in <code>nginx.conf</code> to avoid reloading Nginx.
+
+ Nginx variables are supported in the file path for dynamic dispatch, for example:
+
+ <geshi lang="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;
+@@ -1327,8 +1359,7 @@ But be very careful about malicious user inputs and always carefully validate or
+
+ '''phase:''' ''rewrite tail''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> 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 <code><lua-script-str></code> 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 +1407,7 @@ The right way of doing this is as follows:
+ return ngx.redirect("/bar");
+ end
+ ';
+-
++
+ echo "res = $b";
+ }
+ </geshi>
+@@ -1388,11 +1419,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 ...;
+ }
+ </geshi>
+@@ -1404,7 +1435,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 +1443,7 @@ can be implemented in ngx_lua as:
+ return ngx.redirect("/terms-of-use.html")
+ end
+ ';
+-
++
+ fastcgi_pass ...;
+ }
+ </geshi>
+@@ -1447,7 +1478,7 @@ The <code>rewrite_by_lua</code> code will always run at the end of the <code>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 (<code>{}</code>) instead of in an NGINX string literal (which requires
+ special character escaping).
+
+ For instance,
+@@ -1488,8 +1519,7 @@ Nginx variables are supported in the file path for dynamic dispatch just as in [
+
+ '''phase:''' ''access tail''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> 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 <code><lua-script-str></code> 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 +1532,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/...
+ }
+ </geshi>
+@@ -1519,7 +1549,7 @@ Note that the [http://mdounin.ru/hg/ngx_http_auth_request_module/ ngx_auth_reque
+ <geshi lang="nginx">
+ location / {
+ auth_request /auth;
+-
++
+ # proxy_pass/fastcgi_pass/postgres_pass/...
+ }
+ </geshi>
+@@ -1530,18 +1560,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/...
+ }
+ </geshi>
+@@ -1564,7 +1594,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 (<code>{}</code>) instead of in an NGINX string literal (which requires
+ special character escaping).
+
+ For instance,
+@@ -1591,7 +1621,7 @@ Nginx variables can be used in the <code><path-to-lua-script-file></code> string
+
+ When a relative path like <code>foo/bar.lua</code> is given, they will be turned into the absolute path relative to the <code>server prefix</code> path determined by the <code>-p PATH</code> 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]] <code>off</code> in <code>nginx.conf</code> to avoid repeatedly reloading Nginx.
+
+@@ -1605,8 +1635,7 @@ Nginx variables are supported in the file path for dynamic dispatch just as in [
+
+ '''phase:''' ''output-header-filter''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> release. Use the [[#header_filter_by_lua_block|header_filter_by_lua_block]] directive instead.
+
+ Uses Lua code specified in <code><lua-script-str></code> to define an output header filter.
+
+@@ -1638,7 +1667,7 @@ This directive was first introduced in the <code>v0.2.1rc20</code> 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 (<code>{}</code>) instead of in an NGINX string literal (which requires
+ special character escaping).
+
+ For instance,
+@@ -1673,8 +1702,7 @@ This directive was first introduced in the <code>v0.2.1rc20</code> release.
+
+ '''phase:''' ''output-body-filter''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> release. Use the [[#body_filter_by_lua_block|body_filter_by_lua_block]] directive instead.
+
+ Uses Lua code specified in <code><lua-script-str></code> to define an output body filter.
+
+@@ -1761,7 +1789,7 @@ This directive was first introduced in the <code>v0.5.0rc32</code> 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 (<code>{}</code>) instead of in an NGINX string literal (which requires
+ special character escaping).
+
+ For instance,
+@@ -1796,15 +1824,14 @@ This directive was first introduced in the <code>v0.5.0rc32</code> release.
+
+ '''phase:''' ''log''
+
+-'''WARNING''' Since the <code>v0.9.17</code> 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 <code>v0.9.17</code> release. Use the [[#log_by_lua_block|log_by_lua_block]] directive instead.
+
+ Runs the Lua source code inlined as the <code><lua-script-str></code> at the <code>log</code> 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 +1865,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 +1889,7 @@ This directive was first introduced in the <code>v0.5.0rc31</code> 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 (<code>{}</code>) instead of in an NGINX string literal (which requires
+ special character escaping).
+
+ For instance,
+@@ -2430,7 +2457,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 <code>Content-Length</code> 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 <code>Content-Length</code> response header.
+
+ If the Lua code explicitly sets a <code>Content-Length</code> 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 +2513,7 @@ This directive was first introduced in the <code>v0.5.0rc32</code> 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 <code>nil</code>).
+
+@@ -2592,11 +2619,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;
+ }
+ </geshi>
+@@ -2646,7 +2673,7 @@ Setting <code>ngx.var.Foo</code> to a <code>nil</code> value will unset the <cod
+ ngx.var.args = nil
+ </geshi>
+
+-'''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,
+
+ <geshi lang="lua">
+ local val = ngx.var.some_var
+@@ -2655,7 +2682,7 @@ Setting <code>ngx.var.Foo</code> to a <code>nil</code> value will unset the <cod
+
+ to prevent (temporary) memory leaking within the current request's lifetime. Another way of caching the result is to use the [[#ngx.ctx|ngx.ctx]] table.
+
+-Undefined NGINX variables are evaluated to `nil` while uninitialized (but defined) NGINX variables are evaluated to an empty Lua string.
++Undefined NGINX variables are evaluated to <code>nil</code> 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 +2807,7 @@ There is a hard coded <code>2048</code> 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 +2843,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 +2874,7 @@ Internal redirection will destroy the original request <code>ngx.ctx</code> data
+ ngx.say(ngx.ctx.foo)
+ }
+ }
+-
++
+ location /orig {
+ content_by_lua_block {
+ ngx.ctx.foo = "hello"
+@@ -2876,14 +2903,14 @@ When being used in the context of [[#init_worker_by_lua|init_worker_by_lua*]], t
+
+ The <code>ngx.ctx</code> 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 <code>ngx.ctx</code> 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 <code>ngx.ctx</code> 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:
+
+ <geshi lang="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
++-- data while this <code>ctx</code> variable is on the Lua module level
+ -- and thus is per-nginx-worker.
+ local ctx = ngx.ctx
+
+@@ -2907,7 +2934,7 @@ end
+ return _M
+ </geshi>
+
+-That is, let the caller pass the `ctx` table explicitly via a function argument.
++That is, let the caller pass the <code>ctx</code> table explicitly via a function argument.
+
+ == ngx.location.capture ==
+ '''syntax:''' ''res = ngx.location.capture(uri, options?)''
+@@ -3024,7 +3051,7 @@ The <code>args</code> option can also take plain query strings:
+
+ This is functionally identical to the previous examples.
+
+-The <code>share_all_vars</code> option controls whether to share nginx variables among the current request and its subrequests.
++The <code>share_all_vars</code> option controls whether to share nginx variables among the current request and its subrequests.
+ If this option is set to <code>true</code>, 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 <code>args</code>, <code>vars</code>, or <code>copy_all_vars</code> options are generally preferable instead.
+@@ -3089,7 +3116,7 @@ In addition to the two settings above, it is possible to specify
+ values for variables in the subrequest using the <code>vars</code> 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.
+
+ <geshi lang="nginx">
+@@ -3171,7 +3198,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 <code>ngx_proxy</code> 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 <code>off</code> in subrequest locations.
+
+ When the <code>body</code> option is not specified and the <code>always_forward_body</code> option is false (the default value), the <code>POST</code> and <code>PUT</code> subrequests will inherit the request bodies of the parent request (if any).
+@@ -3201,11 +3228,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 +3250,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 +3305,7 @@ The header names are matched case-insensitively.
+ <geshi lang="lua">
+ -- equivalent to ngx.header["Content-Type"] = 'text/plain'
+ ngx.header.content_type = 'text/plain';
+-
++
+ ngx.header["X-My-Header"] = 'blah blah';
+ </geshi>
+
+@@ -3295,7 +3322,7 @@ will yield
+ Set-Cookie: b=4; path=/
+ </geshi>
+
+-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 <code>Content-Type</code> that only accept a single value).
+
+@@ -3323,7 +3350,7 @@ The same applies to assigning an empty table:
+
+ Setting <code>ngx.header.HEADER</code> 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 <code>ngx.header.HEADER</code> will return the value of the response header named <code>HEADER</code>.
++Reading <code>ngx.header.HEADER</code> will return the value of the response header named <code>HEADER</code>.
+
+ Underscores (<code>_</code>) in the header names will also be replaced by dashes (<code>-</code>) and the header names will be matched case-insensitively. If the response header is not present at all, <code>nil</code> will be returned.
+
+@@ -3655,8 +3682,8 @@ Arguments without the <code>=<value></code> parts are treated as boolean argumen
+ That is, they will take Lua boolean values <code>true</code>. However, they are different from arguments taking empty string values. <code>GET /test?foo=&bar=</code> will give something like
+
+ <geshi lang="bash">
+- foo:
+- bar:
++ foo:
++ bar:
+ </geshi>
+
+ Empty key arguments are discarded. <code>GET /test?=hello&=world</code> will yield an empty output for instance.
+@@ -3760,13 +3787,13 @@ Arguments without the <code>=<value></code> parts are treated as boolean argumen
+ That is, they will take Lua boolean values <code>true</code>. However, they are different from arguments taking empty string values. <code>POST /test</code> with request body <code>foo=&bar=</code> will return something like
+
+ <geshi lang="bash">
+- foo:
+- bar:
++ foo:
++ bar:
+ </geshi>
+
+ Empty key arguments are discarded. <code>POST /test</code> with body <code>=hello&=world</code> 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 <code>max_args</code> function argument can be used to override this limit:
+
+@@ -3818,7 +3845,7 @@ the value of <code>ngx.req.get_headers()["Foo"]</code> will be a Lua (array) tab
+ {"foo", "bar", "baz"}
+ </geshi>
+
+-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 <code>max_headers</code> function argument can be used to override this limit:
+
+@@ -4164,6 +4191,7 @@ The optional <code>status</code> parameter specifies the HTTP status code to be
+
+ * <code>301</code>
+ * <code>302</code> (default)
++* <code>303</code>
+ * <code>307</code>
+
+ It is <code>302</code> (<code>ngx.HTTP_MOVED_TEMPORARILY</code>) by default.
+@@ -4367,7 +4395,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 <code>return</code> statement, i.e., <code>return ngx.exit(...)</code> 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*]], <code>ngx.exit()</code> is
+ an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use <code>return</code> in combination as suggested above.
+
+@@ -4378,14 +4406,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:
+
+ <geshi lang="nginx">
+ 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...
+ }
+ }
+@@ -5024,7 +5052,7 @@ When the <code>replace</code> is a string, then it is treated as a special templ
+
+ where <code>$0</code> referring to the whole substring matched by the pattern and <code>$1</code> 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:
+
+ <geshi lang="lua">
+ local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "${0}00")
+@@ -5343,7 +5371,7 @@ The <code>value</code> argument and <code>init</code> argument can be any valid
+
+ This method was first introduced in the <code>v0.3.1rc22</code> release.
+
+-The optional `init` parameter was first added in the <code>v0.10.6</code> release.
++The optional <code>init</code> parameter was first added in the <code>v0.10.6</code> release.
+
+ See also [[#ngx.shared.DICT|ngx.shared.DICT]].
+
+@@ -5445,7 +5473,7 @@ Fetch a list of the keys from the dictionary, up to <code><max_count></code>.
+
+ By default, only the first 1024 keys (if any) are returned. When the <code><max_count></code> argument is given the value <code>0</code>, 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 <code>v0.7.3</code> release.
+
+@@ -5724,7 +5752,7 @@ session userdata returned by a previous <code>sslhandshake</code>
+ 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
++<code>nil</code>. If this argument takes the boolean <code>false</code> 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 +5765,7 @@ also used to validate the server name specified in the server certificate sent f
+ the remote.
+
+ The optional <code>ssl_verify</code> 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 <code>true</code>, 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 +6176,7 @@ Then it will generate the output
+ 4
+ </geshi>
+
+-"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):
+
+ <geshi lang="lua">
+ -- query mysql, memcached, and a remote http service at the same time,
+@@ -6187,7 +6215,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
+ </geshi>
+
+ This API was first enabled in the <code>v0.7.0</code> release.
+@@ -6413,7 +6441,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)
+@@ -6481,8 +6509,8 @@ This directive was first introduced in the <code>v0.9.20</code> 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 <code>"http"</code>. For
++[https://github.com/openresty/stream-lua-nginx-module#readme ngx_stream_lua_module], however, this field takes the value <code>"stream"</code>.
+
+ This field was first introduced in the <code>0.10.1</code>.
+
+@@ -6563,7 +6591,7 @@ This API was first introduced in the <code>0.9.5</code> 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 <code>nginx.conf</code>).
+
+ This API was first introduced in the <code>0.9.20</code> release.
+
+@@ -6575,11 +6603,11 @@ This API was first introduced in the <code>0.9.20</code> 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 <code>N</code>, then this method may return a number between 0
++and <code>N - 1</code> (inclusive).
+
+ This function returns meaningful values only for NGINX 1.9.1+. With earlier versions of NGINX, it
+-always returns `nil`.
++always returns <code>nil</code>.
+
+ See also [[#ngx.worker.count|ngx.worker.count]].
+
+diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h
+index 3737149..b0df5ae 100644
+--- a/src/api/ngx_http_lua_api.h
++++ b/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 10008
+
+
+ typedef struct {
+diff --git a/src/ngx_http_lua_api.c b/src/ngx_http_lua_api.c
+index b72c707..7b590e7 100644
+--- a/src/ngx_http_lua_api.c
++++ b/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/src/ngx_http_lua_args.c b/src/ngx_http_lua_args.c
+index 0c307d6..b43697c 100644
+--- a/src/ngx_http_lua_args.c
++++ b/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/src/ngx_http_lua_balancer.c b/src/ngx_http_lua_balancer.c
+index 0adf787..03d9eac 100644
+--- a/src/ngx_http_lua_balancer.c
++++ b/src/ngx_http_lua_balancer.c
+@@ -640,7 +640,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 +681,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/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h
+index 267952b..f37d776 100644
+--- a/src/ngx_http_lua_common.h
++++ b/src/ngx_http_lua_common.h
+@@ -138,7 +138,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 {
+@@ -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_control.c b/src/ngx_http_lua_control.c
+index 249d763..ae36505 100644
+--- a/src/ngx_http_lua_control.c
++++ b/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/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c
+index 0af56f6..6700ce8 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) {
+@@ -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/src/ngx_http_lua_headers.h b/src/ngx_http_lua_headers.h
+index 39f1114..ee4d21c 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 6e93c8e..72f934d 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);
+@@ -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);
+
+@@ -592,13 +585,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 +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
+
+@@ -730,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");
+
+@@ -955,7 +952,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 +964,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 +1264,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/src/ngx_http_lua_semaphore.c b/src/ngx_http_lua_semaphore.c
+index 8a3f832..604d943 100644
+--- a/src/ngx_http_lua_semaphore.c
++++ b/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) {
+diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c
+index 6db6e2d..4981116 100644
+--- a/src/ngx_http_lua_socket_tcp.c
++++ b/src/ngx_http_lua_socket_tcp.c
+@@ -501,6 +501,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 +1214,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 +1334,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);
+diff --git a/src/ngx_http_lua_ssl.h b/src/ngx_http_lua_ssl.h
+index 7a245ff..acb8c4b 100644
+--- a/src/ngx_http_lua_ssl.h
++++ b/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/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c
+index aca4735..84e3093 100644
+--- a/src/ngx_http_lua_ssl_certby.c
++++ b/src/ngx_http_lua_ssl_certby.c
+@@ -1129,7 +1129,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/t/000--init.t b/t/000--init.t
+index 364334f..ad2d70e 100644
+--- a/t/000--init.t
++++ b/t/000--init.t
+@@ -84,4 +84,3 @@ GET /flush
+ --- timeout: 10
+ --- no_error_log
+ [error]
+-
+diff --git a/t/000-sanity.t b/t/000-sanity.t
+index 3f66752..87854ef 100644
+--- a/t/000-sanity.t
++++ b/t/000-sanity.t
+@@ -31,4 +31,3 @@ GET /lua
+ GET /lua
+ --- response_body
+ helloworld
+-
+diff --git a/t/001-set.t b/t/001-set.t
+index 2295a2d..ba8f22c 100644
+--- a/t/001-set.t
++++ b/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/t/002-content.t b/t/002-content.t
+index e6cb62d..3f2460e 100644
+--- a/t/002-content.t
++++ b/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/t/003-errors.t b/t/003-errors.t
+index 764300a..ad3a506 100644
+--- a/t/003-errors.t
++++ b/t/003-errors.t
+@@ -126,4 +126,3 @@ GET /main
+ GET /main
+ --- response_body
+ 500
+-
+diff --git a/t/004-require.t b/t/004-require.t
+index 3250b2f..ec74116 100644
+--- a/t/004-require.t
++++ b/t/004-require.t
+@@ -208,4 +208,3 @@ GET /ndk
+ GET /ndk
+ --- response_body
+ %20
+-
+diff --git a/t/005-exit.t b/t/005-exit.t
+index 781531f..a5a28b3 100644
+--- a/t/005-exit.t
++++ b/t/005-exit.t
+@@ -723,4 +723,3 @@ GET /t
+ --- response_body
+ --- no_error_log
+ [error]
+-
+diff --git a/t/006-escape.t b/t/006-escape.t
+index 7b26bba..0fb67a3 100644
+--- a/t/006-escape.t
++++ b/t/006-escape.t
+@@ -180,4 +180,3 @@ GET /t
+ GET /t
+ --- response_body
+ [32]
+-
+diff --git a/t/007-md5.t b/t/007-md5.t
+index 501e3af..2ae9efb 100644
+--- a/t/007-md5.t
++++ b/t/007-md5.t
+@@ -100,4 +100,3 @@ d41d8cd98f00b204e9800998ecf8427e
+ GET /md5
+ --- response_body
+ 6c8349cc7260ae62e3b1396831a8398f
+-
+diff --git a/t/008-today.t b/t/008-today.t
+index 54bd949..ec2f433 100644
+--- a/t/008-today.t
++++ b/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/t/009-log.t b/t/009-log.t
+index 0c6a9a5..68c057f 100644
+--- a/t/009-log.t
++++ b/t/009-log.t
+@@ -542,4 +542,3 @@ ok
+ [error]
+ --- error_log eval
+ "2: hello\0world, client: "
+-
+diff --git a/t/010-request_body.t b/t/010-request_body.t
+index 2640a54..e669d94 100644
+--- a/t/010-request_body.t
++++ b/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/t/012-now.t b/t/012-now.t
+index abcb735..5885187 100644
+--- a/t/012-now.t
++++ b/t/012-now.t
+@@ -116,4 +116,3 @@ GET /time
+ --- request
+ GET /time
+ --- response_body_like: ^\d{10,}(\.\d{1,3})?$
+-
+diff --git a/t/014-bugs.t b/t/014-bugs.t
+index 44337e3..9aadff0 100644
+--- a/t/014-bugs.t
++++ b/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/t/016-resp-header.t b/t/016-resp-header.t
+index 179b411..1fae292 100644
+--- a/t/016-resp-header.t
++++ b/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/t/017-exec.t b/t/017-exec.t
+index 4c7a918..535c4ab 100644
+--- a/t/017-exec.t
++++ b/t/017-exec.t
+@@ -572,4 +572,3 @@ hello, bah
+ ["dummy", "dummy"]
+ --- no_error_log
+ [error]
+-
+diff --git a/t/018-ndk.t b/t/018-ndk.t
+index d68306b..1429377 100644
+--- a/t/018-ndk.t
++++ b/t/018-ndk.t
+@@ -171,4 +171,3 @@ ok
+ foo = a b
+ --- no_error_log
+ [error]
+-
+diff --git a/t/019-const.t b/t/019-const.t
+index fe79bfb..4f9c764 100644
+--- a/t/019-const.t
++++ b/t/019-const.t
+@@ -44,4 +44,3 @@ GET /read
+ GET /read
+ --- response_body
+ 504
+-
+diff --git a/t/021-cookie-time.t b/t/021-cookie-time.t
+index c00bbea..b05e401 100644
+--- a/t/021-cookie-time.t
++++ b/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/t/022-redirect.t b/t/022-redirect.t
+index 57c7add..fae39e3 100644
+--- a/t/022-redirect.t
++++ b/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/t/023-rewrite/client-abort.t b/t/023-rewrite/client-abort.t
+index e970802..117d17e 100644
+--- a/t/023-rewrite/client-abort.t
++++ b/t/023-rewrite/client-abort.t
+@@ -848,4 +848,3 @@ delete thread 1
+ --- no_error_log
+ [error]
+ [alert]
+-
+diff --git a/t/023-rewrite/exec.t b/t/023-rewrite/exec.t
+index a063b5b..bd97968 100644
+--- a/t/023-rewrite/exec.t
++++ b/t/023-rewrite/exec.t
+@@ -376,4 +376,3 @@ ngx.exec("@proxy")
+ GET /main
+ --- response_body
+ hello, bah
+-
+diff --git a/t/023-rewrite/exit.t b/t/023-rewrite/exit.t
+index 9d292f7..39ea5cb 100644
+--- a/t/023-rewrite/exit.t
++++ b/t/023-rewrite/exit.t
+@@ -595,4 +595,3 @@ F(ngx_http_send_header) {
+ --- error_code: 204
+ --- no_error_log
+ [error]
+-
+diff --git a/t/023-rewrite/mixed.t b/t/023-rewrite/mixed.t
+index 1156567..0f742b2 100644
+--- a/t/023-rewrite/mixed.t
++++ b/t/023-rewrite/mixed.t
+@@ -167,4 +167,3 @@ world\x03\x04\xff
+ hello\x00\x01\x02
+ world\x03\x04\xff
+ "
+-
+diff --git a/t/023-rewrite/multi-capture.t b/t/023-rewrite/multi-capture.t
+index 44629b0..083ec78 100644
+--- a/t/023-rewrite/multi-capture.t
++++ b/t/023-rewrite/multi-capture.t
+@@ -392,4 +392,3 @@ res4.status = 201
+ res4.body = STORED\r
+
+ "
+-
+diff --git a/t/023-rewrite/on-abort.t b/t/023-rewrite/on-abort.t
+index aca2ab6..336b7ce 100644
+--- a/t/023-rewrite/on-abort.t
++++ b/t/023-rewrite/on-abort.t
+@@ -654,4 +654,3 @@ delete thread 2
+
+ --- no_error_log
+ [error]
+-
+diff --git a/t/023-rewrite/redirect.t b/t/023-rewrite/redirect.t
+index 8843f1a..99f3fd4 100644
+--- a/t/023-rewrite/redirect.t
++++ b/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/t/023-rewrite/req-body.t b/t/023-rewrite/req-body.t
+index 2f42e0a..13bdcb2 100644
+--- a/t/023-rewrite/req-body.t
++++ b/t/023-rewrite/req-body.t
+@@ -221,4 +221,3 @@ hiya, world"]
+ --- no_error_log
+ [error]
+ [alert]
+-
+diff --git a/t/023-rewrite/req-socket.t b/t/023-rewrite/req-socket.t
+index 34aedaa..87cbbbe 100644
+--- a/t/023-rewrite/req-socket.t
++++ b/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/t/023-rewrite/request_body.t b/t/023-rewrite/request_body.t
+index 0594001..b867d3a 100644
+--- a/t/023-rewrite/request_body.t
++++ b/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/t/023-rewrite/sanity.t b/t/023-rewrite/sanity.t
+index 20b00e2..b90aa0e 100644
+--- a/t/023-rewrite/sanity.t
++++ b/t/023-rewrite/sanity.t
+@@ -799,4 +799,3 @@ test
+ test
+ --- no_error_log
+ [alert]
+-
+diff --git a/t/023-rewrite/sleep.t b/t/023-rewrite/sleep.t
+index 1719784..8d4c2da 100644
+--- a/t/023-rewrite/sleep.t
++++ b/t/023-rewrite/sleep.t
+@@ -219,4 +219,3 @@ hello world
+ hello world
+ --- no_error_log
+ [error]
+-
+diff --git a/t/023-rewrite/socket-keepalive.t b/t/023-rewrite/socket-keepalive.t
+index 50de0b3..489a70f 100644
+--- a/t/023-rewrite/socket-keepalive.t
++++ b/t/023-rewrite/socket-keepalive.t
+@@ -1007,4 +1007,3 @@ Not found, dear...
+ --- error_code: 404
+ --- no_error_log
+ [error]
+-
+diff --git a/t/023-rewrite/subrequest.t b/t/023-rewrite/subrequest.t
+index a307388..5d1e8f0 100644
+--- a/t/023-rewrite/subrequest.t
++++ b/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/t/023-rewrite/tcp-socket-timeout.t b/t/023-rewrite/tcp-socket-timeout.t
+index 79cd0b9..15bec7f 100644
+--- a/t/023-rewrite/tcp-socket-timeout.t
++++ b/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/t/023-rewrite/tcp-socket.t b/t/023-rewrite/tcp-socket.t
+index cf9d80a..bff69a5 100644
+--- a/t/023-rewrite/tcp-socket.t
++++ b/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/t/023-rewrite/unix-socket.t b/t/023-rewrite/unix-socket.t
+index 098dd67..8a5f000 100644
+--- a/t/023-rewrite/unix-socket.t
++++ b/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/t/023-rewrite/uthread-redirect.t b/t/023-rewrite/uthread-redirect.t
+index 0f125e0..83de1a3 100644
+--- a/t/023-rewrite/uthread-redirect.t
++++ b/t/023-rewrite/uthread-redirect.t
+@@ -186,4 +186,3 @@ free request
+ --- error_code: 302
+ --- no_error_log
+ [error]
+-
+diff --git a/t/023-rewrite/uthread-spawn.t b/t/023-rewrite/uthread-spawn.t
+index 58af7d0..5552107 100644
+--- a/t/023-rewrite/uthread-spawn.t
++++ b/t/023-rewrite/uthread-spawn.t
+@@ -1449,4 +1449,3 @@ status: 204
+ --- no_error_log
+ [error]
+ --- timeout: 3
+-
+diff --git a/t/024-access/auth.t b/t/024-access/auth.t
+index 5da09cb..56e9862 100644
+--- a/t/024-access/auth.t
++++ b/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/t/024-access/client-abort.t b/t/024-access/client-abort.t
+index a94f822..c16f4ea 100644
+--- a/t/024-access/client-abort.t
++++ b/t/024-access/client-abort.t
+@@ -850,4 +850,3 @@ delete thread 1
+ --- no_error_log
+ [error]
+ [alert]
+-
+diff --git a/t/024-access/exit.t b/t/024-access/exit.t
+index 8470ab9..d6d66b8 100644
+--- a/t/024-access/exit.t
++++ b/t/024-access/exit.t
+@@ -545,4 +545,3 @@ Not found, dear...
+ --- response_body
+ Not found, dear...
+ --- error_code: 404
+-
+diff --git a/t/024-access/multi-capture.t b/t/024-access/multi-capture.t
+index 368d401..930b74d 100644
+--- a/t/024-access/multi-capture.t
++++ b/t/024-access/multi-capture.t
+@@ -392,4 +392,3 @@ res4.status = 201
+ res4.body = STORED\r
+
+ "
+-
+diff --git a/t/024-access/on-abort.t b/t/024-access/on-abort.t
+index 0c17b55..5bb948b 100644
+--- a/t/024-access/on-abort.t
++++ b/t/024-access/on-abort.t
+@@ -649,4 +649,3 @@ delete thread 2
+
+ --- no_error_log
+ [error]
+-
+diff --git a/t/024-access/redirect.t b/t/024-access/redirect.t
+index c7ce512..b45fac7 100644
+--- a/t/024-access/redirect.t
++++ b/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/t/024-access/req-body.t b/t/024-access/req-body.t
+index fd33aff..70db85c 100644
+--- a/t/024-access/req-body.t
++++ b/t/024-access/req-body.t
+@@ -218,4 +218,3 @@ hiya, world"]
+ --- no_error_log
+ [error]
+ [alert]
+-
+diff --git a/t/024-access/request_body.t b/t/024-access/request_body.t
+index a6fead2..fa03195 100644
+--- a/t/024-access/request_body.t
++++ b/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/t/024-access/sanity.t b/t/024-access/sanity.t
+index de63a68..7ff177f 100644
+--- a/t/024-access/sanity.t
++++ b/t/024-access/sanity.t
+@@ -741,4 +741,3 @@ test
+ test
+ --- no_error_log
+ [alert]
+-
+diff --git a/t/024-access/satisfy.t b/t/024-access/satisfy.t
+index 10d3ece..7902f49 100644
+--- a/t/024-access/satisfy.t
++++ b/t/024-access/satisfy.t
+@@ -209,4 +209,3 @@ something important
+ --- error_code: 200
+ --- no_error_log
+ [error]
+-
+diff --git a/t/024-access/sleep.t b/t/024-access/sleep.t
+index 2eb0822..fc1fc02 100644
+--- a/t/024-access/sleep.t
++++ b/t/024-access/sleep.t
+@@ -219,4 +219,3 @@ hello world
+ hello world
+ --- no_error_log
+ [error]
+-
+diff --git a/t/024-access/subrequest.t b/t/024-access/subrequest.t
+index bfe96d6..b6ccf11 100644
+--- a/t/024-access/subrequest.t
++++ b/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/t/024-access/uthread-exec.t b/t/024-access/uthread-exec.t
+index d7c2321..7add3d4 100644
+--- a/t/024-access/uthread-exec.t
++++ b/t/024-access/uthread-exec.t
+@@ -344,4 +344,3 @@ free request
+ end
+ --- error_log
+ attempt to abort with pending subrequests
+-
+diff --git a/t/024-access/uthread-exit.t b/t/024-access/uthread-exit.t
+index da4a9db..7c146ae 100644
+--- a/t/024-access/uthread-exit.t
++++ b/t/024-access/uthread-exit.t
+@@ -1311,4 +1311,3 @@ free request
+ end
+ --- error_log
+ attempt to abort with pending subrequests
+-
+diff --git a/t/024-access/uthread-redirect.t b/t/024-access/uthread-redirect.t
+index 8b030ac..4eb4759 100644
+--- a/t/024-access/uthread-redirect.t
++++ b/t/024-access/uthread-redirect.t
+@@ -187,4 +187,3 @@ free request
+ --- error_code: 302
+ --- no_error_log
+ [error]
+-
+diff --git a/t/024-access/uthread-spawn.t b/t/024-access/uthread-spawn.t
+index 415e4c0..7c7ba3b 100644
+--- a/t/024-access/uthread-spawn.t
++++ b/t/024-access/uthread-spawn.t
+@@ -1116,4 +1116,3 @@ body: hello world)$
+
+ --- no_error_log
+ [error]
+-
+diff --git a/t/025-codecache.t b/t/025-codecache.t
+index f33452a..0b02a27 100644
+--- a/t/025-codecache.t
++++ b/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/t/026-mysql.t b/t/026-mysql.t
+index e14ffb6..569f96f 100644
+--- a/t/026-mysql.t
++++ b/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/t/027-multi-capture.t b/t/027-multi-capture.t
+index 3588c69..9227fe5 100644
+--- a/t/027-multi-capture.t
++++ b/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/t/029-http-time.t b/t/029-http-time.t
+index 71a7758..ecef492 100644
+--- a/t/029-http-time.t
++++ b/t/029-http-time.t
+@@ -85,4 +85,3 @@ GET /lua
+ GET /lua
+ --- response_body
+ nil
+-
+diff --git a/t/030-uri-args.t b/t/030-uri-args.t
+index 8ee8401..30d66d0 100644
+--- a/t/030-uri-args.t
++++ b/t/030-uri-args.t
+@@ -1389,4 +1389,3 @@ GET /lua
+ GET /foo?world
+ --- response_body_like
+ ^HTTP/1.0 (a=3&b|b&a=3)$
+-
+diff --git a/t/031-post-args.t b/t/031-post-args.t
+index c2b6b8f..62c88c1 100644
+--- a/t/031-post-args.t
++++ b/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/t/032-iolist.t b/t/032-iolist.t
+index ddf3d7f..3c56032 100644
+--- a/t/032-iolist.t
++++ b/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/t/033-ctx.t b/t/033-ctx.t
+index eefb216..8fc50aa 100644
+--- a/t/033-ctx.t
++++ b/t/033-ctx.t
+@@ -440,4 +440,3 @@ lua release ngx.ctx at ref
+ --- response_body
+ --- no_error_log
+ [error]
+-
+diff --git a/t/034-match.t b/t/034-match.t
+index 35149f1..ebe5762 100644
+--- a/t/034-match.t
++++ b/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/t/035-gmatch.t b/t/035-gmatch.t
+index 69b9512..5b63ae4 100644
+--- a/t/035-gmatch.t
++++ b/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/t/036-sub.t b/t/036-sub.t
+index f08c50f..2b4b075 100644
+--- a/t/036-sub.t
++++ b/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/t/037-gsub.t b/t/037-gsub.t
+index 2a1e00f..4c5810d 100644
+--- a/t/037-gsub.t
++++ b/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/t/038-match-o.t b/t/038-match-o.t
+index 628e27f..d61ff1f 100644
+--- a/t/038-match-o.t
++++ b/t/038-match-o.t
+@@ -740,4 +740,3 @@ false
+ hello
+ false
+ false
+-
+diff --git a/t/039-sub-o.t b/t/039-sub-o.t
+index a861b6c..580a671 100644
+--- a/t/039-sub-o.t
++++ b/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/t/040-gsub-o.t b/t/040-gsub-o.t
+index 90619b0..5347266 100644
+--- a/t/040-gsub-o.t
++++ b/t/040-gsub-o.t
+@@ -198,4 +198,3 @@ hello, world
+ --- response_body
+ [hello,h], [world,w]
+ 2
+-
+diff --git a/t/041-header-filter.t b/t/041-header-filter.t
+index 553ee43..9cca3b7 100644
+--- a/t/041-header-filter.t
++++ b/t/041-header-filter.t
+@@ -790,4 +790,3 @@ GET /t
+ --- error_code: 302
+ --- no_error_log
+ [error]
+-
+diff --git a/t/042-crc32.t b/t/042-crc32.t
+index 86d9201..73aa1f4 100644
+--- a/t/042-crc32.t
++++ b/t/042-crc32.t
+@@ -54,4 +54,3 @@ GET /test
+ GET /test
+ --- response_body
+ 0
+-
+diff --git a/t/045-ngx-var.t b/t/045-ngx-var.t
+index 8f2dcb3..b5fcc81 100644
+--- a/t/045-ngx-var.t
++++ b/t/045-ngx-var.t
+@@ -226,4 +226,3 @@ GET /test?hello
+ --- error_log
+ variable "query_string" not changeable
+ --- error_code: 500
+-
+diff --git a/t/046-hmac.t b/t/046-hmac.t
+index 686b479..32e222b 100644
+--- a/t/046-hmac.t
++++ b/t/046-hmac.t
+@@ -29,4 +29,3 @@ __DATA__
+ GET /lua
+ --- response_body
+ R/pvxzHC4NLtj7S+kXFg/NePTmk=
+-
+diff --git a/t/047-match-jit.t b/t/047-match-jit.t
+index 077ebb6..2417a63 100644
+--- a/t/047-match-jit.t
++++ b/t/047-match-jit.t
+@@ -212,4 +212,3 @@ end
+ GET /re
+ --- response_body
+ failed to match
+-
+diff --git a/t/048-match-dfa.t b/t/048-match-dfa.t
+index 8a0a328..28b5a60 100644
+--- a/t/048-match-dfa.t
++++ b/t/048-match-dfa.t
+@@ -207,4 +207,3 @@ exec opts: 0
+ 你
+ --- no_error_log
+ [error]
+-
+diff --git a/t/049-gmatch-jit.t b/t/049-gmatch-jit.t
+index 614c440..5134d52 100644
+--- a/t/049-gmatch-jit.t
++++ b/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/t/051-sub-jit.t b/t/051-sub-jit.t
+index 789e897..c8a49c0 100644
+--- a/t/051-sub-jit.t
++++ b/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/t/053-gsub-jit.t b/t/053-gsub-jit.t
+index 3a2a1aa..3efc0a2 100644
+--- a/t/053-gsub-jit.t
++++ b/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/t/055-subreq-vars.t b/t/055-subreq-vars.t
+index 2fc6960..eb5e24d 100644
+--- a/t/055-subreq-vars.t
++++ b/t/055-subreq-vars.t
+@@ -336,4 +336,3 @@ dog = hiya
+ cat = 56
+ parent dog: blah
+ parent cat: foo
+-
+diff --git a/t/056-flush.t b/t/056-flush.t
+index d189cd5..6b697a4 100644
+--- a/t/056-flush.t
++++ b/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/t/057-flush-timeout.t b/t/057-flush-timeout.t
+index d6e0f86..a046539 100644
+--- a/t/057-flush-timeout.t
++++ b/t/057-flush-timeout.t
+@@ -318,4 +318,3 @@ qr/failed to flush: client aborted/,
+ --- timeout: 0.2
+ --- abort
+ --- wait: 1
+-
+diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t
+index acf69f0..1ee113b 100644
+--- a/t/058-tcp-socket.t
++++ b/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/t/060-lua-memcached.t b/t/060-lua-memcached.t
+index e1ebb92..0751238 100644
+--- a/t/060-lua-memcached.t
++++ b/t/060-lua-memcached.t
+@@ -166,4 +166,3 @@ some_key: hello 1234
+ [error]
+ --- error_log
+ lua reuse free buf memory
+-
+diff --git a/t/061-lua-redis.t b/t/061-lua-redis.t
+index d7b1876..ebfa6d1 100644
+--- a/t/061-lua-redis.t
++++ b/t/061-lua-redis.t
+@@ -182,4 +182,3 @@ abort: function
+ msg type: nil
+ --- no_error_log
+ [error]
+-
+diff --git a/t/063-abort.t b/t/063-abort.t
+index c112ee1..411a07e 100644
+--- a/t/063-abort.t
++++ b/t/063-abort.t
+@@ -1017,4 +1017,3 @@ foo
+ --- no_error_log
+ [error]
+ --- timeout: 2
+-
+diff --git a/t/064-pcall.t b/t/064-pcall.t
+index cf90a07..3011f3e 100644
+--- a/t/064-pcall.t
++++ b/t/064-pcall.t
+@@ -104,4 +104,3 @@ $/
+
+ --- no_error_log
+ [error]
+-
+diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t
+index ec79891..212766e 100644
+--- a/t/065-tcp-socket-timeout.t
++++ b/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/t/066-socket-receiveuntil.t b/t/066-socket-receiveuntil.t
+index 3bf5229..ffe74aa 100644
+--- a/t/066-socket-receiveuntil.t
++++ b/t/066-socket-receiveuntil.t
+@@ -1329,4 +1329,3 @@ this exposed a memory leak in receiveuntil
+ ok
+ --- no_error_log
+ [error]
+-
+diff --git a/t/067-req-socket.t b/t/067-req-socket.t
+index 30a653a..229d5cc 100644
+--- a/t/067-req-socket.t
++++ b/t/067-req-socket.t
+@@ -1096,4 +1096,3 @@ done
+ --- grep_error_log_out
+ lua finalize socket
+ GC cycle done
+-
+diff --git a/t/069-null.t b/t/069-null.t
+index 7761c91..e4c26af 100644
+--- a/t/069-null.t
++++ b/t/069-null.t
+@@ -93,4 +93,3 @@ done
+ ngx.null: null
+ --- no_error_log
+ [error]
+-
+diff --git a/t/071-idle-socket.t b/t/071-idle-socket.t
+index 55d25c6..c9002be 100644
+--- a/t/071-idle-socket.t
++++ b/t/071-idle-socket.t
+@@ -431,4 +431,3 @@ failed to set keepalive: unread data in buffer
+ }
+ --- no_error_log
+ [error]
+-
+diff --git a/t/072-conditional-get.t b/t/072-conditional-get.t
+index 4bb567a..7cf2dcd 100644
+--- a/t/072-conditional-get.t
++++ b/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/t/073-backtrace.t b/t/073-backtrace.t
+index aae4bae..6c54692 100644
+--- a/t/073-backtrace.t
++++ b/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/t/074-prefix-var.t b/t/074-prefix-var.t
+index 3cc4587..c116d84 100644
+--- a/t/074-prefix-var.t
++++ b/t/074-prefix-var.t
+@@ -64,4 +64,3 @@ GET /t
+ Greetings from module foo.
+ --- no_error_log
+ [error]
+-
+diff --git a/t/075-logby.t b/t/075-logby.t
+index f987c8e..520c62e 100644
+--- a/t/075-logby.t
++++ b/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/t/077-sleep.t b/t/077-sleep.t
+index a7c251a..7d295c2 100644
+--- a/t/077-sleep.t
++++ b/t/077-sleep.t
+@@ -404,4 +404,3 @@ ok
+ --- no_error_log
+ [error]
+ [alert]
+-
+diff --git a/t/078-hup-vars.t b/t/078-hup-vars.t
+index 8acc346..5072c4d 100644
+--- a/t/078-hup-vars.t
++++ b/t/078-hup-vars.t
+@@ -62,4 +62,3 @@ GET /t
+ localhost
+ --- no_error_log
+ [error]
+-
+diff --git a/t/079-unused-directives.t b/t/079-unused-directives.t
+index cba0e41..aacd0d3 100644
+--- a/t/079-unused-directives.t
++++ b/t/079-unused-directives.t
+@@ -340,4 +340,3 @@ GET /t
+ sub: sub
+ --- no_error_log
+ [error]
+-
+diff --git a/t/080-hup-shdict.t b/t/080-hup-shdict.t
+index f9a0278..c762556 100644
+--- a/t/080-hup-shdict.t
++++ b/t/080-hup-shdict.t
+@@ -82,4 +82,3 @@ GET /test
+ 10502 number
+ --- no_error_log
+ [error]
+-
+diff --git a/t/083-bad-sock-self.t b/t/083-bad-sock-self.t
+index b93849f..7a76752 100644
+--- a/t/083-bad-sock-self.t
++++ b/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/t/084-inclusive-receiveuntil.t b/t/084-inclusive-receiveuntil.t
+index c966015..f7d5d3d 100644
+--- a/t/084-inclusive-receiveuntil.t
++++ b/t/084-inclusive-receiveuntil.t
+@@ -743,4 +743,3 @@ close: 1 nil
+ }
+ --- no_error_log
+ [error]
+-
+diff --git a/t/085-if.t b/t/085-if.t
+index e08b43c..33f57ca 100644
+--- a/t/085-if.t
++++ b/t/085-if.t
+@@ -198,4 +198,3 @@ GET /proxy-pass-uri
+ --- response_body_like: It works!
+ --- no_error_log
+ [error]
+-
+diff --git a/t/086-init-by.t b/t/086-init-by.t
+index 3a474fe..bea34a4 100644
+--- a/t/086-init-by.t
++++ b/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/t/087-udp-socket.t b/t/087-udp-socket.t
+index 79ba452..a847031 100644
+--- a/t/087-udp-socket.t
++++ b/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/t/088-req-method.t b/t/088-req-method.t
+index 9ced40c..198b3b3 100644
+--- a/t/088-req-method.t
++++ b/t/088-req-method.t
+@@ -262,4 +262,3 @@ method: PATCH
+ method: TRACE
+ --- no_error_log
+ [error]
+-
+diff --git a/t/089-phase.t b/t/089-phase.t
+index 57921fc..94b7619 100644
+--- a/t/089-phase.t
++++ b/t/089-phase.t
+@@ -176,4 +176,3 @@ GET /lua
+ init_worker
+ --- no_error_log
+ [error]
+-
+diff --git a/t/090-log-socket-errors.t b/t/090-log-socket-errors.t
+index a5943c2..8e498cd 100644
+--- a/t/090-log-socket-errors.t
++++ b/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/t/091-coroutine.t b/t/091-coroutine.t
+index b047ccb..bceb512 100644
+--- a/t/091-coroutine.t
++++ b/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/t/092-eof.t b/t/092-eof.t
+index a75711f..86778de 100644
+--- a/t/092-eof.t
++++ b/t/092-eof.t
+@@ -80,4 +80,3 @@ GET /t
+ --- error_log
+ hello, tom
+ hello, jim
+-
+diff --git a/t/093-uthread-spawn.t b/t/093-uthread-spawn.t
+index 772e866..b622d30 100644
+--- a/t/093-uthread-spawn.t
++++ b/t/093-uthread-spawn.t
+@@ -1672,4 +1672,3 @@ delete thread 2
+ f
+ --- no_error_log
+ [error]
+-
+diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t
+index cd678c0..a623773 100644
+--- a/t/094-uthread-exit.t
++++ b/t/094-uthread-exit.t
+@@ -1648,4 +1648,3 @@ free request
+ [alert]
+ [error]
+ [warn]
+-
+diff --git a/t/095-uthread-exec.t b/t/095-uthread-exec.t
+index 4459360..56156c4 100644
+--- a/t/095-uthread-exec.t
++++ b/t/095-uthread-exec.t
+@@ -423,4 +423,3 @@ attempt to abort with pending subrequests
+ --- no_error_log
+ [alert]
+ [warn]
+-
+diff --git a/t/096-uthread-redirect.t b/t/096-uthread-redirect.t
+index b0258fb..003c642 100644
+--- a/t/096-uthread-redirect.t
++++ b/t/096-uthread-redirect.t
+@@ -277,4 +277,3 @@ attempt to abort with pending subrequests
+ --- no_error_log
+ [alert]
+ [warn]
+-
+diff --git a/t/097-uthread-rewrite.t b/t/097-uthread-rewrite.t
+index 178a374..a93adc8 100644
+--- a/t/097-uthread-rewrite.t
++++ b/t/097-uthread-rewrite.t
+@@ -344,4 +344,3 @@ free request
+ end
+ --- error_log
+ attempt to abort with pending subrequests
+-
+diff --git a/t/098-uthread-wait.t b/t/098-uthread-wait.t
+index aaf020a..4948596 100644
+--- a/t/098-uthread-wait.t
++++ b/t/098-uthread-wait.t
+@@ -1321,4 +1321,3 @@ $s;
+ --- no_error_log
+ [error]
+ [alert]
+-
+diff --git a/t/100-client-abort.t b/t/100-client-abort.t
+index cd46859..89c1f6a 100644
+--- a/t/100-client-abort.t
++++ b/t/100-client-abort.t
+@@ -1064,4 +1064,3 @@ GET /t
+ eof succeeded
+ --- error_log
+ eof failed: nginx output filter error
+-
+diff --git a/t/101-on-abort.t b/t/101-on-abort.t
+index 81cec78..182d12c 100644
+--- a/t/101-on-abort.t
++++ b/t/101-on-abort.t
+@@ -846,4 +846,3 @@ done
+ client prematurely closed connection
+ on abort called
+ main handler done
+-
+diff --git a/t/102-req-start-time.t b/t/102-req-start-time.t
+index 1d5fe28..3b041af 100644
+--- a/t/102-req-start-time.t
++++ b/t/102-req-start-time.t
+@@ -113,4 +113,3 @@ true$
+ --- no_error_log
+ [error]
+ --- SKIP
+-
+diff --git a/t/103-req-http-ver.t b/t/103-req-http-ver.t
+index 6ded75a..e6de238 100644
+--- a/t/103-req-http-ver.t
++++ b/t/103-req-http-ver.t
+@@ -46,4 +46,3 @@ GET /t HTTP/1.0
+ 1
+ --- no_error_log
+ [error]
+-
+diff --git a/t/104-req-raw-header.t b/t/104-req-raw-header.t
+index 439b9de..efea03c 100644
+--- a/t/104-req-raw-header.t
++++ b/t/104-req-raw-header.t
+@@ -876,4 +876,3 @@ Foo: bar\r
+ --- no_error_log
+ [error]
+ --- timeout: 5
+-
+diff --git a/t/105-pressure.t b/t/105-pressure.t
+index 10f495e..9d1ba1f 100644
+--- a/t/105-pressure.t
++++ b/t/105-pressure.t
+@@ -51,4 +51,3 @@ $::Id = int rand 10000;
+
+ --- no_error_log
+ [error]
+-
+diff --git a/t/106-timer.t b/t/106-timer.t
+index d0f6f36..04a532e 100644
+--- a/t/106-timer.t
++++ b/t/106-timer.t
+@@ -2193,4 +2193,3 @@ ok
+ --- error_log
+ Bad bad bad
+ --- skip_nginx: 4: < 1.7.1
+-
+diff --git a/t/107-timer-errors.t b/t/107-timer-errors.t
+index 9ed1334..3201612 100644
+--- a/t/107-timer-errors.t
++++ b/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/t/108-timer-safe.t b/t/108-timer-safe.t
+index 19c9f6d..2795998 100644
+--- a/t/108-timer-safe.t
++++ b/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/t/109-timer-hup.t b/t/109-timer-hup.t
+index 15aaa0e..0864046 100644
+--- a/t/109-timer-hup.t
++++ b/t/109-timer-hup.t
+@@ -500,4 +500,3 @@ ok
+ --- grep_error_log_out
+ lua found 8191 pending timers
+ --- timeout: 20
+-
+diff --git a/t/110-etag.t b/t/110-etag.t
+index 351fec4..0a94d3d 100644
+--- a/t/110-etag.t
++++ b/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/t/111-req-header-ua.t b/t/111-req-header-ua.t
+index 7c980d0..9e501e3 100644
+--- a/t/111-req-header-ua.t
++++ b/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/t/112-req-header-conn.t b/t/112-req-header-conn.t
+index 51df730..51bc8a4 100644
+--- a/t/112-req-header-conn.t
++++ b/t/112-req-header-conn.t
+@@ -146,4 +146,3 @@ content: conn type: 0
+ connection: bad
+ --- no_error_log
+ [error]
+-
+diff --git a/t/113-req-header-cookie.t b/t/113-req-header-cookie.t
+index b26b709..4a93053 100644
+--- a/t/113-req-header-cookie.t
++++ b/t/113-req-header-cookie.t
+@@ -247,4 +247,3 @@ Cookie: boo=123; foo=bar
+
+ --- no_error_log
+ [error]
+-
+diff --git a/t/115-quote-sql-str.t b/t/115-quote-sql-str.t
+index 0c20dfb..66553b1 100644
+--- a/t/115-quote-sql-str.t
++++ b/t/115-quote-sql-str.t
+@@ -74,4 +74,3 @@ GET /set
+ 'a\Zb\Z'
+ --- no_error_log
+ [error]
+-
+diff --git a/t/116-raw-req-socket.t b/t/116-raw-req-socket.t
+index 6518f0e..ab06ee4 100644
+--- a/t/116-raw-req-socket.t
++++ b/t/116-raw-req-socket.t
+@@ -876,4 +876,3 @@ request body: hey, hello world
+ --- no_error_log
+ [error]
+ [alert]
+-
+diff --git a/t/117-raw-req-socket-timeout.t b/t/117-raw-req-socket-timeout.t
+index 4e3929b..07abadc 100644
+--- a/t/117-raw-req-socket-timeout.t
++++ b/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/t/119-config-prefix.t b/t/119-config-prefix.t
+index 4581aa1..3f79320 100644
+--- a/t/119-config-prefix.t
++++ b/t/119-config-prefix.t
+@@ -30,4 +30,3 @@ GET /lua
+ ^prefix: \/\S+$
+ --- no_error_log
+ [error]
+-
+diff --git a/t/120-re-find.t b/t/120-re-find.t
+index 34c0207..73e6134 100644
+--- a/t/120-re-find.t
++++ b/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/t/121-version.t b/t/121-version.t
+index 2b7a306..9000eb3 100644
+--- a/t/121-version.t
++++ b/t/121-version.t
+@@ -46,4 +46,3 @@ GET /lua
+ ^version: \d+$
+ --- no_error_log
+ [error]
+-
+diff --git a/t/122-worker.t b/t/122-worker.t
+index fa42b1d..b74c81f 100644
+--- a/t/122-worker.t
++++ b/t/122-worker.t
+@@ -79,4 +79,3 @@ worker pid: \d+
+ worker pid is correct\.
+ --- no_error_log
+ [error]
+-
+diff --git a/t/123-lua-path.t b/t/123-lua-path.t
+index da97909..23681a9 100644
+--- a/t/123-lua-path.t
++++ b/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/t/124-init-worker.t b/t/124-init-worker.t
+index d6ea675..22a943e 100644
+--- a/t/124-init-worker.t
++++ b/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/t/125-configure-args.t b/t/125-configure-args.t
+index adec129..4160d4e 100644
+--- a/t/125-configure-args.t
++++ b/t/125-configure-args.t
+@@ -29,4 +29,3 @@ GET /configure_args
+ ^\s*\-\-[^-]+
+ --- no_error_log
+ [error]
+-
+diff --git a/t/126-shdict-frag.t b/t/126-shdict-frag.t
+index 94422fb..5a2aff8 100644
+--- a/t/126-shdict-frag.t
++++ b/t/126-shdict-frag.t
+@@ -1264,4 +1264,3 @@ ok
+ --- no_error_log
+ [error]
+ --- timeout: 60
+-
+diff --git a/t/127-uthread-kill.t b/t/127-uthread-kill.t
+index 2ab8abe..cc43c62 100644
+--- a/t/127-uthread-kill.t
++++ b/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/t/128-duplex-tcp-socket.t b/t/128-duplex-tcp-socket.t
+index d3ef3f5..e8434a3 100644
+--- a/t/128-duplex-tcp-socket.t
++++ b/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/t/129-ssl-socket.t b/t/129-ssl-socket.t
+index 9da9a5c..726b442 100644
+--- a/t/129-ssl-socket.t
++++ b/t/129-ssl-socket.t
+@@ -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;
+@@ -202,7 +202,7 @@ 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;
+@@ -280,7 +280,7 @@ SSL reused session
+ === TEST 4: ssl session reuse
+ --- 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;
+@@ -374,7 +374,7 @@ lua ssl free session
+ The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.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 {
+@@ -453,7 +453,7 @@ SSL reused session
+ The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.org".
+ --- config
+ server_tokens off;
+- resolver $TEST_NGINX_RESOLVER;
++ resolver $TEST_NGINX_RESOLVER ipv6=off;
+ lua_ssl_trusted_certificate ../html/trusted.crt;
+ lua_socket_log_errors off;
+ lua_ssl_verify_depth 2;
+@@ -532,7 +532,7 @@ SSL reused session
+ === TEST 7: certificate does not match host name (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;
+@@ -611,7 +611,7 @@ SSL reused session
+ === TEST 8: iscribblet.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 {
+@@ -696,7 +696,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 {
+@@ -774,7 +774,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;
+@@ -1033,7 +1033,7 @@ SSL reused session
+ === TEST 13: iscribblet.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 {
+@@ -1119,7 +1119,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;
+@@ -1198,7 +1198,7 @@ SSL reused session
+ === TEST 15: explicit cipher configuration
+ --- config
+ server_tokens off;
+- resolver $TEST_NGINX_RESOLVER;
++ resolver $TEST_NGINX_RESOLVER ipv6=off;
+ lua_ssl_ciphers RC4-SHA;
+ location /t {
+ #set $port 5000;
+@@ -1278,7 +1278,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;
+@@ -1358,7 +1358,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 {
+@@ -1435,7 +1435,7 @@ SSL reused session
+ === TEST 18: iscribblet.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 {
+@@ -1512,7 +1512,7 @@ SSL reused session
+ === TEST 19: iscribblet.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 {
+@@ -1592,7 +1592,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 {
+@@ -1647,7 +1647,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 +1750,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 +1854,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 +1946,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 +2031,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;
+@@ -2115,7 +2115,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;
+@@ -2183,7 +2183,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 +2254,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 +2328,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 +2405,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 +2510,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 +2589,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;
+@@ -2614,7 +2614,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/t/130-internal-api.t b/t/130-internal-api.t
+index d641ab5..eba0980 100644
+--- a/t/130-internal-api.t
++++ b/t/130-internal-api.t
+@@ -47,4 +47,3 @@ content req=0x[a-f0-9]{4,}
+ $
+ --- no_error_log
+ [error]
+-
+diff --git a/t/137-req-misc.t b/t/137-req-misc.t
+index 20ada3c..d56f80e 100644
+--- a/t/137-req-misc.t
++++ b/t/137-req-misc.t
+@@ -59,4 +59,3 @@ not internal
+ GET /test
+ --- response_body
+ internal
+-
+diff --git a/t/138-balancer.t b/t/138-balancer.t
+index 8d45c24..fc26173 100644
+--- a/t/138-balancer.t
++++ b/t/138-balancer.t
+@@ -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/t/140-ssl-c-api.t b/t/140-ssl-c-api.t
+index 44ad93d..854ff30 100644
+--- a/t/140-ssl-c-api.t
++++ b/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
+@@ -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
+diff --git a/t/141-luajit.t b/t/141-luajit.t
+index be03fe3..36418d1 100644
+--- a/t/141-luajit.t
++++ b/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/t/142-ssl-session-store.t b/t/142-ssl-session-store.t
+index 5c9fad3..73b6e19 100644
+--- a/t/142-ssl-session-store.t
++++ b/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/t/143-ssl-session-fetch.t b/t/143-ssl-session-fetch.t
+index bd800ff..701ead7 100644
+--- a/t/143-ssl-session-fetch.t
++++ b/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/t/146-malloc-trim.t b/t/146-malloc-trim.t
+index 45fb9f2..fc425ce 100644
+--- a/t/146-malloc-trim.t
++++ b/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/t/147-tcp-socket-timeouts.t b/t/147-tcp-socket-timeouts.t
+index 52f015a..0689a9b 100644
+--- a/t/147-tcp-socket-timeouts.t
++++ b/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/t/150-fake-delayed-load.t b/t/150-fake-delayed-load.t
+new file mode 100644
+index 0000000..232bbf3
+--- /dev/null
++++ b/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/t/151-initby-hup.t b/t/151-initby-hup.t
+new file mode 100644
+index 0000000..f278867
+--- /dev/null
++++ b/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/t/data/fake-delayed-load-module/config b/t/data/fake-delayed-load-module/config
+new file mode 100644
+index 0000000..a5fa6fb
+--- /dev/null
++++ b/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/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c b/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c
+new file mode 100644
+index 0000000..2898255
+--- /dev/null
++++ b/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 <ngx_config.h>
++#include <ngx_core.h>
++#include <ngx_http.h>
++#include <nginx.h>
++
++
++#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/t/data/fake-module/ngx_http_fake_module.c b/t/data/fake-module/ngx_http_fake_module.c
+index 42cde55..650f4f7 100644
+--- a/t/data/fake-module/ngx_http_fake_module.c
++++ b/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/util/build.sh b/util/build.sh
+index 7887fe9..e45c00a 100755
+--- a/util/build.sh
++++ b/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/util/reindex b/util/reindex
+index bd54c9d..d0a0927 100755
+--- a/util/reindex
++++ b/util/reindex
+@@ -1,8 +1,7 @@
+-#!/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
++#!/usr/bin/env perl
++
++#: reindexes .t files for Test::Base based test files
++#: Copyright (c) Yichun Zhang
+
+ use strict;
+ use warnings;
+@@ -44,7 +43,9 @@ sub reindex {
+ push @lines, $_;
+ }
+ close $in;
++
+ my $text = join '', @lines;
++ $text =~ s/\n\n+\z/\n/sm;
+ $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;
+diff --git a/valgrind.suppress b/valgrind.suppress
+index fe161e8..d0bcc56 100644
+--- a/valgrind.suppress
++++ b/valgrind.suppress
+@@ -149,3 +149,18 @@ fun:main
+ fun:__libc_res_nquerydomain
+ fun:__libc_res_nsearch
+ }
++{
++ <insert_a_suppression_name_here>
++ Memcheck:Leak
++ match-leak-kinds: definite
++ fun:malloc
++ fun:ngx_alloc
++ fun:ngx_set_environment
++ fun:ngx_single_process_cycle
++ fun:main
++}
++{
++ <insert_a_suppression_name_here>
++ Memcheck:Cond
++ obj:*
++}
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..b7b515b 100644
--- a/debian/modules/patches/nginx-lua/openssl-1.1.0.patch
+++ b/debian/modules/patches/nginx-lua/openssl-1.1.0.patch
@@ -935,7 +935,7 @@
@@ -1199,7 +1199,7 @@ SSL reused session
--- config
server_tokens off;
- resolver $TEST_NGINX_RESOLVER;
+ resolver $TEST_NGINX_RESOLVER ipv6=off;
- lua_ssl_ciphers RC4-SHA;
+ lua_ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256;
location /t {
diff --git a/debian/modules/patches/nginx-lua/series b/debian/modules/patches/nginx-lua/series
index ed0d540..cb106b4 100644
--- a/debian/modules/patches/nginx-lua/series
+++ b/debian/modules/patches/nginx-lua/series
@@ -1 +1,2 @@
+lua-update.patch
openssl-1.1.0.patch
--
To view, visit https://gerrit.wikimedia.org/r/350178
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I1a82df8da0d0fe8b1dc3612eff19a7996434491e
Gerrit-PatchSet: 1
Gerrit-Project: operations/software/nginx
Gerrit-Branch: wmf-1.11.10
Gerrit-Owner: BBlack <***@wikimedia.org>